Deluan Quintão f1e75c40dc
feat(plugins): add JSONForms-based plugin configuration UI (#4911)
* feat(plugins): add JSONForms schema for plugin configuration

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: enhance error handling by formatting validation errors with field names

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: enforce required fields in config validation and improve error handling

Signed-off-by: Deluan <deluan@navidrome.org>

* format JS code

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: add config schema validation and enhance manifest structure

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: refactor plugin config parsing and add unit tests

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: add config validation error message in Portuguese

* feat: enhance AlwaysExpandedArrayLayout with description support and improve array control testing

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: update Discord Rust plugin configuration to use JSONForm for user tokens and enhance schema validation

Signed-off-by: Deluan <deluan@navidrome.org>

* fix: resolve React Hooks linting issues in plugin UI components

* Apply suggestions from code review

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* format code

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: migrate schema validation to use santhosh-tekuri/jsonschema and improve error formatting

Signed-off-by: Deluan <deluan@navidrome.org>

* address PR comments

Signed-off-by: Deluan <deluan@navidrome.org>

* fix flaky test

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: enhance array layout and configuration handling with AJV defaults

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: implement custom tester to exclude enum arrays from AlwaysExpandedArrayLayout

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: add error boundary for schema rendering and improve error messages

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: refine non-enum array control logic by utilizing JSONForms schema resolution

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: add error styling to ToggleEnabledSwitch for disabled state

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: adjust label positioning and styling in SchemaConfigEditor for improved layout

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: implement outlined input controls renderers to replace custom fragile CSS

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: remove margin from last form control inside array items for better spacing

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: enhance AJV error handling to transform required errors for field-level validation

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: set default value for User Tokens in manifest.json to improve user experience

Signed-off-by: Deluan <deluan@navidrome.org>

* format

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: add margin to outlined input controls for improved spacing

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: remove redundant margin rule for last form control in array items

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: adjust font size of label elements in SchemaConfigEditor for improved readability

Signed-off-by: Deluan <deluan@navidrome.org>

---------

Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-01-19 20:51:00 -05:00
..

Crypto Ticker Plugin

This is a WebSocket-based WASM plugin for Navidrome that displays real-time cryptocurrency prices from Coinbase.

Features

  • Connects to Coinbase WebSocket API to receive real-time ticker updates
  • Configurable to track multiple cryptocurrency pairs
  • Implements WebSocket callback handlers for message processing
  • Automatically reconnects on connection loss using the scheduler service
  • Displays price, best bid, best ask, and 24-hour percentage change

Configuration

Configure in the Navidrome UI (Settings → Plugins → crypto-ticker):

Key Description Default
tickers Comma-separated list of cryptocurrency symbols (e.g., BTC,ETH,SOL) BTC,ETH

The plugin will append -USD to any symbol without a trading pair specified.

How it Works

  1. On plugin initialization, connects to Coinbase's WebSocket API
  2. Subscribes to ticker updates for the configured cryptocurrencies
  3. Incoming ticker data is processed via nd_websocket_on_text_message callback
  4. On connection loss, schedules a reconnection attempt via the scheduler service
  5. Reconnection is attempted until successful

Building

To build the plugin and package as .ndp:

# Using TinyGo (recommended - smaller binary)
tinygo build -o plugin.wasm -target wasip1 -buildmode=c-shared .
zip -j crypto-ticker.ndp manifest.json plugin.wasm

Or from the plugins/examples/ directory:

make crypto-ticker.ndp

Installation

Copy the resulting crypto-ticker.ndp to your Navidrome plugins folder.

Example Output

[Crypto] Crypto Ticker Plugin initializing...
[Crypto] Configured tickers: [BTC-USD ETH-USD]
[Crypto] Connected to Coinbase WebSocket API (connection: crypto-ticker-conn)
[Crypto] Subscription message sent to Coinbase WebSocket API
[Crypto] Received subscriptions message
[Crypto] 💰 BTC-USD: $98765.43 (24h: +2.35%) Bid: $98764.00 Ask: $98766.00
[Crypto] 💰 ETH-USD: $3456.78 (24h: -0.54%) Bid: $3455.90 Ask: $3457.80

Permissions Required

  • config: Read ticker symbols configuration
  • websocket: Connect to ws-feed.exchange.coinbase.com
  • scheduler: Schedule reconnection attempts

Files

  • main.go - Main plugin implementation
  • go.mod - Go module file

PDK

This plugin imports the Navidrome PDK subpackages directly:

import (
    "github.com/navidrome/navidrome/plugins/pdk/go/host"
    "github.com/navidrome/navidrome/plugins/pdk/go/lifecycle"
    "github.com/navidrome/navidrome/plugins/pdk/go/scheduler"
    "github.com/navidrome/navidrome/plugins/pdk/go/websocket"
)

The go.mod file uses replace directives to point to the local packages for development.


For more details, see the source code in main.go.