"""download-provider cmdlet: Download items from external providers.""" from __future__ import annotations from typing import Any, Dict, Sequence, List, Optional from pathlib import Path import sys import json from SYS.logger import log, debug from Provider.registry import get_search_provider, SearchResult from SYS.utils import unique_path from ._shared import Cmdlet, CmdletArg, should_show_help, get_field, coerce_to_pipe_object import pipeline as ctx # Optional dependencies try: from config import get_local_storage_path, resolve_output_dir except Exception: # pragma: no cover get_local_storage_path = None # type: ignore resolve_output_dir = None # type: ignore class Download_Provider(Cmdlet): """Download items from external providers.""" def __init__(self): super().__init__( name="download-provider", summary="Download items from external providers (soulseek, libgen, etc).", usage="download-provider [item] [-output DIR]", arg=[ CmdletArg("output", type="string", alias="o", description="Output directory"), ], detail=[ "Download items from external providers.", "Usually called automatically by @N selection on provider results.", "Can be used manually by piping a provider result item.", ], exec=self.run ) self.register() def run(self, result: Any, args: Sequence[str], config: Dict[str, Any]) -> int: """Execute download-provider cmdlet.""" if should_show_help(args): ctx.emit(self.__dict__) return 0 # Parse arguments output_dir_arg = None i = 0 while i < len(args): arg = args[i] if arg in ("-output", "--output", "-o") and i + 1 < len(args): output_dir_arg = args[i+1] i += 2 else: i += 1 # Determine output directory if output_dir_arg: output_dir = Path(output_dir_arg) elif resolve_output_dir: output_dir = resolve_output_dir(config) else: output_dir = Path("./downloads") output_dir.mkdir(parents=True, exist_ok=True) # Process input result items = [] if isinstance(result, list): items = result elif result: items = [result] if not items: log("No items to download", file=sys.stderr) return 1 success_count = 0 for item in items: try: # Extract provider info table = get_field(item, "table") if not table: log(f"Skipping item without provider info: {item}", file=sys.stderr) continue provider = get_search_provider(table, config) if not provider: log(f"Provider '{table}' not available for download", file=sys.stderr) continue # Reconstruct SearchResult if needed # The provider.download method expects a SearchResult object or compatible dict if isinstance(item, dict): # Ensure full_metadata is present if "full_metadata" not in item and "extra" in item: item["full_metadata"] = item["extra"].get("full_metadata", {}) search_result = SearchResult( table=table, title=item.get("title", "Unknown"), path=item.get("path", ""), full_metadata=item.get("full_metadata", {}) ) else: # Assume it's an object with attributes (like PipeObject) full_metadata = getattr(item, "full_metadata", {}) # Check extra dict if full_metadata is missing/empty if not full_metadata and hasattr(item, "extra") and isinstance(item.extra, dict): full_metadata = item.extra.get("full_metadata", {}) # Fallback: if full_metadata key isn't there, maybe the extra dict IS the metadata if not full_metadata and "username" in item.extra: full_metadata = item.extra search_result = SearchResult( table=table, title=getattr(item, "title", "Unknown"), path=getattr(item, "path", ""), full_metadata=full_metadata ) debug(f"[download-provider] Downloading '{search_result.title}' via {table}...") downloaded_path = provider.download(search_result, output_dir) if downloaded_path: debug(f"[download-provider] Download successful: {downloaded_path}") # Create PipeObject for the downloaded file pipe_obj = coerce_to_pipe_object({ "path": str(downloaded_path), "title": search_result.title, "table": "local", # Now it's a local file "media_kind": getattr(item, "media_kind", "other"), "tags": getattr(item, "tags", []), "full_metadata": search_result.full_metadata }) ctx.emit(pipe_obj) success_count += 1 else: log(f"Download failed for '{search_result.title}'", file=sys.stderr) except Exception as e: log(f"Error downloading item: {e}", file=sys.stderr) import traceback debug(traceback.format_exc()) if success_count > 0: return 0 return 1 # Register cmdlet instance Download_Provider_Instance = Download_Provider()