Navidrome Plugin Examples

This folder contains example plugins demonstrating various capabilities and languages supported by Navidrome's plugin system.

Available Examples

Plugin Language Capabilities Description
minimal Go MetadataAgent Basic plugin structure
wikimedia Go MetadataAgent Wikidata/Wikipedia metadata
crypto-ticker Go Scheduler, WebSocket, Cache Real-time crypto prices (demo)
discord-rich-presence Go Scrobbler, Scheduler, WebSocket, Cache, Artwork Discord integration
coverartarchive-py Python MetadataAgent Cover Art Archive
nowplaying-py Python Scheduler, SubsonicAPI Now playing logger
webhook-rs Rust Scrobbler HTTP webhook on scrobble
library-inspector Rust Library, Scheduler Periodic library stats logging

Building

Prerequisites

  • Go plugins: TinyGo 0.30+
  • Python plugins: extism-py
  • Rust plugins: Rust with wasm32-unknown-unknown target

Build All (Go plugins)

make all

Build Individual Plugin

make minimal.wasm
make wikimedia.wasm
make discord-rich-presence.wasm

Clean

make clean

Testing Plugins

With Extism CLI

Test any plugin without running Navidrome:

# Install: https://extism.org/docs/install

# Test manifest
extism call minimal.wasm nd_manifest --wasi

# Test with input
extism call minimal.wasm nd_get_artist_biography --wasi \
  --input '{"id":"1","name":"The Beatles"}'

For plugins that make HTTP requests, allow the hosts:

extism call wikimedia.wasm nd_get_artist_biography --wasi \
  --input '{"id":"1","name":"Yussef Dayes"}' \
  --allow-host "query.wikidata.org" \
  --allow-host "en.wikipedia.org"

With Navidrome

  1. Copy the .wasm file to your plugins folder
  2. Enable plugins in navidrome.toml:
    [Plugins]
    Enabled = true
    Folder = "/path/to/plugins"
    
  3. For metadata agents, add to your agents list:
    Agents = "lastfm,spotify,wikimedia"
    

Creating Your Own Plugin

Option 1: Start from Minimal

Copy the minimal example and modify:

cp -r minimal my-plugin
cd my-plugin
# Edit main.go
tinygo build -o my-plugin.wasm -target wasip1 -buildmode=c-shared .

Option 2: Bootstrap with XTP CLI

Generate boilerplate from a schema:

# Install XTP: https://docs.xtp.dylibso.com/docs/cli

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

Available schemas in ../schemas/:

  • metadata_agent.yaml Artist/album metadata
  • scrobbler.yaml Scrobbling integration
  • lifecycle.yaml Init callbacks
  • scheduler_callback.yaml Scheduled tasks
  • websocket_callback.yaml WebSocket events

Option 3: Different Language

See language-specific examples:

Example Breakdown

Minimal (Go)

The simplest possible plugin. Shows:

  • Manifest export
  • Single capability function
  • Basic input/output handling

Wikimedia (Go)

Real-world metadata agent. Shows:

  • HTTP requests to external APIs
  • SPARQL queries (Wikidata)
  • Error handling
  • Host allowlisting

Discord Rich Presence (Go)

Complex multi-capability plugin. Shows:

  • Scrobbler Receives play events
  • WebSocket Maintains Discord gateway connection
  • Scheduler Heartbeat and timeout management
  • Cache Connection state storage
  • Artwork Getting album art URLs

Cover Art Archive (Python)

Python metadata agent. Shows:

  • extism-py plugin structure
  • HTTP requests
  • JSON handling

Webhook (Rust)

Rust scrobbler. Shows:

  • extism-rs plugin structure
  • HTTP POST requests
  • Minimal dependencies

Resources