cleanup and rename provider to plugin

This commit is contained in:
2026-05-21 16:19:17 -07:00
parent 02d84f423e
commit e8913d1344
62 changed files with 553 additions and 165 deletions
+2 -2
View File
@@ -29,13 +29,13 @@ drop-in plugin search paths are:
Plugin rules:
- A plugin can be a single `.py` file or a package directory with `__init__.py`.
- Current plugin classes inherit from `ProviderCore.base.Provider`.
- Current plugin classes inherit from `PluginCore.base.Provider`.
- Give the plugin a stable name using `PLUGIN_NAME` or the class name.
Example skeleton:
```python
from ProviderCore.base import Provider, SearchResult
from PluginCore.base import Provider, SearchResult
class MyPlugin(Provider):
+3 -3
View File
@@ -13,8 +13,8 @@ from urllib.parse import urlparse
from API.HTTP import HTTPClient, _download_direct_file
from plugins.alldebrid.api import AllDebridClient, parse_magnet_or_hash, is_torrent_file
from ProviderCore.base import Provider, SearchResult
from SYS.provider_helpers import TableProviderMixin
from PluginCore.base import Provider, SearchResult
from SYS.plugin_helpers import TablePluginMixin
from SYS.item_accessors import get_field as _extract_value
from SYS.utils import sanitize_filename
from SYS.logger import log, debug, debug_panel
@@ -637,7 +637,7 @@ def adjust_output_dir_for_alldebrid(
return output_dir
class AllDebrid(TableProviderMixin, Provider):
class AllDebrid(TablePluginMixin, Provider):
"""AllDebrid account provider with magnet folder/file browsing and downloads.
This provider uses the new table system (strict ResultTable adapter pattern) for
+1 -1
View File
@@ -4,7 +4,7 @@ import sys
from urllib.parse import urlparse
from typing import Any, Dict, List, Optional
from ProviderCore.base import Provider, SearchResult
from PluginCore.base import Provider, SearchResult
from SYS.logger import log, debug, debug_panel
from tool.playwright import PlaywrightTool
@@ -1,11 +1,11 @@
"""Example plugin that uses the new `ResultTable` API.
This module demonstrates a minimal provider adapter that yields `ResultModel`
This module demonstrates a minimal plugin adapter that yields `ResultModel`
instances, a set of `ColumnSpec` definitions, and a tiny CLI-friendly renderer
(`render_table`) for demonstration.
Run this to see sample output:
python -m Provider.example_provider
python -m plugins.example_plugin
Example usage (piped selector):
plugin-table -plugin example -sample | select -select 1 | add-file -instance default
@@ -44,7 +44,7 @@ SAMPLE_ITEMS = [
def adapter(items: Iterable[Dict[str, Any]]) -> Iterable[ResultModel]:
"""Convert provider-specific items into `ResultModel` instances.
"""Convert plugin-specific items into `ResultModel` instances.
This adapter enforces the strict API requirement: it yields only
`ResultModel` instances (no legacy dict objects).
@@ -62,7 +62,7 @@ def adapter(items: Iterable[Dict[str, Any]]) -> Iterable[ResultModel]:
# Columns are intentionally *not* mandated. Create a factory that inspects
# sample rows and builds only columns that make sense for the provider data.
# sample rows and builds only columns that make sense for the plugin data.
from SYS.result_table_api import metadata_column
@@ -112,7 +112,7 @@ register_plugin(
adapter,
columns=columns_factory,
selection_fn=selection_fn,
metadata={"description": "Example provider demonstrating dynamic columns and selectors"},
metadata={"description": "Example plugin demonstrating dynamic columns and selectors"},
)
+1 -1
View File
@@ -4,7 +4,7 @@ import os
import sys
from typing import Any, Dict, List, Optional
from ProviderCore.base import Provider
from PluginCore.base import Provider
from SYS.logger import log
+1 -1
View File
@@ -9,7 +9,7 @@ from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
from urllib.parse import quote, unquote, urlparse
from ProviderCore.base import Provider, SearchResult, parse_inline_query_arguments
from PluginCore.base import Provider, SearchResult, parse_inline_query_arguments
def _coerce_bool(value: Any, default: bool = False) -> bool:
+2 -2
View File
@@ -5,7 +5,7 @@ This minimal plugin demonstrates the typical hooks a plugin may implement:
- `search()` to return `SearchResult` items
- `download()` to persist a sample file (useful for local tests)
See `docs/provider_guide.md` for authoring guidance.
See `docs/plugin_guide.md` for authoring guidance.
"""
from __future__ import annotations
@@ -13,7 +13,7 @@ from __future__ import annotations
from pathlib import Path
from typing import Any, Dict, List, Optional
from ProviderCore.base import Provider, SearchResult
from PluginCore.base import Provider, SearchResult
class HelloProvider(Provider):
+1 -1
View File
@@ -16,7 +16,7 @@ from plugins.tidal.api import (
extract_artists,
stringify,
)
from ProviderCore.base import Provider, SearchResult, parse_inline_query_arguments
from PluginCore.base import Provider, SearchResult, parse_inline_query_arguments
from SYS.field_access import get_field
from plugins.tidal_manifest import resolve_tidal_manifest_path
from SYS import pipeline as pipeline_context
+1 -1
View File
@@ -11,7 +11,7 @@ from typing import Any, Dict, List, Optional
from urllib.parse import quote, unquote, urlparse
from API.HTTP import _download_direct_file
from ProviderCore.base import Provider, SearchResult
from PluginCore.base import Provider, SearchResult
from SYS.utils import sanitize_filename, unique_path
from SYS.logger import log
from SYS.config import get_provider_block
+4 -4
View File
@@ -12,7 +12,7 @@ from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Tuple
from urllib.parse import urljoin, urlparse, unquote
from ProviderCore.base import Provider, SearchResult
from PluginCore.base import Provider, SearchResult
from SYS.utils import sanitize_filename
from SYS.logger import log, debug
from SYS.models import ProgressBar
@@ -383,7 +383,7 @@ def _enrich_book_tags_from_isbn(isbn: str,
# 2) isbnsearch metadata plugin fallback.
try:
from plugins.metadata_provider import get_metadata_plugin
from plugins.metadata_plugin import get_metadata_plugin
provider = get_metadata_plugin("isbnsearch",
config or {})
@@ -660,7 +660,7 @@ class Libgen(Provider):
"libgen": ["download-file"],
}
# Domains that should be routed to this provider when the user supplies a URL.
# (Used by ProviderCore.registry.match_provider_name_for_url)
# (Used by PluginCore.registry.match_provider_name_for_url)
URL_DOMAINS = (
"libgen.gl",
"libgen.li",
@@ -1056,7 +1056,7 @@ class Libgen(Provider):
def download_url(self, url: str, output_dir: Path) -> Optional[Path]:
"""Download a direct LibGen URL using the regular mirror logic."""
try:
from ProviderCore.base import SearchResult
from PluginCore.base import SearchResult
sr = SearchResult(
table="libgen",
title="libgen",
+1 -1
View File
@@ -3,7 +3,7 @@ from __future__ import annotations
from typing import Any, Dict, List, Optional
from plugins.loc.api import LOCClient
from ProviderCore.base import Provider, SearchResult
from PluginCore.base import Provider, SearchResult
from SYS.cli_syntax import get_free_text, parse_query
from SYS.logger import log
+1 -1
View File
@@ -4,7 +4,7 @@ import shutil
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
from ProviderCore.base import Provider
from PluginCore.base import Provider
from SYS.metadata import write_metadata, write_tags
from SYS.utils import sanitize_filename, sha256_file, unique_path
+3 -3
View File
@@ -11,8 +11,8 @@ from urllib.parse import quote
from API.requests_client import get_requests_session
from SYS.utils import ffprobe as probe_media_metadata
from ProviderCore.base import Provider, SearchResult
from SYS.provider_helpers import TableProviderMixin
from PluginCore.base import Provider, SearchResult
from SYS.plugin_helpers import TablePluginMixin
from SYS.logger import log
_MATRIX_INIT_CHECK_CACHE: Dict[str,
@@ -276,7 +276,7 @@ def _matrix_health_check(*,
return False, str(exc)
class Matrix(TableProviderMixin, Provider):
class Matrix(TablePluginMixin, Provider):
"""Matrix (Element) room provider with file uploads and selection.
This provider uses the new table system (strict ResultTable adapter pattern) for
+1 -1
View File
@@ -22,7 +22,7 @@ from SYS.command_parsing import (
normalize_to_list as _normalize_to_list,
)
from SYS import pipeline as ctx
from ProviderCore.registry import get_plugin, get_plugin_for_url
from PluginCore.registry import get_plugin, get_plugin_for_url
_MATRIX_PENDING_ITEMS_KEY = "matrix_pending_items"
_MATRIX_PENDING_TEXT_KEY = "matrix_pending_text"
@@ -10,7 +10,7 @@ import subprocess
from API.HTTP import HTTPClient
from API.requests_client import get_requests_session
from ProviderCore.base import SearchResult
from PluginCore.base import SearchResult
try:
from plugins.tidal import Tidal
except ImportError: # pragma: no cover - optional
+1 -1
View File
@@ -10,7 +10,7 @@ from datetime import datetime, timedelta
from urllib.parse import urlparse, parse_qs
from pathlib import Path
from SYS.cmdlet_spec import Cmdlet, CmdletArg, parse_cmdlet_args
from ProviderCore.registry import get_plugin, get_plugin_for_url, list_plugin_names_with_capability
from PluginCore.registry import get_plugin, get_plugin_for_url, list_plugin_names_with_capability
from SYS.logger import debug, get_thread_stream, is_debug_enabled, set_debug, set_thread_stream
from SYS.result_table import Table
from plugins.mpv.mpv_ipc import MPV
+1 -1
View File
@@ -1170,7 +1170,7 @@ def _infer_hydrus_store_from_url_target(*, target: str, config: dict) -> Optiona
is_hydrus_backend = backend_type == "hydrusnetwork" or backend_class == "hydrusnetwork"
if not is_hydrus_backend:
try:
from ProviderCore.registry import get_plugin
from PluginCore.registry import get_plugin
hydrus_provider = get_plugin("hydrusnetwork", config)
checker = getattr(hydrus_provider, "is_backend", None) if hydrus_provider is not None else None
+1 -1
View File
@@ -70,7 +70,7 @@ from SYS.config import load_config, reload_config # noqa: E402
from SYS.logger import set_debug, debug, set_thread_stream # noqa: E402
from SYS.repl_queue import enqueue_repl_command # noqa: E402
from SYS.utils import format_bytes # noqa: E402
from ProviderCore.registry import get_plugin, get_plugin_class # noqa: E402
from PluginCore.registry import get_plugin, get_plugin_class # noqa: E402
from tool.ytdlp import get_display_format_id, get_selection_format_id # noqa: E402
REQUEST_PROP = "user-data/medeia-pipeline-request"
+3 -3
View File
@@ -18,11 +18,11 @@ import requests
from API.HTTP import HTTPClient
from API.requests_client import get_requests_session
from ProviderCore.base import Provider, SearchResult
from PluginCore.base import Provider, SearchResult
from SYS.utils import sanitize_filename
from SYS.cli_syntax import get_field, get_free_text, parse_query
from SYS.logger import log
from plugins.metadata_provider import (
from plugins.metadata_plugin import (
archive_item_metadata_to_tags,
fetch_archive_item_metadata,
)
@@ -654,7 +654,7 @@ class OpenLibrary(Provider):
]
# Domains that should be routed to this provider when the user supplies a URL.
# (Used by ProviderCore.registry.match_provider_name_for_url)
# (Used by PluginCore.registry.match_provider_name_for_url)
URL_DOMAINS = (
"openlibrary.org",
"archive.org",
+1 -1
View File
@@ -5,7 +5,7 @@ import hashlib
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
from ProviderCore.base import Provider, SearchResult
from PluginCore.base import Provider, SearchResult
from SYS.logger import log
from SYS.utils import format_bytes
+1 -1
View File
@@ -13,7 +13,7 @@ from urllib.parse import quote, unquote, urlparse
import paramiko
from scp import SCPClient
from ProviderCore.base import Provider, SearchResult, parse_inline_query_arguments
from PluginCore.base import Provider, SearchResult, parse_inline_query_arguments
def _coerce_bool(value: Any, default: bool = False) -> bool:
+1 -1
View File
@@ -11,7 +11,7 @@ import time
from pathlib import Path
from typing import Any, Dict, List, Optional
from ProviderCore.base import Provider, SearchResult
from PluginCore.base import Provider, SearchResult
from SYS.logger import log, debug, debug_panel
from SYS.models import ProgressBar
+1 -1
View File
@@ -12,7 +12,7 @@ from pathlib import Path
from typing import Any, Dict, List, Optional, Sequence, Tuple
from urllib.parse import urlparse
from ProviderCore.base import Provider, SearchResult
from PluginCore.base import Provider, SearchResult
from SYS.logger import debug
_TELEGRAM_DEFAULT_TIMESTAMP_STEM_RE = re.compile(
+1 -1
View File
@@ -9,7 +9,7 @@ from SYS.command_parsing import has_flag as _has_flag, normalize_to_list as _nor
from SYS.logger import log
from SYS.result_table import Table
from SYS import pipeline as ctx
from ProviderCore.registry import get_plugin
from PluginCore.registry import get_plugin
_TELEGRAM_PENDING_ITEMS_KEY = "telegram_pending_items"
+2 -2
View File
@@ -16,7 +16,7 @@ from plugins.tidal.api import (
extract_artists,
stringify,
)
from ProviderCore.base import Provider, SearchResult
from PluginCore.base import Provider, SearchResult
from SYS.field_access import get_field
from plugins.tidal_manifest import resolve_tidal_manifest_path
from SYS import pipeline as pipeline_context
@@ -216,7 +216,7 @@ class Tidal(Provider):
def extract_query_arguments(self, query: str) -> Tuple[str, Dict[str, Any]]:
"""Parse inline `key:value` query arguments.
Unlike the generic parser in ProviderCore, this supports multi-word
Unlike the generic parser in PluginCore, this supports multi-word
values (e.g. `artist:elliott smith`).
Returns:
+1 -1
View File
@@ -8,7 +8,7 @@ from typing import Any, Dict, List, Optional
import requests
from API.requests_client import get_requests_session
from ProviderCore.base import Provider, SearchResult
from PluginCore.base import Provider, SearchResult
from SYS.logger import debug, log
try: # Preferred HTML parser
from lxml import html as lxml_html
+5 -5
View File
@@ -16,14 +16,14 @@ import re
from pathlib import Path
from API.HTTP import HTTPClient
from ProviderCore.base import Provider, SearchResult, parse_inline_query_arguments
from ProviderCore.inline_utils import resolve_filter
from PluginCore.base import Provider, SearchResult, parse_inline_query_arguments
from PluginCore.inline_utils import resolve_filter
from SYS.logger import debug, debug_panel
from SYS.provider_helpers import TableProviderMixin
from SYS.plugin_helpers import TablePluginMixin
from tool.playwright import PlaywrightTool
class Vimm(TableProviderMixin, Provider):
class Vimm(TablePluginMixin, Provider):
"""Minimal provider for vimm.net vault listings using TableProvider mixin.
NOTES / HOW-TO (selection & auto-download):
@@ -142,7 +142,7 @@ class Vimm(TableProviderMixin, Provider):
],
"region": REGION_CHOICES,
}
# ProviderCore still looks for INLINE_QUERY_FIELD_CHOICES, so expose this
# PluginCore still looks for INLINE_QUERY_FIELD_CHOICES, so expose this
# mapping once and keep QUERY_ARG_CHOICES as the readable name we prefer.
INLINE_QUERY_FIELD_CHOICES = QUERY_ARG_CHOICES
+3 -3
View File
@@ -13,8 +13,8 @@ from pathlib import Path
from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple
from urllib.parse import urlparse
from ProviderCore.base import Provider, SearchResult, parse_inline_query_arguments
from SYS.provider_helpers import TableProviderMixin
from PluginCore.base import Provider, SearchResult, parse_inline_query_arguments
from SYS.plugin_helpers import TablePluginMixin
from SYS.logger import debug, log
from SYS.models import DownloadError, DownloadMediaResult, DownloadOptions
from SYS.payload_builders import build_file_result_payload, build_table_result_payload
@@ -501,7 +501,7 @@ def _build_pipe_objects(
return pipe_objects
class ytdlp(TableProviderMixin, Provider):
class ytdlp(TablePluginMixin, Provider):
"""yt-dlp-backed search and direct download plugin."""
PLUGIN_NAME = "ytdlp"
+1 -1
View File
@@ -4,7 +4,7 @@ import os
import sys
from typing import Any
from ProviderCore.base import Provider
from PluginCore.base import Provider
from SYS.logger import log