Plugins
This folder is the primary home for bundled plugins and also the default search path for drop-in plugins.
User-facing docs and CLI flows treat these integrations as plugins. Some Python
types and some stored config keys still use older Provider naming internally,
but that is a legacy implementation detail rather than the preferred public
term.
Preferred layout:
- Put each plugin in its own folder under
plugins/<name>/with an__init__.py. - Keep plugin-specific assets beside the code in that same folder.
- Single-file
.pyplugins are still supported, but package folders are the recommended plug-and-play format.
That means a plugin can ship as a drag-and-drop folder with extras such as:
cookies.txt- templates or fixture files
- helper modules
- small static assets
Built-in bundled plugins use the same layout as external plugins. Additional drop-in plugin search paths are:
plugins/in the repo rootplugins/in the current working directory- Any directory listed in
MM_PLUGIN_PATH - Any directory listed in
MEDEIA_PLUGIN_PATH
Plugin rules:
- A plugin can be a single
.pyfile or a package directory with__init__.py. - Current plugin classes inherit from
PluginCore.base.Provider. - Give the plugin a stable name using
PLUGIN_NAMEor the class name.
Example skeleton:
from PluginCore.base import Provider, SearchResult
class MyPlugin(Provider):
PLUGIN_NAME = "myplugin"
URL_DOMAINS = ("example.com",)
def search(self, query, limit=50, filters=None, **kwargs):
text = str(query or "").strip()
if not text:
return []
return [
SearchResult(
table="myplugin",
title=f"Result for {text}",
path=f"https://example.com/{text}",
)
]
Bundled walkthrough:
- Plugins can expose named config instances. The current stored config may still
use legacy key paths such as
provider.<plugin>.<instance>, and cmdlets target instances with-instance <name>. - Use
.config pluginsin the CLI to browse configured plugin instances. - The repo now includes a real FTP example plugin in plugins/ftp/__init__.py.
- The walkthrough is in docs/ftp_plugin_tutorial.md and shows
search-file -plugin ftp -instance <name>, folder drill-in via@N, file download routing,@N | add-file -instance ..., andadd-file -plugin ftp -instance <name>uploads. - The repo also includes an SCP example plugin in plugins/scp/__init__.py.
- The walkthrough is in docs/scp_plugin_tutorial.md and shows
search-file -plugin scp -instance <name>, SSH-backed directory drill-in, file download routing,@N | add-file -instance ..., andadd-file -plugin scp -instance <name>uploads. - The repo also includes a built-in HydrusNetwork plugin in plugins/hydrusnetwork/__init__.py. Its Hydrus client API now lives in the plugin-owned package plugins/hydrusnetwork/api/__init__.py, its registry-facing store adapter lives in plugins/hydrusnetwork/store_proxy.py, and its heavy internal operations live in plugins/hydrusnetwork/store_backend.py. This
plugins/<name>/api/package shape is the intended pattern for plugin-owned API helpers going forward. The plugin resolves configured Hydrus instances directly from plugin config instead of routing back throughStore.registry; the proxy exists only so generic store callers can still target configured Hydrus stores. API/HydrusNetwork.py and Store/HydrusNetwork.py are legacy compatibility shims only, and store discovery prefers the plugin-owned Hydrus hook over those shims.