feat(plugins): New Plugin System with multi-language PDK support (#4833)
* chore(plugins): remove the old plugins system implementation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement new plugin system with using Extism
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add capability detection for plugins based on exported functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add auto-reload functionality for plugins with file watcher support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add auto-reload functionality for plugins with file watcher support
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): standardize variable names and remove superfluous wrapper functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): improve error handling and logging in plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): implement plugin function call helper and refactor MetadataAgent methods
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): race condition in plugin manager
* tests(plugins): change BeforeEach to BeforeAll in MetadataAgent tests
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(plugins): optimize tests
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(plugins): more optimizations
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): ignore goroutine leaks from notify library in tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Wikimedia plugin for Navidrome to fetch artist metadata
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance plugin logging and set User-Agent header
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement scrobbler plugin with authorization and scrobbling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): integrate logs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): clean up manifest struct and improve plugin loading logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add metadata agent and scrobbler schemas for bootstrapping plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(hostgen): add hostgen tool for generating Extism host function wrappers
- Implemented hostgen tool to generate wrappers from annotated Go interfaces.
- Added command-line flags for input/output directories and package name.
- Introduced parsing and code generation logic for host services.
- Created test data for various service interfaces and expected generated code.
- Added documentation for host services and annotations for code generation.
- Implemented SubsonicAPI service with corresponding generated code.
* feat(subsonicapi): update Call method to return JSON string response
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement SubsonicAPI host function integration with permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(generator): error-only methods in response handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate client wrappers for host functions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(generator): remove error handling for response.Error in client templates
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): add Scheduler service interface with host function wrappers for scheduling tasks
* feat(plugins): add WASI build constraints to client wrapper templates, to avoid lint errors
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): implement Scheduler service with one-time and recurring scheduling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(manifest): remove unused ConfigPermission from permissions schema
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): add scheduler callback schema and implementation for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): streamline scheduling logic and remove unused callback tracking
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): add Close method for resource cleanup on plugin unload
Signed-off-by: Deluan <deluan@navidrome.org>
* docs(scheduler): clarify SchedulerCallback requirement for scheduling functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update wasm build rule to include all Go files in the directory
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: rewrite the wikimedia plugin using the XTP CLI
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): replace uuid with id.NewRandom for schedule ID generation
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: capabilities registration
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add scheduler service isolation test for plugin instances
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update plugin manager initialization and encapsulate logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add WebSocket service definitions for plugin communication
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement WebSocket service for plugin integration and connection management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Crypto Ticker example plugin for real-time cryptocurrency price updates via Coinbase WebSocket API
Also add the lifecycle capability
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: use context.Background() in invokeCallback for scheduled tasks
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename plugin.create() to plugin.instance()
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename pluginInstance to plugin for consistency across the codebase
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: simplify schedule cloning in Close method and enhance plugin cleanup error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement Artwork service for generating artwork URLs in Navidrome plugins - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: moved public URL builders to avoid import cycles
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Cache service for in-memory TTL-based caching in plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Discord Rich Presence example plugin for Navidrome integration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: host function wrappers to use structured request and response types
- Updated the host function signatures in `nd_host_artwork.go`, `nd_host_scheduler.go`, `nd_host_subsonicapi.go`, and `nd_host_websocket.go` to accept a single parameter for JSON requests.
- Introduced structured request and response types for various cache operations in `nd_host_cache.go`.
- Modified cache functions to marshal requests to JSON and unmarshal responses, improving error handling and code clarity.
- Removed redundant memory allocation for string parameters in favor of JSON marshaling.
- Enhanced error handling in WebSocket and cache operations to return structured error responses.
* refactor: error handling in various plugins to convert response.Error to Go errors
- Updated error handling in `nd_host_scheduler.go`, `nd_host_websocket.go`, `nd_host_artwork.go`, `nd_host_cache.go`, and `nd_host_subsonicapi.go` to convert string errors from responses into Go errors.
- Removed redundant error checks in test data plugins for cleaner code.
- Ensured consistent error handling across all plugins to improve reliability and maintainability.
* refactor: rename fake plugins to test plugins for clarity in integration tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add help target to Makefile for plugin usage instructions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Cover Art Archive plugin as an example of Python plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Makefile and README to clarify Go plugin usage
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: include plugin capabilities in loading log message
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add trace logging for plugin availability and error handling in agents
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Now Playing Logger plugin to showcase calling host functions from Python plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: generate Python client wrappers for various host services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add generated host function wrappers for Scheduler and SubsonicAPI services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Python plugin documentation and usage instructions for host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Webhook Scrobbler plugin in Rust to send HTTP notifications on scrobble events
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enable parallel loading of plugins during startup
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to include WebSocket callback schema in plugin documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: extend plugin watcher with improved logging and debounce duration adjustment
Signed-off-by: Deluan <deluan@navidrome.org>
* add trace message for plugin recompiles
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement plugin cache purging functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* test: move purgeCacheBySize unit tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add plugin repository and database support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add plugin management routes and middleware
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): implement plugin synchronization with database for add, update, and remove actions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add PluginList and PluginShow components with plugin management functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): optimize plugin change detection
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins UI): improve PluginList structure
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): enhance PluginShow with author, website, and permissions display
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): refactor to use MUI and RA components
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add error handling for plugin enable/disable actions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): inject PluginManager into native API
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update GetManager to accept DataStore parameter
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add subsonicRouter to Manager and refactor host service registration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): enhance debug logging for plugin actions and recompile logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): break manager.go into smaller, focused files
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): streamline error handling and improve plugin retrieval logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update newWebSocketService to use WebSocketPermission for allowed hosts
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): introduce ToggleEnabledSwitch for managing plugin enable/disable state
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update READMEs
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): add Library service for metadata access and filesystem integration
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Library Inspector plugin for periodic library inspection and file size logging
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to reflect JSON configuration format for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(build): update target to wasm32-wasip1 for improved WASI support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement configuration management UI with key-value pairs support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): adjust grid layout in InfoRow component for improved responsiveness
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): rename ErrorIndicator to EnabledOrErrorField and enhance error handling logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(i18n): add Portuguese translations for plugin management and notifications
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add support for .ndp plugin packages and update build process
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README for .ndp plugin packaging and installation instructions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement KVStore service for persistent key-value storage
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: enhance README with Extism plugin development resources and recommendations
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): integrate event broker into plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): update config handling in PluginShow to track last record state
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Rust host function library and example implementation of Discord Rich Presence plugin in Rust
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate Rust lib.rs file to expose host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update JSON field names to camelCase for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: reduce cyclomatic complexity by refactoring main function
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance Rust code generation with typed struct support and improved type handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Go client library with host function wrappers and documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate Go client stubs for non-WASM platforms
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): update client template file names for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add initial implementation of the Navidrome Plugin Development Kit code generator - Pahse 1
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2 (2)
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 3
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 4
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 5
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): consistent naming/types across PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): streamline plugin function signatures and error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update scrobbler interface to return errors directly instead of response structs
Signed-off-by: Deluan <deluan@navidrome.org>
* test: make all test plugins use the PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize and sort type definitions for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update error handling for methods to return errors directly
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update function signatures to return values directly instead of response structs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update request/response types to use private naming conventions
Signed-off-by: Deluan <deluan@navidrome.org>
* build: mark .wasm files as intermediate for cleanup after building .ndp
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): consolidate PDK module path and update Go version to 1.25
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement Rust PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize Rust output structure to follow standard conventions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update Discord Rich Presence and Library Inspector plugins to use nd-pdk for service calls and implement lifecycle management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update macro names for websocket and metadata registration to improve clarity and consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): rename scheduler callback methods for consistency and clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update export wrappers to use `//go:wasmexport` for WebAssembly compatibility
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update plugin registration docs
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): generate host wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): conditionally run goleak checks based on CI environment
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to reflect changes in plugin import paths
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update plugin instance creation to accept context for cancellation support
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update return types in metadata interfaces to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): enhance type handling for Rust and XTP output in capability generation
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update IsAuthorized method to return boolean instead of response object
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): add unit tests for rustOutputType and isPrimitiveRustType functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement XTP JSONSchema validation for generated schemas
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update response types in testMetadataAgent methods to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update Go and Rust plugin developer sections for clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: correct example link for library inspector in README
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: clarify artwork URL generation capabilities in service descriptions
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to include Rust PDK crate information for plugin developers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: handle URL parsing errors and use atomic upsert in plugin repository
Added proper error handling for url.Parse calls in PublicURL and AbsoluteURL
functions. When parsing fails, PublicURL now falls back to AbsoluteURL, and
AbsoluteURL logs the error and returns an empty string, preventing malformed
URLs from being generated.
Replaced the non-atomic UPDATE-then-INSERT pattern in plugin repository Put
method with a single atomic INSERT ... ON CONFLICT statement. This eliminates
potential race conditions and improves consistency with the upsert pattern
already used in host_kvstore.go.
* feat: implement mock service instances for non-WASM builds using testify/mock
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: Discord RPC struct to encapsulate WebSocket logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add support for experimental WebAssembly threads
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add PDK abstraction layer with mock support for non-WASM builds
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add unit tests for Discord plugin and RPC functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update return types in minimalPlugin and wikimediaPlugin methods to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: context cancellation and implement WebSocket callback timeout for improved error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: conditionally include error handling in generated client code templates
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement ConfigService for plugin configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance plugin manager to support metrics recording
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: make MockPDK private
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update interface types to use 'any' in plugin repository methods
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename List method to Keys for clarity in configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add ndpgen plugin tests in the pipeline and update Makefile
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add users permission management to plugin system
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: streamline users integration tests and enhance plugin user management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: remove UserID from scrobbler request structure
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add integration tests for UsersService enable gate behavior
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement user permissions for SubsonicAPI and scrobbler plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: show proper error in the UI when enabling a plugin fails
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add library permission management to plugin system
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add user permission for processing scrobbles in Discord Rich Presence plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: implement dynamic loading for buffered scrobbler plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add GetAdmins method to retrieve admin users from the plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Portuguese translations for user and library permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* reorder migrations
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: remove unnecessary bulkActionButtons prop from PluginList component
* feat: add manual plugin rescan functionality and corresponding UI action
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement user/library and plugin management integration with cleanup on deletion
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: replace core mock services with test-specific implementations to avoid import cycles
* feat: add ID fields to Artist and Song structs and enhance track loading logic by prioritizing ID matches
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update plugin permissions from allowedHosts to requiredHosts for better clarity and consistency
* feat: refactor plugin host permissions to use RequiredHosts directly for improved clarity
* fix: don't record metrics for plugin calls that aren't implemented at all
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: enhance connection management with improved error handling and cleanup logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: introduce ArtistRef struct for better artist representation and update track metadata handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update user configuration handling to use user key prefix for improved clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance ConfigCard input fields with multiline support and vertical resizing
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: rust plugin compilation error
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement IsOptionPattern method for better return type handling in Rust PDK generation
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-01-14 19:22:48 -05:00
|
|
|
package capabilities
|
|
|
|
|
|
feat(plugins): share plugin DTOs via a types package (#5655)
* refactor(plugins): remove Python PDK generation from ndpgen
* feat(plugins): parse Go type aliases distinctly in ndpgen
* feat(plugins): resolve shared-type aliases against a registry in ndpgen
* fix(plugins): resolve host-service shared aliases package-wide
Mirror the capability approach in ParseDirectoryWithShared: do a first
pass over all package files to build a package-wide alias map, then pass
it into parseServiceFile so that a shared-type alias declared in a sibling
file is visible when resolving types in the service interface file.
Add a focused test that writes the alias in one file and the hostservice
in another, confirming RED before the fix and GREEN after. Also
strengthens the existing Task 3 test with an ArtistRef.Target assertion.
* feat(plugins): add ndpgen -shared-types mode for the Go types package
* feat(plugins): generate the nd-pdk-types Rust crate from -shared-types
* feat(plugins): inject types import and emit deprecated aliases in Go output
* feat(plugins): emit deprecated Rust aliases to the shared types crate
* feat(plugins): inline shared-type shapes into XTP schemas
* feat(plugins): add nd-pdk-types crate and wire dependents
* feat(plugins): move shared capability types to plugins/types with deprecated aliases
* fix(plugins): point Rust deprecated-alias note at the replacement type
* fix(plugins): include shared aliases in KnownStructs so Rust fields keep their type
Capability.KnownStructs() and Service.KnownStructs() previously only
registered names from .Structs. After the shared-types migration, types
like ArtistRef/TrackInfo/SongRef live in .SharedAliases instead, so
ToRustTypeWithStructs could not find them and fell back to serde_json::Value
for every struct field referencing a shared type.
Add the shared-alias names to the knownStructs map in both methods.
Regenerate the Rust capability files; track/song/artist fields now render
as their named types (TrackInfo, SongRef, ArtistRef, etc.).
Add a regression test that verifies a struct field whose type is only in
SharedAliases renders as the named type and not serde_json::Value.
* docs(plugins): remove stale Python references from ndpgen and plugins READMEs
ndpgen no longer has a -python flag; remove it from the usage synopsis,
flags table, and defaults note in ndpgen/README.md. Delete the "Python
Client Library" section that described its output.
plugins/README.md referenced plugins/pdk/python/host/ (deleted) as the
source for Python host-service stubs. Remove that paragraph; Python plugins
still work via the XTP-schema / extism-py path (see examples/*-py).
* refactor(plugins): dedupe ndpgen helpers and tidy shared-type codegen
* docs(plugins): restore Python as a supported XTP schema target
The ndpgen-generated Python PDK was removed, but the XTP YAML schemas are
language-neutral and the XTP CLI still generates Python bindings from them
(as the extism-py examples demonstrate). Only the ndpgen Python output was
dropped, not Python support itself.
* test(plugins): use the shared types package in test plugins
The test fixtures referenced the now-deprecated capability aliases
(sonicsimilarity.SongRef, metadata.ArtistRef/SongRef). Point them at the
canonical types package so our own fixtures don't depend on symbols slated
for removal.
* refactor(plugins): use the shared types package in host adapters
Replace deprecated capabilities.TrackInfo, capabilities.ArtistRef, and
capabilities.SongRef aliases with the canonical types.TrackInfo,
types.ArtistRef, and types.SongRef from plugins/types.
* fix(plugins): reference shared types by canonical path in generated Rust
Previously the generator emitted `pub field: SongRef` (the local deprecated
alias) for struct fields whose type came from SharedAliases. Refactored
ToRustTypeWithStructs into a private toRustType that accepts a shared map,
and added ToRustTypeWithShared which resolves shared-alias names to their
canonical nd_pdk_types::X path before falling through to the knownStructs
check. Both rustCapabilityFuncMap and rustFuncMap now build the shared map
from SharedAliases and use it for fieldRustType, so the generated capability
files reference nd_pdk_types::SongRef / nd_pdk_types::TrackInfo directly.
The deprecated pub type aliases remain in place as the external back-compat
surface. Deprecation warning count from cargo build drops to 0.
* fix(examples): implement missing Scrobbler.playback_report in Rust examples
The Scrobbler trait gained a playback_report method but the two Rust example
plugins (webhook-rs and discord-rich-presence-rs) were not updated, causing
E0046 compile errors. Added the missing fn playback_report to both: webhook-rs
logs and returns Ok(()) mirroring its now_playing handler; discord-rich-presence-rs
is a no-op since Discord presence does not need playback reports. make all-rust
now exits 0.
* refactor(plugins): point Rust deprecation notes at the nd_pdk::types umbrella path
Plugin authors depend on the nd-pdk umbrella crate, which re-exports
nd_pdk_types as 'types', so the migration target they should type is
nd_pdk::types::X. The alias target stays nd_pdk_types::X (the real path
inside nd-pdk-capabilities).
* fix(plugins): error when a shared-type alias can't be resolved against the registry
* refactor(plugins): parse each Go source file once in ndpgen
* fix(plugins): correct ndpgen review nits (flag name, unused dep, docs)
* refactor(plugins): drop the now-unused path param from parseServiceFile
* refactor(plugins): use shared types directly, rename TrackInfo to Track
Capability interfaces now reference the shared `types` package by qualified
name (types.Track, types.SongRef, types.ArtistRef) instead of the package-local
deprecated aliases, and the shared TrackInfo type is renamed to Track to match
its role as the plugin-facing projection of a library media file.
The deprecated bare aliases (scrobbler.TrackInfo, metadata.ArtistRef,
sonicsimilarity.SongRef, etc.) are kept as re-exports so existing plugins keep
compiling, with a deprecation warning steering them to the canonical types.
To support this, ndpgen now resolves qualified types.X references: it collects
them during type discovery, maps each used canonical type back to its declared
deprecated alias for re-export, emits nd_pdk_types::X paths in Rust, and names
the XTP schema components by their canonical type. Regenerated the Go and Rust
PDK and the XTP schemas, and added generator tests covering the qualified-ref
path. Also adds clarifying doc comments to the shared types.
* refactor(plugins): extract shared types selector into a named const
Replace the "types." string literal that detects and strips the shared types
package selector with a single sharedTypesPrefix constant across the ndpgen
generator (parser, types, generator, xtp_schema), giving the package one source
of truth for the selector.
Also restore the single reused scratch map (cleared each iteration) in the
resolveSharedAliases BFS instead of allocating a fresh map per shared-struct
field, matching the prior implementation.
Pure cleanup from a /simplify pass: regeneration produces byte-for-byte
identical Go, Rust, and XTP output.
* refactor(plugins): keep TrackInfo in the capability package for now
Move the track type back out of the shared plugins/types package: it is again
defined inline as TrackInfo in plugins/capabilities/scrobbler.go and referenced
directly by the scrobbler and lyrics capabilities, reverting the rename to
types.Track. The host helper is renamed back to mediaFileToTrackInfo and now
returns capabilities.TrackInfo. SongRef and ArtistRef stay in the shared types
package; TrackInfo keeps using types.ArtistRef for its artist lists.
This type is expected to be reshaped in upcoming work, so leaving it in the
capability package avoids churning the shared types twice. Regenerated the Go
and Rust PDK and the XTP schemas accordingly.
* fix(plugins): emit the Go types import for direct shared-type refs
ndpgen's Capability/Service.ImportsSharedTypes only reported a shared-types
dependency when a deprecated re-export alias (type X = types.X) was declared. A
struct field referencing the canonical form directly (e.g. types.SongRef) with
no such alias produced an empty SharedAliases slice, so the Go templates skipped
the import while still emitting fields/signatures using types.SongRef — leaving
generated PDK code for new shared DTOs uncompilable unless an otherwise
unnecessary alias was added.
ImportsSharedTypes now also returns true when any struct field references the
types. package by qualified name, via a new structsReferenceSharedTypes helper
that reuses collectReferencedTypes (so []types.X and map[...]types.X are covered
too).
* fix(plugins): preserve base64 encoding for shared byte fields in Rust
The Rust shared-types crate template rendered a []byte field as a plain Vec<u8>
without the base64_bytes serde override used by the capability/client templates.
Go's encoding/json serializes []byte as a base64 string, so a Rust plugin using
nd_pdk::types would have serialized an array of numbers instead of the wire
format the Go/server side expects.
GenerateSharedTypesRust now registers the base64_bytes partial and passes a
HasByteFields flag (new anyFieldIsByteSlice helper); types.rs.tmpl emits the
base64_bytes module and a #[serde(with = "base64_bytes")] attribute on []byte
fields, mirroring the capability template.
* fix(plugins): include directly-referenced shared types in XTP schemas
buildSchemas registered shared types into the schema components only by iterating
cap.SharedAliases, which records deprecated re-export aliases. A capability that
referenced a shared DTO solely as types.Foo (no declared alias) therefore never
got Foo into the component set, so the self-contained XTP schema rendered the
field as a generic object (or emitted a dangling $ref), breaking the direct
shared-type use case enabled by -shared.
resolveSharedAliases now also returns the resolved shapes of every used shared
type (alias or not); these are carried on the new Capability.SharedTypes field
and registered by buildSchemas alongside SharedAliases. Validated end-to-end with
the xtp CLI: a direct types.Foo reference now produces a proper component plus a
$ref, so xtp generates a typed struct instead of an untyped serde_json::Map.
* fix(plugins): resolve renamed shared aliases to canonical schema refs
When a deprecated alias renames its canonical type (e.g. type TrackInfo =
types.Track) and a capability field is typed with the alias name (TrackInfo),
buildProperty emitted a $ref to #/components/schemas/TrackInfo. Components are
keyed by the canonical name (Track), so no TrackInfo component was emitted,
leaving a dangling reference that crashes the xtp code generator.
buildSchemas now builds an alias->canonical map; buildProperty (and the slice
item path) resolves $ref targets through it, and a used alias name marks its
canonical component used so it is emitted. Validated with the xtp CLI: the
renamed-alias schema previously crashed xtp and now generates cleanly.
* fix(plugins): detect shared types used directly in method signatures
ImportsSharedTypes only inspected struct fields, so a capability method using a
shared type directly in its signature (e.g. types.SongRef as input/output rather
than inside a local struct) was not detected. The generated Go templates still
rendered the provider/export signatures with types.SongRef, so the capability
package omitted the types import and failed to compile; the same gap applied to
service params/returns.
ImportsSharedTypes now also scans capability method input/output types and
service method params/returns, via a typeReferencesSharedTypes helper that reuses
collectReferencedTypes (covering pointer/slice/map wrappers).
* fix(plugins): add base64 dependency to the shared Rust types crate
When a shared DTO has a []byte field, ndpgen emits the base64_bytes serde helper
and use base64::... imports into nd-pdk-types/src/lib.rs, but the crate manifest
declared only serde. In that case make gen produced a crate that failed to
compile with 'unresolved module base64'.
Add base64 = "0.22" (matching nd-pdk-capabilities) so the generated shared types
crate compiles whenever a []byte field is present. Verified by generating a
shared crate with a []byte field and confirming cargo check fails before and
passes after.
* fix(plugins): translate shared method types in generated Rust
A capability method using a shared DTO directly as input/output (e.g.
types.SongRef) was passed through rustOutputType unchanged, so the Rust template
emitted invalid trait and extism_pdk::Json<$crate::pkg::types.SongRef> signatures
that do not compile.
Method input/output types now resolve through the shared registry: trait
signatures use rustTraitType (shared -> nd_pdk_types::X, locals stay bare) and the
export macros use rustMethodType (fully qualified: shared -> nd_pdk_types::X,
primitives -> Rust, locals -> $crate::<pkg>::X). Verified end-to-end by compiling
a generated capability that takes types.SongRef directly against the real
nd-pdk-types crate.
* fix(plugins): canonicalize XTP export refs for renamed shared aliases
buildSchemas canonicalized alias-to-canonical references for struct-field $ref
targets, but buildExport built export input/output $refs straight from
fieldBaseType. A capability whose export used a renamed deprecated alias
directly (e.g. type TrackInfo = types.Track with NowPlaying(TrackInfo)) emitted
$ref: #/components/schemas/TrackInfo, while the component is emitted under the
canonical name Track — a dangling export reference.
Lift the alias-to-canonical map into GenerateSchema (buildAliasToCanonical) and
apply it to export refs via canonicalRefName, the same resolution already used
for field properties.
* fix(plugins): route shared macro types through $crate for plugin builds
When a capability method used a shared type directly, the generated export macro
named the type as nd_pdk_types::SongRef. The macro expands in the downstream
plugin crate, which depends on the umbrella nd-pdk crate and not on nd-pdk-types
directly, so that path is unresolvable there and the plugin fails to build.
rustMethodType (macro-facing) now emits $crate::types::X, and the generated
nd-pdk-capabilities lib.rs re-exports nd_pdk_types as types so $crate resolves
it. Trait signatures keep nd_pdk_types::X since they live in nd-pdk-capabilities,
which has the direct dependency. Verified end-to-end: a plugin crate depending
only on the umbrella that uses a capability with a direct types.X method now
compiles via the macro.
* fix(plugins): add nd-pdk-types dependency to the Rust host crate
When a host service uses a shared type, ndpgen emits nd_pdk_types::X into the
generated nd-pdk-host client wrappers, but the host crate's manifest did not
depend on nd-pdk-types, so the crate failed to compile with 'unresolved module
nd_pdk_types'. Host client wrappers are plain functions resolved in the host
crate's own context (not macros expanded downstream), so a direct dependency is
the right fix.
Add nd-pdk-types = { path = "../nd-pdk-types" } to nd-pdk-host, mirroring
nd-pdk-capabilities. Found while auditing all Rust paths against the realistic
crate topology after the capability-side $crate fix; verified by generating a
host service with a shared-type return and confirming cargo check fails before
and passes after.
* fix(plugins): resolve shared aliases in Rust host signatures
The Rust host client rendered method params and returns through
RustTypeWithStructs, which only consults KnownStructs. A host service using a
shared alias in a signature (e.g. type Track = types.Track plus
MatchSongs(...) ([]Track, error)) therefore emitted a bare Vec<Track>, but the
client template emits no Track alias or import, so the generated nd-pdk-host
crate did not compile. Only struct fields went through the shared map.
rustType/rustParamType now use the shared map too (RustTypeWithShared /
RustParamTypeWithShared), so an aliased param/return resolves to its canonical
nd_pdk_types::X path, matching field handling. Verified by generating a host
service returning a shared alias and confirming cargo check fails before and
passes after.
2026-06-29 21:20:33 -04:00
|
|
|
import "github.com/navidrome/navidrome/plugins/types"
|
|
|
|
|
|
feat(plugins): New Plugin System with multi-language PDK support (#4833)
* chore(plugins): remove the old plugins system implementation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement new plugin system with using Extism
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add capability detection for plugins based on exported functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add auto-reload functionality for plugins with file watcher support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add auto-reload functionality for plugins with file watcher support
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): standardize variable names and remove superfluous wrapper functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): improve error handling and logging in plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): implement plugin function call helper and refactor MetadataAgent methods
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): race condition in plugin manager
* tests(plugins): change BeforeEach to BeforeAll in MetadataAgent tests
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(plugins): optimize tests
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(plugins): more optimizations
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): ignore goroutine leaks from notify library in tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Wikimedia plugin for Navidrome to fetch artist metadata
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance plugin logging and set User-Agent header
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement scrobbler plugin with authorization and scrobbling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): integrate logs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): clean up manifest struct and improve plugin loading logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add metadata agent and scrobbler schemas for bootstrapping plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(hostgen): add hostgen tool for generating Extism host function wrappers
- Implemented hostgen tool to generate wrappers from annotated Go interfaces.
- Added command-line flags for input/output directories and package name.
- Introduced parsing and code generation logic for host services.
- Created test data for various service interfaces and expected generated code.
- Added documentation for host services and annotations for code generation.
- Implemented SubsonicAPI service with corresponding generated code.
* feat(subsonicapi): update Call method to return JSON string response
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement SubsonicAPI host function integration with permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(generator): error-only methods in response handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate client wrappers for host functions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(generator): remove error handling for response.Error in client templates
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): add Scheduler service interface with host function wrappers for scheduling tasks
* feat(plugins): add WASI build constraints to client wrapper templates, to avoid lint errors
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): implement Scheduler service with one-time and recurring scheduling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(manifest): remove unused ConfigPermission from permissions schema
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): add scheduler callback schema and implementation for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): streamline scheduling logic and remove unused callback tracking
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): add Close method for resource cleanup on plugin unload
Signed-off-by: Deluan <deluan@navidrome.org>
* docs(scheduler): clarify SchedulerCallback requirement for scheduling functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update wasm build rule to include all Go files in the directory
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: rewrite the wikimedia plugin using the XTP CLI
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): replace uuid with id.NewRandom for schedule ID generation
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: capabilities registration
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add scheduler service isolation test for plugin instances
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update plugin manager initialization and encapsulate logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add WebSocket service definitions for plugin communication
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement WebSocket service for plugin integration and connection management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Crypto Ticker example plugin for real-time cryptocurrency price updates via Coinbase WebSocket API
Also add the lifecycle capability
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: use context.Background() in invokeCallback for scheduled tasks
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename plugin.create() to plugin.instance()
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename pluginInstance to plugin for consistency across the codebase
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: simplify schedule cloning in Close method and enhance plugin cleanup error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement Artwork service for generating artwork URLs in Navidrome plugins - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: moved public URL builders to avoid import cycles
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Cache service for in-memory TTL-based caching in plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Discord Rich Presence example plugin for Navidrome integration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: host function wrappers to use structured request and response types
- Updated the host function signatures in `nd_host_artwork.go`, `nd_host_scheduler.go`, `nd_host_subsonicapi.go`, and `nd_host_websocket.go` to accept a single parameter for JSON requests.
- Introduced structured request and response types for various cache operations in `nd_host_cache.go`.
- Modified cache functions to marshal requests to JSON and unmarshal responses, improving error handling and code clarity.
- Removed redundant memory allocation for string parameters in favor of JSON marshaling.
- Enhanced error handling in WebSocket and cache operations to return structured error responses.
* refactor: error handling in various plugins to convert response.Error to Go errors
- Updated error handling in `nd_host_scheduler.go`, `nd_host_websocket.go`, `nd_host_artwork.go`, `nd_host_cache.go`, and `nd_host_subsonicapi.go` to convert string errors from responses into Go errors.
- Removed redundant error checks in test data plugins for cleaner code.
- Ensured consistent error handling across all plugins to improve reliability and maintainability.
* refactor: rename fake plugins to test plugins for clarity in integration tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add help target to Makefile for plugin usage instructions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Cover Art Archive plugin as an example of Python plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Makefile and README to clarify Go plugin usage
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: include plugin capabilities in loading log message
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add trace logging for plugin availability and error handling in agents
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Now Playing Logger plugin to showcase calling host functions from Python plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: generate Python client wrappers for various host services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add generated host function wrappers for Scheduler and SubsonicAPI services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Python plugin documentation and usage instructions for host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Webhook Scrobbler plugin in Rust to send HTTP notifications on scrobble events
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enable parallel loading of plugins during startup
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to include WebSocket callback schema in plugin documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: extend plugin watcher with improved logging and debounce duration adjustment
Signed-off-by: Deluan <deluan@navidrome.org>
* add trace message for plugin recompiles
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement plugin cache purging functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* test: move purgeCacheBySize unit tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add plugin repository and database support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add plugin management routes and middleware
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): implement plugin synchronization with database for add, update, and remove actions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add PluginList and PluginShow components with plugin management functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): optimize plugin change detection
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins UI): improve PluginList structure
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): enhance PluginShow with author, website, and permissions display
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): refactor to use MUI and RA components
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add error handling for plugin enable/disable actions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): inject PluginManager into native API
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update GetManager to accept DataStore parameter
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add subsonicRouter to Manager and refactor host service registration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): enhance debug logging for plugin actions and recompile logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): break manager.go into smaller, focused files
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): streamline error handling and improve plugin retrieval logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update newWebSocketService to use WebSocketPermission for allowed hosts
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): introduce ToggleEnabledSwitch for managing plugin enable/disable state
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update READMEs
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): add Library service for metadata access and filesystem integration
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Library Inspector plugin for periodic library inspection and file size logging
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to reflect JSON configuration format for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(build): update target to wasm32-wasip1 for improved WASI support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement configuration management UI with key-value pairs support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): adjust grid layout in InfoRow component for improved responsiveness
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): rename ErrorIndicator to EnabledOrErrorField and enhance error handling logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(i18n): add Portuguese translations for plugin management and notifications
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add support for .ndp plugin packages and update build process
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README for .ndp plugin packaging and installation instructions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement KVStore service for persistent key-value storage
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: enhance README with Extism plugin development resources and recommendations
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): integrate event broker into plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): update config handling in PluginShow to track last record state
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Rust host function library and example implementation of Discord Rich Presence plugin in Rust
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate Rust lib.rs file to expose host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update JSON field names to camelCase for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: reduce cyclomatic complexity by refactoring main function
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance Rust code generation with typed struct support and improved type handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Go client library with host function wrappers and documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate Go client stubs for non-WASM platforms
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): update client template file names for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add initial implementation of the Navidrome Plugin Development Kit code generator - Pahse 1
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2 (2)
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 3
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 4
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 5
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): consistent naming/types across PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): streamline plugin function signatures and error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update scrobbler interface to return errors directly instead of response structs
Signed-off-by: Deluan <deluan@navidrome.org>
* test: make all test plugins use the PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize and sort type definitions for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update error handling for methods to return errors directly
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update function signatures to return values directly instead of response structs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update request/response types to use private naming conventions
Signed-off-by: Deluan <deluan@navidrome.org>
* build: mark .wasm files as intermediate for cleanup after building .ndp
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): consolidate PDK module path and update Go version to 1.25
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement Rust PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize Rust output structure to follow standard conventions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update Discord Rich Presence and Library Inspector plugins to use nd-pdk for service calls and implement lifecycle management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update macro names for websocket and metadata registration to improve clarity and consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): rename scheduler callback methods for consistency and clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update export wrappers to use `//go:wasmexport` for WebAssembly compatibility
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update plugin registration docs
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): generate host wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): conditionally run goleak checks based on CI environment
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to reflect changes in plugin import paths
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update plugin instance creation to accept context for cancellation support
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update return types in metadata interfaces to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): enhance type handling for Rust and XTP output in capability generation
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update IsAuthorized method to return boolean instead of response object
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): add unit tests for rustOutputType and isPrimitiveRustType functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement XTP JSONSchema validation for generated schemas
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update response types in testMetadataAgent methods to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update Go and Rust plugin developer sections for clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: correct example link for library inspector in README
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: clarify artwork URL generation capabilities in service descriptions
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to include Rust PDK crate information for plugin developers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: handle URL parsing errors and use atomic upsert in plugin repository
Added proper error handling for url.Parse calls in PublicURL and AbsoluteURL
functions. When parsing fails, PublicURL now falls back to AbsoluteURL, and
AbsoluteURL logs the error and returns an empty string, preventing malformed
URLs from being generated.
Replaced the non-atomic UPDATE-then-INSERT pattern in plugin repository Put
method with a single atomic INSERT ... ON CONFLICT statement. This eliminates
potential race conditions and improves consistency with the upsert pattern
already used in host_kvstore.go.
* feat: implement mock service instances for non-WASM builds using testify/mock
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: Discord RPC struct to encapsulate WebSocket logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add support for experimental WebAssembly threads
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add PDK abstraction layer with mock support for non-WASM builds
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add unit tests for Discord plugin and RPC functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update return types in minimalPlugin and wikimediaPlugin methods to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: context cancellation and implement WebSocket callback timeout for improved error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: conditionally include error handling in generated client code templates
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement ConfigService for plugin configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance plugin manager to support metrics recording
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: make MockPDK private
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update interface types to use 'any' in plugin repository methods
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename List method to Keys for clarity in configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add ndpgen plugin tests in the pipeline and update Makefile
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add users permission management to plugin system
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: streamline users integration tests and enhance plugin user management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: remove UserID from scrobbler request structure
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add integration tests for UsersService enable gate behavior
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement user permissions for SubsonicAPI and scrobbler plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: show proper error in the UI when enabling a plugin fails
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add library permission management to plugin system
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add user permission for processing scrobbles in Discord Rich Presence plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: implement dynamic loading for buffered scrobbler plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add GetAdmins method to retrieve admin users from the plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Portuguese translations for user and library permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* reorder migrations
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: remove unnecessary bulkActionButtons prop from PluginList component
* feat: add manual plugin rescan functionality and corresponding UI action
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement user/library and plugin management integration with cleanup on deletion
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: replace core mock services with test-specific implementations to avoid import cycles
* feat: add ID fields to Artist and Song structs and enhance track loading logic by prioritizing ID matches
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update plugin permissions from allowedHosts to requiredHosts for better clarity and consistency
* feat: refactor plugin host permissions to use RequiredHosts directly for improved clarity
* fix: don't record metrics for plugin calls that aren't implemented at all
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: enhance connection management with improved error handling and cleanup logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: introduce ArtistRef struct for better artist representation and update track metadata handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update user configuration handling to use user key prefix for improved clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance ConfigCard input fields with multiline support and vertical resizing
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: rust plugin compilation error
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement IsOptionPattern method for better return type handling in Rust PDK generation
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-01-14 19:22:48 -05:00
|
|
|
// MetadataAgent provides artist and album metadata retrieval.
|
|
|
|
|
// This capability allows plugins to provide external metadata for artists and albums,
|
|
|
|
|
// such as biographies, images, similar artists, and top songs.
|
|
|
|
|
//
|
|
|
|
|
// Plugins implementing this capability can choose which methods to implement.
|
|
|
|
|
// Each method is optional - plugins only need to provide the functionality they support.
|
|
|
|
|
//
|
2026-08-20 22:48:26 -04:00
|
|
|
// To say "no data for this item", return a nil response and a nil error. Return an error only when
|
|
|
|
|
// the plugin itself failed, because Navidrome retries failed calls with backoff.
|
|
|
|
|
//
|
feat(plugins): New Plugin System with multi-language PDK support (#4833)
* chore(plugins): remove the old plugins system implementation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement new plugin system with using Extism
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add capability detection for plugins based on exported functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add auto-reload functionality for plugins with file watcher support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add auto-reload functionality for plugins with file watcher support
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): standardize variable names and remove superfluous wrapper functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): improve error handling and logging in plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): implement plugin function call helper and refactor MetadataAgent methods
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): race condition in plugin manager
* tests(plugins): change BeforeEach to BeforeAll in MetadataAgent tests
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(plugins): optimize tests
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(plugins): more optimizations
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): ignore goroutine leaks from notify library in tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Wikimedia plugin for Navidrome to fetch artist metadata
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance plugin logging and set User-Agent header
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement scrobbler plugin with authorization and scrobbling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): integrate logs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): clean up manifest struct and improve plugin loading logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add metadata agent and scrobbler schemas for bootstrapping plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(hostgen): add hostgen tool for generating Extism host function wrappers
- Implemented hostgen tool to generate wrappers from annotated Go interfaces.
- Added command-line flags for input/output directories and package name.
- Introduced parsing and code generation logic for host services.
- Created test data for various service interfaces and expected generated code.
- Added documentation for host services and annotations for code generation.
- Implemented SubsonicAPI service with corresponding generated code.
* feat(subsonicapi): update Call method to return JSON string response
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement SubsonicAPI host function integration with permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(generator): error-only methods in response handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate client wrappers for host functions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(generator): remove error handling for response.Error in client templates
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): add Scheduler service interface with host function wrappers for scheduling tasks
* feat(plugins): add WASI build constraints to client wrapper templates, to avoid lint errors
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): implement Scheduler service with one-time and recurring scheduling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(manifest): remove unused ConfigPermission from permissions schema
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): add scheduler callback schema and implementation for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): streamline scheduling logic and remove unused callback tracking
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): add Close method for resource cleanup on plugin unload
Signed-off-by: Deluan <deluan@navidrome.org>
* docs(scheduler): clarify SchedulerCallback requirement for scheduling functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update wasm build rule to include all Go files in the directory
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: rewrite the wikimedia plugin using the XTP CLI
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): replace uuid with id.NewRandom for schedule ID generation
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: capabilities registration
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add scheduler service isolation test for plugin instances
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update plugin manager initialization and encapsulate logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add WebSocket service definitions for plugin communication
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement WebSocket service for plugin integration and connection management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Crypto Ticker example plugin for real-time cryptocurrency price updates via Coinbase WebSocket API
Also add the lifecycle capability
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: use context.Background() in invokeCallback for scheduled tasks
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename plugin.create() to plugin.instance()
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename pluginInstance to plugin for consistency across the codebase
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: simplify schedule cloning in Close method and enhance plugin cleanup error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement Artwork service for generating artwork URLs in Navidrome plugins - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: moved public URL builders to avoid import cycles
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Cache service for in-memory TTL-based caching in plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Discord Rich Presence example plugin for Navidrome integration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: host function wrappers to use structured request and response types
- Updated the host function signatures in `nd_host_artwork.go`, `nd_host_scheduler.go`, `nd_host_subsonicapi.go`, and `nd_host_websocket.go` to accept a single parameter for JSON requests.
- Introduced structured request and response types for various cache operations in `nd_host_cache.go`.
- Modified cache functions to marshal requests to JSON and unmarshal responses, improving error handling and code clarity.
- Removed redundant memory allocation for string parameters in favor of JSON marshaling.
- Enhanced error handling in WebSocket and cache operations to return structured error responses.
* refactor: error handling in various plugins to convert response.Error to Go errors
- Updated error handling in `nd_host_scheduler.go`, `nd_host_websocket.go`, `nd_host_artwork.go`, `nd_host_cache.go`, and `nd_host_subsonicapi.go` to convert string errors from responses into Go errors.
- Removed redundant error checks in test data plugins for cleaner code.
- Ensured consistent error handling across all plugins to improve reliability and maintainability.
* refactor: rename fake plugins to test plugins for clarity in integration tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add help target to Makefile for plugin usage instructions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Cover Art Archive plugin as an example of Python plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Makefile and README to clarify Go plugin usage
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: include plugin capabilities in loading log message
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add trace logging for plugin availability and error handling in agents
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Now Playing Logger plugin to showcase calling host functions from Python plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: generate Python client wrappers for various host services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add generated host function wrappers for Scheduler and SubsonicAPI services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Python plugin documentation and usage instructions for host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Webhook Scrobbler plugin in Rust to send HTTP notifications on scrobble events
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enable parallel loading of plugins during startup
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to include WebSocket callback schema in plugin documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: extend plugin watcher with improved logging and debounce duration adjustment
Signed-off-by: Deluan <deluan@navidrome.org>
* add trace message for plugin recompiles
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement plugin cache purging functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* test: move purgeCacheBySize unit tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add plugin repository and database support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add plugin management routes and middleware
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): implement plugin synchronization with database for add, update, and remove actions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add PluginList and PluginShow components with plugin management functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): optimize plugin change detection
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins UI): improve PluginList structure
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): enhance PluginShow with author, website, and permissions display
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): refactor to use MUI and RA components
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add error handling for plugin enable/disable actions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): inject PluginManager into native API
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update GetManager to accept DataStore parameter
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add subsonicRouter to Manager and refactor host service registration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): enhance debug logging for plugin actions and recompile logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): break manager.go into smaller, focused files
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): streamline error handling and improve plugin retrieval logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update newWebSocketService to use WebSocketPermission for allowed hosts
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): introduce ToggleEnabledSwitch for managing plugin enable/disable state
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update READMEs
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): add Library service for metadata access and filesystem integration
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Library Inspector plugin for periodic library inspection and file size logging
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to reflect JSON configuration format for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(build): update target to wasm32-wasip1 for improved WASI support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement configuration management UI with key-value pairs support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): adjust grid layout in InfoRow component for improved responsiveness
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): rename ErrorIndicator to EnabledOrErrorField and enhance error handling logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(i18n): add Portuguese translations for plugin management and notifications
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add support for .ndp plugin packages and update build process
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README for .ndp plugin packaging and installation instructions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement KVStore service for persistent key-value storage
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: enhance README with Extism plugin development resources and recommendations
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): integrate event broker into plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): update config handling in PluginShow to track last record state
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Rust host function library and example implementation of Discord Rich Presence plugin in Rust
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate Rust lib.rs file to expose host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update JSON field names to camelCase for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: reduce cyclomatic complexity by refactoring main function
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance Rust code generation with typed struct support and improved type handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Go client library with host function wrappers and documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate Go client stubs for non-WASM platforms
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): update client template file names for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add initial implementation of the Navidrome Plugin Development Kit code generator - Pahse 1
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2 (2)
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 3
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 4
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 5
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): consistent naming/types across PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): streamline plugin function signatures and error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update scrobbler interface to return errors directly instead of response structs
Signed-off-by: Deluan <deluan@navidrome.org>
* test: make all test plugins use the PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize and sort type definitions for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update error handling for methods to return errors directly
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update function signatures to return values directly instead of response structs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update request/response types to use private naming conventions
Signed-off-by: Deluan <deluan@navidrome.org>
* build: mark .wasm files as intermediate for cleanup after building .ndp
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): consolidate PDK module path and update Go version to 1.25
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement Rust PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize Rust output structure to follow standard conventions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update Discord Rich Presence and Library Inspector plugins to use nd-pdk for service calls and implement lifecycle management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update macro names for websocket and metadata registration to improve clarity and consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): rename scheduler callback methods for consistency and clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update export wrappers to use `//go:wasmexport` for WebAssembly compatibility
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update plugin registration docs
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): generate host wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): conditionally run goleak checks based on CI environment
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to reflect changes in plugin import paths
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update plugin instance creation to accept context for cancellation support
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update return types in metadata interfaces to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): enhance type handling for Rust and XTP output in capability generation
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update IsAuthorized method to return boolean instead of response object
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): add unit tests for rustOutputType and isPrimitiveRustType functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement XTP JSONSchema validation for generated schemas
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update response types in testMetadataAgent methods to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update Go and Rust plugin developer sections for clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: correct example link for library inspector in README
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: clarify artwork URL generation capabilities in service descriptions
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to include Rust PDK crate information for plugin developers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: handle URL parsing errors and use atomic upsert in plugin repository
Added proper error handling for url.Parse calls in PublicURL and AbsoluteURL
functions. When parsing fails, PublicURL now falls back to AbsoluteURL, and
AbsoluteURL logs the error and returns an empty string, preventing malformed
URLs from being generated.
Replaced the non-atomic UPDATE-then-INSERT pattern in plugin repository Put
method with a single atomic INSERT ... ON CONFLICT statement. This eliminates
potential race conditions and improves consistency with the upsert pattern
already used in host_kvstore.go.
* feat: implement mock service instances for non-WASM builds using testify/mock
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: Discord RPC struct to encapsulate WebSocket logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add support for experimental WebAssembly threads
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add PDK abstraction layer with mock support for non-WASM builds
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add unit tests for Discord plugin and RPC functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update return types in minimalPlugin and wikimediaPlugin methods to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: context cancellation and implement WebSocket callback timeout for improved error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: conditionally include error handling in generated client code templates
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement ConfigService for plugin configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance plugin manager to support metrics recording
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: make MockPDK private
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update interface types to use 'any' in plugin repository methods
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename List method to Keys for clarity in configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add ndpgen plugin tests in the pipeline and update Makefile
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add users permission management to plugin system
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: streamline users integration tests and enhance plugin user management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: remove UserID from scrobbler request structure
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add integration tests for UsersService enable gate behavior
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement user permissions for SubsonicAPI and scrobbler plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: show proper error in the UI when enabling a plugin fails
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add library permission management to plugin system
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add user permission for processing scrobbles in Discord Rich Presence plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: implement dynamic loading for buffered scrobbler plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add GetAdmins method to retrieve admin users from the plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Portuguese translations for user and library permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* reorder migrations
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: remove unnecessary bulkActionButtons prop from PluginList component
* feat: add manual plugin rescan functionality and corresponding UI action
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement user/library and plugin management integration with cleanup on deletion
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: replace core mock services with test-specific implementations to avoid import cycles
* feat: add ID fields to Artist and Song structs and enhance track loading logic by prioritizing ID matches
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update plugin permissions from allowedHosts to requiredHosts for better clarity and consistency
* feat: refactor plugin host permissions to use RequiredHosts directly for improved clarity
* fix: don't record metrics for plugin calls that aren't implemented at all
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: enhance connection management with improved error handling and cleanup logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: introduce ArtistRef struct for better artist representation and update track metadata handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update user configuration handling to use user key prefix for improved clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance ConfigCard input fields with multiline support and vertical resizing
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: rust plugin compilation error
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement IsOptionPattern method for better return type handling in Rust PDK generation
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-01-14 19:22:48 -05:00
|
|
|
//nd:capability name=metadata
|
|
|
|
|
type MetadataAgent interface {
|
|
|
|
|
// GetArtistMBID retrieves the MusicBrainz ID for an artist.
|
|
|
|
|
//nd:export name=nd_get_artist_mbid
|
|
|
|
|
GetArtistMBID(ArtistMBIDRequest) (*ArtistMBIDResponse, error)
|
|
|
|
|
|
|
|
|
|
// GetArtistURL retrieves the external URL for an artist.
|
|
|
|
|
//nd:export name=nd_get_artist_url
|
|
|
|
|
GetArtistURL(ArtistRequest) (*ArtistURLResponse, error)
|
|
|
|
|
|
|
|
|
|
// GetArtistBiography retrieves the biography for an artist.
|
|
|
|
|
//nd:export name=nd_get_artist_biography
|
|
|
|
|
GetArtistBiography(ArtistRequest) (*ArtistBiographyResponse, error)
|
|
|
|
|
|
|
|
|
|
// GetSimilarArtists retrieves similar artists for a given artist.
|
|
|
|
|
//nd:export name=nd_get_similar_artists
|
|
|
|
|
GetSimilarArtists(SimilarArtistsRequest) (*SimilarArtistsResponse, error)
|
|
|
|
|
|
|
|
|
|
// GetArtistImages retrieves images for an artist.
|
|
|
|
|
//nd:export name=nd_get_artist_images
|
|
|
|
|
GetArtistImages(ArtistRequest) (*ArtistImagesResponse, error)
|
|
|
|
|
|
|
|
|
|
// GetArtistTopSongs retrieves top songs for an artist.
|
|
|
|
|
//nd:export name=nd_get_artist_top_songs
|
|
|
|
|
GetArtistTopSongs(TopSongsRequest) (*TopSongsResponse, error)
|
|
|
|
|
|
|
|
|
|
// GetAlbumInfo retrieves album information.
|
|
|
|
|
//nd:export name=nd_get_album_info
|
|
|
|
|
GetAlbumInfo(AlbumRequest) (*AlbumInfoResponse, error)
|
|
|
|
|
|
|
|
|
|
// GetAlbumImages retrieves images for an album.
|
|
|
|
|
//nd:export name=nd_get_album_images
|
|
|
|
|
GetAlbumImages(AlbumRequest) (*AlbumImagesResponse, error)
|
2026-01-26 18:28:41 -05:00
|
|
|
|
|
|
|
|
// GetSimilarSongsByTrack retrieves songs similar to a specific track.
|
|
|
|
|
//nd:export name=nd_get_similar_songs_by_track
|
|
|
|
|
GetSimilarSongsByTrack(SimilarSongsByTrackRequest) (*SimilarSongsResponse, error)
|
|
|
|
|
|
|
|
|
|
// GetSimilarSongsByAlbum retrieves songs similar to tracks on an album.
|
|
|
|
|
//nd:export name=nd_get_similar_songs_by_album
|
|
|
|
|
GetSimilarSongsByAlbum(SimilarSongsByAlbumRequest) (*SimilarSongsResponse, error)
|
|
|
|
|
|
|
|
|
|
// GetSimilarSongsByArtist retrieves songs similar to an artist's catalog.
|
|
|
|
|
//nd:export name=nd_get_similar_songs_by_artist
|
|
|
|
|
GetSimilarSongsByArtist(SimilarSongsByArtistRequest) (*SimilarSongsResponse, error)
|
feat(plugins): New Plugin System with multi-language PDK support (#4833)
* chore(plugins): remove the old plugins system implementation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement new plugin system with using Extism
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add capability detection for plugins based on exported functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add auto-reload functionality for plugins with file watcher support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add auto-reload functionality for plugins with file watcher support
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): standardize variable names and remove superfluous wrapper functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): improve error handling and logging in plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): implement plugin function call helper and refactor MetadataAgent methods
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): race condition in plugin manager
* tests(plugins): change BeforeEach to BeforeAll in MetadataAgent tests
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(plugins): optimize tests
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(plugins): more optimizations
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): ignore goroutine leaks from notify library in tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Wikimedia plugin for Navidrome to fetch artist metadata
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance plugin logging and set User-Agent header
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement scrobbler plugin with authorization and scrobbling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): integrate logs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): clean up manifest struct and improve plugin loading logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add metadata agent and scrobbler schemas for bootstrapping plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(hostgen): add hostgen tool for generating Extism host function wrappers
- Implemented hostgen tool to generate wrappers from annotated Go interfaces.
- Added command-line flags for input/output directories and package name.
- Introduced parsing and code generation logic for host services.
- Created test data for various service interfaces and expected generated code.
- Added documentation for host services and annotations for code generation.
- Implemented SubsonicAPI service with corresponding generated code.
* feat(subsonicapi): update Call method to return JSON string response
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement SubsonicAPI host function integration with permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(generator): error-only methods in response handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate client wrappers for host functions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(generator): remove error handling for response.Error in client templates
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): add Scheduler service interface with host function wrappers for scheduling tasks
* feat(plugins): add WASI build constraints to client wrapper templates, to avoid lint errors
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): implement Scheduler service with one-time and recurring scheduling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(manifest): remove unused ConfigPermission from permissions schema
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): add scheduler callback schema and implementation for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): streamline scheduling logic and remove unused callback tracking
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): add Close method for resource cleanup on plugin unload
Signed-off-by: Deluan <deluan@navidrome.org>
* docs(scheduler): clarify SchedulerCallback requirement for scheduling functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update wasm build rule to include all Go files in the directory
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: rewrite the wikimedia plugin using the XTP CLI
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): replace uuid with id.NewRandom for schedule ID generation
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: capabilities registration
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add scheduler service isolation test for plugin instances
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update plugin manager initialization and encapsulate logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add WebSocket service definitions for plugin communication
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement WebSocket service for plugin integration and connection management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Crypto Ticker example plugin for real-time cryptocurrency price updates via Coinbase WebSocket API
Also add the lifecycle capability
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: use context.Background() in invokeCallback for scheduled tasks
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename plugin.create() to plugin.instance()
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename pluginInstance to plugin for consistency across the codebase
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: simplify schedule cloning in Close method and enhance plugin cleanup error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement Artwork service for generating artwork URLs in Navidrome plugins - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: moved public URL builders to avoid import cycles
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Cache service for in-memory TTL-based caching in plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Discord Rich Presence example plugin for Navidrome integration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: host function wrappers to use structured request and response types
- Updated the host function signatures in `nd_host_artwork.go`, `nd_host_scheduler.go`, `nd_host_subsonicapi.go`, and `nd_host_websocket.go` to accept a single parameter for JSON requests.
- Introduced structured request and response types for various cache operations in `nd_host_cache.go`.
- Modified cache functions to marshal requests to JSON and unmarshal responses, improving error handling and code clarity.
- Removed redundant memory allocation for string parameters in favor of JSON marshaling.
- Enhanced error handling in WebSocket and cache operations to return structured error responses.
* refactor: error handling in various plugins to convert response.Error to Go errors
- Updated error handling in `nd_host_scheduler.go`, `nd_host_websocket.go`, `nd_host_artwork.go`, `nd_host_cache.go`, and `nd_host_subsonicapi.go` to convert string errors from responses into Go errors.
- Removed redundant error checks in test data plugins for cleaner code.
- Ensured consistent error handling across all plugins to improve reliability and maintainability.
* refactor: rename fake plugins to test plugins for clarity in integration tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add help target to Makefile for plugin usage instructions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Cover Art Archive plugin as an example of Python plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Makefile and README to clarify Go plugin usage
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: include plugin capabilities in loading log message
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add trace logging for plugin availability and error handling in agents
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Now Playing Logger plugin to showcase calling host functions from Python plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: generate Python client wrappers for various host services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add generated host function wrappers for Scheduler and SubsonicAPI services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Python plugin documentation and usage instructions for host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Webhook Scrobbler plugin in Rust to send HTTP notifications on scrobble events
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enable parallel loading of plugins during startup
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to include WebSocket callback schema in plugin documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: extend plugin watcher with improved logging and debounce duration adjustment
Signed-off-by: Deluan <deluan@navidrome.org>
* add trace message for plugin recompiles
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement plugin cache purging functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* test: move purgeCacheBySize unit tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add plugin repository and database support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add plugin management routes and middleware
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): implement plugin synchronization with database for add, update, and remove actions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add PluginList and PluginShow components with plugin management functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): optimize plugin change detection
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins UI): improve PluginList structure
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): enhance PluginShow with author, website, and permissions display
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): refactor to use MUI and RA components
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add error handling for plugin enable/disable actions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): inject PluginManager into native API
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update GetManager to accept DataStore parameter
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add subsonicRouter to Manager and refactor host service registration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): enhance debug logging for plugin actions and recompile logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): break manager.go into smaller, focused files
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): streamline error handling and improve plugin retrieval logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update newWebSocketService to use WebSocketPermission for allowed hosts
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): introduce ToggleEnabledSwitch for managing plugin enable/disable state
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update READMEs
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): add Library service for metadata access and filesystem integration
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Library Inspector plugin for periodic library inspection and file size logging
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to reflect JSON configuration format for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(build): update target to wasm32-wasip1 for improved WASI support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement configuration management UI with key-value pairs support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): adjust grid layout in InfoRow component for improved responsiveness
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): rename ErrorIndicator to EnabledOrErrorField and enhance error handling logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(i18n): add Portuguese translations for plugin management and notifications
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add support for .ndp plugin packages and update build process
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README for .ndp plugin packaging and installation instructions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement KVStore service for persistent key-value storage
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: enhance README with Extism plugin development resources and recommendations
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): integrate event broker into plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): update config handling in PluginShow to track last record state
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Rust host function library and example implementation of Discord Rich Presence plugin in Rust
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate Rust lib.rs file to expose host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update JSON field names to camelCase for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: reduce cyclomatic complexity by refactoring main function
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance Rust code generation with typed struct support and improved type handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Go client library with host function wrappers and documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate Go client stubs for non-WASM platforms
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): update client template file names for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add initial implementation of the Navidrome Plugin Development Kit code generator - Pahse 1
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2 (2)
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 3
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 4
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 5
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): consistent naming/types across PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): streamline plugin function signatures and error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update scrobbler interface to return errors directly instead of response structs
Signed-off-by: Deluan <deluan@navidrome.org>
* test: make all test plugins use the PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize and sort type definitions for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update error handling for methods to return errors directly
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update function signatures to return values directly instead of response structs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update request/response types to use private naming conventions
Signed-off-by: Deluan <deluan@navidrome.org>
* build: mark .wasm files as intermediate for cleanup after building .ndp
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): consolidate PDK module path and update Go version to 1.25
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement Rust PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize Rust output structure to follow standard conventions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update Discord Rich Presence and Library Inspector plugins to use nd-pdk for service calls and implement lifecycle management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update macro names for websocket and metadata registration to improve clarity and consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): rename scheduler callback methods for consistency and clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update export wrappers to use `//go:wasmexport` for WebAssembly compatibility
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update plugin registration docs
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): generate host wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): conditionally run goleak checks based on CI environment
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to reflect changes in plugin import paths
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update plugin instance creation to accept context for cancellation support
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update return types in metadata interfaces to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): enhance type handling for Rust and XTP output in capability generation
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update IsAuthorized method to return boolean instead of response object
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): add unit tests for rustOutputType and isPrimitiveRustType functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement XTP JSONSchema validation for generated schemas
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update response types in testMetadataAgent methods to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update Go and Rust plugin developer sections for clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: correct example link for library inspector in README
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: clarify artwork URL generation capabilities in service descriptions
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to include Rust PDK crate information for plugin developers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: handle URL parsing errors and use atomic upsert in plugin repository
Added proper error handling for url.Parse calls in PublicURL and AbsoluteURL
functions. When parsing fails, PublicURL now falls back to AbsoluteURL, and
AbsoluteURL logs the error and returns an empty string, preventing malformed
URLs from being generated.
Replaced the non-atomic UPDATE-then-INSERT pattern in plugin repository Put
method with a single atomic INSERT ... ON CONFLICT statement. This eliminates
potential race conditions and improves consistency with the upsert pattern
already used in host_kvstore.go.
* feat: implement mock service instances for non-WASM builds using testify/mock
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: Discord RPC struct to encapsulate WebSocket logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add support for experimental WebAssembly threads
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add PDK abstraction layer with mock support for non-WASM builds
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add unit tests for Discord plugin and RPC functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update return types in minimalPlugin and wikimediaPlugin methods to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: context cancellation and implement WebSocket callback timeout for improved error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: conditionally include error handling in generated client code templates
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement ConfigService for plugin configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance plugin manager to support metrics recording
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: make MockPDK private
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update interface types to use 'any' in plugin repository methods
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename List method to Keys for clarity in configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add ndpgen plugin tests in the pipeline and update Makefile
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add users permission management to plugin system
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: streamline users integration tests and enhance plugin user management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: remove UserID from scrobbler request structure
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add integration tests for UsersService enable gate behavior
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement user permissions for SubsonicAPI and scrobbler plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: show proper error in the UI when enabling a plugin fails
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add library permission management to plugin system
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add user permission for processing scrobbles in Discord Rich Presence plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: implement dynamic loading for buffered scrobbler plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add GetAdmins method to retrieve admin users from the plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Portuguese translations for user and library permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* reorder migrations
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: remove unnecessary bulkActionButtons prop from PluginList component
* feat: add manual plugin rescan functionality and corresponding UI action
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement user/library and plugin management integration with cleanup on deletion
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: replace core mock services with test-specific implementations to avoid import cycles
* feat: add ID fields to Artist and Song structs and enhance track loading logic by prioritizing ID matches
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update plugin permissions from allowedHosts to requiredHosts for better clarity and consistency
* feat: refactor plugin host permissions to use RequiredHosts directly for improved clarity
* fix: don't record metrics for plugin calls that aren't implemented at all
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: enhance connection management with improved error handling and cleanup logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: introduce ArtistRef struct for better artist representation and update track metadata handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update user configuration handling to use user key prefix for improved clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance ConfigCard input fields with multiline support and vertical resizing
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: rust plugin compilation error
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement IsOptionPattern method for better return type handling in Rust PDK generation
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-01-14 19:22:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ArtistMBIDRequest is the request for GetArtistMBID.
|
|
|
|
|
type ArtistMBIDRequest struct {
|
|
|
|
|
// ID is the internal Navidrome artist ID.
|
|
|
|
|
ID string `json:"id"`
|
|
|
|
|
// Name is the artist name.
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ArtistMBIDResponse is the response for GetArtistMBID.
|
|
|
|
|
type ArtistMBIDResponse struct {
|
|
|
|
|
// MBID is the MusicBrainz ID for the artist.
|
|
|
|
|
MBID string `json:"mbid"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ArtistRequest is the common request for artist-related functions.
|
|
|
|
|
type ArtistRequest struct {
|
|
|
|
|
// ID is the internal Navidrome artist ID.
|
|
|
|
|
ID string `json:"id"`
|
|
|
|
|
// Name is the artist name.
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
// MBID is the MusicBrainz ID for the artist (if known).
|
|
|
|
|
MBID string `json:"mbid,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ArtistURLResponse is the response for GetArtistURL.
|
|
|
|
|
type ArtistURLResponse struct {
|
|
|
|
|
// URL is the external URL for the artist.
|
|
|
|
|
URL string `json:"url"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ArtistBiographyResponse is the response for GetArtistBiography.
|
|
|
|
|
type ArtistBiographyResponse struct {
|
|
|
|
|
// Biography is the artist biography text.
|
|
|
|
|
Biography string `json:"biography"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SimilarArtistsRequest is the request for GetSimilarArtists.
|
|
|
|
|
type SimilarArtistsRequest struct {
|
|
|
|
|
// ID is the internal Navidrome artist ID.
|
|
|
|
|
ID string `json:"id"`
|
|
|
|
|
// Name is the artist name.
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
// MBID is the MusicBrainz ID for the artist (if known).
|
|
|
|
|
MBID string `json:"mbid,omitempty"`
|
|
|
|
|
// Limit is the maximum number of similar artists to return.
|
|
|
|
|
Limit int32 `json:"limit"`
|
|
|
|
|
}
|
|
|
|
|
|
feat(plugins): share plugin DTOs via a types package (#5655)
* refactor(plugins): remove Python PDK generation from ndpgen
* feat(plugins): parse Go type aliases distinctly in ndpgen
* feat(plugins): resolve shared-type aliases against a registry in ndpgen
* fix(plugins): resolve host-service shared aliases package-wide
Mirror the capability approach in ParseDirectoryWithShared: do a first
pass over all package files to build a package-wide alias map, then pass
it into parseServiceFile so that a shared-type alias declared in a sibling
file is visible when resolving types in the service interface file.
Add a focused test that writes the alias in one file and the hostservice
in another, confirming RED before the fix and GREEN after. Also
strengthens the existing Task 3 test with an ArtistRef.Target assertion.
* feat(plugins): add ndpgen -shared-types mode for the Go types package
* feat(plugins): generate the nd-pdk-types Rust crate from -shared-types
* feat(plugins): inject types import and emit deprecated aliases in Go output
* feat(plugins): emit deprecated Rust aliases to the shared types crate
* feat(plugins): inline shared-type shapes into XTP schemas
* feat(plugins): add nd-pdk-types crate and wire dependents
* feat(plugins): move shared capability types to plugins/types with deprecated aliases
* fix(plugins): point Rust deprecated-alias note at the replacement type
* fix(plugins): include shared aliases in KnownStructs so Rust fields keep their type
Capability.KnownStructs() and Service.KnownStructs() previously only
registered names from .Structs. After the shared-types migration, types
like ArtistRef/TrackInfo/SongRef live in .SharedAliases instead, so
ToRustTypeWithStructs could not find them and fell back to serde_json::Value
for every struct field referencing a shared type.
Add the shared-alias names to the knownStructs map in both methods.
Regenerate the Rust capability files; track/song/artist fields now render
as their named types (TrackInfo, SongRef, ArtistRef, etc.).
Add a regression test that verifies a struct field whose type is only in
SharedAliases renders as the named type and not serde_json::Value.
* docs(plugins): remove stale Python references from ndpgen and plugins READMEs
ndpgen no longer has a -python flag; remove it from the usage synopsis,
flags table, and defaults note in ndpgen/README.md. Delete the "Python
Client Library" section that described its output.
plugins/README.md referenced plugins/pdk/python/host/ (deleted) as the
source for Python host-service stubs. Remove that paragraph; Python plugins
still work via the XTP-schema / extism-py path (see examples/*-py).
* refactor(plugins): dedupe ndpgen helpers and tidy shared-type codegen
* docs(plugins): restore Python as a supported XTP schema target
The ndpgen-generated Python PDK was removed, but the XTP YAML schemas are
language-neutral and the XTP CLI still generates Python bindings from them
(as the extism-py examples demonstrate). Only the ndpgen Python output was
dropped, not Python support itself.
* test(plugins): use the shared types package in test plugins
The test fixtures referenced the now-deprecated capability aliases
(sonicsimilarity.SongRef, metadata.ArtistRef/SongRef). Point them at the
canonical types package so our own fixtures don't depend on symbols slated
for removal.
* refactor(plugins): use the shared types package in host adapters
Replace deprecated capabilities.TrackInfo, capabilities.ArtistRef, and
capabilities.SongRef aliases with the canonical types.TrackInfo,
types.ArtistRef, and types.SongRef from plugins/types.
* fix(plugins): reference shared types by canonical path in generated Rust
Previously the generator emitted `pub field: SongRef` (the local deprecated
alias) for struct fields whose type came from SharedAliases. Refactored
ToRustTypeWithStructs into a private toRustType that accepts a shared map,
and added ToRustTypeWithShared which resolves shared-alias names to their
canonical nd_pdk_types::X path before falling through to the knownStructs
check. Both rustCapabilityFuncMap and rustFuncMap now build the shared map
from SharedAliases and use it for fieldRustType, so the generated capability
files reference nd_pdk_types::SongRef / nd_pdk_types::TrackInfo directly.
The deprecated pub type aliases remain in place as the external back-compat
surface. Deprecation warning count from cargo build drops to 0.
* fix(examples): implement missing Scrobbler.playback_report in Rust examples
The Scrobbler trait gained a playback_report method but the two Rust example
plugins (webhook-rs and discord-rich-presence-rs) were not updated, causing
E0046 compile errors. Added the missing fn playback_report to both: webhook-rs
logs and returns Ok(()) mirroring its now_playing handler; discord-rich-presence-rs
is a no-op since Discord presence does not need playback reports. make all-rust
now exits 0.
* refactor(plugins): point Rust deprecation notes at the nd_pdk::types umbrella path
Plugin authors depend on the nd-pdk umbrella crate, which re-exports
nd_pdk_types as 'types', so the migration target they should type is
nd_pdk::types::X. The alias target stays nd_pdk_types::X (the real path
inside nd-pdk-capabilities).
* fix(plugins): error when a shared-type alias can't be resolved against the registry
* refactor(plugins): parse each Go source file once in ndpgen
* fix(plugins): correct ndpgen review nits (flag name, unused dep, docs)
* refactor(plugins): drop the now-unused path param from parseServiceFile
* refactor(plugins): use shared types directly, rename TrackInfo to Track
Capability interfaces now reference the shared `types` package by qualified
name (types.Track, types.SongRef, types.ArtistRef) instead of the package-local
deprecated aliases, and the shared TrackInfo type is renamed to Track to match
its role as the plugin-facing projection of a library media file.
The deprecated bare aliases (scrobbler.TrackInfo, metadata.ArtistRef,
sonicsimilarity.SongRef, etc.) are kept as re-exports so existing plugins keep
compiling, with a deprecation warning steering them to the canonical types.
To support this, ndpgen now resolves qualified types.X references: it collects
them during type discovery, maps each used canonical type back to its declared
deprecated alias for re-export, emits nd_pdk_types::X paths in Rust, and names
the XTP schema components by their canonical type. Regenerated the Go and Rust
PDK and the XTP schemas, and added generator tests covering the qualified-ref
path. Also adds clarifying doc comments to the shared types.
* refactor(plugins): extract shared types selector into a named const
Replace the "types." string literal that detects and strips the shared types
package selector with a single sharedTypesPrefix constant across the ndpgen
generator (parser, types, generator, xtp_schema), giving the package one source
of truth for the selector.
Also restore the single reused scratch map (cleared each iteration) in the
resolveSharedAliases BFS instead of allocating a fresh map per shared-struct
field, matching the prior implementation.
Pure cleanup from a /simplify pass: regeneration produces byte-for-byte
identical Go, Rust, and XTP output.
* refactor(plugins): keep TrackInfo in the capability package for now
Move the track type back out of the shared plugins/types package: it is again
defined inline as TrackInfo in plugins/capabilities/scrobbler.go and referenced
directly by the scrobbler and lyrics capabilities, reverting the rename to
types.Track. The host helper is renamed back to mediaFileToTrackInfo and now
returns capabilities.TrackInfo. SongRef and ArtistRef stay in the shared types
package; TrackInfo keeps using types.ArtistRef for its artist lists.
This type is expected to be reshaped in upcoming work, so leaving it in the
capability package avoids churning the shared types twice. Regenerated the Go
and Rust PDK and the XTP schemas accordingly.
* fix(plugins): emit the Go types import for direct shared-type refs
ndpgen's Capability/Service.ImportsSharedTypes only reported a shared-types
dependency when a deprecated re-export alias (type X = types.X) was declared. A
struct field referencing the canonical form directly (e.g. types.SongRef) with
no such alias produced an empty SharedAliases slice, so the Go templates skipped
the import while still emitting fields/signatures using types.SongRef — leaving
generated PDK code for new shared DTOs uncompilable unless an otherwise
unnecessary alias was added.
ImportsSharedTypes now also returns true when any struct field references the
types. package by qualified name, via a new structsReferenceSharedTypes helper
that reuses collectReferencedTypes (so []types.X and map[...]types.X are covered
too).
* fix(plugins): preserve base64 encoding for shared byte fields in Rust
The Rust shared-types crate template rendered a []byte field as a plain Vec<u8>
without the base64_bytes serde override used by the capability/client templates.
Go's encoding/json serializes []byte as a base64 string, so a Rust plugin using
nd_pdk::types would have serialized an array of numbers instead of the wire
format the Go/server side expects.
GenerateSharedTypesRust now registers the base64_bytes partial and passes a
HasByteFields flag (new anyFieldIsByteSlice helper); types.rs.tmpl emits the
base64_bytes module and a #[serde(with = "base64_bytes")] attribute on []byte
fields, mirroring the capability template.
* fix(plugins): include directly-referenced shared types in XTP schemas
buildSchemas registered shared types into the schema components only by iterating
cap.SharedAliases, which records deprecated re-export aliases. A capability that
referenced a shared DTO solely as types.Foo (no declared alias) therefore never
got Foo into the component set, so the self-contained XTP schema rendered the
field as a generic object (or emitted a dangling $ref), breaking the direct
shared-type use case enabled by -shared.
resolveSharedAliases now also returns the resolved shapes of every used shared
type (alias or not); these are carried on the new Capability.SharedTypes field
and registered by buildSchemas alongside SharedAliases. Validated end-to-end with
the xtp CLI: a direct types.Foo reference now produces a proper component plus a
$ref, so xtp generates a typed struct instead of an untyped serde_json::Map.
* fix(plugins): resolve renamed shared aliases to canonical schema refs
When a deprecated alias renames its canonical type (e.g. type TrackInfo =
types.Track) and a capability field is typed with the alias name (TrackInfo),
buildProperty emitted a $ref to #/components/schemas/TrackInfo. Components are
keyed by the canonical name (Track), so no TrackInfo component was emitted,
leaving a dangling reference that crashes the xtp code generator.
buildSchemas now builds an alias->canonical map; buildProperty (and the slice
item path) resolves $ref targets through it, and a used alias name marks its
canonical component used so it is emitted. Validated with the xtp CLI: the
renamed-alias schema previously crashed xtp and now generates cleanly.
* fix(plugins): detect shared types used directly in method signatures
ImportsSharedTypes only inspected struct fields, so a capability method using a
shared type directly in its signature (e.g. types.SongRef as input/output rather
than inside a local struct) was not detected. The generated Go templates still
rendered the provider/export signatures with types.SongRef, so the capability
package omitted the types import and failed to compile; the same gap applied to
service params/returns.
ImportsSharedTypes now also scans capability method input/output types and
service method params/returns, via a typeReferencesSharedTypes helper that reuses
collectReferencedTypes (covering pointer/slice/map wrappers).
* fix(plugins): add base64 dependency to the shared Rust types crate
When a shared DTO has a []byte field, ndpgen emits the base64_bytes serde helper
and use base64::... imports into nd-pdk-types/src/lib.rs, but the crate manifest
declared only serde. In that case make gen produced a crate that failed to
compile with 'unresolved module base64'.
Add base64 = "0.22" (matching nd-pdk-capabilities) so the generated shared types
crate compiles whenever a []byte field is present. Verified by generating a
shared crate with a []byte field and confirming cargo check fails before and
passes after.
* fix(plugins): translate shared method types in generated Rust
A capability method using a shared DTO directly as input/output (e.g.
types.SongRef) was passed through rustOutputType unchanged, so the Rust template
emitted invalid trait and extism_pdk::Json<$crate::pkg::types.SongRef> signatures
that do not compile.
Method input/output types now resolve through the shared registry: trait
signatures use rustTraitType (shared -> nd_pdk_types::X, locals stay bare) and the
export macros use rustMethodType (fully qualified: shared -> nd_pdk_types::X,
primitives -> Rust, locals -> $crate::<pkg>::X). Verified end-to-end by compiling
a generated capability that takes types.SongRef directly against the real
nd-pdk-types crate.
* fix(plugins): canonicalize XTP export refs for renamed shared aliases
buildSchemas canonicalized alias-to-canonical references for struct-field $ref
targets, but buildExport built export input/output $refs straight from
fieldBaseType. A capability whose export used a renamed deprecated alias
directly (e.g. type TrackInfo = types.Track with NowPlaying(TrackInfo)) emitted
$ref: #/components/schemas/TrackInfo, while the component is emitted under the
canonical name Track — a dangling export reference.
Lift the alias-to-canonical map into GenerateSchema (buildAliasToCanonical) and
apply it to export refs via canonicalRefName, the same resolution already used
for field properties.
* fix(plugins): route shared macro types through $crate for plugin builds
When a capability method used a shared type directly, the generated export macro
named the type as nd_pdk_types::SongRef. The macro expands in the downstream
plugin crate, which depends on the umbrella nd-pdk crate and not on nd-pdk-types
directly, so that path is unresolvable there and the plugin fails to build.
rustMethodType (macro-facing) now emits $crate::types::X, and the generated
nd-pdk-capabilities lib.rs re-exports nd_pdk_types as types so $crate resolves
it. Trait signatures keep nd_pdk_types::X since they live in nd-pdk-capabilities,
which has the direct dependency. Verified end-to-end: a plugin crate depending
only on the umbrella that uses a capability with a direct types.X method now
compiles via the macro.
* fix(plugins): add nd-pdk-types dependency to the Rust host crate
When a host service uses a shared type, ndpgen emits nd_pdk_types::X into the
generated nd-pdk-host client wrappers, but the host crate's manifest did not
depend on nd-pdk-types, so the crate failed to compile with 'unresolved module
nd_pdk_types'. Host client wrappers are plain functions resolved in the host
crate's own context (not macros expanded downstream), so a direct dependency is
the right fix.
Add nd-pdk-types = { path = "../nd-pdk-types" } to nd-pdk-host, mirroring
nd-pdk-capabilities. Found while auditing all Rust paths against the realistic
crate topology after the capability-side $crate fix; verified by generating a
host service with a shared-type return and confirming cargo check fails before
and passes after.
* fix(plugins): resolve shared aliases in Rust host signatures
The Rust host client rendered method params and returns through
RustTypeWithStructs, which only consults KnownStructs. A host service using a
shared alias in a signature (e.g. type Track = types.Track plus
MatchSongs(...) ([]Track, error)) therefore emitted a bare Vec<Track>, but the
client template emits no Track alias or import, so the generated nd-pdk-host
crate did not compile. Only struct fields went through the shared map.
rustType/rustParamType now use the shared map too (RustTypeWithShared /
RustParamTypeWithShared), so an aliased param/return resolves to its canonical
nd_pdk_types::X path, matching field handling. Verified by generating a host
service returning a shared alias and confirming cargo check fails before and
passes after.
2026-06-29 21:20:33 -04:00
|
|
|
// Deprecated: use types.ArtistRef.
|
|
|
|
|
type ArtistRef = types.ArtistRef
|
|
|
|
|
|
feat(plugins): New Plugin System with multi-language PDK support (#4833)
* chore(plugins): remove the old plugins system implementation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement new plugin system with using Extism
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add capability detection for plugins based on exported functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add auto-reload functionality for plugins with file watcher support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add auto-reload functionality for plugins with file watcher support
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): standardize variable names and remove superfluous wrapper functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): improve error handling and logging in plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): implement plugin function call helper and refactor MetadataAgent methods
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): race condition in plugin manager
* tests(plugins): change BeforeEach to BeforeAll in MetadataAgent tests
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(plugins): optimize tests
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(plugins): more optimizations
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): ignore goroutine leaks from notify library in tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Wikimedia plugin for Navidrome to fetch artist metadata
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance plugin logging and set User-Agent header
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement scrobbler plugin with authorization and scrobbling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): integrate logs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): clean up manifest struct and improve plugin loading logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add metadata agent and scrobbler schemas for bootstrapping plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(hostgen): add hostgen tool for generating Extism host function wrappers
- Implemented hostgen tool to generate wrappers from annotated Go interfaces.
- Added command-line flags for input/output directories and package name.
- Introduced parsing and code generation logic for host services.
- Created test data for various service interfaces and expected generated code.
- Added documentation for host services and annotations for code generation.
- Implemented SubsonicAPI service with corresponding generated code.
* feat(subsonicapi): update Call method to return JSON string response
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement SubsonicAPI host function integration with permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(generator): error-only methods in response handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate client wrappers for host functions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(generator): remove error handling for response.Error in client templates
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): add Scheduler service interface with host function wrappers for scheduling tasks
* feat(plugins): add WASI build constraints to client wrapper templates, to avoid lint errors
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): implement Scheduler service with one-time and recurring scheduling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(manifest): remove unused ConfigPermission from permissions schema
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): add scheduler callback schema and implementation for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): streamline scheduling logic and remove unused callback tracking
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): add Close method for resource cleanup on plugin unload
Signed-off-by: Deluan <deluan@navidrome.org>
* docs(scheduler): clarify SchedulerCallback requirement for scheduling functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update wasm build rule to include all Go files in the directory
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: rewrite the wikimedia plugin using the XTP CLI
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): replace uuid with id.NewRandom for schedule ID generation
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: capabilities registration
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add scheduler service isolation test for plugin instances
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update plugin manager initialization and encapsulate logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add WebSocket service definitions for plugin communication
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement WebSocket service for plugin integration and connection management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Crypto Ticker example plugin for real-time cryptocurrency price updates via Coinbase WebSocket API
Also add the lifecycle capability
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: use context.Background() in invokeCallback for scheduled tasks
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename plugin.create() to plugin.instance()
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename pluginInstance to plugin for consistency across the codebase
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: simplify schedule cloning in Close method and enhance plugin cleanup error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement Artwork service for generating artwork URLs in Navidrome plugins - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: moved public URL builders to avoid import cycles
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Cache service for in-memory TTL-based caching in plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Discord Rich Presence example plugin for Navidrome integration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: host function wrappers to use structured request and response types
- Updated the host function signatures in `nd_host_artwork.go`, `nd_host_scheduler.go`, `nd_host_subsonicapi.go`, and `nd_host_websocket.go` to accept a single parameter for JSON requests.
- Introduced structured request and response types for various cache operations in `nd_host_cache.go`.
- Modified cache functions to marshal requests to JSON and unmarshal responses, improving error handling and code clarity.
- Removed redundant memory allocation for string parameters in favor of JSON marshaling.
- Enhanced error handling in WebSocket and cache operations to return structured error responses.
* refactor: error handling in various plugins to convert response.Error to Go errors
- Updated error handling in `nd_host_scheduler.go`, `nd_host_websocket.go`, `nd_host_artwork.go`, `nd_host_cache.go`, and `nd_host_subsonicapi.go` to convert string errors from responses into Go errors.
- Removed redundant error checks in test data plugins for cleaner code.
- Ensured consistent error handling across all plugins to improve reliability and maintainability.
* refactor: rename fake plugins to test plugins for clarity in integration tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add help target to Makefile for plugin usage instructions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Cover Art Archive plugin as an example of Python plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Makefile and README to clarify Go plugin usage
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: include plugin capabilities in loading log message
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add trace logging for plugin availability and error handling in agents
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Now Playing Logger plugin to showcase calling host functions from Python plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: generate Python client wrappers for various host services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add generated host function wrappers for Scheduler and SubsonicAPI services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Python plugin documentation and usage instructions for host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Webhook Scrobbler plugin in Rust to send HTTP notifications on scrobble events
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enable parallel loading of plugins during startup
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to include WebSocket callback schema in plugin documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: extend plugin watcher with improved logging and debounce duration adjustment
Signed-off-by: Deluan <deluan@navidrome.org>
* add trace message for plugin recompiles
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement plugin cache purging functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* test: move purgeCacheBySize unit tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add plugin repository and database support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add plugin management routes and middleware
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): implement plugin synchronization with database for add, update, and remove actions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add PluginList and PluginShow components with plugin management functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): optimize plugin change detection
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins UI): improve PluginList structure
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): enhance PluginShow with author, website, and permissions display
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): refactor to use MUI and RA components
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add error handling for plugin enable/disable actions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): inject PluginManager into native API
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update GetManager to accept DataStore parameter
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add subsonicRouter to Manager and refactor host service registration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): enhance debug logging for plugin actions and recompile logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): break manager.go into smaller, focused files
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): streamline error handling and improve plugin retrieval logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update newWebSocketService to use WebSocketPermission for allowed hosts
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): introduce ToggleEnabledSwitch for managing plugin enable/disable state
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update READMEs
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): add Library service for metadata access and filesystem integration
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Library Inspector plugin for periodic library inspection and file size logging
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to reflect JSON configuration format for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(build): update target to wasm32-wasip1 for improved WASI support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement configuration management UI with key-value pairs support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): adjust grid layout in InfoRow component for improved responsiveness
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): rename ErrorIndicator to EnabledOrErrorField and enhance error handling logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(i18n): add Portuguese translations for plugin management and notifications
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add support for .ndp plugin packages and update build process
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README for .ndp plugin packaging and installation instructions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement KVStore service for persistent key-value storage
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: enhance README with Extism plugin development resources and recommendations
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): integrate event broker into plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): update config handling in PluginShow to track last record state
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Rust host function library and example implementation of Discord Rich Presence plugin in Rust
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate Rust lib.rs file to expose host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update JSON field names to camelCase for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: reduce cyclomatic complexity by refactoring main function
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance Rust code generation with typed struct support and improved type handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Go client library with host function wrappers and documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate Go client stubs for non-WASM platforms
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): update client template file names for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add initial implementation of the Navidrome Plugin Development Kit code generator - Pahse 1
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2 (2)
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 3
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 4
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 5
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): consistent naming/types across PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): streamline plugin function signatures and error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update scrobbler interface to return errors directly instead of response structs
Signed-off-by: Deluan <deluan@navidrome.org>
* test: make all test plugins use the PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize and sort type definitions for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update error handling for methods to return errors directly
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update function signatures to return values directly instead of response structs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update request/response types to use private naming conventions
Signed-off-by: Deluan <deluan@navidrome.org>
* build: mark .wasm files as intermediate for cleanup after building .ndp
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): consolidate PDK module path and update Go version to 1.25
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement Rust PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize Rust output structure to follow standard conventions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update Discord Rich Presence and Library Inspector plugins to use nd-pdk for service calls and implement lifecycle management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update macro names for websocket and metadata registration to improve clarity and consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): rename scheduler callback methods for consistency and clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update export wrappers to use `//go:wasmexport` for WebAssembly compatibility
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update plugin registration docs
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): generate host wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): conditionally run goleak checks based on CI environment
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to reflect changes in plugin import paths
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update plugin instance creation to accept context for cancellation support
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update return types in metadata interfaces to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): enhance type handling for Rust and XTP output in capability generation
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update IsAuthorized method to return boolean instead of response object
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): add unit tests for rustOutputType and isPrimitiveRustType functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement XTP JSONSchema validation for generated schemas
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update response types in testMetadataAgent methods to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update Go and Rust plugin developer sections for clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: correct example link for library inspector in README
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: clarify artwork URL generation capabilities in service descriptions
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to include Rust PDK crate information for plugin developers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: handle URL parsing errors and use atomic upsert in plugin repository
Added proper error handling for url.Parse calls in PublicURL and AbsoluteURL
functions. When parsing fails, PublicURL now falls back to AbsoluteURL, and
AbsoluteURL logs the error and returns an empty string, preventing malformed
URLs from being generated.
Replaced the non-atomic UPDATE-then-INSERT pattern in plugin repository Put
method with a single atomic INSERT ... ON CONFLICT statement. This eliminates
potential race conditions and improves consistency with the upsert pattern
already used in host_kvstore.go.
* feat: implement mock service instances for non-WASM builds using testify/mock
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: Discord RPC struct to encapsulate WebSocket logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add support for experimental WebAssembly threads
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add PDK abstraction layer with mock support for non-WASM builds
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add unit tests for Discord plugin and RPC functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update return types in minimalPlugin and wikimediaPlugin methods to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: context cancellation and implement WebSocket callback timeout for improved error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: conditionally include error handling in generated client code templates
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement ConfigService for plugin configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance plugin manager to support metrics recording
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: make MockPDK private
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update interface types to use 'any' in plugin repository methods
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename List method to Keys for clarity in configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add ndpgen plugin tests in the pipeline and update Makefile
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add users permission management to plugin system
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: streamline users integration tests and enhance plugin user management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: remove UserID from scrobbler request structure
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add integration tests for UsersService enable gate behavior
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement user permissions for SubsonicAPI and scrobbler plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: show proper error in the UI when enabling a plugin fails
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add library permission management to plugin system
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add user permission for processing scrobbles in Discord Rich Presence plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: implement dynamic loading for buffered scrobbler plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add GetAdmins method to retrieve admin users from the plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Portuguese translations for user and library permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* reorder migrations
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: remove unnecessary bulkActionButtons prop from PluginList component
* feat: add manual plugin rescan functionality and corresponding UI action
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement user/library and plugin management integration with cleanup on deletion
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: replace core mock services with test-specific implementations to avoid import cycles
* feat: add ID fields to Artist and Song structs and enhance track loading logic by prioritizing ID matches
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update plugin permissions from allowedHosts to requiredHosts for better clarity and consistency
* feat: refactor plugin host permissions to use RequiredHosts directly for improved clarity
* fix: don't record metrics for plugin calls that aren't implemented at all
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: enhance connection management with improved error handling and cleanup logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: introduce ArtistRef struct for better artist representation and update track metadata handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update user configuration handling to use user key prefix for improved clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance ConfigCard input fields with multiline support and vertical resizing
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: rust plugin compilation error
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement IsOptionPattern method for better return type handling in Rust PDK generation
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-01-14 19:22:48 -05:00
|
|
|
// SimilarArtistsResponse is the response for GetSimilarArtists.
|
|
|
|
|
type SimilarArtistsResponse struct {
|
|
|
|
|
// Artists is the list of similar artists.
|
feat(plugins): share plugin DTOs via a types package (#5655)
* refactor(plugins): remove Python PDK generation from ndpgen
* feat(plugins): parse Go type aliases distinctly in ndpgen
* feat(plugins): resolve shared-type aliases against a registry in ndpgen
* fix(plugins): resolve host-service shared aliases package-wide
Mirror the capability approach in ParseDirectoryWithShared: do a first
pass over all package files to build a package-wide alias map, then pass
it into parseServiceFile so that a shared-type alias declared in a sibling
file is visible when resolving types in the service interface file.
Add a focused test that writes the alias in one file and the hostservice
in another, confirming RED before the fix and GREEN after. Also
strengthens the existing Task 3 test with an ArtistRef.Target assertion.
* feat(plugins): add ndpgen -shared-types mode for the Go types package
* feat(plugins): generate the nd-pdk-types Rust crate from -shared-types
* feat(plugins): inject types import and emit deprecated aliases in Go output
* feat(plugins): emit deprecated Rust aliases to the shared types crate
* feat(plugins): inline shared-type shapes into XTP schemas
* feat(plugins): add nd-pdk-types crate and wire dependents
* feat(plugins): move shared capability types to plugins/types with deprecated aliases
* fix(plugins): point Rust deprecated-alias note at the replacement type
* fix(plugins): include shared aliases in KnownStructs so Rust fields keep their type
Capability.KnownStructs() and Service.KnownStructs() previously only
registered names from .Structs. After the shared-types migration, types
like ArtistRef/TrackInfo/SongRef live in .SharedAliases instead, so
ToRustTypeWithStructs could not find them and fell back to serde_json::Value
for every struct field referencing a shared type.
Add the shared-alias names to the knownStructs map in both methods.
Regenerate the Rust capability files; track/song/artist fields now render
as their named types (TrackInfo, SongRef, ArtistRef, etc.).
Add a regression test that verifies a struct field whose type is only in
SharedAliases renders as the named type and not serde_json::Value.
* docs(plugins): remove stale Python references from ndpgen and plugins READMEs
ndpgen no longer has a -python flag; remove it from the usage synopsis,
flags table, and defaults note in ndpgen/README.md. Delete the "Python
Client Library" section that described its output.
plugins/README.md referenced plugins/pdk/python/host/ (deleted) as the
source for Python host-service stubs. Remove that paragraph; Python plugins
still work via the XTP-schema / extism-py path (see examples/*-py).
* refactor(plugins): dedupe ndpgen helpers and tidy shared-type codegen
* docs(plugins): restore Python as a supported XTP schema target
The ndpgen-generated Python PDK was removed, but the XTP YAML schemas are
language-neutral and the XTP CLI still generates Python bindings from them
(as the extism-py examples demonstrate). Only the ndpgen Python output was
dropped, not Python support itself.
* test(plugins): use the shared types package in test plugins
The test fixtures referenced the now-deprecated capability aliases
(sonicsimilarity.SongRef, metadata.ArtistRef/SongRef). Point them at the
canonical types package so our own fixtures don't depend on symbols slated
for removal.
* refactor(plugins): use the shared types package in host adapters
Replace deprecated capabilities.TrackInfo, capabilities.ArtistRef, and
capabilities.SongRef aliases with the canonical types.TrackInfo,
types.ArtistRef, and types.SongRef from plugins/types.
* fix(plugins): reference shared types by canonical path in generated Rust
Previously the generator emitted `pub field: SongRef` (the local deprecated
alias) for struct fields whose type came from SharedAliases. Refactored
ToRustTypeWithStructs into a private toRustType that accepts a shared map,
and added ToRustTypeWithShared which resolves shared-alias names to their
canonical nd_pdk_types::X path before falling through to the knownStructs
check. Both rustCapabilityFuncMap and rustFuncMap now build the shared map
from SharedAliases and use it for fieldRustType, so the generated capability
files reference nd_pdk_types::SongRef / nd_pdk_types::TrackInfo directly.
The deprecated pub type aliases remain in place as the external back-compat
surface. Deprecation warning count from cargo build drops to 0.
* fix(examples): implement missing Scrobbler.playback_report in Rust examples
The Scrobbler trait gained a playback_report method but the two Rust example
plugins (webhook-rs and discord-rich-presence-rs) were not updated, causing
E0046 compile errors. Added the missing fn playback_report to both: webhook-rs
logs and returns Ok(()) mirroring its now_playing handler; discord-rich-presence-rs
is a no-op since Discord presence does not need playback reports. make all-rust
now exits 0.
* refactor(plugins): point Rust deprecation notes at the nd_pdk::types umbrella path
Plugin authors depend on the nd-pdk umbrella crate, which re-exports
nd_pdk_types as 'types', so the migration target they should type is
nd_pdk::types::X. The alias target stays nd_pdk_types::X (the real path
inside nd-pdk-capabilities).
* fix(plugins): error when a shared-type alias can't be resolved against the registry
* refactor(plugins): parse each Go source file once in ndpgen
* fix(plugins): correct ndpgen review nits (flag name, unused dep, docs)
* refactor(plugins): drop the now-unused path param from parseServiceFile
* refactor(plugins): use shared types directly, rename TrackInfo to Track
Capability interfaces now reference the shared `types` package by qualified
name (types.Track, types.SongRef, types.ArtistRef) instead of the package-local
deprecated aliases, and the shared TrackInfo type is renamed to Track to match
its role as the plugin-facing projection of a library media file.
The deprecated bare aliases (scrobbler.TrackInfo, metadata.ArtistRef,
sonicsimilarity.SongRef, etc.) are kept as re-exports so existing plugins keep
compiling, with a deprecation warning steering them to the canonical types.
To support this, ndpgen now resolves qualified types.X references: it collects
them during type discovery, maps each used canonical type back to its declared
deprecated alias for re-export, emits nd_pdk_types::X paths in Rust, and names
the XTP schema components by their canonical type. Regenerated the Go and Rust
PDK and the XTP schemas, and added generator tests covering the qualified-ref
path. Also adds clarifying doc comments to the shared types.
* refactor(plugins): extract shared types selector into a named const
Replace the "types." string literal that detects and strips the shared types
package selector with a single sharedTypesPrefix constant across the ndpgen
generator (parser, types, generator, xtp_schema), giving the package one source
of truth for the selector.
Also restore the single reused scratch map (cleared each iteration) in the
resolveSharedAliases BFS instead of allocating a fresh map per shared-struct
field, matching the prior implementation.
Pure cleanup from a /simplify pass: regeneration produces byte-for-byte
identical Go, Rust, and XTP output.
* refactor(plugins): keep TrackInfo in the capability package for now
Move the track type back out of the shared plugins/types package: it is again
defined inline as TrackInfo in plugins/capabilities/scrobbler.go and referenced
directly by the scrobbler and lyrics capabilities, reverting the rename to
types.Track. The host helper is renamed back to mediaFileToTrackInfo and now
returns capabilities.TrackInfo. SongRef and ArtistRef stay in the shared types
package; TrackInfo keeps using types.ArtistRef for its artist lists.
This type is expected to be reshaped in upcoming work, so leaving it in the
capability package avoids churning the shared types twice. Regenerated the Go
and Rust PDK and the XTP schemas accordingly.
* fix(plugins): emit the Go types import for direct shared-type refs
ndpgen's Capability/Service.ImportsSharedTypes only reported a shared-types
dependency when a deprecated re-export alias (type X = types.X) was declared. A
struct field referencing the canonical form directly (e.g. types.SongRef) with
no such alias produced an empty SharedAliases slice, so the Go templates skipped
the import while still emitting fields/signatures using types.SongRef — leaving
generated PDK code for new shared DTOs uncompilable unless an otherwise
unnecessary alias was added.
ImportsSharedTypes now also returns true when any struct field references the
types. package by qualified name, via a new structsReferenceSharedTypes helper
that reuses collectReferencedTypes (so []types.X and map[...]types.X are covered
too).
* fix(plugins): preserve base64 encoding for shared byte fields in Rust
The Rust shared-types crate template rendered a []byte field as a plain Vec<u8>
without the base64_bytes serde override used by the capability/client templates.
Go's encoding/json serializes []byte as a base64 string, so a Rust plugin using
nd_pdk::types would have serialized an array of numbers instead of the wire
format the Go/server side expects.
GenerateSharedTypesRust now registers the base64_bytes partial and passes a
HasByteFields flag (new anyFieldIsByteSlice helper); types.rs.tmpl emits the
base64_bytes module and a #[serde(with = "base64_bytes")] attribute on []byte
fields, mirroring the capability template.
* fix(plugins): include directly-referenced shared types in XTP schemas
buildSchemas registered shared types into the schema components only by iterating
cap.SharedAliases, which records deprecated re-export aliases. A capability that
referenced a shared DTO solely as types.Foo (no declared alias) therefore never
got Foo into the component set, so the self-contained XTP schema rendered the
field as a generic object (or emitted a dangling $ref), breaking the direct
shared-type use case enabled by -shared.
resolveSharedAliases now also returns the resolved shapes of every used shared
type (alias or not); these are carried on the new Capability.SharedTypes field
and registered by buildSchemas alongside SharedAliases. Validated end-to-end with
the xtp CLI: a direct types.Foo reference now produces a proper component plus a
$ref, so xtp generates a typed struct instead of an untyped serde_json::Map.
* fix(plugins): resolve renamed shared aliases to canonical schema refs
When a deprecated alias renames its canonical type (e.g. type TrackInfo =
types.Track) and a capability field is typed with the alias name (TrackInfo),
buildProperty emitted a $ref to #/components/schemas/TrackInfo. Components are
keyed by the canonical name (Track), so no TrackInfo component was emitted,
leaving a dangling reference that crashes the xtp code generator.
buildSchemas now builds an alias->canonical map; buildProperty (and the slice
item path) resolves $ref targets through it, and a used alias name marks its
canonical component used so it is emitted. Validated with the xtp CLI: the
renamed-alias schema previously crashed xtp and now generates cleanly.
* fix(plugins): detect shared types used directly in method signatures
ImportsSharedTypes only inspected struct fields, so a capability method using a
shared type directly in its signature (e.g. types.SongRef as input/output rather
than inside a local struct) was not detected. The generated Go templates still
rendered the provider/export signatures with types.SongRef, so the capability
package omitted the types import and failed to compile; the same gap applied to
service params/returns.
ImportsSharedTypes now also scans capability method input/output types and
service method params/returns, via a typeReferencesSharedTypes helper that reuses
collectReferencedTypes (covering pointer/slice/map wrappers).
* fix(plugins): add base64 dependency to the shared Rust types crate
When a shared DTO has a []byte field, ndpgen emits the base64_bytes serde helper
and use base64::... imports into nd-pdk-types/src/lib.rs, but the crate manifest
declared only serde. In that case make gen produced a crate that failed to
compile with 'unresolved module base64'.
Add base64 = "0.22" (matching nd-pdk-capabilities) so the generated shared types
crate compiles whenever a []byte field is present. Verified by generating a
shared crate with a []byte field and confirming cargo check fails before and
passes after.
* fix(plugins): translate shared method types in generated Rust
A capability method using a shared DTO directly as input/output (e.g.
types.SongRef) was passed through rustOutputType unchanged, so the Rust template
emitted invalid trait and extism_pdk::Json<$crate::pkg::types.SongRef> signatures
that do not compile.
Method input/output types now resolve through the shared registry: trait
signatures use rustTraitType (shared -> nd_pdk_types::X, locals stay bare) and the
export macros use rustMethodType (fully qualified: shared -> nd_pdk_types::X,
primitives -> Rust, locals -> $crate::<pkg>::X). Verified end-to-end by compiling
a generated capability that takes types.SongRef directly against the real
nd-pdk-types crate.
* fix(plugins): canonicalize XTP export refs for renamed shared aliases
buildSchemas canonicalized alias-to-canonical references for struct-field $ref
targets, but buildExport built export input/output $refs straight from
fieldBaseType. A capability whose export used a renamed deprecated alias
directly (e.g. type TrackInfo = types.Track with NowPlaying(TrackInfo)) emitted
$ref: #/components/schemas/TrackInfo, while the component is emitted under the
canonical name Track — a dangling export reference.
Lift the alias-to-canonical map into GenerateSchema (buildAliasToCanonical) and
apply it to export refs via canonicalRefName, the same resolution already used
for field properties.
* fix(plugins): route shared macro types through $crate for plugin builds
When a capability method used a shared type directly, the generated export macro
named the type as nd_pdk_types::SongRef. The macro expands in the downstream
plugin crate, which depends on the umbrella nd-pdk crate and not on nd-pdk-types
directly, so that path is unresolvable there and the plugin fails to build.
rustMethodType (macro-facing) now emits $crate::types::X, and the generated
nd-pdk-capabilities lib.rs re-exports nd_pdk_types as types so $crate resolves
it. Trait signatures keep nd_pdk_types::X since they live in nd-pdk-capabilities,
which has the direct dependency. Verified end-to-end: a plugin crate depending
only on the umbrella that uses a capability with a direct types.X method now
compiles via the macro.
* fix(plugins): add nd-pdk-types dependency to the Rust host crate
When a host service uses a shared type, ndpgen emits nd_pdk_types::X into the
generated nd-pdk-host client wrappers, but the host crate's manifest did not
depend on nd-pdk-types, so the crate failed to compile with 'unresolved module
nd_pdk_types'. Host client wrappers are plain functions resolved in the host
crate's own context (not macros expanded downstream), so a direct dependency is
the right fix.
Add nd-pdk-types = { path = "../nd-pdk-types" } to nd-pdk-host, mirroring
nd-pdk-capabilities. Found while auditing all Rust paths against the realistic
crate topology after the capability-side $crate fix; verified by generating a
host service with a shared-type return and confirming cargo check fails before
and passes after.
* fix(plugins): resolve shared aliases in Rust host signatures
The Rust host client rendered method params and returns through
RustTypeWithStructs, which only consults KnownStructs. A host service using a
shared alias in a signature (e.g. type Track = types.Track plus
MatchSongs(...) ([]Track, error)) therefore emitted a bare Vec<Track>, but the
client template emits no Track alias or import, so the generated nd-pdk-host
crate did not compile. Only struct fields went through the shared map.
rustType/rustParamType now use the shared map too (RustTypeWithShared /
RustParamTypeWithShared), so an aliased param/return resolves to its canonical
nd_pdk_types::X path, matching field handling. Verified by generating a host
service returning a shared alias and confirming cargo check fails before and
passes after.
2026-06-29 21:20:33 -04:00
|
|
|
Artists []types.ArtistRef `json:"artists"`
|
feat(plugins): New Plugin System with multi-language PDK support (#4833)
* chore(plugins): remove the old plugins system implementation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement new plugin system with using Extism
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add capability detection for plugins based on exported functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add auto-reload functionality for plugins with file watcher support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add auto-reload functionality for plugins with file watcher support
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): standardize variable names and remove superfluous wrapper functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): improve error handling and logging in plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): implement plugin function call helper and refactor MetadataAgent methods
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): race condition in plugin manager
* tests(plugins): change BeforeEach to BeforeAll in MetadataAgent tests
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(plugins): optimize tests
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(plugins): more optimizations
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): ignore goroutine leaks from notify library in tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Wikimedia plugin for Navidrome to fetch artist metadata
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance plugin logging and set User-Agent header
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement scrobbler plugin with authorization and scrobbling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): integrate logs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): clean up manifest struct and improve plugin loading logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add metadata agent and scrobbler schemas for bootstrapping plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(hostgen): add hostgen tool for generating Extism host function wrappers
- Implemented hostgen tool to generate wrappers from annotated Go interfaces.
- Added command-line flags for input/output directories and package name.
- Introduced parsing and code generation logic for host services.
- Created test data for various service interfaces and expected generated code.
- Added documentation for host services and annotations for code generation.
- Implemented SubsonicAPI service with corresponding generated code.
* feat(subsonicapi): update Call method to return JSON string response
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement SubsonicAPI host function integration with permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(generator): error-only methods in response handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate client wrappers for host functions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(generator): remove error handling for response.Error in client templates
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): add Scheduler service interface with host function wrappers for scheduling tasks
* feat(plugins): add WASI build constraints to client wrapper templates, to avoid lint errors
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): implement Scheduler service with one-time and recurring scheduling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(manifest): remove unused ConfigPermission from permissions schema
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): add scheduler callback schema and implementation for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): streamline scheduling logic and remove unused callback tracking
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): add Close method for resource cleanup on plugin unload
Signed-off-by: Deluan <deluan@navidrome.org>
* docs(scheduler): clarify SchedulerCallback requirement for scheduling functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update wasm build rule to include all Go files in the directory
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: rewrite the wikimedia plugin using the XTP CLI
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): replace uuid with id.NewRandom for schedule ID generation
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: capabilities registration
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add scheduler service isolation test for plugin instances
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update plugin manager initialization and encapsulate logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add WebSocket service definitions for plugin communication
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement WebSocket service for plugin integration and connection management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Crypto Ticker example plugin for real-time cryptocurrency price updates via Coinbase WebSocket API
Also add the lifecycle capability
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: use context.Background() in invokeCallback for scheduled tasks
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename plugin.create() to plugin.instance()
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename pluginInstance to plugin for consistency across the codebase
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: simplify schedule cloning in Close method and enhance plugin cleanup error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement Artwork service for generating artwork URLs in Navidrome plugins - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: moved public URL builders to avoid import cycles
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Cache service for in-memory TTL-based caching in plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Discord Rich Presence example plugin for Navidrome integration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: host function wrappers to use structured request and response types
- Updated the host function signatures in `nd_host_artwork.go`, `nd_host_scheduler.go`, `nd_host_subsonicapi.go`, and `nd_host_websocket.go` to accept a single parameter for JSON requests.
- Introduced structured request and response types for various cache operations in `nd_host_cache.go`.
- Modified cache functions to marshal requests to JSON and unmarshal responses, improving error handling and code clarity.
- Removed redundant memory allocation for string parameters in favor of JSON marshaling.
- Enhanced error handling in WebSocket and cache operations to return structured error responses.
* refactor: error handling in various plugins to convert response.Error to Go errors
- Updated error handling in `nd_host_scheduler.go`, `nd_host_websocket.go`, `nd_host_artwork.go`, `nd_host_cache.go`, and `nd_host_subsonicapi.go` to convert string errors from responses into Go errors.
- Removed redundant error checks in test data plugins for cleaner code.
- Ensured consistent error handling across all plugins to improve reliability and maintainability.
* refactor: rename fake plugins to test plugins for clarity in integration tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add help target to Makefile for plugin usage instructions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Cover Art Archive plugin as an example of Python plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Makefile and README to clarify Go plugin usage
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: include plugin capabilities in loading log message
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add trace logging for plugin availability and error handling in agents
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Now Playing Logger plugin to showcase calling host functions from Python plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: generate Python client wrappers for various host services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add generated host function wrappers for Scheduler and SubsonicAPI services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Python plugin documentation and usage instructions for host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Webhook Scrobbler plugin in Rust to send HTTP notifications on scrobble events
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enable parallel loading of plugins during startup
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to include WebSocket callback schema in plugin documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: extend plugin watcher with improved logging and debounce duration adjustment
Signed-off-by: Deluan <deluan@navidrome.org>
* add trace message for plugin recompiles
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement plugin cache purging functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* test: move purgeCacheBySize unit tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add plugin repository and database support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add plugin management routes and middleware
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): implement plugin synchronization with database for add, update, and remove actions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add PluginList and PluginShow components with plugin management functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): optimize plugin change detection
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins UI): improve PluginList structure
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): enhance PluginShow with author, website, and permissions display
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): refactor to use MUI and RA components
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add error handling for plugin enable/disable actions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): inject PluginManager into native API
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update GetManager to accept DataStore parameter
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add subsonicRouter to Manager and refactor host service registration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): enhance debug logging for plugin actions and recompile logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): break manager.go into smaller, focused files
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): streamline error handling and improve plugin retrieval logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update newWebSocketService to use WebSocketPermission for allowed hosts
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): introduce ToggleEnabledSwitch for managing plugin enable/disable state
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update READMEs
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): add Library service for metadata access and filesystem integration
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Library Inspector plugin for periodic library inspection and file size logging
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to reflect JSON configuration format for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(build): update target to wasm32-wasip1 for improved WASI support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement configuration management UI with key-value pairs support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): adjust grid layout in InfoRow component for improved responsiveness
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): rename ErrorIndicator to EnabledOrErrorField and enhance error handling logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(i18n): add Portuguese translations for plugin management and notifications
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add support for .ndp plugin packages and update build process
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README for .ndp plugin packaging and installation instructions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement KVStore service for persistent key-value storage
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: enhance README with Extism plugin development resources and recommendations
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): integrate event broker into plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): update config handling in PluginShow to track last record state
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Rust host function library and example implementation of Discord Rich Presence plugin in Rust
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate Rust lib.rs file to expose host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update JSON field names to camelCase for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: reduce cyclomatic complexity by refactoring main function
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance Rust code generation with typed struct support and improved type handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Go client library with host function wrappers and documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate Go client stubs for non-WASM platforms
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): update client template file names for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add initial implementation of the Navidrome Plugin Development Kit code generator - Pahse 1
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2 (2)
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 3
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 4
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 5
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): consistent naming/types across PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): streamline plugin function signatures and error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update scrobbler interface to return errors directly instead of response structs
Signed-off-by: Deluan <deluan@navidrome.org>
* test: make all test plugins use the PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize and sort type definitions for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update error handling for methods to return errors directly
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update function signatures to return values directly instead of response structs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update request/response types to use private naming conventions
Signed-off-by: Deluan <deluan@navidrome.org>
* build: mark .wasm files as intermediate for cleanup after building .ndp
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): consolidate PDK module path and update Go version to 1.25
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement Rust PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize Rust output structure to follow standard conventions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update Discord Rich Presence and Library Inspector plugins to use nd-pdk for service calls and implement lifecycle management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update macro names for websocket and metadata registration to improve clarity and consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): rename scheduler callback methods for consistency and clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update export wrappers to use `//go:wasmexport` for WebAssembly compatibility
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update plugin registration docs
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): generate host wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): conditionally run goleak checks based on CI environment
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to reflect changes in plugin import paths
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update plugin instance creation to accept context for cancellation support
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update return types in metadata interfaces to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): enhance type handling for Rust and XTP output in capability generation
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update IsAuthorized method to return boolean instead of response object
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): add unit tests for rustOutputType and isPrimitiveRustType functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement XTP JSONSchema validation for generated schemas
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update response types in testMetadataAgent methods to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update Go and Rust plugin developer sections for clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: correct example link for library inspector in README
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: clarify artwork URL generation capabilities in service descriptions
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to include Rust PDK crate information for plugin developers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: handle URL parsing errors and use atomic upsert in plugin repository
Added proper error handling for url.Parse calls in PublicURL and AbsoluteURL
functions. When parsing fails, PublicURL now falls back to AbsoluteURL, and
AbsoluteURL logs the error and returns an empty string, preventing malformed
URLs from being generated.
Replaced the non-atomic UPDATE-then-INSERT pattern in plugin repository Put
method with a single atomic INSERT ... ON CONFLICT statement. This eliminates
potential race conditions and improves consistency with the upsert pattern
already used in host_kvstore.go.
* feat: implement mock service instances for non-WASM builds using testify/mock
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: Discord RPC struct to encapsulate WebSocket logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add support for experimental WebAssembly threads
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add PDK abstraction layer with mock support for non-WASM builds
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add unit tests for Discord plugin and RPC functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update return types in minimalPlugin and wikimediaPlugin methods to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: context cancellation and implement WebSocket callback timeout for improved error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: conditionally include error handling in generated client code templates
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement ConfigService for plugin configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance plugin manager to support metrics recording
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: make MockPDK private
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update interface types to use 'any' in plugin repository methods
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename List method to Keys for clarity in configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add ndpgen plugin tests in the pipeline and update Makefile
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add users permission management to plugin system
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: streamline users integration tests and enhance plugin user management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: remove UserID from scrobbler request structure
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add integration tests for UsersService enable gate behavior
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement user permissions for SubsonicAPI and scrobbler plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: show proper error in the UI when enabling a plugin fails
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add library permission management to plugin system
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add user permission for processing scrobbles in Discord Rich Presence plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: implement dynamic loading for buffered scrobbler plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add GetAdmins method to retrieve admin users from the plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Portuguese translations for user and library permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* reorder migrations
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: remove unnecessary bulkActionButtons prop from PluginList component
* feat: add manual plugin rescan functionality and corresponding UI action
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement user/library and plugin management integration with cleanup on deletion
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: replace core mock services with test-specific implementations to avoid import cycles
* feat: add ID fields to Artist and Song structs and enhance track loading logic by prioritizing ID matches
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update plugin permissions from allowedHosts to requiredHosts for better clarity and consistency
* feat: refactor plugin host permissions to use RequiredHosts directly for improved clarity
* fix: don't record metrics for plugin calls that aren't implemented at all
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: enhance connection management with improved error handling and cleanup logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: introduce ArtistRef struct for better artist representation and update track metadata handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update user configuration handling to use user key prefix for improved clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance ConfigCard input fields with multiline support and vertical resizing
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: rust plugin compilation error
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement IsOptionPattern method for better return type handling in Rust PDK generation
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-01-14 19:22:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ImageInfo represents an image with URL and size.
|
|
|
|
|
type ImageInfo struct {
|
|
|
|
|
// URL is the URL of the image.
|
|
|
|
|
URL string `json:"url"`
|
|
|
|
|
// Size is the size of the image in pixels (width or height).
|
|
|
|
|
Size int32 `json:"size"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ArtistImagesResponse is the response for GetArtistImages.
|
|
|
|
|
type ArtistImagesResponse struct {
|
|
|
|
|
// Images is the list of artist images.
|
|
|
|
|
Images []ImageInfo `json:"images"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TopSongsRequest is the request for GetArtistTopSongs.
|
|
|
|
|
type TopSongsRequest struct {
|
|
|
|
|
// ID is the internal Navidrome artist ID.
|
|
|
|
|
ID string `json:"id"`
|
|
|
|
|
// Name is the artist name.
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
// MBID is the MusicBrainz ID for the artist (if known).
|
|
|
|
|
MBID string `json:"mbid,omitempty"`
|
|
|
|
|
// Count is the maximum number of top songs to return.
|
|
|
|
|
Count int32 `json:"count"`
|
|
|
|
|
}
|
|
|
|
|
|
feat(plugins): share plugin DTOs via a types package (#5655)
* refactor(plugins): remove Python PDK generation from ndpgen
* feat(plugins): parse Go type aliases distinctly in ndpgen
* feat(plugins): resolve shared-type aliases against a registry in ndpgen
* fix(plugins): resolve host-service shared aliases package-wide
Mirror the capability approach in ParseDirectoryWithShared: do a first
pass over all package files to build a package-wide alias map, then pass
it into parseServiceFile so that a shared-type alias declared in a sibling
file is visible when resolving types in the service interface file.
Add a focused test that writes the alias in one file and the hostservice
in another, confirming RED before the fix and GREEN after. Also
strengthens the existing Task 3 test with an ArtistRef.Target assertion.
* feat(plugins): add ndpgen -shared-types mode for the Go types package
* feat(plugins): generate the nd-pdk-types Rust crate from -shared-types
* feat(plugins): inject types import and emit deprecated aliases in Go output
* feat(plugins): emit deprecated Rust aliases to the shared types crate
* feat(plugins): inline shared-type shapes into XTP schemas
* feat(plugins): add nd-pdk-types crate and wire dependents
* feat(plugins): move shared capability types to plugins/types with deprecated aliases
* fix(plugins): point Rust deprecated-alias note at the replacement type
* fix(plugins): include shared aliases in KnownStructs so Rust fields keep their type
Capability.KnownStructs() and Service.KnownStructs() previously only
registered names from .Structs. After the shared-types migration, types
like ArtistRef/TrackInfo/SongRef live in .SharedAliases instead, so
ToRustTypeWithStructs could not find them and fell back to serde_json::Value
for every struct field referencing a shared type.
Add the shared-alias names to the knownStructs map in both methods.
Regenerate the Rust capability files; track/song/artist fields now render
as their named types (TrackInfo, SongRef, ArtistRef, etc.).
Add a regression test that verifies a struct field whose type is only in
SharedAliases renders as the named type and not serde_json::Value.
* docs(plugins): remove stale Python references from ndpgen and plugins READMEs
ndpgen no longer has a -python flag; remove it from the usage synopsis,
flags table, and defaults note in ndpgen/README.md. Delete the "Python
Client Library" section that described its output.
plugins/README.md referenced plugins/pdk/python/host/ (deleted) as the
source for Python host-service stubs. Remove that paragraph; Python plugins
still work via the XTP-schema / extism-py path (see examples/*-py).
* refactor(plugins): dedupe ndpgen helpers and tidy shared-type codegen
* docs(plugins): restore Python as a supported XTP schema target
The ndpgen-generated Python PDK was removed, but the XTP YAML schemas are
language-neutral and the XTP CLI still generates Python bindings from them
(as the extism-py examples demonstrate). Only the ndpgen Python output was
dropped, not Python support itself.
* test(plugins): use the shared types package in test plugins
The test fixtures referenced the now-deprecated capability aliases
(sonicsimilarity.SongRef, metadata.ArtistRef/SongRef). Point them at the
canonical types package so our own fixtures don't depend on symbols slated
for removal.
* refactor(plugins): use the shared types package in host adapters
Replace deprecated capabilities.TrackInfo, capabilities.ArtistRef, and
capabilities.SongRef aliases with the canonical types.TrackInfo,
types.ArtistRef, and types.SongRef from plugins/types.
* fix(plugins): reference shared types by canonical path in generated Rust
Previously the generator emitted `pub field: SongRef` (the local deprecated
alias) for struct fields whose type came from SharedAliases. Refactored
ToRustTypeWithStructs into a private toRustType that accepts a shared map,
and added ToRustTypeWithShared which resolves shared-alias names to their
canonical nd_pdk_types::X path before falling through to the knownStructs
check. Both rustCapabilityFuncMap and rustFuncMap now build the shared map
from SharedAliases and use it for fieldRustType, so the generated capability
files reference nd_pdk_types::SongRef / nd_pdk_types::TrackInfo directly.
The deprecated pub type aliases remain in place as the external back-compat
surface. Deprecation warning count from cargo build drops to 0.
* fix(examples): implement missing Scrobbler.playback_report in Rust examples
The Scrobbler trait gained a playback_report method but the two Rust example
plugins (webhook-rs and discord-rich-presence-rs) were not updated, causing
E0046 compile errors. Added the missing fn playback_report to both: webhook-rs
logs and returns Ok(()) mirroring its now_playing handler; discord-rich-presence-rs
is a no-op since Discord presence does not need playback reports. make all-rust
now exits 0.
* refactor(plugins): point Rust deprecation notes at the nd_pdk::types umbrella path
Plugin authors depend on the nd-pdk umbrella crate, which re-exports
nd_pdk_types as 'types', so the migration target they should type is
nd_pdk::types::X. The alias target stays nd_pdk_types::X (the real path
inside nd-pdk-capabilities).
* fix(plugins): error when a shared-type alias can't be resolved against the registry
* refactor(plugins): parse each Go source file once in ndpgen
* fix(plugins): correct ndpgen review nits (flag name, unused dep, docs)
* refactor(plugins): drop the now-unused path param from parseServiceFile
* refactor(plugins): use shared types directly, rename TrackInfo to Track
Capability interfaces now reference the shared `types` package by qualified
name (types.Track, types.SongRef, types.ArtistRef) instead of the package-local
deprecated aliases, and the shared TrackInfo type is renamed to Track to match
its role as the plugin-facing projection of a library media file.
The deprecated bare aliases (scrobbler.TrackInfo, metadata.ArtistRef,
sonicsimilarity.SongRef, etc.) are kept as re-exports so existing plugins keep
compiling, with a deprecation warning steering them to the canonical types.
To support this, ndpgen now resolves qualified types.X references: it collects
them during type discovery, maps each used canonical type back to its declared
deprecated alias for re-export, emits nd_pdk_types::X paths in Rust, and names
the XTP schema components by their canonical type. Regenerated the Go and Rust
PDK and the XTP schemas, and added generator tests covering the qualified-ref
path. Also adds clarifying doc comments to the shared types.
* refactor(plugins): extract shared types selector into a named const
Replace the "types." string literal that detects and strips the shared types
package selector with a single sharedTypesPrefix constant across the ndpgen
generator (parser, types, generator, xtp_schema), giving the package one source
of truth for the selector.
Also restore the single reused scratch map (cleared each iteration) in the
resolveSharedAliases BFS instead of allocating a fresh map per shared-struct
field, matching the prior implementation.
Pure cleanup from a /simplify pass: regeneration produces byte-for-byte
identical Go, Rust, and XTP output.
* refactor(plugins): keep TrackInfo in the capability package for now
Move the track type back out of the shared plugins/types package: it is again
defined inline as TrackInfo in plugins/capabilities/scrobbler.go and referenced
directly by the scrobbler and lyrics capabilities, reverting the rename to
types.Track. The host helper is renamed back to mediaFileToTrackInfo and now
returns capabilities.TrackInfo. SongRef and ArtistRef stay in the shared types
package; TrackInfo keeps using types.ArtistRef for its artist lists.
This type is expected to be reshaped in upcoming work, so leaving it in the
capability package avoids churning the shared types twice. Regenerated the Go
and Rust PDK and the XTP schemas accordingly.
* fix(plugins): emit the Go types import for direct shared-type refs
ndpgen's Capability/Service.ImportsSharedTypes only reported a shared-types
dependency when a deprecated re-export alias (type X = types.X) was declared. A
struct field referencing the canonical form directly (e.g. types.SongRef) with
no such alias produced an empty SharedAliases slice, so the Go templates skipped
the import while still emitting fields/signatures using types.SongRef — leaving
generated PDK code for new shared DTOs uncompilable unless an otherwise
unnecessary alias was added.
ImportsSharedTypes now also returns true when any struct field references the
types. package by qualified name, via a new structsReferenceSharedTypes helper
that reuses collectReferencedTypes (so []types.X and map[...]types.X are covered
too).
* fix(plugins): preserve base64 encoding for shared byte fields in Rust
The Rust shared-types crate template rendered a []byte field as a plain Vec<u8>
without the base64_bytes serde override used by the capability/client templates.
Go's encoding/json serializes []byte as a base64 string, so a Rust plugin using
nd_pdk::types would have serialized an array of numbers instead of the wire
format the Go/server side expects.
GenerateSharedTypesRust now registers the base64_bytes partial and passes a
HasByteFields flag (new anyFieldIsByteSlice helper); types.rs.tmpl emits the
base64_bytes module and a #[serde(with = "base64_bytes")] attribute on []byte
fields, mirroring the capability template.
* fix(plugins): include directly-referenced shared types in XTP schemas
buildSchemas registered shared types into the schema components only by iterating
cap.SharedAliases, which records deprecated re-export aliases. A capability that
referenced a shared DTO solely as types.Foo (no declared alias) therefore never
got Foo into the component set, so the self-contained XTP schema rendered the
field as a generic object (or emitted a dangling $ref), breaking the direct
shared-type use case enabled by -shared.
resolveSharedAliases now also returns the resolved shapes of every used shared
type (alias or not); these are carried on the new Capability.SharedTypes field
and registered by buildSchemas alongside SharedAliases. Validated end-to-end with
the xtp CLI: a direct types.Foo reference now produces a proper component plus a
$ref, so xtp generates a typed struct instead of an untyped serde_json::Map.
* fix(plugins): resolve renamed shared aliases to canonical schema refs
When a deprecated alias renames its canonical type (e.g. type TrackInfo =
types.Track) and a capability field is typed with the alias name (TrackInfo),
buildProperty emitted a $ref to #/components/schemas/TrackInfo. Components are
keyed by the canonical name (Track), so no TrackInfo component was emitted,
leaving a dangling reference that crashes the xtp code generator.
buildSchemas now builds an alias->canonical map; buildProperty (and the slice
item path) resolves $ref targets through it, and a used alias name marks its
canonical component used so it is emitted. Validated with the xtp CLI: the
renamed-alias schema previously crashed xtp and now generates cleanly.
* fix(plugins): detect shared types used directly in method signatures
ImportsSharedTypes only inspected struct fields, so a capability method using a
shared type directly in its signature (e.g. types.SongRef as input/output rather
than inside a local struct) was not detected. The generated Go templates still
rendered the provider/export signatures with types.SongRef, so the capability
package omitted the types import and failed to compile; the same gap applied to
service params/returns.
ImportsSharedTypes now also scans capability method input/output types and
service method params/returns, via a typeReferencesSharedTypes helper that reuses
collectReferencedTypes (covering pointer/slice/map wrappers).
* fix(plugins): add base64 dependency to the shared Rust types crate
When a shared DTO has a []byte field, ndpgen emits the base64_bytes serde helper
and use base64::... imports into nd-pdk-types/src/lib.rs, but the crate manifest
declared only serde. In that case make gen produced a crate that failed to
compile with 'unresolved module base64'.
Add base64 = "0.22" (matching nd-pdk-capabilities) so the generated shared types
crate compiles whenever a []byte field is present. Verified by generating a
shared crate with a []byte field and confirming cargo check fails before and
passes after.
* fix(plugins): translate shared method types in generated Rust
A capability method using a shared DTO directly as input/output (e.g.
types.SongRef) was passed through rustOutputType unchanged, so the Rust template
emitted invalid trait and extism_pdk::Json<$crate::pkg::types.SongRef> signatures
that do not compile.
Method input/output types now resolve through the shared registry: trait
signatures use rustTraitType (shared -> nd_pdk_types::X, locals stay bare) and the
export macros use rustMethodType (fully qualified: shared -> nd_pdk_types::X,
primitives -> Rust, locals -> $crate::<pkg>::X). Verified end-to-end by compiling
a generated capability that takes types.SongRef directly against the real
nd-pdk-types crate.
* fix(plugins): canonicalize XTP export refs for renamed shared aliases
buildSchemas canonicalized alias-to-canonical references for struct-field $ref
targets, but buildExport built export input/output $refs straight from
fieldBaseType. A capability whose export used a renamed deprecated alias
directly (e.g. type TrackInfo = types.Track with NowPlaying(TrackInfo)) emitted
$ref: #/components/schemas/TrackInfo, while the component is emitted under the
canonical name Track — a dangling export reference.
Lift the alias-to-canonical map into GenerateSchema (buildAliasToCanonical) and
apply it to export refs via canonicalRefName, the same resolution already used
for field properties.
* fix(plugins): route shared macro types through $crate for plugin builds
When a capability method used a shared type directly, the generated export macro
named the type as nd_pdk_types::SongRef. The macro expands in the downstream
plugin crate, which depends on the umbrella nd-pdk crate and not on nd-pdk-types
directly, so that path is unresolvable there and the plugin fails to build.
rustMethodType (macro-facing) now emits $crate::types::X, and the generated
nd-pdk-capabilities lib.rs re-exports nd_pdk_types as types so $crate resolves
it. Trait signatures keep nd_pdk_types::X since they live in nd-pdk-capabilities,
which has the direct dependency. Verified end-to-end: a plugin crate depending
only on the umbrella that uses a capability with a direct types.X method now
compiles via the macro.
* fix(plugins): add nd-pdk-types dependency to the Rust host crate
When a host service uses a shared type, ndpgen emits nd_pdk_types::X into the
generated nd-pdk-host client wrappers, but the host crate's manifest did not
depend on nd-pdk-types, so the crate failed to compile with 'unresolved module
nd_pdk_types'. Host client wrappers are plain functions resolved in the host
crate's own context (not macros expanded downstream), so a direct dependency is
the right fix.
Add nd-pdk-types = { path = "../nd-pdk-types" } to nd-pdk-host, mirroring
nd-pdk-capabilities. Found while auditing all Rust paths against the realistic
crate topology after the capability-side $crate fix; verified by generating a
host service with a shared-type return and confirming cargo check fails before
and passes after.
* fix(plugins): resolve shared aliases in Rust host signatures
The Rust host client rendered method params and returns through
RustTypeWithStructs, which only consults KnownStructs. A host service using a
shared alias in a signature (e.g. type Track = types.Track plus
MatchSongs(...) ([]Track, error)) therefore emitted a bare Vec<Track>, but the
client template emits no Track alias or import, so the generated nd-pdk-host
crate did not compile. Only struct fields went through the shared map.
rustType/rustParamType now use the shared map too (RustTypeWithShared /
RustParamTypeWithShared), so an aliased param/return resolves to its canonical
nd_pdk_types::X path, matching field handling. Verified by generating a host
service returning a shared alias and confirming cargo check fails before and
passes after.
2026-06-29 21:20:33 -04:00
|
|
|
// Deprecated: use types.SongRef.
|
|
|
|
|
type SongRef = types.SongRef
|
feat(plugins): New Plugin System with multi-language PDK support (#4833)
* chore(plugins): remove the old plugins system implementation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement new plugin system with using Extism
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add capability detection for plugins based on exported functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add auto-reload functionality for plugins with file watcher support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add auto-reload functionality for plugins with file watcher support
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): standardize variable names and remove superfluous wrapper functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): improve error handling and logging in plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): implement plugin function call helper and refactor MetadataAgent methods
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): race condition in plugin manager
* tests(plugins): change BeforeEach to BeforeAll in MetadataAgent tests
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(plugins): optimize tests
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(plugins): more optimizations
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): ignore goroutine leaks from notify library in tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Wikimedia plugin for Navidrome to fetch artist metadata
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance plugin logging and set User-Agent header
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement scrobbler plugin with authorization and scrobbling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): integrate logs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): clean up manifest struct and improve plugin loading logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add metadata agent and scrobbler schemas for bootstrapping plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(hostgen): add hostgen tool for generating Extism host function wrappers
- Implemented hostgen tool to generate wrappers from annotated Go interfaces.
- Added command-line flags for input/output directories and package name.
- Introduced parsing and code generation logic for host services.
- Created test data for various service interfaces and expected generated code.
- Added documentation for host services and annotations for code generation.
- Implemented SubsonicAPI service with corresponding generated code.
* feat(subsonicapi): update Call method to return JSON string response
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement SubsonicAPI host function integration with permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(generator): error-only methods in response handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate client wrappers for host functions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(generator): remove error handling for response.Error in client templates
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): add Scheduler service interface with host function wrappers for scheduling tasks
* feat(plugins): add WASI build constraints to client wrapper templates, to avoid lint errors
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): implement Scheduler service with one-time and recurring scheduling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(manifest): remove unused ConfigPermission from permissions schema
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): add scheduler callback schema and implementation for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): streamline scheduling logic and remove unused callback tracking
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): add Close method for resource cleanup on plugin unload
Signed-off-by: Deluan <deluan@navidrome.org>
* docs(scheduler): clarify SchedulerCallback requirement for scheduling functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update wasm build rule to include all Go files in the directory
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: rewrite the wikimedia plugin using the XTP CLI
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): replace uuid with id.NewRandom for schedule ID generation
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: capabilities registration
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add scheduler service isolation test for plugin instances
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update plugin manager initialization and encapsulate logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add WebSocket service definitions for plugin communication
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement WebSocket service for plugin integration and connection management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Crypto Ticker example plugin for real-time cryptocurrency price updates via Coinbase WebSocket API
Also add the lifecycle capability
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: use context.Background() in invokeCallback for scheduled tasks
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename plugin.create() to plugin.instance()
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename pluginInstance to plugin for consistency across the codebase
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: simplify schedule cloning in Close method and enhance plugin cleanup error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement Artwork service for generating artwork URLs in Navidrome plugins - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: moved public URL builders to avoid import cycles
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Cache service for in-memory TTL-based caching in plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Discord Rich Presence example plugin for Navidrome integration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: host function wrappers to use structured request and response types
- Updated the host function signatures in `nd_host_artwork.go`, `nd_host_scheduler.go`, `nd_host_subsonicapi.go`, and `nd_host_websocket.go` to accept a single parameter for JSON requests.
- Introduced structured request and response types for various cache operations in `nd_host_cache.go`.
- Modified cache functions to marshal requests to JSON and unmarshal responses, improving error handling and code clarity.
- Removed redundant memory allocation for string parameters in favor of JSON marshaling.
- Enhanced error handling in WebSocket and cache operations to return structured error responses.
* refactor: error handling in various plugins to convert response.Error to Go errors
- Updated error handling in `nd_host_scheduler.go`, `nd_host_websocket.go`, `nd_host_artwork.go`, `nd_host_cache.go`, and `nd_host_subsonicapi.go` to convert string errors from responses into Go errors.
- Removed redundant error checks in test data plugins for cleaner code.
- Ensured consistent error handling across all plugins to improve reliability and maintainability.
* refactor: rename fake plugins to test plugins for clarity in integration tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add help target to Makefile for plugin usage instructions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Cover Art Archive plugin as an example of Python plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Makefile and README to clarify Go plugin usage
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: include plugin capabilities in loading log message
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add trace logging for plugin availability and error handling in agents
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Now Playing Logger plugin to showcase calling host functions from Python plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: generate Python client wrappers for various host services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add generated host function wrappers for Scheduler and SubsonicAPI services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Python plugin documentation and usage instructions for host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Webhook Scrobbler plugin in Rust to send HTTP notifications on scrobble events
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enable parallel loading of plugins during startup
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to include WebSocket callback schema in plugin documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: extend plugin watcher with improved logging and debounce duration adjustment
Signed-off-by: Deluan <deluan@navidrome.org>
* add trace message for plugin recompiles
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement plugin cache purging functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* test: move purgeCacheBySize unit tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add plugin repository and database support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add plugin management routes and middleware
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): implement plugin synchronization with database for add, update, and remove actions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add PluginList and PluginShow components with plugin management functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): optimize plugin change detection
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins UI): improve PluginList structure
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): enhance PluginShow with author, website, and permissions display
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): refactor to use MUI and RA components
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add error handling for plugin enable/disable actions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): inject PluginManager into native API
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update GetManager to accept DataStore parameter
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add subsonicRouter to Manager and refactor host service registration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): enhance debug logging for plugin actions and recompile logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): break manager.go into smaller, focused files
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): streamline error handling and improve plugin retrieval logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update newWebSocketService to use WebSocketPermission for allowed hosts
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): introduce ToggleEnabledSwitch for managing plugin enable/disable state
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update READMEs
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): add Library service for metadata access and filesystem integration
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Library Inspector plugin for periodic library inspection and file size logging
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to reflect JSON configuration format for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(build): update target to wasm32-wasip1 for improved WASI support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement configuration management UI with key-value pairs support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): adjust grid layout in InfoRow component for improved responsiveness
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): rename ErrorIndicator to EnabledOrErrorField and enhance error handling logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(i18n): add Portuguese translations for plugin management and notifications
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add support for .ndp plugin packages and update build process
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README for .ndp plugin packaging and installation instructions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement KVStore service for persistent key-value storage
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: enhance README with Extism plugin development resources and recommendations
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): integrate event broker into plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): update config handling in PluginShow to track last record state
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Rust host function library and example implementation of Discord Rich Presence plugin in Rust
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate Rust lib.rs file to expose host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update JSON field names to camelCase for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: reduce cyclomatic complexity by refactoring main function
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance Rust code generation with typed struct support and improved type handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Go client library with host function wrappers and documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate Go client stubs for non-WASM platforms
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): update client template file names for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add initial implementation of the Navidrome Plugin Development Kit code generator - Pahse 1
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2 (2)
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 3
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 4
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 5
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): consistent naming/types across PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): streamline plugin function signatures and error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update scrobbler interface to return errors directly instead of response structs
Signed-off-by: Deluan <deluan@navidrome.org>
* test: make all test plugins use the PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize and sort type definitions for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update error handling for methods to return errors directly
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update function signatures to return values directly instead of response structs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update request/response types to use private naming conventions
Signed-off-by: Deluan <deluan@navidrome.org>
* build: mark .wasm files as intermediate for cleanup after building .ndp
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): consolidate PDK module path and update Go version to 1.25
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement Rust PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize Rust output structure to follow standard conventions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update Discord Rich Presence and Library Inspector plugins to use nd-pdk for service calls and implement lifecycle management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update macro names for websocket and metadata registration to improve clarity and consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): rename scheduler callback methods for consistency and clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update export wrappers to use `//go:wasmexport` for WebAssembly compatibility
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update plugin registration docs
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): generate host wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): conditionally run goleak checks based on CI environment
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to reflect changes in plugin import paths
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update plugin instance creation to accept context for cancellation support
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update return types in metadata interfaces to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): enhance type handling for Rust and XTP output in capability generation
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update IsAuthorized method to return boolean instead of response object
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): add unit tests for rustOutputType and isPrimitiveRustType functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement XTP JSONSchema validation for generated schemas
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update response types in testMetadataAgent methods to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update Go and Rust plugin developer sections for clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: correct example link for library inspector in README
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: clarify artwork URL generation capabilities in service descriptions
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to include Rust PDK crate information for plugin developers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: handle URL parsing errors and use atomic upsert in plugin repository
Added proper error handling for url.Parse calls in PublicURL and AbsoluteURL
functions. When parsing fails, PublicURL now falls back to AbsoluteURL, and
AbsoluteURL logs the error and returns an empty string, preventing malformed
URLs from being generated.
Replaced the non-atomic UPDATE-then-INSERT pattern in plugin repository Put
method with a single atomic INSERT ... ON CONFLICT statement. This eliminates
potential race conditions and improves consistency with the upsert pattern
already used in host_kvstore.go.
* feat: implement mock service instances for non-WASM builds using testify/mock
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: Discord RPC struct to encapsulate WebSocket logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add support for experimental WebAssembly threads
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add PDK abstraction layer with mock support for non-WASM builds
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add unit tests for Discord plugin and RPC functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update return types in minimalPlugin and wikimediaPlugin methods to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: context cancellation and implement WebSocket callback timeout for improved error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: conditionally include error handling in generated client code templates
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement ConfigService for plugin configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance plugin manager to support metrics recording
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: make MockPDK private
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update interface types to use 'any' in plugin repository methods
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename List method to Keys for clarity in configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add ndpgen plugin tests in the pipeline and update Makefile
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add users permission management to plugin system
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: streamline users integration tests and enhance plugin user management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: remove UserID from scrobbler request structure
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add integration tests for UsersService enable gate behavior
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement user permissions for SubsonicAPI and scrobbler plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: show proper error in the UI when enabling a plugin fails
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add library permission management to plugin system
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add user permission for processing scrobbles in Discord Rich Presence plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: implement dynamic loading for buffered scrobbler plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add GetAdmins method to retrieve admin users from the plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Portuguese translations for user and library permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* reorder migrations
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: remove unnecessary bulkActionButtons prop from PluginList component
* feat: add manual plugin rescan functionality and corresponding UI action
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement user/library and plugin management integration with cleanup on deletion
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: replace core mock services with test-specific implementations to avoid import cycles
* feat: add ID fields to Artist and Song structs and enhance track loading logic by prioritizing ID matches
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update plugin permissions from allowedHosts to requiredHosts for better clarity and consistency
* feat: refactor plugin host permissions to use RequiredHosts directly for improved clarity
* fix: don't record metrics for plugin calls that aren't implemented at all
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: enhance connection management with improved error handling and cleanup logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: introduce ArtistRef struct for better artist representation and update track metadata handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update user configuration handling to use user key prefix for improved clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance ConfigCard input fields with multiline support and vertical resizing
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: rust plugin compilation error
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement IsOptionPattern method for better return type handling in Rust PDK generation
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-01-14 19:22:48 -05:00
|
|
|
|
|
|
|
|
// TopSongsResponse is the response for GetArtistTopSongs.
|
|
|
|
|
type TopSongsResponse struct {
|
|
|
|
|
// Songs is the list of top songs.
|
feat(plugins): share plugin DTOs via a types package (#5655)
* refactor(plugins): remove Python PDK generation from ndpgen
* feat(plugins): parse Go type aliases distinctly in ndpgen
* feat(plugins): resolve shared-type aliases against a registry in ndpgen
* fix(plugins): resolve host-service shared aliases package-wide
Mirror the capability approach in ParseDirectoryWithShared: do a first
pass over all package files to build a package-wide alias map, then pass
it into parseServiceFile so that a shared-type alias declared in a sibling
file is visible when resolving types in the service interface file.
Add a focused test that writes the alias in one file and the hostservice
in another, confirming RED before the fix and GREEN after. Also
strengthens the existing Task 3 test with an ArtistRef.Target assertion.
* feat(plugins): add ndpgen -shared-types mode for the Go types package
* feat(plugins): generate the nd-pdk-types Rust crate from -shared-types
* feat(plugins): inject types import and emit deprecated aliases in Go output
* feat(plugins): emit deprecated Rust aliases to the shared types crate
* feat(plugins): inline shared-type shapes into XTP schemas
* feat(plugins): add nd-pdk-types crate and wire dependents
* feat(plugins): move shared capability types to plugins/types with deprecated aliases
* fix(plugins): point Rust deprecated-alias note at the replacement type
* fix(plugins): include shared aliases in KnownStructs so Rust fields keep their type
Capability.KnownStructs() and Service.KnownStructs() previously only
registered names from .Structs. After the shared-types migration, types
like ArtistRef/TrackInfo/SongRef live in .SharedAliases instead, so
ToRustTypeWithStructs could not find them and fell back to serde_json::Value
for every struct field referencing a shared type.
Add the shared-alias names to the knownStructs map in both methods.
Regenerate the Rust capability files; track/song/artist fields now render
as their named types (TrackInfo, SongRef, ArtistRef, etc.).
Add a regression test that verifies a struct field whose type is only in
SharedAliases renders as the named type and not serde_json::Value.
* docs(plugins): remove stale Python references from ndpgen and plugins READMEs
ndpgen no longer has a -python flag; remove it from the usage synopsis,
flags table, and defaults note in ndpgen/README.md. Delete the "Python
Client Library" section that described its output.
plugins/README.md referenced plugins/pdk/python/host/ (deleted) as the
source for Python host-service stubs. Remove that paragraph; Python plugins
still work via the XTP-schema / extism-py path (see examples/*-py).
* refactor(plugins): dedupe ndpgen helpers and tidy shared-type codegen
* docs(plugins): restore Python as a supported XTP schema target
The ndpgen-generated Python PDK was removed, but the XTP YAML schemas are
language-neutral and the XTP CLI still generates Python bindings from them
(as the extism-py examples demonstrate). Only the ndpgen Python output was
dropped, not Python support itself.
* test(plugins): use the shared types package in test plugins
The test fixtures referenced the now-deprecated capability aliases
(sonicsimilarity.SongRef, metadata.ArtistRef/SongRef). Point them at the
canonical types package so our own fixtures don't depend on symbols slated
for removal.
* refactor(plugins): use the shared types package in host adapters
Replace deprecated capabilities.TrackInfo, capabilities.ArtistRef, and
capabilities.SongRef aliases with the canonical types.TrackInfo,
types.ArtistRef, and types.SongRef from plugins/types.
* fix(plugins): reference shared types by canonical path in generated Rust
Previously the generator emitted `pub field: SongRef` (the local deprecated
alias) for struct fields whose type came from SharedAliases. Refactored
ToRustTypeWithStructs into a private toRustType that accepts a shared map,
and added ToRustTypeWithShared which resolves shared-alias names to their
canonical nd_pdk_types::X path before falling through to the knownStructs
check. Both rustCapabilityFuncMap and rustFuncMap now build the shared map
from SharedAliases and use it for fieldRustType, so the generated capability
files reference nd_pdk_types::SongRef / nd_pdk_types::TrackInfo directly.
The deprecated pub type aliases remain in place as the external back-compat
surface. Deprecation warning count from cargo build drops to 0.
* fix(examples): implement missing Scrobbler.playback_report in Rust examples
The Scrobbler trait gained a playback_report method but the two Rust example
plugins (webhook-rs and discord-rich-presence-rs) were not updated, causing
E0046 compile errors. Added the missing fn playback_report to both: webhook-rs
logs and returns Ok(()) mirroring its now_playing handler; discord-rich-presence-rs
is a no-op since Discord presence does not need playback reports. make all-rust
now exits 0.
* refactor(plugins): point Rust deprecation notes at the nd_pdk::types umbrella path
Plugin authors depend on the nd-pdk umbrella crate, which re-exports
nd_pdk_types as 'types', so the migration target they should type is
nd_pdk::types::X. The alias target stays nd_pdk_types::X (the real path
inside nd-pdk-capabilities).
* fix(plugins): error when a shared-type alias can't be resolved against the registry
* refactor(plugins): parse each Go source file once in ndpgen
* fix(plugins): correct ndpgen review nits (flag name, unused dep, docs)
* refactor(plugins): drop the now-unused path param from parseServiceFile
* refactor(plugins): use shared types directly, rename TrackInfo to Track
Capability interfaces now reference the shared `types` package by qualified
name (types.Track, types.SongRef, types.ArtistRef) instead of the package-local
deprecated aliases, and the shared TrackInfo type is renamed to Track to match
its role as the plugin-facing projection of a library media file.
The deprecated bare aliases (scrobbler.TrackInfo, metadata.ArtistRef,
sonicsimilarity.SongRef, etc.) are kept as re-exports so existing plugins keep
compiling, with a deprecation warning steering them to the canonical types.
To support this, ndpgen now resolves qualified types.X references: it collects
them during type discovery, maps each used canonical type back to its declared
deprecated alias for re-export, emits nd_pdk_types::X paths in Rust, and names
the XTP schema components by their canonical type. Regenerated the Go and Rust
PDK and the XTP schemas, and added generator tests covering the qualified-ref
path. Also adds clarifying doc comments to the shared types.
* refactor(plugins): extract shared types selector into a named const
Replace the "types." string literal that detects and strips the shared types
package selector with a single sharedTypesPrefix constant across the ndpgen
generator (parser, types, generator, xtp_schema), giving the package one source
of truth for the selector.
Also restore the single reused scratch map (cleared each iteration) in the
resolveSharedAliases BFS instead of allocating a fresh map per shared-struct
field, matching the prior implementation.
Pure cleanup from a /simplify pass: regeneration produces byte-for-byte
identical Go, Rust, and XTP output.
* refactor(plugins): keep TrackInfo in the capability package for now
Move the track type back out of the shared plugins/types package: it is again
defined inline as TrackInfo in plugins/capabilities/scrobbler.go and referenced
directly by the scrobbler and lyrics capabilities, reverting the rename to
types.Track. The host helper is renamed back to mediaFileToTrackInfo and now
returns capabilities.TrackInfo. SongRef and ArtistRef stay in the shared types
package; TrackInfo keeps using types.ArtistRef for its artist lists.
This type is expected to be reshaped in upcoming work, so leaving it in the
capability package avoids churning the shared types twice. Regenerated the Go
and Rust PDK and the XTP schemas accordingly.
* fix(plugins): emit the Go types import for direct shared-type refs
ndpgen's Capability/Service.ImportsSharedTypes only reported a shared-types
dependency when a deprecated re-export alias (type X = types.X) was declared. A
struct field referencing the canonical form directly (e.g. types.SongRef) with
no such alias produced an empty SharedAliases slice, so the Go templates skipped
the import while still emitting fields/signatures using types.SongRef — leaving
generated PDK code for new shared DTOs uncompilable unless an otherwise
unnecessary alias was added.
ImportsSharedTypes now also returns true when any struct field references the
types. package by qualified name, via a new structsReferenceSharedTypes helper
that reuses collectReferencedTypes (so []types.X and map[...]types.X are covered
too).
* fix(plugins): preserve base64 encoding for shared byte fields in Rust
The Rust shared-types crate template rendered a []byte field as a plain Vec<u8>
without the base64_bytes serde override used by the capability/client templates.
Go's encoding/json serializes []byte as a base64 string, so a Rust plugin using
nd_pdk::types would have serialized an array of numbers instead of the wire
format the Go/server side expects.
GenerateSharedTypesRust now registers the base64_bytes partial and passes a
HasByteFields flag (new anyFieldIsByteSlice helper); types.rs.tmpl emits the
base64_bytes module and a #[serde(with = "base64_bytes")] attribute on []byte
fields, mirroring the capability template.
* fix(plugins): include directly-referenced shared types in XTP schemas
buildSchemas registered shared types into the schema components only by iterating
cap.SharedAliases, which records deprecated re-export aliases. A capability that
referenced a shared DTO solely as types.Foo (no declared alias) therefore never
got Foo into the component set, so the self-contained XTP schema rendered the
field as a generic object (or emitted a dangling $ref), breaking the direct
shared-type use case enabled by -shared.
resolveSharedAliases now also returns the resolved shapes of every used shared
type (alias or not); these are carried on the new Capability.SharedTypes field
and registered by buildSchemas alongside SharedAliases. Validated end-to-end with
the xtp CLI: a direct types.Foo reference now produces a proper component plus a
$ref, so xtp generates a typed struct instead of an untyped serde_json::Map.
* fix(plugins): resolve renamed shared aliases to canonical schema refs
When a deprecated alias renames its canonical type (e.g. type TrackInfo =
types.Track) and a capability field is typed with the alias name (TrackInfo),
buildProperty emitted a $ref to #/components/schemas/TrackInfo. Components are
keyed by the canonical name (Track), so no TrackInfo component was emitted,
leaving a dangling reference that crashes the xtp code generator.
buildSchemas now builds an alias->canonical map; buildProperty (and the slice
item path) resolves $ref targets through it, and a used alias name marks its
canonical component used so it is emitted. Validated with the xtp CLI: the
renamed-alias schema previously crashed xtp and now generates cleanly.
* fix(plugins): detect shared types used directly in method signatures
ImportsSharedTypes only inspected struct fields, so a capability method using a
shared type directly in its signature (e.g. types.SongRef as input/output rather
than inside a local struct) was not detected. The generated Go templates still
rendered the provider/export signatures with types.SongRef, so the capability
package omitted the types import and failed to compile; the same gap applied to
service params/returns.
ImportsSharedTypes now also scans capability method input/output types and
service method params/returns, via a typeReferencesSharedTypes helper that reuses
collectReferencedTypes (covering pointer/slice/map wrappers).
* fix(plugins): add base64 dependency to the shared Rust types crate
When a shared DTO has a []byte field, ndpgen emits the base64_bytes serde helper
and use base64::... imports into nd-pdk-types/src/lib.rs, but the crate manifest
declared only serde. In that case make gen produced a crate that failed to
compile with 'unresolved module base64'.
Add base64 = "0.22" (matching nd-pdk-capabilities) so the generated shared types
crate compiles whenever a []byte field is present. Verified by generating a
shared crate with a []byte field and confirming cargo check fails before and
passes after.
* fix(plugins): translate shared method types in generated Rust
A capability method using a shared DTO directly as input/output (e.g.
types.SongRef) was passed through rustOutputType unchanged, so the Rust template
emitted invalid trait and extism_pdk::Json<$crate::pkg::types.SongRef> signatures
that do not compile.
Method input/output types now resolve through the shared registry: trait
signatures use rustTraitType (shared -> nd_pdk_types::X, locals stay bare) and the
export macros use rustMethodType (fully qualified: shared -> nd_pdk_types::X,
primitives -> Rust, locals -> $crate::<pkg>::X). Verified end-to-end by compiling
a generated capability that takes types.SongRef directly against the real
nd-pdk-types crate.
* fix(plugins): canonicalize XTP export refs for renamed shared aliases
buildSchemas canonicalized alias-to-canonical references for struct-field $ref
targets, but buildExport built export input/output $refs straight from
fieldBaseType. A capability whose export used a renamed deprecated alias
directly (e.g. type TrackInfo = types.Track with NowPlaying(TrackInfo)) emitted
$ref: #/components/schemas/TrackInfo, while the component is emitted under the
canonical name Track — a dangling export reference.
Lift the alias-to-canonical map into GenerateSchema (buildAliasToCanonical) and
apply it to export refs via canonicalRefName, the same resolution already used
for field properties.
* fix(plugins): route shared macro types through $crate for plugin builds
When a capability method used a shared type directly, the generated export macro
named the type as nd_pdk_types::SongRef. The macro expands in the downstream
plugin crate, which depends on the umbrella nd-pdk crate and not on nd-pdk-types
directly, so that path is unresolvable there and the plugin fails to build.
rustMethodType (macro-facing) now emits $crate::types::X, and the generated
nd-pdk-capabilities lib.rs re-exports nd_pdk_types as types so $crate resolves
it. Trait signatures keep nd_pdk_types::X since they live in nd-pdk-capabilities,
which has the direct dependency. Verified end-to-end: a plugin crate depending
only on the umbrella that uses a capability with a direct types.X method now
compiles via the macro.
* fix(plugins): add nd-pdk-types dependency to the Rust host crate
When a host service uses a shared type, ndpgen emits nd_pdk_types::X into the
generated nd-pdk-host client wrappers, but the host crate's manifest did not
depend on nd-pdk-types, so the crate failed to compile with 'unresolved module
nd_pdk_types'. Host client wrappers are plain functions resolved in the host
crate's own context (not macros expanded downstream), so a direct dependency is
the right fix.
Add nd-pdk-types = { path = "../nd-pdk-types" } to nd-pdk-host, mirroring
nd-pdk-capabilities. Found while auditing all Rust paths against the realistic
crate topology after the capability-side $crate fix; verified by generating a
host service with a shared-type return and confirming cargo check fails before
and passes after.
* fix(plugins): resolve shared aliases in Rust host signatures
The Rust host client rendered method params and returns through
RustTypeWithStructs, which only consults KnownStructs. A host service using a
shared alias in a signature (e.g. type Track = types.Track plus
MatchSongs(...) ([]Track, error)) therefore emitted a bare Vec<Track>, but the
client template emits no Track alias or import, so the generated nd-pdk-host
crate did not compile. Only struct fields went through the shared map.
rustType/rustParamType now use the shared map too (RustTypeWithShared /
RustParamTypeWithShared), so an aliased param/return resolves to its canonical
nd_pdk_types::X path, matching field handling. Verified by generating a host
service returning a shared alias and confirming cargo check fails before and
passes after.
2026-06-29 21:20:33 -04:00
|
|
|
Songs []types.SongRef `json:"songs"`
|
feat(plugins): New Plugin System with multi-language PDK support (#4833)
* chore(plugins): remove the old plugins system implementation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement new plugin system with using Extism
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add capability detection for plugins based on exported functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add auto-reload functionality for plugins with file watcher support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add auto-reload functionality for plugins with file watcher support
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): standardize variable names and remove superfluous wrapper functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): improve error handling and logging in plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): implement plugin function call helper and refactor MetadataAgent methods
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): race condition in plugin manager
* tests(plugins): change BeforeEach to BeforeAll in MetadataAgent tests
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(plugins): optimize tests
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(plugins): more optimizations
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): ignore goroutine leaks from notify library in tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Wikimedia plugin for Navidrome to fetch artist metadata
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance plugin logging and set User-Agent header
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement scrobbler plugin with authorization and scrobbling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): integrate logs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): clean up manifest struct and improve plugin loading logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add metadata agent and scrobbler schemas for bootstrapping plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(hostgen): add hostgen tool for generating Extism host function wrappers
- Implemented hostgen tool to generate wrappers from annotated Go interfaces.
- Added command-line flags for input/output directories and package name.
- Introduced parsing and code generation logic for host services.
- Created test data for various service interfaces and expected generated code.
- Added documentation for host services and annotations for code generation.
- Implemented SubsonicAPI service with corresponding generated code.
* feat(subsonicapi): update Call method to return JSON string response
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement SubsonicAPI host function integration with permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(generator): error-only methods in response handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate client wrappers for host functions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(generator): remove error handling for response.Error in client templates
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): add Scheduler service interface with host function wrappers for scheduling tasks
* feat(plugins): add WASI build constraints to client wrapper templates, to avoid lint errors
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): implement Scheduler service with one-time and recurring scheduling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(manifest): remove unused ConfigPermission from permissions schema
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): add scheduler callback schema and implementation for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): streamline scheduling logic and remove unused callback tracking
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): add Close method for resource cleanup on plugin unload
Signed-off-by: Deluan <deluan@navidrome.org>
* docs(scheduler): clarify SchedulerCallback requirement for scheduling functions
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update wasm build rule to include all Go files in the directory
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: rewrite the wikimedia plugin using the XTP CLI
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): replace uuid with id.NewRandom for schedule ID generation
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: capabilities registration
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add scheduler service isolation test for plugin instances
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update plugin manager initialization and encapsulate logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add WebSocket service definitions for plugin communication
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement WebSocket service for plugin integration and connection management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Crypto Ticker example plugin for real-time cryptocurrency price updates via Coinbase WebSocket API
Also add the lifecycle capability
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: use context.Background() in invokeCallback for scheduled tasks
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename plugin.create() to plugin.instance()
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename pluginInstance to plugin for consistency across the codebase
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: simplify schedule cloning in Close method and enhance plugin cleanup error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement Artwork service for generating artwork URLs in Navidrome plugins - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: moved public URL builders to avoid import cycles
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Cache service for in-memory TTL-based caching in plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Discord Rich Presence example plugin for Navidrome integration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: host function wrappers to use structured request and response types
- Updated the host function signatures in `nd_host_artwork.go`, `nd_host_scheduler.go`, `nd_host_subsonicapi.go`, and `nd_host_websocket.go` to accept a single parameter for JSON requests.
- Introduced structured request and response types for various cache operations in `nd_host_cache.go`.
- Modified cache functions to marshal requests to JSON and unmarshal responses, improving error handling and code clarity.
- Removed redundant memory allocation for string parameters in favor of JSON marshaling.
- Enhanced error handling in WebSocket and cache operations to return structured error responses.
* refactor: error handling in various plugins to convert response.Error to Go errors
- Updated error handling in `nd_host_scheduler.go`, `nd_host_websocket.go`, `nd_host_artwork.go`, `nd_host_cache.go`, and `nd_host_subsonicapi.go` to convert string errors from responses into Go errors.
- Removed redundant error checks in test data plugins for cleaner code.
- Ensured consistent error handling across all plugins to improve reliability and maintainability.
* refactor: rename fake plugins to test plugins for clarity in integration tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add help target to Makefile for plugin usage instructions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Cover Art Archive plugin as an example of Python plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Makefile and README to clarify Go plugin usage
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: include plugin capabilities in loading log message
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add trace logging for plugin availability and error handling in agents
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Now Playing Logger plugin to showcase calling host functions from Python plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: generate Python client wrappers for various host services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add generated host function wrappers for Scheduler and SubsonicAPI services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Python plugin documentation and usage instructions for host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add Webhook Scrobbler plugin in Rust to send HTTP notifications on scrobble events
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enable parallel loading of plugins during startup
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to include WebSocket callback schema in plugin documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: extend plugin watcher with improved logging and debounce duration adjustment
Signed-off-by: Deluan <deluan@navidrome.org>
* add trace message for plugin recompiles
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement plugin cache purging functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* test: move purgeCacheBySize unit tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add plugin repository and database support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add plugin management routes and middleware
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): implement plugin synchronization with database for add, update, and remove actions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add PluginList and PluginShow components with plugin management functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): optimize plugin change detection
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins UI): improve PluginList structure
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): enhance PluginShow with author, website, and permissions display
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): refactor to use MUI and RA components
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins UI): add error handling for plugin enable/disable actions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): inject PluginManager into native API
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update GetManager to accept DataStore parameter
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add subsonicRouter to Manager and refactor host service registration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): enhance debug logging for plugin actions and recompile logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): break manager.go into smaller, focused files
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): streamline error handling and improve plugin retrieval logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update newWebSocketService to use WebSocketPermission for allowed hosts
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): introduce ToggleEnabledSwitch for managing plugin enable/disable state
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update READMEs
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): add Library service for metadata access and filesystem integration
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Library Inspector plugin for periodic library inspection and file size logging
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to reflect JSON configuration format for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(build): update target to wasm32-wasip1 for improved WASI support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement configuration management UI with key-value pairs support
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): adjust grid layout in InfoRow component for improved responsiveness
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): rename ErrorIndicator to EnabledOrErrorField and enhance error handling logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(i18n): add Portuguese translations for plugin management and notifications
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add support for .ndp plugin packages and update build process
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README for .ndp plugin packaging and installation instructions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement KVStore service for persistent key-value storage
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: enhance README with Extism plugin development resources and recommendations
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): integrate event broker into plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): update config handling in PluginShow to track last record state
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Rust host function library and example implementation of Discord Rich Presence plugin in Rust
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate Rust lib.rs file to expose host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update JSON field names to camelCase for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: reduce cyclomatic complexity by refactoring main function
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance Rust code generation with typed struct support and improved type handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add Go client library with host function wrappers and documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): generate Go client stubs for non-WASM platforms
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): update client template file names for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add initial implementation of the Navidrome Plugin Development Kit code generator - Pahse 1
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2 (2)
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 3
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 4
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 5
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): consistent naming/types across PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): streamline plugin function signatures and error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update scrobbler interface to return errors directly instead of response structs
Signed-off-by: Deluan <deluan@navidrome.org>
* test: make all test plugins use the PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize and sort type definitions for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update error handling for methods to return errors directly
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update function signatures to return values directly instead of response structs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update request/response types to use private naming conventions
Signed-off-by: Deluan <deluan@navidrome.org>
* build: mark .wasm files as intermediate for cleanup after building .ndp
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): consolidate PDK module path and update Go version to 1.25
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement Rust PDK
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize Rust output structure to follow standard conventions
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update Discord Rich Presence and Library Inspector plugins to use nd-pdk for service calls and implement lifecycle management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update macro names for websocket and metadata registration to improve clarity and consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): rename scheduler callback methods for consistency and clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update export wrappers to use `//go:wasmexport` for WebAssembly compatibility
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update plugin registration docs
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): generate host wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): conditionally run goleak checks based on CI environment
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to reflect changes in plugin import paths
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update plugin instance creation to accept context for cancellation support
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update return types in metadata interfaces to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): enhance type handling for Rust and XTP output in capability generation
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update IsAuthorized method to return boolean instead of response object
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): add unit tests for rustOutputType and isPrimitiveRustType functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement XTP JSONSchema validation for generated schemas
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update response types in testMetadataAgent methods to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update Go and Rust plugin developer sections for clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: correct example link for library inspector in README
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: clarify artwork URL generation capabilities in service descriptions
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: update README to include Rust PDK crate information for plugin developers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: handle URL parsing errors and use atomic upsert in plugin repository
Added proper error handling for url.Parse calls in PublicURL and AbsoluteURL
functions. When parsing fails, PublicURL now falls back to AbsoluteURL, and
AbsoluteURL logs the error and returns an empty string, preventing malformed
URLs from being generated.
Replaced the non-atomic UPDATE-then-INSERT pattern in plugin repository Put
method with a single atomic INSERT ... ON CONFLICT statement. This eliminates
potential race conditions and improves consistency with the upsert pattern
already used in host_kvstore.go.
* feat: implement mock service instances for non-WASM builds using testify/mock
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: Discord RPC struct to encapsulate WebSocket logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add support for experimental WebAssembly threads
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add PDK abstraction layer with mock support for non-WASM builds
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add unit tests for Discord plugin and RPC functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update return types in minimalPlugin and wikimediaPlugin methods to use pointers
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: context cancellation and implement WebSocket callback timeout for improved error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: conditionally include error handling in generated client code templates
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement ConfigService for plugin configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance plugin manager to support metrics recording
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: make MockPDK private
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update interface types to use 'any' in plugin repository methods
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename List method to Keys for clarity in configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add ndpgen plugin tests in the pipeline and update Makefile
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add users permission management to plugin system
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: streamline users integration tests and enhance plugin user management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: remove UserID from scrobbler request structure
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add integration tests for UsersService enable gate behavior
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement user permissions for SubsonicAPI and scrobbler plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: show proper error in the UI when enabling a plugin fails
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add library permission management to plugin system
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add user permission for processing scrobbles in Discord Rich Presence plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: implement dynamic loading for buffered scrobbler plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add GetAdmins method to retrieve admin users from the plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update Portuguese translations for user and library permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* reorder migrations
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: remove unnecessary bulkActionButtons prop from PluginList component
* feat: add manual plugin rescan functionality and corresponding UI action
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement user/library and plugin management integration with cleanup on deletion
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: replace core mock services with test-specific implementations to avoid import cycles
* feat: add ID fields to Artist and Song structs and enhance track loading logic by prioritizing ID matches
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update plugin permissions from allowedHosts to requiredHosts for better clarity and consistency
* feat: refactor plugin host permissions to use RequiredHosts directly for improved clarity
* fix: don't record metrics for plugin calls that aren't implemented at all
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: enhance connection management with improved error handling and cleanup logic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: introduce ArtistRef struct for better artist representation and update track metadata handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update user configuration handling to use user key prefix for improved clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance ConfigCard input fields with multiline support and vertical resizing
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: rust plugin compilation error
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement IsOptionPattern method for better return type handling in Rust PDK generation
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
2026-01-14 19:22:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AlbumRequest is the common request for album-related functions.
|
|
|
|
|
type AlbumRequest struct {
|
|
|
|
|
// Name is the album name.
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
// Artist is the album artist name.
|
|
|
|
|
Artist string `json:"artist"`
|
|
|
|
|
// MBID is the MusicBrainz ID for the album (if known).
|
|
|
|
|
MBID string `json:"mbid,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AlbumInfoResponse is the response for GetAlbumInfo.
|
|
|
|
|
type AlbumInfoResponse struct {
|
|
|
|
|
// Name is the album name.
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
// MBID is the MusicBrainz ID for the album.
|
|
|
|
|
MBID string `json:"mbid"`
|
|
|
|
|
// Description is the album description/notes.
|
|
|
|
|
Description string `json:"description"`
|
|
|
|
|
// URL is the external URL for the album.
|
|
|
|
|
URL string `json:"url"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AlbumImagesResponse is the response for GetAlbumImages.
|
|
|
|
|
type AlbumImagesResponse struct {
|
|
|
|
|
// Images is the list of album images.
|
|
|
|
|
Images []ImageInfo `json:"images"`
|
|
|
|
|
}
|
2026-01-26 18:28:41 -05:00
|
|
|
|
|
|
|
|
// SimilarSongsByTrackRequest is the request for GetSimilarSongsByTrack.
|
|
|
|
|
type SimilarSongsByTrackRequest struct {
|
|
|
|
|
// ID is the internal Navidrome mediafile ID.
|
|
|
|
|
ID string `json:"id"`
|
|
|
|
|
// Name is the track title.
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
// Artist is the artist name.
|
|
|
|
|
Artist string `json:"artist"`
|
|
|
|
|
// MBID is the MusicBrainz recording ID (if known).
|
|
|
|
|
MBID string `json:"mbid,omitempty"`
|
|
|
|
|
// Count is the maximum number of similar songs to return.
|
|
|
|
|
Count int32 `json:"count"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SimilarSongsByAlbumRequest is the request for GetSimilarSongsByAlbum.
|
|
|
|
|
type SimilarSongsByAlbumRequest struct {
|
|
|
|
|
// ID is the internal Navidrome album ID.
|
|
|
|
|
ID string `json:"id"`
|
|
|
|
|
// Name is the album name.
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
// Artist is the album artist name.
|
|
|
|
|
Artist string `json:"artist"`
|
|
|
|
|
// MBID is the MusicBrainz release ID (if known).
|
|
|
|
|
MBID string `json:"mbid,omitempty"`
|
|
|
|
|
// Count is the maximum number of similar songs to return.
|
|
|
|
|
Count int32 `json:"count"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SimilarSongsByArtistRequest is the request for GetSimilarSongsByArtist.
|
|
|
|
|
type SimilarSongsByArtistRequest struct {
|
|
|
|
|
// ID is the internal Navidrome artist ID.
|
|
|
|
|
ID string `json:"id"`
|
|
|
|
|
// Name is the artist name.
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
// MBID is the MusicBrainz artist ID (if known).
|
|
|
|
|
MBID string `json:"mbid,omitempty"`
|
|
|
|
|
// Count is the maximum number of similar songs to return.
|
|
|
|
|
Count int32 `json:"count"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SimilarSongsResponse is the response for GetSimilarSongsBy* functions.
|
|
|
|
|
type SimilarSongsResponse struct {
|
|
|
|
|
// Songs is the list of similar songs.
|
feat(plugins): share plugin DTOs via a types package (#5655)
* refactor(plugins): remove Python PDK generation from ndpgen
* feat(plugins): parse Go type aliases distinctly in ndpgen
* feat(plugins): resolve shared-type aliases against a registry in ndpgen
* fix(plugins): resolve host-service shared aliases package-wide
Mirror the capability approach in ParseDirectoryWithShared: do a first
pass over all package files to build a package-wide alias map, then pass
it into parseServiceFile so that a shared-type alias declared in a sibling
file is visible when resolving types in the service interface file.
Add a focused test that writes the alias in one file and the hostservice
in another, confirming RED before the fix and GREEN after. Also
strengthens the existing Task 3 test with an ArtistRef.Target assertion.
* feat(plugins): add ndpgen -shared-types mode for the Go types package
* feat(plugins): generate the nd-pdk-types Rust crate from -shared-types
* feat(plugins): inject types import and emit deprecated aliases in Go output
* feat(plugins): emit deprecated Rust aliases to the shared types crate
* feat(plugins): inline shared-type shapes into XTP schemas
* feat(plugins): add nd-pdk-types crate and wire dependents
* feat(plugins): move shared capability types to plugins/types with deprecated aliases
* fix(plugins): point Rust deprecated-alias note at the replacement type
* fix(plugins): include shared aliases in KnownStructs so Rust fields keep their type
Capability.KnownStructs() and Service.KnownStructs() previously only
registered names from .Structs. After the shared-types migration, types
like ArtistRef/TrackInfo/SongRef live in .SharedAliases instead, so
ToRustTypeWithStructs could not find them and fell back to serde_json::Value
for every struct field referencing a shared type.
Add the shared-alias names to the knownStructs map in both methods.
Regenerate the Rust capability files; track/song/artist fields now render
as their named types (TrackInfo, SongRef, ArtistRef, etc.).
Add a regression test that verifies a struct field whose type is only in
SharedAliases renders as the named type and not serde_json::Value.
* docs(plugins): remove stale Python references from ndpgen and plugins READMEs
ndpgen no longer has a -python flag; remove it from the usage synopsis,
flags table, and defaults note in ndpgen/README.md. Delete the "Python
Client Library" section that described its output.
plugins/README.md referenced plugins/pdk/python/host/ (deleted) as the
source for Python host-service stubs. Remove that paragraph; Python plugins
still work via the XTP-schema / extism-py path (see examples/*-py).
* refactor(plugins): dedupe ndpgen helpers and tidy shared-type codegen
* docs(plugins): restore Python as a supported XTP schema target
The ndpgen-generated Python PDK was removed, but the XTP YAML schemas are
language-neutral and the XTP CLI still generates Python bindings from them
(as the extism-py examples demonstrate). Only the ndpgen Python output was
dropped, not Python support itself.
* test(plugins): use the shared types package in test plugins
The test fixtures referenced the now-deprecated capability aliases
(sonicsimilarity.SongRef, metadata.ArtistRef/SongRef). Point them at the
canonical types package so our own fixtures don't depend on symbols slated
for removal.
* refactor(plugins): use the shared types package in host adapters
Replace deprecated capabilities.TrackInfo, capabilities.ArtistRef, and
capabilities.SongRef aliases with the canonical types.TrackInfo,
types.ArtistRef, and types.SongRef from plugins/types.
* fix(plugins): reference shared types by canonical path in generated Rust
Previously the generator emitted `pub field: SongRef` (the local deprecated
alias) for struct fields whose type came from SharedAliases. Refactored
ToRustTypeWithStructs into a private toRustType that accepts a shared map,
and added ToRustTypeWithShared which resolves shared-alias names to their
canonical nd_pdk_types::X path before falling through to the knownStructs
check. Both rustCapabilityFuncMap and rustFuncMap now build the shared map
from SharedAliases and use it for fieldRustType, so the generated capability
files reference nd_pdk_types::SongRef / nd_pdk_types::TrackInfo directly.
The deprecated pub type aliases remain in place as the external back-compat
surface. Deprecation warning count from cargo build drops to 0.
* fix(examples): implement missing Scrobbler.playback_report in Rust examples
The Scrobbler trait gained a playback_report method but the two Rust example
plugins (webhook-rs and discord-rich-presence-rs) were not updated, causing
E0046 compile errors. Added the missing fn playback_report to both: webhook-rs
logs and returns Ok(()) mirroring its now_playing handler; discord-rich-presence-rs
is a no-op since Discord presence does not need playback reports. make all-rust
now exits 0.
* refactor(plugins): point Rust deprecation notes at the nd_pdk::types umbrella path
Plugin authors depend on the nd-pdk umbrella crate, which re-exports
nd_pdk_types as 'types', so the migration target they should type is
nd_pdk::types::X. The alias target stays nd_pdk_types::X (the real path
inside nd-pdk-capabilities).
* fix(plugins): error when a shared-type alias can't be resolved against the registry
* refactor(plugins): parse each Go source file once in ndpgen
* fix(plugins): correct ndpgen review nits (flag name, unused dep, docs)
* refactor(plugins): drop the now-unused path param from parseServiceFile
* refactor(plugins): use shared types directly, rename TrackInfo to Track
Capability interfaces now reference the shared `types` package by qualified
name (types.Track, types.SongRef, types.ArtistRef) instead of the package-local
deprecated aliases, and the shared TrackInfo type is renamed to Track to match
its role as the plugin-facing projection of a library media file.
The deprecated bare aliases (scrobbler.TrackInfo, metadata.ArtistRef,
sonicsimilarity.SongRef, etc.) are kept as re-exports so existing plugins keep
compiling, with a deprecation warning steering them to the canonical types.
To support this, ndpgen now resolves qualified types.X references: it collects
them during type discovery, maps each used canonical type back to its declared
deprecated alias for re-export, emits nd_pdk_types::X paths in Rust, and names
the XTP schema components by their canonical type. Regenerated the Go and Rust
PDK and the XTP schemas, and added generator tests covering the qualified-ref
path. Also adds clarifying doc comments to the shared types.
* refactor(plugins): extract shared types selector into a named const
Replace the "types." string literal that detects and strips the shared types
package selector with a single sharedTypesPrefix constant across the ndpgen
generator (parser, types, generator, xtp_schema), giving the package one source
of truth for the selector.
Also restore the single reused scratch map (cleared each iteration) in the
resolveSharedAliases BFS instead of allocating a fresh map per shared-struct
field, matching the prior implementation.
Pure cleanup from a /simplify pass: regeneration produces byte-for-byte
identical Go, Rust, and XTP output.
* refactor(plugins): keep TrackInfo in the capability package for now
Move the track type back out of the shared plugins/types package: it is again
defined inline as TrackInfo in plugins/capabilities/scrobbler.go and referenced
directly by the scrobbler and lyrics capabilities, reverting the rename to
types.Track. The host helper is renamed back to mediaFileToTrackInfo and now
returns capabilities.TrackInfo. SongRef and ArtistRef stay in the shared types
package; TrackInfo keeps using types.ArtistRef for its artist lists.
This type is expected to be reshaped in upcoming work, so leaving it in the
capability package avoids churning the shared types twice. Regenerated the Go
and Rust PDK and the XTP schemas accordingly.
* fix(plugins): emit the Go types import for direct shared-type refs
ndpgen's Capability/Service.ImportsSharedTypes only reported a shared-types
dependency when a deprecated re-export alias (type X = types.X) was declared. A
struct field referencing the canonical form directly (e.g. types.SongRef) with
no such alias produced an empty SharedAliases slice, so the Go templates skipped
the import while still emitting fields/signatures using types.SongRef — leaving
generated PDK code for new shared DTOs uncompilable unless an otherwise
unnecessary alias was added.
ImportsSharedTypes now also returns true when any struct field references the
types. package by qualified name, via a new structsReferenceSharedTypes helper
that reuses collectReferencedTypes (so []types.X and map[...]types.X are covered
too).
* fix(plugins): preserve base64 encoding for shared byte fields in Rust
The Rust shared-types crate template rendered a []byte field as a plain Vec<u8>
without the base64_bytes serde override used by the capability/client templates.
Go's encoding/json serializes []byte as a base64 string, so a Rust plugin using
nd_pdk::types would have serialized an array of numbers instead of the wire
format the Go/server side expects.
GenerateSharedTypesRust now registers the base64_bytes partial and passes a
HasByteFields flag (new anyFieldIsByteSlice helper); types.rs.tmpl emits the
base64_bytes module and a #[serde(with = "base64_bytes")] attribute on []byte
fields, mirroring the capability template.
* fix(plugins): include directly-referenced shared types in XTP schemas
buildSchemas registered shared types into the schema components only by iterating
cap.SharedAliases, which records deprecated re-export aliases. A capability that
referenced a shared DTO solely as types.Foo (no declared alias) therefore never
got Foo into the component set, so the self-contained XTP schema rendered the
field as a generic object (or emitted a dangling $ref), breaking the direct
shared-type use case enabled by -shared.
resolveSharedAliases now also returns the resolved shapes of every used shared
type (alias or not); these are carried on the new Capability.SharedTypes field
and registered by buildSchemas alongside SharedAliases. Validated end-to-end with
the xtp CLI: a direct types.Foo reference now produces a proper component plus a
$ref, so xtp generates a typed struct instead of an untyped serde_json::Map.
* fix(plugins): resolve renamed shared aliases to canonical schema refs
When a deprecated alias renames its canonical type (e.g. type TrackInfo =
types.Track) and a capability field is typed with the alias name (TrackInfo),
buildProperty emitted a $ref to #/components/schemas/TrackInfo. Components are
keyed by the canonical name (Track), so no TrackInfo component was emitted,
leaving a dangling reference that crashes the xtp code generator.
buildSchemas now builds an alias->canonical map; buildProperty (and the slice
item path) resolves $ref targets through it, and a used alias name marks its
canonical component used so it is emitted. Validated with the xtp CLI: the
renamed-alias schema previously crashed xtp and now generates cleanly.
* fix(plugins): detect shared types used directly in method signatures
ImportsSharedTypes only inspected struct fields, so a capability method using a
shared type directly in its signature (e.g. types.SongRef as input/output rather
than inside a local struct) was not detected. The generated Go templates still
rendered the provider/export signatures with types.SongRef, so the capability
package omitted the types import and failed to compile; the same gap applied to
service params/returns.
ImportsSharedTypes now also scans capability method input/output types and
service method params/returns, via a typeReferencesSharedTypes helper that reuses
collectReferencedTypes (covering pointer/slice/map wrappers).
* fix(plugins): add base64 dependency to the shared Rust types crate
When a shared DTO has a []byte field, ndpgen emits the base64_bytes serde helper
and use base64::... imports into nd-pdk-types/src/lib.rs, but the crate manifest
declared only serde. In that case make gen produced a crate that failed to
compile with 'unresolved module base64'.
Add base64 = "0.22" (matching nd-pdk-capabilities) so the generated shared types
crate compiles whenever a []byte field is present. Verified by generating a
shared crate with a []byte field and confirming cargo check fails before and
passes after.
* fix(plugins): translate shared method types in generated Rust
A capability method using a shared DTO directly as input/output (e.g.
types.SongRef) was passed through rustOutputType unchanged, so the Rust template
emitted invalid trait and extism_pdk::Json<$crate::pkg::types.SongRef> signatures
that do not compile.
Method input/output types now resolve through the shared registry: trait
signatures use rustTraitType (shared -> nd_pdk_types::X, locals stay bare) and the
export macros use rustMethodType (fully qualified: shared -> nd_pdk_types::X,
primitives -> Rust, locals -> $crate::<pkg>::X). Verified end-to-end by compiling
a generated capability that takes types.SongRef directly against the real
nd-pdk-types crate.
* fix(plugins): canonicalize XTP export refs for renamed shared aliases
buildSchemas canonicalized alias-to-canonical references for struct-field $ref
targets, but buildExport built export input/output $refs straight from
fieldBaseType. A capability whose export used a renamed deprecated alias
directly (e.g. type TrackInfo = types.Track with NowPlaying(TrackInfo)) emitted
$ref: #/components/schemas/TrackInfo, while the component is emitted under the
canonical name Track — a dangling export reference.
Lift the alias-to-canonical map into GenerateSchema (buildAliasToCanonical) and
apply it to export refs via canonicalRefName, the same resolution already used
for field properties.
* fix(plugins): route shared macro types through $crate for plugin builds
When a capability method used a shared type directly, the generated export macro
named the type as nd_pdk_types::SongRef. The macro expands in the downstream
plugin crate, which depends on the umbrella nd-pdk crate and not on nd-pdk-types
directly, so that path is unresolvable there and the plugin fails to build.
rustMethodType (macro-facing) now emits $crate::types::X, and the generated
nd-pdk-capabilities lib.rs re-exports nd_pdk_types as types so $crate resolves
it. Trait signatures keep nd_pdk_types::X since they live in nd-pdk-capabilities,
which has the direct dependency. Verified end-to-end: a plugin crate depending
only on the umbrella that uses a capability with a direct types.X method now
compiles via the macro.
* fix(plugins): add nd-pdk-types dependency to the Rust host crate
When a host service uses a shared type, ndpgen emits nd_pdk_types::X into the
generated nd-pdk-host client wrappers, but the host crate's manifest did not
depend on nd-pdk-types, so the crate failed to compile with 'unresolved module
nd_pdk_types'. Host client wrappers are plain functions resolved in the host
crate's own context (not macros expanded downstream), so a direct dependency is
the right fix.
Add nd-pdk-types = { path = "../nd-pdk-types" } to nd-pdk-host, mirroring
nd-pdk-capabilities. Found while auditing all Rust paths against the realistic
crate topology after the capability-side $crate fix; verified by generating a
host service with a shared-type return and confirming cargo check fails before
and passes after.
* fix(plugins): resolve shared aliases in Rust host signatures
The Rust host client rendered method params and returns through
RustTypeWithStructs, which only consults KnownStructs. A host service using a
shared alias in a signature (e.g. type Track = types.Track plus
MatchSongs(...) ([]Track, error)) therefore emitted a bare Vec<Track>, but the
client template emits no Track alias or import, so the generated nd-pdk-host
crate did not compile. Only struct fields went through the shared map.
rustType/rustParamType now use the shared map too (RustTypeWithShared /
RustParamTypeWithShared), so an aliased param/return resolves to its canonical
nd_pdk_types::X path, matching field handling. Verified by generating a host
service returning a shared alias and confirming cargo check fails before and
passes after.
2026-06-29 21:20:33 -04:00
|
|
|
Songs []types.SongRef `json:"songs"`
|
2026-01-26 18:28:41 -05:00
|
|
|
}
|
fix(scrobbler): back off when a provider asks us to, instead of retrying per play (#6028)
* feat(agents): retry-later error type with optional server delay
Add agents.ErrRetryLater and agents.RetryLaterError, which carries the
delay requested by an external service (e.g. ListenBrainz's
X-RateLimit-Reset-In). scrobbler.ErrRetryLater becomes an alias of the new
sentinel, so existing errors.Is checks and the plugin error-string protocol
keep working unchanged. Groundwork for honoring server-requested retry
delays across scrobbling, metadata agents and artwork.
Song.Equals tests moved to song_test.go to enable external test package.
* fix(scrobbler): honor backoff window and server-requested retry delay
ListenBrainz 429s were decoded into a typed error that classified as
unrecoverable, silently discarding the scrobble (a JSON-bodied 429 was
measured live). The client now maps any 429 to agents.RetryLaterError,
carrying X-RateLimit-Reset-In when present (capped at 1h). Last.fm error 29
(rate limit) is now retryable like 11/16. The buffer's drain loop no longer
lets wake signals bypass an active backoff window - new plays enqueue but
drain only when the window closes - and the wait honors the server delay
via max(backoff, retryIn).
* feat(agents): skip cooling-down agents in aggregate calls
When an agent reports retry-later, remember a per-agent cooldown deadline
(the server-requested delay, or 1 minute when unspecified) and skip that
agent in all aggregate metadata calls until it passes. A round that found
no data but skipped or saw a throttled agent returns ErrRetryLater instead
of ErrNotFound, so callers cannot mistake rate limiting for a definitive
'no data' answer.
* feat(artwork): honor server-requested retry delay when rescheduling
When an external image lookup fails with a retry-later error carrying a
delay (e.g. a 429 with X-RateLimit-Reset-In), the chain trace carries the
largest such hint back to the worker, which reschedules the item at
max(exponential backoff, server delay) instead of backoff alone.
* feat(plugins): retry-later with optional delay for scrobbler and agent plugins
Scrobbler plugins can now return scrobbler(retry_later:N) to request a
retry in N seconds (capped at 1h); the bare token keeps its old meaning.
Metadata-agent plugins, which had no error vocabulary at all, gain the
parallel agent(retry_later[:N]) token, mapped to agents.RetryLaterError so
the aggregate's cooldown and the artwork worker honor plugin throttling
the same way as built-in agents.
* fix: address whole-branch review findings for retry-later handling
Narrow the aggregate's throttled rule to the spec sentence: core.Agents returns
ErrRetryLater only when no agent answered at all (all skipped-cooling or
retry-later). An agent that does not implement the called method now returns an
internal errUnsupported instead of ErrNotFound, so it counts as "did not run" —
without that, the always-appended local agent would answer for biography, URL
and images and make ErrRetryLater unreachable.
Wire the consequence in core/external: a throttled round no longer stamps
ExternalInfoUpdatedAt (artist and album), so the empty result is not cached for
the TTL, and TopSongs maps ErrRetryLater to the same empty-200 the not-found
path already produced instead of a new client-facing error.
Move the Last.fm code-29 mapping into the client's central error construction so
every metadata path produces RetryLaterError, and map ListenBrainz's body-level
code 429 (sent with a non-429 HTTP status) the same way.
Clamp server- and plugin-requested delays in seconds before scaling to a
Duration, in all three parse sites: a header of 18446744074 wrapped past 2^64 and
came out as a 0.29s delay.
Also: extract the artwork worker's reschedule computation into retryDelay() and
cover both it and the trace RetryIn wiring with tests; collapse the double regex
call in mapScrobblerError; drop capabilities.ScrobblerErrorRetryLaterIn (ndpgen
never emits funcs, so plugin authors could not reach it); regenerate the PDKs so
MetadataAgentError reaches the Go and Rust SDKs; de-flake the cooldown tests
(long RetryIn for the skip case, separate expiry spec); and cover the max()
retry-delay aggregation across users in the scrobble buffer.
* refactor: dedupe retry-later parsing and simplify error collection
- Add agents.NewRetryLater and agents.RetryLaterFromSeconds, with a single
1h cap, replacing the parse+clamp+multiply logic and the maxRetryInSeconds
constant duplicated across listenbrainz, plugins and the agent adapter.
- Move HTTP header parsing to httpclient.RetryAfter, so the transport layer
owns it and stays domain-agnostic; drop retryInFromHeaders from the
ListenBrainz client. Covered by a new Ginkgo table in that package.
- Collapse the two near-identical plugin retry_later regexes into one
parseRetryLater(prefix, msg) shared by the agent and scrobbler adapters.
- Fold the duplicated noteRetryIn snippet from fetchArtistImage and
fetchAlbumImage into recordAgent, which already branched on the same
isTransientExternal condition.
- Replace the atomic.Bool + note() closure in populateArtistInfo with
errgroup's own error collection; the group carries no context, so a
returned error does not cancel its siblings.
- Reuse recoveringScrobbler for the per-user delay test instead of a third
double, and switch fakeScrobbler's mutex-guarded error to the
atomic.Pointer idiom already used in the same package.
* refactor(listenbrainz): keep rate-limit header parsing in the adapter
The X-RateLimit-Reset-In header is ListenBrainz's own convention, not a
shared one: Last.fm sends no rate-limit headers at all and reports its
limit as a body code, and no other integration in tree sends Retry-After.
A parser in utils/httpclient implied a uniformity across services that
does not exist, so it moves back next to the only client that can know
which header its service sends.
* refactor(agents): collapse the retry-later sentinel and error into one type
ErrRetryLater is now the zero-delay RetryLaterError rather than a separate
errors.New value, so errors.Is and errors.AsType both match the sentinel and
every delay-carrying variant. That removes the trap where a bare sentinel
silently skipped the AsType path, and lets every consumer read the delay off
the error directly: the RetryIn accessor and the two constructors are gone,
with the policy cap applied where untrusted input is parsed.
* refactor(agents): split the cooldown store from the per-dispatch tally
The cooldown map and mutex become a cooldowns value with active/park, holding
no knowledge of errors; agentAttempts records one dispatch's outcomes and owns
the classification that noteAgentError used to hide behind a bool. The three
dispatch loops now touch a single object: skip folds the cooldown check and the
throttled flag into one call, so the store never appears in the loops.
* refactor(agents): share one dispatch loop between the agent call helpers
callAgentMethod and callAgentSliceMethod ran identical loops, differing only in
how they test a result for emptiness: a slice cannot be compared against its
zero value, so the two could not share a constraint. Both now delegate to
callAgent, which takes that test as a parameter. Keeping the loop in one place
matters more than the lines saved: it holds the cooldown skip, the attempt
recording and the empty-dispatch verdict, and a fix applied to one copy but not
the other would be silent.
* test: cover the two retry-later paths a mutation could break silently
Both gaps were proven, not guessed: making the artwork worker pass 0 instead
of the collected hint left all 386 specs green, and replacing the default
agent cooldown with 0 left the agents suite green. The worker test drives a
throttled image agent through drain and asserts the persisted retry_at, and
the cooldown test parks an agent that asked to be retried without naming a
delay, which is what Last.fm does on every rate limit.
* refactor(artwork): carry the external failure as an error, not a flag plus a trace field
The retry delay was riding on ChainTrace, a diagnostic that gets persisted, while
the very same signal — an external source faulted — already travelled by value as
resolution.extError. That was two mechanisms for one idea, and it put control-flow
state inside a serializable trace.
resolution.extError and chainState.extErr become the error itself, so a caller
checks err != nil for the fault and errors.AsType for the delay the provider asked
for. The agent loops return that error last, per convention, and longerRetry keeps
whichever failure wants the longer wait. ChainTrace goes back to holding only steps
and no longer imports core/agents.
* fix(artwork): check the resolve error before reading its resolution
Reading res.extError before the err check was safe only because every error path
in resolve returns a bare resolution{}; a future path returning a partly-filled
one would have been read silently. The failure path now returns no delay
explicitly.
* test(artwork): assert the delay acquire reports, not just its downstream effect
acquire's retry delay was only covered through the worker's persisted retry_at,
one layer away from where the value is computed. Both outcomes are now pinned at
the processor: a plain failure asks for nothing, a throttled provider's delay is
passed through.
* refactor: share the retry-seconds parse and drop the backoff deadline arithmetic
The clamp-before-scaling invariant lived in two parsers and was independently
re-tested in three files with the same magic number; a fix applied to one copy
would have left the others wrapping a huge value down to a fraction of a second.
It moves to agents.ParseRetryIn.
The buffer tracked an absolute retryDeadline only to re-arm a timer that was
already armed for the same instant; a backingOff flag says the same thing without
the arithmetic. The plugin token regex now carries its capability in the pattern
instead of capturing and comparing, so another capability's token in the same
message cannot mask it. resolution.extError becomes extErr, matching its
chainState counterpart.
* fix(agents): keep the longer cooldown when parks overlap
Calls to one agent overlap, so a short cooldown could land after a long one
started and cut it short. park now keeps whichever deadline is later, matching
the rule longerRetry already applies on the artwork side. No in-tree provider
can currently produce two different delays for the same agent, so this is
hardening rather than a fix for observed behaviour.
* fix(agents): parse the retry delay at a fixed width
strconv.Atoi parses into the native int, so on the 32-bit targets we ship
(linux/386, windows/386, three ARM variants) a delay above MaxInt32 seconds
overflowed and became unspecified instead of being capped. No provider sends a
68-year delay, so this is not user-visible, but the overflow tests asserted the
cap and would have failed on those architectures, where tests never run.
* fix(plugins): anchor the retry_later regex to a word boundary
Prevents a superstring like useragent(retry_later) from matching the
agent capability token.
2026-08-29 17:28:29 -04:00
|
|
|
|
|
|
|
|
// MetadataAgentError represents an error type for metadata agent operations.
|
|
|
|
|
type MetadataAgentError string
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// MetadataAgentErrorRetryLater indicates the provider is throttling; retry later.
|
|
|
|
|
// Append ":<seconds>" inside the parentheses to request a specific delay.
|
|
|
|
|
MetadataAgentErrorRetryLater MetadataAgentError = "agent(retry_later)"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Error implements the error interface for MetadataAgentError.
|
|
|
|
|
func (e MetadataAgentError) Error() string { return string(e) }
|