Deluan aa83d3af6c docs: update READMEs
Signed-off-by: Deluan <deluan@navidrome.org>
2025-12-31 17:06:30 -05:00

4.7 KiB
Raw Blame History

Navidrome Plugin Schemas

This directory contains XTP schemas that define plugin capabilities. Use these schemas to bootstrap new plugins with the xtp CLI.

Available Schemas

Schema Description
metadata_agent.yaml Artist/album metadata retrieval
scrobbler.yaml Scrobbling to external services
lifecycle.yaml Plugin initialization callback
scheduler_callback.yaml Scheduled task callbacks
websocket_callback.yaml WebSocket event callbacks

Prerequisites

Install the XTP CLI:

curl -fsSL https://static.dylibso.com/cli/install.sh | bash

Or see XTP CLI documentation for other methods.

Bootstrapping a Plugin

Basic Usage

xtp plugin init \
  --schema-file <schema> \
  --template <language> \
  --path <output-dir> \
  --name <plugin-name>

Supported Languages

  • go Go (recommended, use with TinyGo)
  • rust Rust
  • typescript TypeScript
  • python Python
  • csharp C#
  • zig Zig
  • cpp C++

Examples

Go metadata agent:

xtp plugin init \
  --schema-file plugins/schemas/metadata_agent.yaml \
  --template go \
  --path ./my-agent \
  --name my-agent

Rust scrobbler:

xtp plugin init \
  --schema-file plugins/schemas/scrobbler.yaml \
  --template rust \
  --path ./my-scrobbler \
  --name my-scrobbler

TypeScript scrobbler:

xtp plugin init \
  --schema-file plugins/schemas/scrobbler.yaml \
  --template typescript \
  --path ./ts-scrobbler \
  --name ts-scrobbler

Generated Files

After running xtp plugin init, you'll get:

my-plugin/
├── main.go          # Plugin implementation (stubs)
├── pdk.gen.go       # Generated types from schema
├── xtp.toml         # Plugin configuration
└── go.mod           # Go module (for Go plugins)

Implementing Your Plugin

1. Add the Manifest

Every plugin must implement nd_manifest. This is not in the schemas—add it manually:

import (
    "encoding/json"
    "github.com/extism/go-pdk"
)

type Manifest struct {
    Name        string       `json:"name"`
    Author      string       `json:"author"`
    Version     string       `json:"version"`
    Description string       `json:"description,omitempty"`
    Website     string       `json:"website,omitempty"`
    Permissions *Permissions `json:"permissions,omitempty"`
}

//go:wasmexport nd_manifest
func ndManifest() int32 {
    manifest := Manifest{
        Name:        "My Plugin",
        Author:      "Your Name",
        Version:     "1.0.0",
        Description: "What this plugin does",
    }
    out, _ := json.Marshal(manifest)
    pdk.Output(out)
    return 0
}

2. Implement Capability Functions

Replace the generated panic() stubs with your implementation:

// Generated stub:
func NdGetArtistBiography(input ArtistInput) (BiographyOutput, error) {
    panic("not implemented")
}

// Your implementation:
func NdGetArtistBiography(input ArtistInput) (BiographyOutput, error) {
    bio := fetchBiography(input.Name)
    return BiographyOutput{Biography: bio}, nil
}

3. Remove Unused Functions

You don't need to implement all functions from a schema. Delete any you don't need—Navidrome only calls functions that exist.

4. Build

xtp plugin build

Or manually with TinyGo:

tinygo build -o my-plugin.wasm -target wasip1 -buildmode=c-shared .

Combining Capabilities

A single plugin can implement multiple capabilities. Generate from one schema, then manually add functions from others:

# Start with metadata agent
xtp plugin init --schema-file metadata_agent.yaml --template go --path ./my-plugin --name my-plugin

# Manually add scrobbler functions from scrobbler.yaml
# Manually add scheduler callback from scheduler_callback.yaml

Or combine schemas manually before generating (advanced).

Schema Format

These schemas use XTP Schema v1-draft format, which extends JSON Schema with plugin-specific extensions for exports and imports.

Resources