j
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Callable, Dict, Iterable, Sequence
|
||||
import os
|
||||
import sys
|
||||
from typing import Any, Callable, Dict, Iterable, Iterator, Sequence
|
||||
from importlib import import_module as _import_module
|
||||
|
||||
# A cmdlet is a callable taking (result, args, config) -> int
|
||||
@@ -47,51 +49,71 @@ def get(cmd_name: str) -> Cmdlet | None:
|
||||
return REGISTRY.get(_normalize_cmd_name(cmd_name))
|
||||
|
||||
|
||||
# Dynamically import all cmdlet modules in this directory (ignore files starting with _ and __init__.py)
|
||||
# cmdlet self-register when instantiated via their __init__ method
|
||||
import os
|
||||
_MODULES_LOADED = False
|
||||
|
||||
cmdlet_dir = os.path.dirname(__file__)
|
||||
for filename in os.listdir(cmdlet_dir):
|
||||
if not (filename.endswith(".py") and not filename.startswith("_")
|
||||
and filename != "__init__.py"):
|
||||
continue
|
||||
def _iter_cmdlet_module_names() -> Iterator[str]:
|
||||
cmdlet_dir = os.path.dirname(__file__)
|
||||
try:
|
||||
entries = os.listdir(cmdlet_dir)
|
||||
except Exception:
|
||||
return iter(())
|
||||
|
||||
mod_name = filename[:-3]
|
||||
def _generator() -> Iterator[str]:
|
||||
for filename in entries:
|
||||
if not (filename.endswith(".py") and not filename.startswith("_")
|
||||
and filename != "__init__.py"):
|
||||
continue
|
||||
mod_name = filename[:-3]
|
||||
if "_" not in mod_name:
|
||||
continue
|
||||
yield mod_name
|
||||
|
||||
# Enforce Powershell-style two-word cmdlet naming (e.g., add_file, get_file)
|
||||
# Skip native/utility scripts that are not cmdlet (e.g., adjective, worker, matrix, pipe)
|
||||
if "_" not in mod_name:
|
||||
continue
|
||||
return _generator()
|
||||
|
||||
|
||||
def _load_cmdlet_module(mod_name: str) -> None:
|
||||
try:
|
||||
_import_module(f".{mod_name}", __name__)
|
||||
except Exception as e:
|
||||
import sys
|
||||
except Exception as exc:
|
||||
print(f"Error importing cmdlet '{mod_name}': {exc}", file=sys.stderr)
|
||||
|
||||
print(f"Error importing cmdlet '{mod_name}': {e}", file=sys.stderr)
|
||||
continue
|
||||
|
||||
# Import and register native commands that are not considered cmdlet
|
||||
try:
|
||||
from cmdnat import register_native_commands as _register_native_commands
|
||||
def _load_root_modules() -> None:
|
||||
for root in ("select_cmdlet",):
|
||||
try:
|
||||
_import_module(root)
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
_register_native_commands(REGISTRY)
|
||||
except Exception:
|
||||
# Native commands are optional; ignore if unavailable
|
||||
pass
|
||||
|
||||
# Import root-level modules that also register cmdlet
|
||||
for _root_mod in ("select_cmdlet",
|
||||
):
|
||||
def _load_helper_modules() -> None:
|
||||
try:
|
||||
_import_module(_root_mod)
|
||||
import API.alldebrid as _alldebrid
|
||||
except Exception:
|
||||
# Allow missing optional modules
|
||||
continue
|
||||
pass
|
||||
|
||||
# Also import helper modules that register cmdlet
|
||||
try:
|
||||
import API.alldebrid as _alldebrid
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _register_native_commands() -> None:
|
||||
try:
|
||||
from cmdnat import register_native_commands
|
||||
except Exception:
|
||||
return
|
||||
try:
|
||||
register_native_commands(REGISTRY)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def ensure_cmdlet_modules_loaded() -> None:
|
||||
global _MODULES_LOADED
|
||||
|
||||
if _MODULES_LOADED:
|
||||
return
|
||||
|
||||
for mod_name in _iter_cmdlet_module_names():
|
||||
_load_cmdlet_module(mod_name)
|
||||
|
||||
_load_root_modules()
|
||||
_load_helper_modules()
|
||||
_register_native_commands()
|
||||
_MODULES_LOADED = True
|
||||
|
||||
@@ -519,8 +519,11 @@ class Add_File(Cmdlet):
|
||||
# - If the sample URL only has one available format, force it for the batch.
|
||||
# - If the sample URL appears audio-only (no video codecs), prefer audio mode.
|
||||
try:
|
||||
from cmdlet.download_media import is_url_supported_by_ytdlp, list_formats
|
||||
from tool.ytdlp import YtDlpTool
|
||||
from tool.ytdlp import (
|
||||
YtDlpTool,
|
||||
is_url_supported_by_ytdlp,
|
||||
list_formats,
|
||||
)
|
||||
|
||||
sample_url = unique_urls[0] if unique_urls else None
|
||||
if sample_url and is_url_supported_by_ytdlp(str(sample_url)):
|
||||
@@ -677,6 +680,59 @@ class Add_File(Cmdlet):
|
||||
# Update pipe_obj with resolved path
|
||||
pipe_obj.path = str(media_path_or_url)
|
||||
|
||||
table = None
|
||||
full_metadata = None
|
||||
if isinstance(pipe_obj.extra, dict):
|
||||
table = pipe_obj.extra.get("table")
|
||||
full_metadata = pipe_obj.extra.get("full_metadata")
|
||||
|
||||
provider_table = str(
|
||||
table or getattr(pipe_obj, "provider", "")
|
||||
).strip().lower()
|
||||
if (provider_table == "alldebrid"
|
||||
and isinstance(media_path_or_url, str)
|
||||
and media_path_or_url.lower().startswith(
|
||||
("http://", "https://"))
|
||||
and (provider_name or location)):
|
||||
url_str = str(media_path_or_url)
|
||||
if url_str in skip_url_downloads:
|
||||
log(
|
||||
f"Skipping download (already stored): {url_str}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
successes += 1
|
||||
continue
|
||||
|
||||
temp_dir_candidate = Path(
|
||||
tempfile.mkdtemp(prefix="medios_alldebrid_")
|
||||
)
|
||||
downloaded_path: Optional[Path] = None
|
||||
try:
|
||||
from ProviderCore.registry import get_search_provider
|
||||
|
||||
provider = get_search_provider("alldebrid", config)
|
||||
if provider is not None:
|
||||
downloaded = provider.download(
|
||||
pipe_obj,
|
||||
temp_dir_candidate,
|
||||
)
|
||||
if downloaded:
|
||||
downloaded_path = Path(downloaded)
|
||||
except Exception as exc:
|
||||
log(
|
||||
f"[add-file] AllDebrid download failed: {exc}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
if downloaded_path and downloaded_path.exists():
|
||||
media_path_or_url = downloaded_path
|
||||
pipe_obj.path = str(downloaded_path)
|
||||
pipe_obj.is_temp = True
|
||||
delete_after_item = True
|
||||
temp_dir_to_cleanup = temp_dir_candidate
|
||||
processed_url_items.add(url_str)
|
||||
else:
|
||||
shutil.rmtree(temp_dir_candidate, ignore_errors=True)
|
||||
|
||||
# URL targets: prefer provider-aware download for OpenLibrary selections.
|
||||
if isinstance(media_path_or_url,
|
||||
str) and media_path_or_url.lower().startswith(
|
||||
@@ -684,12 +740,6 @@ class Add_File(Cmdlet):
|
||||
"https://",
|
||||
"magnet:",
|
||||
"torrent:")):
|
||||
table = None
|
||||
full_metadata = None
|
||||
if isinstance(pipe_obj.extra, dict):
|
||||
table = pipe_obj.extra.get("table")
|
||||
full_metadata = pipe_obj.extra.get("full_metadata")
|
||||
|
||||
is_openlibrary = (str(table or "").lower() == "openlibrary") or (
|
||||
"openlibrary.org/books/" in media_path_or_url.lower()
|
||||
)
|
||||
@@ -1079,7 +1129,7 @@ class Add_File(Cmdlet):
|
||||
continue
|
||||
|
||||
# No destination specified: keep legacy behavior (download-media only).
|
||||
code = self._delegate_to_download_media(
|
||||
code = self._delegate_to_download_file(
|
||||
item,
|
||||
url_str,
|
||||
location,
|
||||
@@ -2052,7 +2102,7 @@ class Add_File(Cmdlet):
|
||||
pass
|
||||
return None
|
||||
|
||||
def _delegate_to_download_media(
|
||||
def _delegate_to_download_file(
|
||||
self,
|
||||
result: Any,
|
||||
url_str: str,
|
||||
@@ -2062,13 +2112,13 @@ class Add_File(Cmdlet):
|
||||
config: Dict[str,
|
||||
Any],
|
||||
) -> int:
|
||||
"""Delegate URL handling to download-media cmdlet."""
|
||||
"""Delegate URL handling to download-file cmdlet (yt-dlp path)."""
|
||||
log(
|
||||
f"Target is a URL, delegating to download-media: {url_str}",
|
||||
f"Target is a URL, delegating to download-file: {url_str}",
|
||||
file=sys.stderr
|
||||
)
|
||||
# Reuse the globally-registered cmdlet instance to avoid duplicative registration
|
||||
from cmdlet.download_media import CMDLET as dl_cmdlet
|
||||
from cmdlet.download_file import CMDLET as dl_cmdlet
|
||||
|
||||
dl_args = list(args) if args else []
|
||||
|
||||
@@ -2087,11 +2137,11 @@ class Add_File(Cmdlet):
|
||||
if selection_args:
|
||||
dl_args.extend(selection_args)
|
||||
|
||||
# download-media doesn't support -storage flag
|
||||
# download-file doesn't support -storage flag
|
||||
# It downloads to the configured directory, then add-file will handle storage
|
||||
# Note: Provider uploads (0x0) are not supported via this path
|
||||
|
||||
# Call download-media with the URL in args
|
||||
# Call download-file with the URL in args
|
||||
return dl_cmdlet.run(None, dl_args, config)
|
||||
|
||||
@staticmethod
|
||||
@@ -2832,17 +2882,16 @@ class Add_File(Cmdlet):
|
||||
return []
|
||||
|
||||
try:
|
||||
from cmdlet.download_media import (
|
||||
CMDLET as dl_cmdlet,
|
||||
from SYS.models import DownloadOptions
|
||||
from tool.ytdlp import (
|
||||
YtDlpTool,
|
||||
_best_subtitle_sidecar,
|
||||
_download_with_timeout,
|
||||
_format_chapters_note,
|
||||
_read_text_file,
|
||||
is_url_supported_by_ytdlp,
|
||||
list_formats,
|
||||
_format_chapters_note,
|
||||
_best_subtitle_sidecar,
|
||||
_read_text_file,
|
||||
)
|
||||
from SYS.models import DownloadOptions
|
||||
from tool.ytdlp import YtDlpTool
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
|
||||
@@ -540,9 +540,11 @@ class Add_Tag(Cmdlet):
|
||||
)
|
||||
return 1
|
||||
|
||||
hash_override = normalize_hash(query_hash) if query_hash else None
|
||||
|
||||
# If add-tag is in the middle of a pipeline (has downstream stages), default to
|
||||
# including temp files. This enables common flows like:
|
||||
# @N | download-media | add-tag ... | add-file ...
|
||||
# @N | download-file | add-tag ... | add-file ...
|
||||
store_override = parsed.get("store")
|
||||
stage_ctx = ctx.get_stage_context()
|
||||
has_downstream = bool(
|
||||
@@ -562,6 +564,10 @@ class Add_Tag(Cmdlet):
|
||||
if not include_temp:
|
||||
results = filter_results_by_temp(results, include_temp=False)
|
||||
|
||||
# When no pipeline payload is present but -query/-store pinpoints a hash, tag it directly.
|
||||
if not results and hash_override and store_override:
|
||||
results = [{"hash": hash_override, "store": store_override}]
|
||||
|
||||
if not results:
|
||||
log(
|
||||
"No valid files to tag (all results were temporary; use --all to include temporary files)",
|
||||
@@ -628,7 +634,6 @@ class Add_Tag(Cmdlet):
|
||||
return 1
|
||||
|
||||
# Get other flags
|
||||
hash_override = normalize_hash(query_hash) if query_hash else None
|
||||
duplicate_arg = parsed.get("duplicate")
|
||||
|
||||
# tag ARE provided - apply them to each store-backed result
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,280 +0,0 @@
|
||||
"""Download torrent/magnet links via AllDebrid in a dedicated cmdlet.
|
||||
|
||||
Features:
|
||||
- Accepts magnet links and .torrent files/url
|
||||
- Uses AllDebrid API for background downloads
|
||||
- Progress tracking and worker management
|
||||
- Self-registering class-based cmdlet
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
import sys
|
||||
import uuid
|
||||
import threading
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Optional, Sequence
|
||||
|
||||
from SYS.logger import log
|
||||
from . import _shared as sh
|
||||
|
||||
|
||||
class Download_Torrent(sh.Cmdlet):
|
||||
"""Class-based download-torrent cmdlet with self-registration."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__(
|
||||
name="download-torrent",
|
||||
summary="Download torrent/magnet links via AllDebrid",
|
||||
usage="download-torrent <magnet|.torrent> [options]",
|
||||
alias=["torrent",
|
||||
"magnet"],
|
||||
arg=[
|
||||
sh.CmdletArg(
|
||||
name="magnet",
|
||||
type="string",
|
||||
required=False,
|
||||
description="Magnet link or .torrent file/URL",
|
||||
variadic=True,
|
||||
),
|
||||
sh.CmdletArg(
|
||||
name="output",
|
||||
type="string",
|
||||
description="Output directory for downloaded files",
|
||||
),
|
||||
sh.CmdletArg(
|
||||
name="wait",
|
||||
type="float",
|
||||
description="Wait time (seconds) for magnet processing timeout",
|
||||
),
|
||||
sh.CmdletArg(
|
||||
name="background",
|
||||
type="flag",
|
||||
alias="bg",
|
||||
description="Start download in background",
|
||||
),
|
||||
],
|
||||
detail=["Download torrents/magnets via AllDebrid API."],
|
||||
exec=self.run,
|
||||
)
|
||||
self.register()
|
||||
|
||||
def run(self, result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
||||
parsed = sh.parse_cmdlet_args(args, self)
|
||||
magnet_args = parsed.get("magnet", [])
|
||||
output_dir = Path(parsed.get("output") or Path.home() / "Downloads")
|
||||
wait_timeout = int(float(parsed.get("wait", 600)))
|
||||
background_mode = parsed.get("background", False)
|
||||
api_key = None
|
||||
try:
|
||||
from Provider.alldebrid import _get_debrid_api_key # type: ignore
|
||||
|
||||
api_key = _get_debrid_api_key(config)
|
||||
except Exception:
|
||||
api_key = None
|
||||
if not api_key:
|
||||
log(
|
||||
"AllDebrid API key not configured (check config.conf [provider=alldebrid] api_key=...)",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
for magnet_url in magnet_args:
|
||||
if background_mode:
|
||||
self._start_background_worker(
|
||||
magnet_url,
|
||||
output_dir,
|
||||
config,
|
||||
api_key,
|
||||
wait_timeout
|
||||
)
|
||||
log(f"⧗ Torrent download queued in background: {magnet_url}")
|
||||
else:
|
||||
# Foreground mode: submit quickly, then continue processing in background
|
||||
# so we return control to the REPL immediately.
|
||||
worker_id = str(uuid.uuid4())
|
||||
magnet_id = self._submit_magnet(worker_id, magnet_url, api_key)
|
||||
if magnet_id <= 0:
|
||||
continue
|
||||
self._start_background_magnet_worker(
|
||||
worker_id,
|
||||
magnet_id,
|
||||
output_dir,
|
||||
api_key,
|
||||
wait_timeout
|
||||
)
|
||||
log(f"⧗ Torrent processing started (ID: {magnet_id})")
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
def _submit_magnet(worker_id: str, magnet_url: str, api_key: str) -> int:
|
||||
"""Submit a magnet and return its AllDebrid magnet ID.
|
||||
|
||||
This is intentionally fast so the caller can return to the REPL.
|
||||
"""
|
||||
try:
|
||||
from API.alldebrid import AllDebridClient
|
||||
|
||||
client = AllDebridClient(api_key)
|
||||
log(f"[Worker {worker_id}] Submitting magnet to AllDebrid...")
|
||||
magnet_info = client.magnet_add(magnet_url)
|
||||
magnet_id = int(magnet_info.get("id", 0))
|
||||
if magnet_id <= 0:
|
||||
log(f"[Worker {worker_id}] Magnet add failed", file=sys.stderr)
|
||||
return 0
|
||||
log(f"[Worker {worker_id}] ✓ Magnet added (ID: {magnet_id})")
|
||||
return magnet_id
|
||||
except Exception as e:
|
||||
log(f"[Worker {worker_id}] Magnet submit failed: {e}", file=sys.stderr)
|
||||
return 0
|
||||
|
||||
def _start_background_magnet_worker(
|
||||
self,
|
||||
worker_id: str,
|
||||
magnet_id: int,
|
||||
output_dir: Path,
|
||||
api_key: str,
|
||||
wait_timeout: int
|
||||
) -> None:
|
||||
thread = threading.Thread(
|
||||
target=self._download_magnet_worker,
|
||||
args=(worker_id,
|
||||
magnet_id,
|
||||
output_dir,
|
||||
api_key,
|
||||
wait_timeout),
|
||||
daemon=True,
|
||||
name=f"TorrentWorker_{worker_id}",
|
||||
)
|
||||
thread.start()
|
||||
|
||||
@staticmethod
|
||||
def _download_magnet_worker(
|
||||
worker_id: str,
|
||||
magnet_id: int,
|
||||
output_dir: Path,
|
||||
api_key: str,
|
||||
wait_timeout: int = 600,
|
||||
) -> None:
|
||||
"""Poll AllDebrid magnet status until ready, then download the files."""
|
||||
try:
|
||||
from API.alldebrid import AllDebridClient
|
||||
|
||||
client = AllDebridClient(api_key)
|
||||
|
||||
# Poll for ready status (simplified)
|
||||
import time
|
||||
|
||||
elapsed = 0
|
||||
while elapsed < wait_timeout:
|
||||
status = client.magnet_status(magnet_id)
|
||||
if status.get("ready"):
|
||||
break
|
||||
time.sleep(5)
|
||||
elapsed += 5
|
||||
if elapsed >= wait_timeout:
|
||||
log(f"[Worker {worker_id}] Timeout waiting for magnet", file=sys.stderr)
|
||||
return
|
||||
|
||||
files_result = client.magnet_links([magnet_id])
|
||||
magnet_files = files_result.get(str(magnet_id),
|
||||
{})
|
||||
files_array = magnet_files.get("files", [])
|
||||
if not files_array:
|
||||
log(f"[Worker {worker_id}] No files found", file=sys.stderr)
|
||||
return
|
||||
for file_info in files_array:
|
||||
file_url = file_info.get("link")
|
||||
file_name = file_info.get("name")
|
||||
if file_url and file_name:
|
||||
Download_Torrent._download_file(file_url, output_dir / file_name)
|
||||
log(f"[Worker {worker_id}] ✓ Downloaded {file_name}")
|
||||
except Exception as e:
|
||||
log(f"[Worker {worker_id}] Torrent download failed: {e}", file=sys.stderr)
|
||||
|
||||
@staticmethod
|
||||
def _download_torrent_worker(
|
||||
worker_id: str,
|
||||
magnet_url: str,
|
||||
output_dir: Path,
|
||||
config: Dict[str,
|
||||
Any],
|
||||
api_key: str,
|
||||
wait_timeout: int = 600,
|
||||
worker_manager: Optional[Any] = None,
|
||||
) -> None:
|
||||
try:
|
||||
from API.alldebrid import AllDebridClient
|
||||
|
||||
client = AllDebridClient(api_key)
|
||||
log(f"[Worker {worker_id}] Submitting magnet to AllDebrid...")
|
||||
magnet_info = client.magnet_add(magnet_url)
|
||||
magnet_id = int(magnet_info.get("id", 0))
|
||||
if magnet_id <= 0:
|
||||
log(f"[Worker {worker_id}] Magnet add failed", file=sys.stderr)
|
||||
return
|
||||
log(f"[Worker {worker_id}] ✓ Magnet added (ID: {magnet_id})")
|
||||
# Poll for ready status (simplified)
|
||||
import time
|
||||
|
||||
elapsed = 0
|
||||
while elapsed < wait_timeout:
|
||||
status = client.magnet_status(magnet_id)
|
||||
if status.get("ready"):
|
||||
break
|
||||
time.sleep(5)
|
||||
elapsed += 5
|
||||
if elapsed >= wait_timeout:
|
||||
log(f"[Worker {worker_id}] Timeout waiting for magnet", file=sys.stderr)
|
||||
return
|
||||
files_result = client.magnet_links([magnet_id])
|
||||
magnet_files = files_result.get(str(magnet_id),
|
||||
{})
|
||||
files_array = magnet_files.get("files", [])
|
||||
if not files_array:
|
||||
log(f"[Worker {worker_id}] No files found", file=sys.stderr)
|
||||
return
|
||||
for file_info in files_array:
|
||||
file_url = file_info.get("link")
|
||||
file_name = file_info.get("name")
|
||||
if file_url:
|
||||
Download_Torrent._download_file(file_url, output_dir / file_name)
|
||||
log(f"[Worker {worker_id}] ✓ Downloaded {file_name}")
|
||||
except Exception as e:
|
||||
log(f"[Worker {worker_id}] Torrent download failed: {e}", file=sys.stderr)
|
||||
|
||||
@staticmethod
|
||||
def _download_file(url: str, dest: Path) -> None:
|
||||
try:
|
||||
import requests
|
||||
|
||||
resp = requests.get(url, stream=True)
|
||||
with open(dest, "wb") as f:
|
||||
for chunk in resp.iter_content(chunk_size=8192):
|
||||
if chunk:
|
||||
f.write(chunk)
|
||||
except Exception as e:
|
||||
log(f"File download failed: {e}", file=sys.stderr)
|
||||
|
||||
def _start_background_worker(
|
||||
self,
|
||||
magnet_url,
|
||||
output_dir,
|
||||
config,
|
||||
api_key,
|
||||
wait_timeout
|
||||
):
|
||||
worker_id = f"torrent_{uuid.uuid4().hex[:6]}"
|
||||
thread = threading.Thread(
|
||||
target=self._download_torrent_worker,
|
||||
args=(worker_id,
|
||||
magnet_url,
|
||||
output_dir,
|
||||
config,
|
||||
api_key,
|
||||
wait_timeout),
|
||||
daemon=True,
|
||||
name=f"TorrentWorker_{worker_id}",
|
||||
)
|
||||
thread.start()
|
||||
|
||||
|
||||
CMDLET = Download_Torrent()
|
||||
@@ -155,8 +155,7 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
||||
mode_hint: Optional[str] = None
|
||||
forced_format: Optional[str] = None
|
||||
try:
|
||||
from cmdlet.download_media import list_formats
|
||||
from tool.ytdlp import YtDlpTool
|
||||
from tool.ytdlp import YtDlpTool, list_formats
|
||||
|
||||
sample_url = urls_to_download[0]
|
||||
cookiefile = None
|
||||
|
||||
@@ -209,6 +209,18 @@ class search_file(Cmdlet):
|
||||
|
||||
provider_text = str(provider_name or "").strip()
|
||||
provider_lower = provider_text.lower()
|
||||
id_match = re.search(r"\bid\s*[=:]\s*(\d+)", query, flags=re.IGNORECASE)
|
||||
parsed_open_id = open_id
|
||||
if id_match and parsed_open_id is None:
|
||||
try:
|
||||
parsed_open_id = int(id_match.group(1))
|
||||
except Exception:
|
||||
parsed_open_id = None
|
||||
query = re.sub(r"\bid\s*[=:]\s*\d+", "", query, flags=re.IGNORECASE).strip()
|
||||
if not query:
|
||||
query = "*"
|
||||
|
||||
effective_open_id = parsed_open_id if parsed_open_id is not None else open_id
|
||||
if provider_lower == "youtube":
|
||||
provider_label = "Youtube"
|
||||
elif provider_lower == "openlibrary":
|
||||
@@ -218,22 +230,32 @@ class search_file(Cmdlet):
|
||||
else:
|
||||
provider_label = provider_text[:1].upper() + provider_text[1:] if provider_text else "Provider"
|
||||
|
||||
if provider_lower == "alldebrid" and open_id is not None:
|
||||
table_title = f"{provider_label} Files: {open_id}".strip().rstrip(":")
|
||||
if provider_lower == "alldebrid" and effective_open_id is not None:
|
||||
table_title = f"{provider_label} Files: {effective_open_id}".strip().rstrip(":")
|
||||
else:
|
||||
table_title = f"{provider_label}: {query}".strip().rstrip(":")
|
||||
|
||||
preserve_order = provider_lower in {"youtube", "openlibrary", "loc"}
|
||||
table = ResultTable(table_title).set_preserve_order(preserve_order)
|
||||
table.set_table(provider_name)
|
||||
table_meta: Dict[str, Any] = {"provider": provider_name}
|
||||
if provider_lower == "alldebrid":
|
||||
table_meta["view"] = "files" if effective_open_id is not None else "folders"
|
||||
if effective_open_id is not None:
|
||||
table_meta["magnet_id"] = effective_open_id
|
||||
try:
|
||||
table.set_table_metadata(table_meta)
|
||||
except Exception:
|
||||
pass
|
||||
table.set_source_command("search-file", list(args_list))
|
||||
|
||||
debug(f"[search-file] Calling {provider_name}.search()")
|
||||
if provider_lower == "alldebrid":
|
||||
if open_id is not None:
|
||||
results = provider.search(query, limit=limit, filters={"view": "files", "magnet_id": open_id})
|
||||
else:
|
||||
results = provider.search(query, limit=limit, filters={"view": "folders"})
|
||||
filters = {"view": "folders"}
|
||||
search_open_id = parsed_open_id if parsed_open_id is not None else open_id
|
||||
if search_open_id is not None:
|
||||
filters = {"view": "files", "magnet_id": search_open_id}
|
||||
results = provider.search(query, limit=limit, filters=filters)
|
||||
else:
|
||||
results = provider.search(query, limit=limit)
|
||||
debug(f"[search-file] {provider_name} -> {len(results or [])} result(s)")
|
||||
@@ -260,17 +282,6 @@ class search_file(Cmdlet):
|
||||
row_index = len(table.rows)
|
||||
table.add_result(search_result)
|
||||
|
||||
try:
|
||||
if provider_lower == "alldebrid" and getattr(search_result, "media_kind", "") == "folder":
|
||||
magnet_id = None
|
||||
meta = getattr(search_result, "full_metadata", None)
|
||||
if isinstance(meta, dict):
|
||||
magnet_id = meta.get("magnet_id")
|
||||
if magnet_id is not None:
|
||||
table.set_row_selection_args(row_index, ["-open", str(magnet_id), "-query", "*"])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
results_list.append(item_dict)
|
||||
ctx.emit(item_dict)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user