Skip to content

Conversation

deluan
Copy link
Member

@deluan deluan commented Apr 24, 2025

🧩 Experimental Plugin System for Navidrome

This PR introduces an experimental WebAssembly-based plugin system that allows extending Navidrome's functionality without modifying the core codebase.

Key Features

  • Secure WASM Runtime: Plugins run in sandboxed WebAssembly environment
  • Plugin Types: MetadataAgent, Scrobbler, SchedulerCallback, WebSocketCallback, LifecycleManagement
  • Host Services: Artwork, Cache, Config, HTTP, Scheduler, WebSocket APIs for plugin integration
  • CLI Management: Install, remove, list, and update plugins via command line

Plugin Management

navidrome plugin list           # List installed plugins
navidrome plugin install <path> # Install plugin
navidrome plugin remove <id>    # Remove plugin
navidrome plugin help           # For more options

Configuration

[Plugins]
Enabled = true
Folder = "/path/to/plugins"
CacheSize = 50

Example Plugins Included

Security

  • Sandboxed execution with granular permissions
  • Network access controls and URL restrictions
  • Resource limits and timeout protection

Status

⚠️ Experimental - API may change in future versions. Plugins are opt-in via configuration.

Documentation

https://github.com/navidrome/navidrome/blob/master/plugins/README.md

Currently this system enables custom metadata sources, and specialized scrobblers, but the functionality will be expanded in future versions.

deluan added 30 commits April 21, 2025 16:22
Signed-off-by: Deluan <deluan@navidrome.org>
Introduced a plugin manager that scans the plugins folder for subdirectories containing plugin.wasm files and auto-registers them as agents using the directory name as the unique agent name. Updated the configuration to support plugins with enabled/folder options, and ensured the plugin manager is started as a concurrent task during server startup. The wasmAgent now returns the plugin directory name for AgentName, ensuring each plugin agent is uniquely identifiable. This enables dynamic plugin discovery and integration with the agents orchestrator.
Added a Ginkgo v2 suite bootstrap (plugins_suite_test.go) for the plugins package and a test (manager_test.go) to verify that plugins in the testdata folder are auto-registered and can be loaded as agents. The test uses a mock DataStore and asserts that the agent is registered and its AgentName matches the plugin directory. Updated go.mod and go.sum for wazero dependency required by plugin WASM support.
… running suite; add real-plugin Ginkgo tests. Add BeforeSuite to plugins suite to build plugins/testdata/agent/plugin.wasm using Go WASI build command, matching README instructions. Remove plugin.wasm before build to guarantee a clean build. Add full real-plugin Ginkgo/Gomega tests for wasmAgent, covering all methods and error cases. Fix manager_test.go to use pointer to Manager. This ensures plugin tests are always run against a freshly compiled WASM binary, increasing reliability and reproducibility.

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

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

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

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

Also add a sample Wikimedia plugin

Signed-off-by: Deluan <deluan@navidrome.org>
Standardized error creation using 'errors.New' where formatting was not needed. Introduced a constant for HTTP request timeouts. Removed commented-out log statement. Improved code comments for clarity and accuracy.
…nses

Introduced a single SPARQLResult struct to represent all possible SPARQL response fields (sitelink, wiki, comment, img). Added a parseSPARQLResult helper to unmarshal and check for empty results, simplifying all fetch functions and improving type safety and maintainability.
Signed-off-by: Deluan <deluan@navidrome.org>
Implemented background WASM plugin compilation with concurrency limits, proper closure capture, and global compilation cache to avoid data races. Added debug and warning logs for plugin compilation results, including elapsed time. Ensured plugin registration is correct and all tests pass.
Changed agent instantiation to be fully lazy. The Agents struct now stores agent names in order and only instantiates each agent on first use, caching the result. This preserves agent call order, improves server startup time, and ensures thread safety. Updated all agent methods and tests to use the new pattern. No changes to agent registration or interface. All tests pass.
Introduced runtime.AddCleanup to guarantee that the Close method of WASM plugin instances is called, even if they are garbage collected from the sync.Pool. Modified the sync.Pool.New function in manager.go to register a cleanup function for each loaded instance that implements Close. Updated agent.go to handle the pooledInstance wrapper containing the instance and its cleanup handle. Ensured cleanup.Stop() is called before explicitly closing an instance (on error or agent shutdown) to prevent double closing. This fixes a potential resource leak where instances could be GC'd from the pool without proper cleanup.
Refactored plugins/manager.go and plugins/agent.go to improve readability and reduce function length. Extracted pool initialization logic into newPluginPool and background compilation/agent factory logic into precompilePlugin/createAgentFactory in manager.go. Extracted pool retrieval/validation and cleanup function creation into getValidPooledInstance/createPoolCleanupFunc in agent.go.

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

