# Plugins This folder is the primary home for bundled plugins and also the default search path for drop-in plugins. Preferred layout: - Put each plugin in its own folder under `plugins//` with an `__init__.py`. - Keep plugin-specific assets beside the code in that same folder. - Single-file `.py` plugins 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 root - `plugins/` 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 `.py` file or a package directory with `__init__.py`. - Define a class that inherits from `ProviderCore.base.Provider`. - Give it a stable name using `PLUGIN_NAME` or the class name. Example skeleton: ```python from ProviderCore.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: - Providers can now expose named config instances under `provider..` and cmdlets can target them with `-instance `; plugin-mode `-store ` remains a compatibility alias while store-backed flows still use real backend stores. - The repo now includes a real FTP example plugin in [plugins/ftp/__init__.py](plugins/ftp/__init__.py). - The walkthrough is in [docs/ftp_plugin_tutorial.md](docs/ftp_plugin_tutorial.md) and shows `search-file -plugin ftp -instance `, folder drill-in via `@N`, file download routing, `@N | add-file -store ...`, and `add-file -plugin ftp -instance ` uploads. - The repo also includes an SCP example plugin in [plugins/scp/__init__.py](plugins/scp/__init__.py). - The walkthrough is in [docs/scp_plugin_tutorial.md](docs/scp_plugin_tutorial.md) and shows `search-file -plugin scp -instance `, SSH-backed directory drill-in, file download routing, `@N | add-file -store ...`, and `add-file -plugin scp -instance ` uploads. - The repo now also includes a built-in HydrusNetwork provider in [plugins/hydrusnetwork/__init__.py](plugins/hydrusnetwork/__init__.py). Its Hydrus client API now lives in the plugin-owned package [plugins/hydrusnetwork/api/__init__.py](plugins/hydrusnetwork/api/__init__.py), its registry-facing store adapter lives in [plugins/hydrusnetwork/store_proxy.py](plugins/hydrusnetwork/store_proxy.py), and its heavy internal operations live in [plugins/hydrusnetwork/store_backend.py](plugins/hydrusnetwork/store_backend.py). This `plugins//api/` package shape is the intended pattern for plugin-owned API helpers going forward. The provider now resolves configured Hydrus instances directly from plugin config instead of routing back through `Store.registry`; the proxy exists only so generic store callers can still target configured Hydrus stores. [API/HydrusNetwork.py](API/HydrusNetwork.py) and [Store/HydrusNetwork.py](Store/HydrusNetwork.py) are legacy compatibility shims only, and store discovery prefers the plugin-owned Hydrus hook over those shims.