dfd
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from typing import Callable, Optional
|
||||
import sys
|
||||
|
||||
import requests
|
||||
@@ -22,13 +22,20 @@ def sanitize_filename(name: str, *, max_len: int = 150) -> str:
|
||||
return cleaned[:max_len]
|
||||
|
||||
|
||||
def download_file(url: str, output_path: Path, *, session: Optional[requests.Session] = None, timeout_s: float = 30.0) -> bool:
|
||||
def download_file(
|
||||
url: str,
|
||||
output_path: Path,
|
||||
*,
|
||||
session: Optional[requests.Session] = None,
|
||||
timeout_s: float = 30.0,
|
||||
progress_callback: Optional[Callable[[int, Optional[int], str], None]] = None,
|
||||
) -> bool:
|
||||
output_path = Path(output_path)
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
s = session or requests.Session()
|
||||
|
||||
bar = ProgressBar()
|
||||
bar = ProgressBar() if progress_callback is None else None
|
||||
downloaded = 0
|
||||
total = None
|
||||
|
||||
@@ -41,9 +48,14 @@ def download_file(url: str, output_path: Path, *, session: Optional[requests.Ses
|
||||
except Exception:
|
||||
total = None
|
||||
|
||||
label = str(output_path.name or "download")
|
||||
|
||||
# Render once immediately so fast downloads still show something.
|
||||
try:
|
||||
bar.update(downloaded=0, total=total, label=str(output_path.name or "download"), file=sys.stderr)
|
||||
if progress_callback is not None:
|
||||
progress_callback(0, total, label)
|
||||
elif bar is not None:
|
||||
bar.update(downloaded=0, total=total, label=label, file=sys.stderr)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -53,18 +65,23 @@ def download_file(url: str, output_path: Path, *, session: Optional[requests.Ses
|
||||
f.write(chunk)
|
||||
downloaded += len(chunk)
|
||||
try:
|
||||
bar.update(downloaded=downloaded, total=total, label=str(output_path.name or "download"), file=sys.stderr)
|
||||
if progress_callback is not None:
|
||||
progress_callback(downloaded, total, label)
|
||||
elif bar is not None:
|
||||
bar.update(downloaded=downloaded, total=total, label=label, file=sys.stderr)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
bar.finish()
|
||||
if bar is not None:
|
||||
bar.finish()
|
||||
except Exception:
|
||||
pass
|
||||
return output_path.exists() and output_path.stat().st_size > 0
|
||||
except Exception:
|
||||
try:
|
||||
bar.finish()
|
||||
if bar is not None:
|
||||
bar.finish()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
|
||||
@@ -6,8 +6,9 @@ This module is the single source of truth for provider discovery.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Dict, Optional, Type
|
||||
from typing import Any, Dict, Optional, Sequence, Type
|
||||
import sys
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from SYS.logger import log
|
||||
|
||||
@@ -141,6 +142,45 @@ def list_file_providers(config: Optional[Dict[str, Any]] = None) -> Dict[str, bo
|
||||
return availability
|
||||
|
||||
|
||||
def match_provider_name_for_url(url: str) -> Optional[str]:
|
||||
"""Return a registered provider name that claims the URL's domain.
|
||||
|
||||
Providers can declare domains via a class attribute `URL_DOMAINS` (sequence of strings).
|
||||
This matcher is intentionally cheap (no provider instantiation, no network).
|
||||
"""
|
||||
|
||||
try:
|
||||
parsed = urlparse(str(url))
|
||||
host = (parsed.hostname or "").strip().lower()
|
||||
except Exception:
|
||||
host = ""
|
||||
|
||||
if not host:
|
||||
return None
|
||||
|
||||
for name, provider_class in _PROVIDERS.items():
|
||||
domains = getattr(provider_class, "URL_DOMAINS", None)
|
||||
if not isinstance(domains, (list, tuple)):
|
||||
continue
|
||||
for d in domains:
|
||||
dom = str(d or "").strip().lower()
|
||||
if not dom:
|
||||
continue
|
||||
if host == dom or host.endswith("." + dom):
|
||||
return name
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def get_provider_for_url(url: str, config: Optional[Dict[str, Any]] = None) -> Optional[Provider]:
|
||||
"""Instantiate and return the matching provider for a URL, if any."""
|
||||
|
||||
name = match_provider_name_for_url(url)
|
||||
if not name:
|
||||
return None
|
||||
return get_provider(name, config)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"SearchResult",
|
||||
"Provider",
|
||||
@@ -152,5 +192,7 @@ __all__ = [
|
||||
"list_search_providers",
|
||||
"get_file_provider",
|
||||
"list_file_providers",
|
||||
"match_provider_name_for_url",
|
||||
"get_provider_for_url",
|
||||
"download_soulseek_file",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user