fdsfjlk
This commit is contained in:
@@ -39,14 +39,26 @@ class SearchResult:
|
||||
}
|
||||
|
||||
|
||||
class SearchProvider(ABC):
|
||||
"""Base class for search providers."""
|
||||
class Provider(ABC):
|
||||
"""Unified provider base class.
|
||||
|
||||
This replaces the older split between "search providers" and "file providers".
|
||||
Concrete providers may implement any subset of:
|
||||
- search(query, ...)
|
||||
- download(result, output_dir)
|
||||
- upload(file_path, ...)
|
||||
- login(...)
|
||||
- validate()
|
||||
"""
|
||||
|
||||
def __init__(self, config: Optional[Dict[str, Any]] = None):
|
||||
self.config = config or {}
|
||||
self.name = self.__class__.__name__.lower()
|
||||
|
||||
@abstractmethod
|
||||
# Standard lifecycle/auth hook.
|
||||
def login(self, **_kwargs: Any) -> bool:
|
||||
return True
|
||||
|
||||
def search(
|
||||
self,
|
||||
query: str,
|
||||
@@ -55,30 +67,46 @@ class SearchProvider(ABC):
|
||||
**kwargs: Any,
|
||||
) -> List[SearchResult]:
|
||||
"""Search for items matching the query."""
|
||||
raise NotImplementedError(f"Provider '{self.name}' does not support search")
|
||||
|
||||
def download(self, result: SearchResult, output_dir: Path) -> Optional[Path]:
|
||||
"""Download an item from a search result."""
|
||||
|
||||
return None
|
||||
|
||||
def upload(self, file_path: str, **kwargs: Any) -> str:
|
||||
"""Upload a file and return a URL or identifier."""
|
||||
raise NotImplementedError(f"Provider '{self.name}' does not support upload")
|
||||
|
||||
def validate(self) -> bool:
|
||||
"""Check if provider is available and properly configured."""
|
||||
|
||||
return True
|
||||
|
||||
def selector(self, selected_items: List[Any], *, ctx: Any, stage_is_last: bool = True, **_kwargs: Any) -> bool:
|
||||
"""Optional hook for handling `@N` selection semantics.
|
||||
|
||||
class FileProvider(ABC):
|
||||
"""Base class for file upload providers."""
|
||||
The CLI can delegate selection behavior to a provider/store instead of
|
||||
applying the default selection filtering.
|
||||
|
||||
def __init__(self, config: Optional[Dict[str, Any]] = None):
|
||||
self.config = config or {}
|
||||
self.name = self.__class__.__name__.lower()
|
||||
Return True if the selection was handled and default behavior should be skipped.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def upload(self, file_path: str, **kwargs: Any) -> str:
|
||||
"""Upload a file and return the URL."""
|
||||
_ = selected_items
|
||||
_ = ctx
|
||||
_ = stage_is_last
|
||||
return False
|
||||
|
||||
def validate(self) -> bool:
|
||||
"""Check if provider is available/configured."""
|
||||
|
||||
return True
|
||||
class SearchProvider(Provider):
|
||||
"""Compatibility alias for older code.
|
||||
|
||||
Prefer inheriting from Provider directly.
|
||||
"""
|
||||
|
||||
|
||||
class FileProvider(Provider):
|
||||
"""Compatibility alias for older code.
|
||||
|
||||
Prefer inheriting from Provider directly.
|
||||
"""
|
||||
|
||||
@@ -11,33 +11,47 @@ import sys
|
||||
|
||||
from SYS.logger import log
|
||||
|
||||
from ProviderCore.base import FileProvider, SearchProvider, SearchResult
|
||||
from ProviderCore.base import Provider, SearchProvider, FileProvider, SearchResult
|
||||
from Provider.alldebrid import AllDebrid
|
||||
from Provider.bandcamp import Bandcamp
|
||||
from Provider.libgen import Libgen
|
||||
from Provider.matrix import Matrix
|
||||
from Provider.openlibrary import OpenLibrary
|
||||
from Provider.soulseek import Soulseek, download_soulseek_file
|
||||
from Provider.telegram import Telegram
|
||||
from Provider.youtube import YouTube
|
||||
from Provider.zeroxzero import ZeroXZero
|
||||
|
||||
|
||||
_SEARCH_PROVIDERS: Dict[str, Type[SearchProvider]] = {
|
||||
_PROVIDERS: Dict[str, Type[Provider]] = {
|
||||
# Search-capable providers
|
||||
"alldebrid": AllDebrid,
|
||||
"libgen": Libgen,
|
||||
"openlibrary": OpenLibrary,
|
||||
"soulseek": Soulseek,
|
||||
"bandcamp": Bandcamp,
|
||||
"youtube": YouTube,
|
||||
"telegram": Telegram,
|
||||
# Upload-capable providers
|
||||
"0x0": ZeroXZero,
|
||||
"matrix": Matrix,
|
||||
}
|
||||
|
||||
|
||||
def get_search_provider(name: str, config: Optional[Dict[str, Any]] = None) -> Optional[SearchProvider]:
|
||||
"""Get a search provider by name."""
|
||||
def _supports_search(provider: Provider) -> bool:
|
||||
return provider.__class__.search is not Provider.search
|
||||
|
||||
provider_class = _SEARCH_PROVIDERS.get((name or "").lower())
|
||||
|
||||
def _supports_upload(provider: Provider) -> bool:
|
||||
return provider.__class__.upload is not Provider.upload
|
||||
|
||||
|
||||
def get_provider(name: str, config: Optional[Dict[str, Any]] = None) -> Optional[Provider]:
|
||||
"""Get a provider by name (unified registry)."""
|
||||
|
||||
provider_class = _PROVIDERS.get((name or "").lower())
|
||||
if provider_class is None:
|
||||
log(f"[provider] Unknown search provider: {name}", file=sys.stderr)
|
||||
log(f"[provider] Unknown provider: {name}", file=sys.stderr)
|
||||
return None
|
||||
|
||||
try:
|
||||
@@ -51,11 +65,11 @@ def get_search_provider(name: str, config: Optional[Dict[str, Any]] = None) -> O
|
||||
return None
|
||||
|
||||
|
||||
def list_search_providers(config: Optional[Dict[str, Any]] = None) -> Dict[str, bool]:
|
||||
"""List all search providers and their availability."""
|
||||
def list_providers(config: Optional[Dict[str, Any]] = None) -> Dict[str, bool]:
|
||||
"""List all providers and their availability."""
|
||||
|
||||
availability: Dict[str, bool] = {}
|
||||
for name, provider_class in _SEARCH_PROVIDERS.items():
|
||||
for name, provider_class in _PROVIDERS.items():
|
||||
try:
|
||||
provider = provider_class(config)
|
||||
availability[name] = provider.validate()
|
||||
@@ -64,39 +78,51 @@ def list_search_providers(config: Optional[Dict[str, Any]] = None) -> Dict[str,
|
||||
return availability
|
||||
|
||||
|
||||
_FILE_PROVIDERS: Dict[str, Type[FileProvider]] = {
|
||||
"0x0": ZeroXZero,
|
||||
"matrix": Matrix,
|
||||
}
|
||||
def get_search_provider(name: str, config: Optional[Dict[str, Any]] = None) -> Optional[SearchProvider]:
|
||||
"""Get a search-capable provider by name (compat API)."""
|
||||
|
||||
provider = get_provider(name, config)
|
||||
if provider is None:
|
||||
return None
|
||||
if not _supports_search(provider):
|
||||
log(f"[provider] Provider '{name}' does not support search", file=sys.stderr)
|
||||
return None
|
||||
return provider # type: ignore[return-value]
|
||||
|
||||
|
||||
def list_search_providers(config: Optional[Dict[str, Any]] = None) -> Dict[str, bool]:
|
||||
"""List all search providers and their availability."""
|
||||
|
||||
availability: Dict[str, bool] = {}
|
||||
for name, provider_class in _PROVIDERS.items():
|
||||
try:
|
||||
provider = provider_class(config)
|
||||
availability[name] = bool(provider.validate() and _supports_search(provider))
|
||||
except Exception:
|
||||
availability[name] = False
|
||||
return availability
|
||||
|
||||
|
||||
def get_file_provider(name: str, config: Optional[Dict[str, Any]] = None) -> Optional[FileProvider]:
|
||||
"""Get a file provider by name."""
|
||||
"""Get an upload-capable provider by name (compat API)."""
|
||||
|
||||
provider_class = _FILE_PROVIDERS.get((name or "").lower())
|
||||
if provider_class is None:
|
||||
log(f"[provider] Unknown file provider: {name}", file=sys.stderr)
|
||||
provider = get_provider(name, config)
|
||||
if provider is None:
|
||||
return None
|
||||
|
||||
try:
|
||||
provider = provider_class(config)
|
||||
if not provider.validate():
|
||||
log(f"[provider] File provider '{name}' is not available", file=sys.stderr)
|
||||
return None
|
||||
return provider
|
||||
except Exception as exc:
|
||||
log(f"[provider] Error initializing file provider '{name}': {exc}", file=sys.stderr)
|
||||
if not _supports_upload(provider):
|
||||
log(f"[provider] Provider '{name}' does not support upload", file=sys.stderr)
|
||||
return None
|
||||
return provider # type: ignore[return-value]
|
||||
|
||||
|
||||
def list_file_providers(config: Optional[Dict[str, Any]] = None) -> Dict[str, bool]:
|
||||
"""List all file providers and their availability."""
|
||||
|
||||
availability: Dict[str, bool] = {}
|
||||
for name, provider_class in _FILE_PROVIDERS.items():
|
||||
for name, provider_class in _PROVIDERS.items():
|
||||
try:
|
||||
provider = provider_class(config)
|
||||
availability[name] = provider.validate()
|
||||
availability[name] = bool(provider.validate() and _supports_upload(provider))
|
||||
except Exception:
|
||||
availability[name] = False
|
||||
return availability
|
||||
@@ -104,8 +130,11 @@ def list_file_providers(config: Optional[Dict[str, Any]] = None) -> Dict[str, bo
|
||||
|
||||
__all__ = [
|
||||
"SearchResult",
|
||||
"Provider",
|
||||
"SearchProvider",
|
||||
"FileProvider",
|
||||
"get_provider",
|
||||
"list_providers",
|
||||
"get_search_provider",
|
||||
"list_search_providers",
|
||||
"get_file_provider",
|
||||
|
||||
Reference in New Issue
Block a user