mirror of
https://github.com/navidrome/navidrome.git
synced 2026-01-12 16:58:09 -05:00
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-rs | Rust | Library, Scheduler | Periodic library stats logging |
| discord-rich-presence-rs | Rust | Scrobbler, Scheduler, WebSocket, Cache, Artwork | Discord integration (Rust) |
Building
Prerequisites
- Go plugins: TinyGo 0.30+
- Python plugins: extism-py
- Rust plugins: Rust with
wasm32-unknown-unknowntarget
Build All Plugins
make all
This creates .ndp package files for each plugin.
Build Individual Plugin
make minimal.ndp
make wikimedia.ndp
make discord-rich-presence.ndp
Clean
make clean
Testing Plugins
With Extism CLI
Test any plugin without running Navidrome. First extract the .wasm file from the .ndp package:
# 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:
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
- Copy the
.ndpfile to your plugins folder - Enable plugins in
navidrome.toml:[Plugins] Enabled = true Folder = "/path/to/plugins" - 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 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:
# 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 metadatascrobbler.yaml– Scrobbling integrationlifecycle.yaml– Init callbacksscheduler_callback.yaml– Scheduled taskswebsocket_callback.yaml– WebSocket events
Option 3: Different Language
See language-specific examples:
- Python: coverartarchive-py
- Rust: webhook-rs
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