Signed-off-by: Deluan <deluan@navidrome.org>
Signed-off-by: Deluan <deluan@navidrome.org>
…etAlbumInfo and GetAlbumImages methods

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

Signed-off-by: Deluan <deluan@navidrome.org>
…aService in plugin manager

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

Signed-off-by: Deluan <deluan@navidrome.org>
…r improved service handling

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

Signed-off-by: Deluan <deluan@navidrome.org>
…ent factory creation

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

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

Signed-off-by: Deluan <deluan@navidrome.org>
deluan added 2 commits June 18, 2025 17:26
… each service

Signed-off-by: Deluan <deluan@navidrome.org>
Signed-off-by: Deluan <deluan@navidrome.org>
deluan added 7 commits June 18, 2025 18:21
…che parameter

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

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

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

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

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

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

Signed-off-by: Deluan <deluan@navidrome.org>
@deluan
Copy link
Member Author

deluan commented Jun 20, 2025

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a substantial and well-designed plugin system. The architecture leverages WASM for security and uses Protocol Buffers for communication, which is a solid approach. The new CLI commands for plugin management are comprehensive. Core components like agents and scrobblers have been thoughtfully refactored to support these plugin extensions.

The permission system is a highlight, enforcing security by default and requiring explicit declarations from plugins. The documentation in plugins/README.md is excellent and will be invaluable for developers looking to create plugins.

I've identified a few areas for minor improvement, primarily concerning error handling in the CLI and ensuring clarity in certain plugin interaction patterns. The critical fix in log/redactrus.go is a good catch.

Overall, this is a strong foundation for extending Navidrome's capabilities.

deluan added 9 commits June 19, 2025 22:48
…tion handling

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

Signed-off-by: Deluan <deluan@navidrome.org>
Signed-off-by: Deluan <deluan@navidrome.org>
…o avoid flakiness

Signed-off-by: Deluan <deluan@navidrome.org>
…ed error handling

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

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

Signed-off-by: Deluan <deluan@navidrome.org>
@deluan deluan changed the title [WIP] Plugin System Experimental Plugin System Jun 23, 2025
@deluan deluan merged commit f1fc2cd into master Jun 23, 2025
35 checks passed
@deluan deluan deleted the plugins-2 branch June 23, 2025 00:45
@starkgate
Copy link

starkgate commented Jul 1, 2025

@deluan This sounds very interesting, thank you! Is it possible with the plugin functionalities of 0.57.0 to create a plugin that ingests the user and album rating tags from the files into the navidrome db? Until now I've added this functionality to my build in a hacky way but this could be a much better way to implement it.

@deluan
Copy link
Member Author

deluan commented Jul 1, 2025

Yes, it will be possible. But for that I still need to add the possibility for plugins to hook into the scanner process. This will be implemented soon.

You can already do that, by using Custom tags

These tags can then be used in Smart Playlists

@starkgate
Copy link

Yes, it will be possible. But for that I still need to add the possibility for plugins to hook into the scanner process. This will be implemented soon.

You can already do that, by using Custom tags

These tags can then be used in Smart Playlists

I assume custom tags would not be able to show up in the UI as star ratings though, or am I misunderstanding them?

@deluan
Copy link
Member Author

deluan commented Jul 2, 2025

I assume custom tags would not be able to show up in the UI as star ratings though, or am I misunderstanding them?

They can only be used in smart playlists and be shown in the "Raw Tags" tab in the Album/Song Get Info dialog.

If you want to map the rating tag to the Navidrome's 5-star rating, then yes, a plugin would be the way to go.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants