This commit is contained in:
2026-01-09 01:22:06 -08:00
parent 89ac3bb7e8
commit 1deddfda5c
10 changed files with 1004 additions and 179 deletions

View File

@@ -11,6 +11,7 @@ from urllib.parse import urlparse
from API.HTTP import HTTPClient, _download_direct_file
from API.alldebrid import AllDebridClient, parse_magnet_or_hash, is_torrent_file
from ProviderCore.base import Provider, SearchResult
from SYS.provider_helpers import TableProviderMixin
from SYS.utils import sanitize_filename
from SYS.logger import log, debug
from SYS.models import DownloadError
@@ -541,7 +542,32 @@ def adjust_output_dir_for_alldebrid(
return output_dir
class AllDebrid(Provider):
class AllDebrid(TableProviderMixin, Provider):
"""AllDebrid account provider with magnet folder/file browsing and downloads.
This provider uses the new table system (strict ResultTable adapter pattern) for
consistent selection and auto-stage integration across all providers. It exposes
magnets as folder rows and files as file rows, with metadata enrichment for:
- magnet_id: For routing to _download_magnet_by_id
- status/ready: For showing sync state
- _selection_args/_selection_action: For @N expansion control
- relpath: For proper file hierarchy in downloads
KEY FEATURES:
- Table system: Using ResultTable adapter for strict column/metadata handling
- Selection override: Full metadata control via _selection_args/_selection_action
- Auto-stages: download-file is auto-inserted when @N is used on magnet folders
- File unlocking: URLs with /f/ paths are automatically unlocked via API before download
- Drill-down: Selecting a folder row (@N) fetches and displays all files
SELECTION FLOW:
1. User runs: search-file -provider alldebrid "ubuntu"
2. Results show magnet folders and (optionally) files
3. User selects a row: @1
4. Selection metadata routes to download-file with -magnet-id
5. download-file calls provider.download_items() with magnet_id
6. Provider fetches files, unlocks locked URLs, and downloads
"""
# Magnet URIs should be routed through this provider.
TABLE_AUTO_STAGES = {"alldebrid": ["download-file"]}
AUTO_STAGE_USE_SELECTION_ARGS = True
@@ -1147,6 +1173,7 @@ class AllDebrid(Provider):
"file": file_node,
"provider": "alldebrid",
"provider_view": "files",
# Selection metadata for table system
"_selection_args": ["-magnet-id", str(magnet_id)],
"_selection_action": ["download-file", "-provider", "alldebrid", "-magnet-id", str(magnet_id)],
}
@@ -1521,6 +1548,12 @@ try:
def _columns_factory(rows: List[ResultModel]) -> List[ColumnSpec]:
"""Build column specifications from available metadata in rows.
This factory inspects all rows and creates ColumnSpec entries only
for metadata that is actually present in the result set. This avoids
empty columns in the display.
"""
cols = [title_column()]
if _has_metadata(rows, "magnet_name"):
cols.append(metadata_column("magnet_name", "Magnet"))
@@ -1531,7 +1564,7 @@ try:
if _has_metadata(rows, "ready"):
cols.append(metadata_column("ready", "Ready"))
if _has_metadata(rows, "relpath"):
cols.append(metadata_column("relpath", "Relpath"))
cols.append(metadata_column("relpath", "File Path"))
if _has_metadata(rows, "provider_view"):
cols.append(metadata_column("provider_view", "View"))
if _has_metadata(rows, "size"):
@@ -1540,22 +1573,45 @@ try:
def _selection_fn(row: ResultModel) -> List[str]:
"""Return selection args for @N expansion and auto-download integration.
Selection precedence:
1. Explicit _selection_action (full command args)
2. Explicit _selection_args (URL-specific args)
3. Magic routing based on provider_view (files vs folders)
4. Magnet ID routing for folder-type rows
5. Direct URL for file rows
This ensures that selector overrides all pre-codes and gives users full power.
"""
metadata = row.metadata or {}
# First try explicit action (full command)
action = metadata.get("_selection_action") or metadata.get("selection_action")
if isinstance(action, (list, tuple)) and action:
return [str(x) for x in action if x is not None]
# Next try explicit args (typically URL-based)
args = metadata.get("_selection_args") or metadata.get("selection_args")
if isinstance(args, (list, tuple)) and args:
return [str(x) for x in args if x is not None]
# Magic routing by view type
view = metadata.get("provider_view") or metadata.get("view") or ""
if view == "files":
# File rows: pass direct URL for immediate download
if row.path:
return ["-url", row.path]
# Folder rows: use magnet_id to fetch and download all files
magnet_id = metadata.get("magnet_id")
if magnet_id is not None:
return ["-magnet-id", str(magnet_id)]
# Fallback: try direct URL
if row.path:
return ["-url", row.path]
return ["-title", row.title or ""]