Back to Navidrome

Navidrome Plugin Examples

plugins/examples/README.md

0.61.25.3 KB
Original Source

Navidrome Plugin Examples

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

Available Examples

PluginLanguageCapabilitiesDescription
minimalGoMetadataAgentBasic plugin structure
wikimediaGoMetadataAgentWikidata/Wikipedia metadata
crypto-tickerGoScheduler, WebSocket, CacheReal-time crypto prices (demo)
coverartarchive-pyPythonMetadataAgentCover Art Archive
nowplaying-pyPythonScheduler, SubsonicAPINow playing logger
webhook-rsRustScrobblerHTTP webhook on scrobble
library-inspector-rsRustLibrary, SchedulerPeriodic library stats logging
discord-rich-presence-rsRustScrobbler, Scheduler, WebSocket, Cache, ArtworkDiscord integration (Rust)

Building

Prerequisites

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

Build All Plugins

bash
make all

This creates .ndp package files for each plugin.

Build Individual Plugin

bash
make minimal.ndp
make wikimedia.ndp
make discord-rich-presence-rs.ndp

Clean

bash
make clean

Testing Plugins

With Extism CLI

Test any plugin without running Navidrome. First extract the .wasm file from the .ndp package:

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

# Extract the wasm file from the package
unzip -p minimal.ndp plugin.wasm > minimal.wasm

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

For plugins that make HTTP requests, allow the hosts:

bash
unzip -p wikimedia.ndp plugin.wasm > wikimedia.wasm
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 .ndp file to your plugins folder
  2. Enable plugins in navidrome.toml:
    toml
    [Plugins]
    Enabled = true
    Folder = "/path/to/plugins"
    
  3. For metadata agents, add to your agents list:
    toml
    Agents = "lastfm,spotify,wikimedia"
    

Creating Your Own Plugin

Option 1: Start from Minimal

Copy the minimal example and modify:

bash
cp -r minimal my-plugin
cd my-plugin
# Edit main.go and manifest.json
tinygo build -o plugin.wasm -target wasip1 -buildmode=c-shared .
zip -j my-plugin.ndp manifest.json plugin.wasm

Option 2: Bootstrap with XTP CLI

Generate boilerplate from a schema:

bash
# 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

# Then create manifest.json and package
cd my-plugin
xtp plugin build
zip -j my-plugin.ndp manifest.json dist/plugin.wasm

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