Files
discord-rich-presence-plugin/README.md

120 lines
5.5 KiB
Markdown

# Discord Rich Presence Plugin
This plugin integrates Navidrome with Discord Rich Presence, displaying your currently playing track in your Discord status. It demonstrates how a Navidrome plugin can maintain real-time connections to external services while remaining completely stateless. Based on the [Navicord](https://github.com/logixism/navicord) project.
**⚠️ WARNING: This plugin requires storing Discord user tokens, which may violate Discord's Terms of Service. Use at your own risk.**
## Features
- Shows currently playing track with title, artist, and album art
- Displays playback progress with start/end timestamps
- Automatic presence clearing when track finishes
- Multi-user support with individual Discord tokens
## How It Works
### Plugin Capabilities
The plugin implements three Navidrome capabilities:
| Capability | Purpose |
|-----------------------|------------------------------------------------------------------------------|
| **Scrobbler** | Receives `NowPlaying` events when users start playing tracks |
| **WebSocketCallback** | Handles incoming Discord gateway messages (heartbeat ACKs, sequence numbers) |
| **SchedulerCallback** | Processes scheduled events for heartbeats and presence clearing |
### Host Services
| Service | Usage |
|---------------|---------------------------------------------------------------------|
| **HTTP** | Discord API calls (gateway discovery, external assets registration) |
| **WebSocket** | Persistent connection to Discord gateway |
| **Cache** | Sequence numbers, processed image URLs |
| **Scheduler** | Recurring heartbeats, one-time presence clearing |
| **Artwork** | Track artwork public URL resolution |
### Flow
1. **Track starts playing** - Navidrome calls `NowPlaying`
2. **Plugin connects** - If not already connected, establishes WebSocket to Discord gateway
3. **Authentication** - Sends identify payload with user's Discord token
4. **Presence update** - Sends activity with track info and processed artwork URL
5. **Heartbeat loop** - Recurring scheduler sends heartbeats every 41 seconds to keep connection alive
6. **Track ends** - One-time scheduler callback clears presence and disconnects
### Stateless Design
Navidrome plugins are stateless - each call creates a fresh instance. This plugin handles that by:
- **WebSocket connections**: Managed by host, keyed by username
- **Sequence numbers**: Stored in cache for heartbeat messages
- **Configuration**: Reloaded on every method call
- **Artwork URLs**: Cached after processing through Discord's external assets API
### Image Processing
Discord requires images to be registered via their external assets API. The plugin:
1. Fetches track artwork URL from Navidrome
2. Registers it with Discord's API to get an `mp:` prefixed URL
3. Caches the result (4 hours for track art, 48 hours for default image)
4. Falls back to a default image if artwork is unavailable
### Files
| File | Description |
|--------------------------------|------------------------------------------------------------------------|
| [main.go](main.go) | Plugin entry point, scrobbler and scheduler implementations |
| [rpc.go](rpc.go) | Discord gateway communication, WebSocket handling, activity management |
| [manifest.json](manifest.json) | Plugin metadata and permission declarations |
| [Makefile](Makefile) | Build automation |
## Configuration
Configure via the Navidrome UI under **Settings > Plugins > Discord Rich Presence**:
| Field | Description |
|---------------|-----------------------------------------------------------------------------------------------------------------|
| **Client ID** | Your Discord Application ID (create at [Discord Developer Portal](https://discord.com/developers/applications)) |
| **Users** | Array of username/token pairs mapping Navidrome users to Discord tokens |
## Building
Although the plugin can be compiled to WebAssembly with standard Go, it is recommended to use
[TinyGo](https://tinygo.org/getting-started/install/) for smaller binary size.
```sh
# Run tests
make test
# Build plugin.wasm
make build
# Create distributable plugin package
make package
```
The `make package` command creates `discord-rich-presence.ndp` containing the compiled WebAssembly module and manifest.
### Manual build:
```sh
tinygo build -target wasip1 -buildmode=c-shared -o plugin.wasm -scheduler=none .
zip discord-rich-presence.ndp plugin.wasm manifest.json
```
### Using standard Go:
```sh
GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o plugin.wasm .
zip discord-rich-presence.ndp plugin.wasm manifest.json
```
## Installation
1. Copy the `discord-rich-presence.ndp` file to your Navidrome plugins folder (default is `plugins/` under the Navidrome data directory).
2. Configure the plugin in **Settings > Plugins > Discord Rich Presence**
3. Enable the plugin
There is no need to restart Navidrome; Check the logs for any errors during initialization.