updating and refining plugin system refactor
This commit is contained in:
+10
-2
@@ -190,10 +190,18 @@ class SharedArgs:
|
||||
name="store",
|
||||
type="enum",
|
||||
choices=[], # Dynamically populated via get_store_choices()
|
||||
description="Selects store",
|
||||
description="Selects a storage backend",
|
||||
query_key="store",
|
||||
)
|
||||
|
||||
INSTANCE = CmdletArg(
|
||||
name="instance",
|
||||
type="string",
|
||||
description="Selects a plugin instance",
|
||||
query_key="instance",
|
||||
query_aliases=["store"],
|
||||
)
|
||||
|
||||
URL = CmdletArg(
|
||||
name="url",
|
||||
type="string",
|
||||
@@ -1410,7 +1418,7 @@ def fetch_hydrus_metadata(
|
||||
Eliminates repeated boilerplate: client initialization, error handling, metadata extraction.
|
||||
|
||||
Args:
|
||||
config: Configuration object used to resolve the Hydrus provider/store
|
||||
config: Configuration object used to resolve the Hydrus plugin/store
|
||||
hash_hex: File hash to fetch metadata for
|
||||
store_name: Optional Hydrus store name. When provided, do not fall back to a global/default Hydrus client.
|
||||
hydrus_client: Optional explicit Hydrus client. When provided, takes precedence.
|
||||
|
||||
+42
-9
@@ -15,6 +15,7 @@ from SYS.logger import log, debug, debug_panel, is_debug_enabled
|
||||
from SYS.payload_builders import build_table_result_payload
|
||||
from SYS.pipeline_progress import PipelineProgress
|
||||
from SYS.result_publication import overlay_existing_result_table, publish_result_table
|
||||
from SYS.rich_display import show_available_plugins_panel, show_plugin_config_panel
|
||||
from SYS.utils_constant import ALL_SUPPORTED_EXTENSIONS
|
||||
from Store import Store
|
||||
from API.HTTP import _download_direct_file
|
||||
@@ -178,10 +179,11 @@ class Add_File(Cmdlet):
|
||||
summary=
|
||||
"Ingest a local media file to a store backend, upload plugin, or local directory.",
|
||||
usage=
|
||||
"add-file (-path <filepath> | <piped>) (-storage <location> | -plugin <upload-plugin>) [-delete]",
|
||||
"add-file (-path <filepath> | <piped>) (-store <backend|path> | -plugin <upload-plugin>) [-instance NAME] [-delete]",
|
||||
arg=[
|
||||
SharedArgs.PATH,
|
||||
SharedArgs.STORE,
|
||||
SharedArgs.INSTANCE,
|
||||
SharedArgs.URL,
|
||||
SharedArgs.PLUGIN,
|
||||
CmdletArg(
|
||||
@@ -194,7 +196,7 @@ class Add_File(Cmdlet):
|
||||
],
|
||||
detail=[
|
||||
"Note: add-file ingests local files. To fetch remote sources, use download-file and pipe into add-file.",
|
||||
"- Storage location options (use -storage):",
|
||||
"- Storage location options (use -store):",
|
||||
" hydrus: Upload to Hydrus database with metadata tagging",
|
||||
" local: Copy file to local directory",
|
||||
" <path>: Copy file to specified directory",
|
||||
@@ -202,9 +204,12 @@ class Add_File(Cmdlet):
|
||||
" 0x0: Upload to 0x0.st for temporary hosting",
|
||||
" file.io: Upload to file.io for temporary hosting",
|
||||
" internetarchive: Upload to archive.org (optional tag: ia:<identifier> to upload into an existing item)",
|
||||
"- Use -instance with -plugin to target a named provider config: add-file -plugin ftp -instance archive -path C:\\Media\\file.pdf",
|
||||
"- In plugin mode, -store <name> is still accepted as a compatibility alias for -instance <name>.",
|
||||
],
|
||||
examples=[
|
||||
'download-file "https://themathesontrust.org/papers/christianity/alcock-alphabet1.pdf" | add-file -store tutorial',
|
||||
'add-file -plugin ftp -instance archive -path C:\\Media\\report.pdf',
|
||||
],
|
||||
exec=self.run,
|
||||
)
|
||||
@@ -223,9 +228,12 @@ class Add_File(Cmdlet):
|
||||
|
||||
path_arg = parsed.get("path")
|
||||
location = parsed.get("store")
|
||||
plugin_instance = parsed.get("instance")
|
||||
source_url_arg = parsed.get("url")
|
||||
plugin_name = parsed.get("plugin")
|
||||
delete_after = parsed.get("delete", False)
|
||||
if plugin_name and not plugin_instance and location:
|
||||
plugin_instance = location
|
||||
|
||||
# Convenience: when piping a file into add-file, allow `-path <existing dir>`
|
||||
# to act as the destination export directory.
|
||||
@@ -412,6 +420,7 @@ class Add_File(Cmdlet):
|
||||
("items", total_items),
|
||||
("location", location),
|
||||
("plugin", plugin_name),
|
||||
("instance", plugin_instance),
|
||||
("delete", delete_after),
|
||||
],
|
||||
border_style="cyan",
|
||||
@@ -647,6 +656,7 @@ class Add_File(Cmdlet):
|
||||
code = self._handle_plugin_upload(
|
||||
media_path,
|
||||
plugin_name,
|
||||
plugin_instance,
|
||||
pipe_obj,
|
||||
config,
|
||||
delete_after_item
|
||||
@@ -1442,9 +1452,9 @@ class Add_File(Cmdlet):
|
||||
if not plugin_key:
|
||||
return None, None, None
|
||||
|
||||
from ProviderCore.registry import get_search_plugin
|
||||
from ProviderCore.registry import get_plugin
|
||||
|
||||
plugin = get_search_plugin(plugin_key, config)
|
||||
plugin = get_plugin(plugin_key, config)
|
||||
if plugin is None:
|
||||
return None, None, None
|
||||
|
||||
@@ -1762,6 +1772,7 @@ class Add_File(Cmdlet):
|
||||
*,
|
||||
hash_value: str,
|
||||
store: str,
|
||||
provider: Optional[str] = None,
|
||||
path: Optional[str],
|
||||
tag: List[str],
|
||||
title: Optional[str],
|
||||
@@ -1770,6 +1781,7 @@ class Add_File(Cmdlet):
|
||||
) -> None:
|
||||
pipe_obj.hash = hash_value
|
||||
pipe_obj.store = store
|
||||
pipe_obj.provider = provider
|
||||
pipe_obj.is_temp = False
|
||||
pipe_obj.path = path
|
||||
pipe_obj.tag = tag
|
||||
@@ -2180,23 +2192,42 @@ class Add_File(Cmdlet):
|
||||
def _handle_plugin_upload(
|
||||
media_path: Path,
|
||||
plugin_name: str,
|
||||
instance_name: Optional[str],
|
||||
pipe_obj: models.PipeObject,
|
||||
config: Dict[str,
|
||||
Any],
|
||||
delete_after: bool,
|
||||
) -> int:
|
||||
"""Handle uploading via an upload plugin (e.g. 0x0)."""
|
||||
from ProviderCore.registry import get_upload_plugin
|
||||
from ProviderCore.registry import (
|
||||
get_plugin_with_capability,
|
||||
list_plugin_names_with_capability,
|
||||
list_plugins_with_capability,
|
||||
)
|
||||
|
||||
log(f"Uploading via {plugin_name}: {media_path.name}", file=sys.stderr)
|
||||
|
||||
try:
|
||||
file_provider = get_upload_plugin(plugin_name, config)
|
||||
file_provider = get_plugin_with_capability(plugin_name, "upload", config)
|
||||
if not file_provider:
|
||||
log(f"Upload plugin '{plugin_name}' not available", file=sys.stderr)
|
||||
available_map = list_plugins_with_capability("upload", config)
|
||||
known_upload_plugins = set(list_plugin_names_with_capability("upload"))
|
||||
available_uploads = [name for name, enabled in available_map.items() if enabled and name in known_upload_plugins]
|
||||
|
||||
if str(plugin_name or "").strip().lower() in known_upload_plugins:
|
||||
show_plugin_config_panel([plugin_name])
|
||||
else:
|
||||
log(f"Upload plugin '{plugin_name}' is not available or does not support upload", file=sys.stderr)
|
||||
|
||||
if available_uploads:
|
||||
show_available_plugins_panel(sorted(available_uploads))
|
||||
return 1
|
||||
|
||||
hoster_url = file_provider.upload(str(media_path), pipe_obj=pipe_obj)
|
||||
hoster_url = file_provider.upload(
|
||||
str(media_path),
|
||||
pipe_obj=pipe_obj,
|
||||
instance=instance_name,
|
||||
)
|
||||
log(f"File uploaded: {hoster_url}", file=sys.stderr)
|
||||
|
||||
f_hash = Add_File._resolve_file_hash(None, media_path, pipe_obj, None)
|
||||
@@ -2209,6 +2240,7 @@ class Add_File(Cmdlet):
|
||||
extra_updates: Dict[str,
|
||||
Any] = {
|
||||
"plugin": plugin_name,
|
||||
"instance": instance_name,
|
||||
"plugin_url": hoster_url,
|
||||
}
|
||||
if isinstance(pipe_obj.extra, dict):
|
||||
@@ -2222,7 +2254,8 @@ class Add_File(Cmdlet):
|
||||
Add_File._update_pipe_object_destination(
|
||||
pipe_obj,
|
||||
hash_value=f_hash or "unknown",
|
||||
store=plugin_name or "plugin",
|
||||
store="",
|
||||
provider=plugin_name or None,
|
||||
path=file_path,
|
||||
tag=pipe_obj.tag,
|
||||
title=pipe_obj.title or (media_path.name if media_path else None),
|
||||
|
||||
+13
-13
@@ -55,12 +55,13 @@ class Download_File(Cmdlet):
|
||||
name="download-file",
|
||||
summary="Download files or streaming media",
|
||||
usage=
|
||||
"download-file <url> [-path DIR] [options] OR @N | download-file [-path DIR|DIR] [options]",
|
||||
"download-file <url> [-plugin NAME] [-instance NAME] [-path DIR] [options] OR @N | download-file [-plugin NAME] [-instance NAME] [-path DIR] [options]",
|
||||
alias=["dl-file",
|
||||
"download-http"],
|
||||
arg=[
|
||||
SharedArgs.URL,
|
||||
SharedArgs.PLUGIN,
|
||||
SharedArgs.INSTANCE,
|
||||
SharedArgs.PATH,
|
||||
SharedArgs.QUERY,
|
||||
QueryArg(
|
||||
@@ -85,6 +86,7 @@ class Download_File(Cmdlet):
|
||||
],
|
||||
detail=[
|
||||
"Download files directly via HTTP or streaming media via yt-dlp.",
|
||||
"Use -plugin with -instance to target a named provider config when a plugin exposes multiple instances.",
|
||||
"For Internet Archive item pages (archive.org/details/...), shows a selectable file/format list; pick with @N to download.",
|
||||
],
|
||||
exec=self.run,
|
||||
@@ -522,13 +524,13 @@ class Download_File(Cmdlet):
|
||||
config: Dict[str,
|
||||
Any],
|
||||
) -> List[Any]:
|
||||
get_search_plugin = registry.get("get_search_plugin")
|
||||
get_provider = registry.get("get_plugin")
|
||||
expanded_items: List[Any] = []
|
||||
|
||||
for item in piped_items:
|
||||
try:
|
||||
provider_key = self._provider_key_from_item(item)
|
||||
provider = get_search_plugin(provider_key, config) if provider_key and get_search_plugin else None
|
||||
provider = get_provider(provider_key, config) if provider_key and get_provider else None
|
||||
|
||||
# Generic hook: If provider has expand_item(item), use it.
|
||||
if provider and hasattr(provider, "expand_item") and callable(provider.expand_item):
|
||||
@@ -566,7 +568,7 @@ class Download_File(Cmdlet):
|
||||
) -> tuple[int, int]:
|
||||
downloaded_count = 0
|
||||
queued_magnet_submissions = 0
|
||||
get_search_plugin = registry.get("get_search_plugin")
|
||||
get_provider = registry.get("get_plugin")
|
||||
SearchResult = registry.get("SearchResult")
|
||||
|
||||
expanded_items = self._expand_provider_items(
|
||||
@@ -622,15 +624,15 @@ class Download_File(Cmdlet):
|
||||
|
||||
transfer_label = label
|
||||
|
||||
# If this looks like a provider item and providers are available, prefer provider.download()
|
||||
# If this looks like a plugin-owned item and a plugin is available, prefer plugin.download().
|
||||
downloaded_path: Optional[Path] = None
|
||||
attempted_provider_download = False
|
||||
provider_sr = None
|
||||
provider_obj = None
|
||||
provider_key = self._provider_key_from_item(item)
|
||||
if provider_key and get_search_plugin and SearchResult:
|
||||
# Reuse helper to derive the provider key from table/provider/source hints.
|
||||
provider_obj = get_search_plugin(provider_key, config)
|
||||
if provider_key and get_provider and SearchResult:
|
||||
# Reuse helper to derive the plugin key from table/plugin/source hints.
|
||||
provider_obj = get_provider(provider_key, config)
|
||||
|
||||
if provider_obj is not None and getattr(provider_obj, "prefers_transfer_progress", False):
|
||||
try:
|
||||
@@ -697,7 +699,7 @@ class Download_File(Cmdlet):
|
||||
)
|
||||
continue
|
||||
|
||||
# Allow providers to add/enrich tags and metadata during download.
|
||||
# Allow plugins to add or enrich tags and metadata during download.
|
||||
if provider_sr is not None:
|
||||
try:
|
||||
sr_md = getattr(provider_sr, "full_metadata", None)
|
||||
@@ -838,9 +840,9 @@ class Download_File(Cmdlet):
|
||||
notes: Optional[Dict[str, str]] = None
|
||||
try:
|
||||
if isinstance(full_metadata, dict):
|
||||
# Providers attach pre-built notes under the generic "_notes" key
|
||||
# Plugins attach pre-built notes under the generic "_notes" key
|
||||
# (e.g. Tidal sets {"lyric": subtitles} during download enrichment).
|
||||
# This keeps provider-specific metadata handling inside the provider.
|
||||
# This keeps plugin-specific metadata handling inside the plugin.
|
||||
_provider_notes = full_metadata.get("_notes")
|
||||
if isinstance(_provider_notes, dict) and _provider_notes:
|
||||
notes = {str(k): str(v) for k, v in _provider_notes.items() if k and v}
|
||||
@@ -949,7 +951,6 @@ class Download_File(Cmdlet):
|
||||
|
||||
return {
|
||||
"get_plugin": getattr(provider_registry, "get_plugin", None),
|
||||
"get_search_plugin": getattr(provider_registry, "get_search_plugin", None),
|
||||
"match_plugin_name_for_url": getattr(provider_registry, "match_plugin_name_for_url", None),
|
||||
"list_selection_url_prefixes": getattr(provider_registry, "list_selection_url_prefixes", None),
|
||||
"SearchResult": SearchResult,
|
||||
@@ -957,7 +958,6 @@ class Download_File(Cmdlet):
|
||||
except Exception:
|
||||
return {
|
||||
"get_plugin": None,
|
||||
"get_search_plugin": None,
|
||||
"match_plugin_name_for_url": None,
|
||||
"list_selection_url_prefixes": None,
|
||||
"SearchResult": None,
|
||||
|
||||
+22
-22
@@ -15,10 +15,10 @@ import sys
|
||||
from SYS.logger import log, debug
|
||||
|
||||
from plugins.metadata_provider import (
|
||||
get_default_subject_scrape_provider,
|
||||
get_metadata_provider,
|
||||
get_metadata_provider_for_url,
|
||||
list_metadata_providers,
|
||||
get_default_subject_scrape_plugin,
|
||||
get_metadata_plugin,
|
||||
get_metadata_plugin_for_url,
|
||||
list_metadata_plugins,
|
||||
scrape_isbn_metadata,
|
||||
scrape_openlibrary_metadata,
|
||||
)
|
||||
@@ -393,33 +393,33 @@ def _run_impl(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
||||
scrape_url = parsed_args.get("scrape")
|
||||
scrape_requested = scrape_flag_present or scrape_url is not None
|
||||
|
||||
# Handle URL or provider scraping mode.
|
||||
# Handle URL or metadata-plugin scraping mode.
|
||||
if scrape_requested:
|
||||
import json as json_module
|
||||
|
||||
scrape_target = str(scrape_url or "").strip() if scrape_url is not None else ""
|
||||
provider = None
|
||||
plugin = None
|
||||
if scrape_target.startswith(("http://", "https://")):
|
||||
provider = get_metadata_provider_for_url(scrape_target, config)
|
||||
if provider is None:
|
||||
log("No metadata provider can scrape this URL", file=sys.stderr)
|
||||
plugin = get_metadata_plugin_for_url(scrape_target, config)
|
||||
if plugin is None:
|
||||
log("No metadata plugin can scrape this URL", file=sys.stderr)
|
||||
return 1
|
||||
payload = provider.scrape_url_payload(scrape_target)
|
||||
payload = plugin.scrape_url_payload(scrape_target)
|
||||
if not isinstance(payload, dict):
|
||||
log(f"No metadata extracted from URL via {provider.name}", file=sys.stderr)
|
||||
log(f"No metadata extracted from URL via {plugin.name}", file=sys.stderr)
|
||||
return 1
|
||||
print(json_module.dumps(payload, ensure_ascii=False))
|
||||
return 0
|
||||
|
||||
if scrape_target:
|
||||
provider = get_metadata_provider(scrape_target, config)
|
||||
plugin = get_metadata_plugin(scrape_target, config)
|
||||
else:
|
||||
provider = get_default_subject_scrape_provider(config)
|
||||
if provider is None:
|
||||
plugin = get_default_subject_scrape_plugin(config)
|
||||
if plugin is None:
|
||||
if scrape_target:
|
||||
log(f"Unknown metadata provider: {scrape_target}", file=sys.stderr)
|
||||
log(f"Unknown metadata plugin: {scrape_target}", file=sys.stderr)
|
||||
else:
|
||||
log("No default metadata provider is available for subject scraping", file=sys.stderr)
|
||||
log("No default metadata plugin is available for subject scraping", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
backend = None
|
||||
@@ -548,7 +548,7 @@ def _run_impl(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
||||
query_hint = resolved_subject_query or identifier_query or combined_query or title_hint
|
||||
if not query_hint:
|
||||
log(
|
||||
f"No query could be resolved for metadata provider '{provider.name}'",
|
||||
f"No query could be resolved for metadata plugin '{provider.name}'",
|
||||
file=sys.stderr
|
||||
)
|
||||
return 1
|
||||
@@ -749,9 +749,9 @@ def _run_impl(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
||||
)
|
||||
return 0
|
||||
|
||||
provider_for_apply = get_metadata_provider(str(result_provider), config)
|
||||
if provider_for_apply is not None:
|
||||
apply_tags = provider_for_apply.filter_tags_for_store_apply(
|
||||
plugin_for_apply = get_metadata_plugin(str(result_provider), config)
|
||||
if plugin_for_apply is not None:
|
||||
apply_tags = plugin_for_apply.filter_tags_for_store_apply(
|
||||
[str(t) for t in result_tags if t is not None]
|
||||
)
|
||||
else:
|
||||
@@ -946,7 +946,7 @@ def _run_impl(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
||||
|
||||
_SCRAPE_CHOICES = []
|
||||
try:
|
||||
_SCRAPE_CHOICES = sorted(list_metadata_providers().keys())
|
||||
_SCRAPE_CHOICES = sorted(list_metadata_plugins().keys())
|
||||
except Exception:
|
||||
_SCRAPE_CHOICES = [
|
||||
"itunes",
|
||||
@@ -1000,7 +1000,7 @@ class Get_Tag(Cmdlet):
|
||||
' -query: Override hash to look up in Hydrus (use: -query "hash:<sha256>")',
|
||||
" -store: Store result to key for downstream pipeline",
|
||||
" -emit: Quiet mode (no interactive selection)",
|
||||
" -scrape: Scrape metadata from URL or metadata provider",
|
||||
" -scrape: Scrape metadata from URL or metadata plugin",
|
||||
],
|
||||
exec=self.run,
|
||||
)
|
||||
|
||||
+37
-17
@@ -1,4 +1,4 @@
|
||||
"""search-file cmdlet: Search for files in storage backends (Hydrus)."""
|
||||
"""search-file cmdlet: Search store backends and search-capable plugins."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -15,11 +15,11 @@ from urllib.parse import urlparse, parse_qs, unquote, urljoin
|
||||
|
||||
from SYS.logger import log, debug, debug_panel
|
||||
from SYS.payload_builders import build_file_result_payload, normalize_file_extension
|
||||
from ProviderCore.registry import get_search_plugin, list_search_plugins
|
||||
from ProviderCore.registry import get_plugin_with_capability, list_plugins_with_capability
|
||||
from SYS.rich_display import (
|
||||
show_provider_config_panel,
|
||||
show_plugin_config_panel,
|
||||
show_store_config_panel,
|
||||
show_available_providers_panel,
|
||||
show_available_plugins_panel,
|
||||
)
|
||||
from SYS.database import insert_worker, update_worker, append_worker_stdout
|
||||
from SYS.item_accessors import get_extension_field, get_int_field, get_result_title
|
||||
@@ -164,13 +164,13 @@ def _summarize_worker_results(results: Sequence[Dict[str, Any]], preview_limit:
|
||||
|
||||
|
||||
class search_file(Cmdlet):
|
||||
"""Class-based search-file cmdlet for searching storage backends."""
|
||||
"""Class-based search-file cmdlet for searching backends and providers."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__(
|
||||
name="search-file",
|
||||
summary="Search storage backends (Hydrus) or external plugins (via -plugin).",
|
||||
usage="search-file [-query <query>] [-store BACKEND] [-limit N] [-plugin NAME]",
|
||||
summary="Search configured store backends or search-capable plugins.",
|
||||
usage="search-file [-query <query>] [-store BACKEND] [-instance NAME] [-limit N] [-plugin NAME]",
|
||||
arg=[
|
||||
CmdletArg(
|
||||
"limit",
|
||||
@@ -178,6 +178,7 @@ class search_file(Cmdlet):
|
||||
description="Limit results (default: 100)"
|
||||
),
|
||||
SharedArgs.STORE,
|
||||
SharedArgs.INSTANCE,
|
||||
SharedArgs.QUERY,
|
||||
SharedArgs.PLUGIN,
|
||||
CmdletArg(
|
||||
@@ -187,8 +188,10 @@ class search_file(Cmdlet):
|
||||
),
|
||||
],
|
||||
detail=[
|
||||
"Search across storage backends: Hydrus instances",
|
||||
"Use -store to search a specific backend by name",
|
||||
"Search across configured store backends or plugin providers.",
|
||||
"Use -store to target a specific store backend by name.",
|
||||
"Use -plugin with -instance to target a named provider config.",
|
||||
"In plugin mode, -store <name> is kept as a compatibility alias for -instance <name>.",
|
||||
"URL search: url:* (any URL) or url:<value> (URL substring)",
|
||||
"Extension search: ext:<value> (e.g., ext:png)",
|
||||
"Hydrus-style extension: system:filetype = png",
|
||||
@@ -207,6 +210,7 @@ class search_file(Cmdlet):
|
||||
"",
|
||||
"Plugin search (-plugin):",
|
||||
"search-file -plugin youtube 'tutorial' # Search YouTube plugin",
|
||||
"search-file -plugin ftp -instance work '*' # Search a named FTP/SCP plugin instance",
|
||||
"search-file -plugin alldebrid '*' # List AllDebrid magnets",
|
||||
"search-file -plugin alldebrid -open 123 '*' # Show files for a magnet",
|
||||
],
|
||||
@@ -1451,6 +1455,7 @@ class search_file(Cmdlet):
|
||||
self,
|
||||
*,
|
||||
plugin_name: str,
|
||||
instance_name: Optional[str],
|
||||
query: str,
|
||||
limit: int,
|
||||
limit_set: bool,
|
||||
@@ -1475,15 +1480,15 @@ class search_file(Cmdlet):
|
||||
log("Error: search-file -plugin requires both plugin and query", file=sys.stderr)
|
||||
log(f"Usage: {self.usage}", file=sys.stderr)
|
||||
|
||||
providers_map = list_search_plugins(config)
|
||||
providers_map = list_plugins_with_capability("search", config)
|
||||
available = [n for n, a in providers_map.items() if a]
|
||||
unconfigured = [n for n, a in providers_map.items() if not a]
|
||||
|
||||
if unconfigured:
|
||||
show_provider_config_panel(unconfigured)
|
||||
show_plugin_config_panel(unconfigured)
|
||||
|
||||
if available:
|
||||
show_available_providers_panel(available)
|
||||
show_available_plugins_panel(available)
|
||||
|
||||
return 1
|
||||
|
||||
@@ -1496,7 +1501,7 @@ class search_file(Cmdlet):
|
||||
if hasattr(ctx_mod, "get_pipeline_state"):
|
||||
progress = ctx_mod.get_pipeline_state().live_progress
|
||||
|
||||
provider = get_search_plugin(plugin_name, config)
|
||||
provider = get_plugin_with_capability(plugin_name, "search", config)
|
||||
if not provider:
|
||||
if progress:
|
||||
try:
|
||||
@@ -1504,12 +1509,12 @@ class search_file(Cmdlet):
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
show_provider_config_panel([plugin_name])
|
||||
show_plugin_config_panel([plugin_name])
|
||||
|
||||
providers_map = list_search_plugins(config)
|
||||
providers_map = list_plugins_with_capability("search", config)
|
||||
available = [n for n, a in providers_map.items() if a]
|
||||
if available:
|
||||
show_available_providers_panel(available)
|
||||
show_available_plugins_panel(available)
|
||||
return 1
|
||||
|
||||
worker_id = str(uuid.uuid4())
|
||||
@@ -1542,6 +1547,8 @@ class search_file(Cmdlet):
|
||||
normalized_query = (normalized_query or "").strip()
|
||||
query = normalized_query or "*"
|
||||
search_filters = dict(provider_filters or {})
|
||||
if instance_name and not search_filters.get("instance"):
|
||||
search_filters["instance"] = str(instance_name).strip()
|
||||
|
||||
# Dynamic table generation via provider
|
||||
table_title = provider.get_table_title(query, search_filters).strip().rstrip(":")
|
||||
@@ -1564,6 +1571,7 @@ class search_file(Cmdlet):
|
||||
"search-file provider request",
|
||||
[
|
||||
("provider", plugin_name),
|
||||
("instance", search_filters.get("instance") or "<default>"),
|
||||
("query", query),
|
||||
("limit", limit),
|
||||
("filters", search_filters or "<none>"),
|
||||
@@ -1581,7 +1589,7 @@ class search_file(Cmdlet):
|
||||
border_style="cyan",
|
||||
)
|
||||
|
||||
# Allow providers to apply provider-specific UX transforms (e.g. auto-expansion)
|
||||
# Allow plugins to apply plugin-specific UX transforms (e.g. auto-expansion)
|
||||
try:
|
||||
post = getattr(provider, "postprocess_search_results", None)
|
||||
if callable(post) and isinstance(results, list):
|
||||
@@ -1737,6 +1745,10 @@ class search_file(Cmdlet):
|
||||
f.lower()
|
||||
for f in (flag_registry.get("store") or {"-store", "--store"})
|
||||
}
|
||||
instance_flags = {
|
||||
f.lower()
|
||||
for f in (flag_registry.get("instance") or {"-instance", "--instance"})
|
||||
}
|
||||
limit_flags = {
|
||||
f.lower()
|
||||
for f in (flag_registry.get("limit") or {"-limit", "--limit"})
|
||||
@@ -1753,6 +1765,7 @@ class search_file(Cmdlet):
|
||||
# Parse arguments
|
||||
query = ""
|
||||
storage_backend: Optional[str] = None
|
||||
instance_name: Optional[str] = None
|
||||
plugin_name: Optional[str] = None
|
||||
open_id: Optional[int] = None
|
||||
limit = 100
|
||||
@@ -1773,6 +1786,10 @@ class search_file(Cmdlet):
|
||||
plugin_name = args_list[i + 1]
|
||||
i += 2
|
||||
continue
|
||||
if low in instance_flags and i + 1 < len(args_list):
|
||||
instance_name = args_list[i + 1]
|
||||
i += 2
|
||||
continue
|
||||
if low in open_flags and i + 1 < len(args_list):
|
||||
try:
|
||||
open_id = int(args_list[i + 1])
|
||||
@@ -1804,8 +1821,11 @@ class search_file(Cmdlet):
|
||||
query = query.strip()
|
||||
|
||||
if plugin_name:
|
||||
if storage_backend and not instance_name:
|
||||
instance_name = storage_backend
|
||||
return self._run_plugin_search(
|
||||
plugin_name=plugin_name,
|
||||
instance_name=instance_name,
|
||||
query=query,
|
||||
limit=limit,
|
||||
limit_set=limit_set,
|
||||
|
||||
Reference in New Issue
Block a user