Creating a Plugin

Step-by-step guide to create, build, and test your first Spotube plugin.

This guide walks through setting up a plugin project from scratch. For the full source, refer to the js_plugin_example in the Spotube repository.

Project setup

You need a Kotlin Multiplatform project targeting JS with three plugins: kotlinMultiplatform, zipline, and spotubeGradle.

Build script

The build.gradle.kts configures the JS target, declares dependencies, and tells Zipline your entry point:

plugins {
    alias(libs.plugins.kotlinMultiplatform)
    alias(libs.plugins.kotlinSerialization)
    alias(libs.plugins.zipline.gradle.plugin)
    alias(libs.plugins.spotubeGradle)
}

kotlin {
    applyDefaultHierarchyTemplate()
    js {
        browser()
        binaries.executable()
    }
    sourceSets {
        commonMain.dependencies {
            implementation("dev.krtirtho.spotube:plugin_interfaces:0.1.0")
            api(libs.zipline.core)
            api(libs.kotlinx.coroutines.core)
            api(libs.semver)
        }
    }
}

zipline {
    mainFunction.set("com.example.myplugin.main")
}

The mainFunction must match the fully qualified path to your entry point function.

Version catalog

Use gradle/libs.versions.toml to pin versions:

[versions]
kotlin = "2.3.0"
zipline = "1.13.0"

[libraries]
zipline-core = { module = "app.cash.zipline:zipline", version.ref = "zipline" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.10.1" }
semver = { module = "net.swiftzer.semver:semver", version = "1.3.0" }

[plugins]
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
zipline-gradle-plugin = { id = "app.cash.zipline.gradle.plugin", version.ref = "zipline" }
spotubeGradle = { id = "dev.krtirtho.spotube.gradle-plugin", version = "0.1.0" }

The plugin manifest

plugin.json at the project root declares what your plugin needs and provides:

{
  "name": "my-plugin",
  "version": "1.0.0",
  "description": "A brief description.",
  "apiVersion": "0.0.1",
  "author": "Your Name",
  "capabilities": ["PERSISTENT_STORAGE", "NETWORK_REQUESTS", "WEBVIEW"],
  "abilities": ["METADATA", "AUDIO", "LYRICS", "SCROBBLE"]
}
Field Description
name Plugin name (alphanumeric with hyphens or underscores)
version Semantic version
description Brief summary of what the plugin does
apiVersion Plugin API version this targets (from plugin_interfaces)
author Your name
capabilities Host APIs the plugin needs: PERSISTENT_STORAGE, NETWORK_REQUESTS, WEBVIEW
abilities What the plugin provides: METADATA, AUDIO, LYRICS, SCROBBLE

Entry point

Create src/jsMain/kotlin/com/example/myplugin/main.kt. This top-level function connects to the Zipline runtime, obtains host services, and registers your implementations. See the example's main.kt for the complete file with all imports and bindings.

Your first implementation

Start with CoreAPI - every plugin must implement it. Create a class that handles authentication state, update checks, and support text. See Architecture for the full CoreAPI reference and RealCoreAPI.kt for working code.

Building and testing

./gradlew packageDevelopmentPlugin   # → build/distributions/plugin-development.smplug
./gradlew packageProductionPlugin    # → build/distributions/plugin-production.smplug

Install the .smplug in Spotube via Settings → Metadata provider plugins → upload button or paste a URL.

Next

Once your project builds, implement the APIs your plugin supports. Start with Architecture to understand the binding model, then dive into specific API pages.