dfdf
This commit is contained in:
@@ -4,8 +4,7 @@ import re
|
||||
import sys
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
import httpx
|
||||
|
||||
from API.hifi import HifiApiClient
|
||||
from ProviderCore.base import Provider, SearchResult
|
||||
from SYS.logger import log
|
||||
|
||||
@@ -38,6 +37,11 @@ class HIFI(Provider):
|
||||
def __init__(self, config: Optional[Dict[str, Any]] = None) -> None:
|
||||
super().__init__(config)
|
||||
self.api_urls = self._resolve_api_urls()
|
||||
try:
|
||||
self.api_timeout = float(self.config.get("timeout", 10.0))
|
||||
except Exception:
|
||||
self.api_timeout = 10.0
|
||||
self.api_clients = [HifiApiClient(base_url=url, timeout=self.api_timeout) for url in self.api_urls]
|
||||
|
||||
def validate(self) -> bool:
|
||||
return bool(self.api_urls)
|
||||
@@ -59,10 +63,10 @@ class HIFI(Provider):
|
||||
for base in self.api_urls:
|
||||
endpoint = f"{base.rstrip('/')}/search/"
|
||||
try:
|
||||
resp = httpx.get(endpoint, params=params, timeout=10.0)
|
||||
resp.raise_for_status()
|
||||
payload = resp.json()
|
||||
break
|
||||
client = self._get_api_client_for_base(base)
|
||||
payload = client.search(params) if client else None
|
||||
if payload is not None:
|
||||
break
|
||||
except Exception as exc:
|
||||
log(f"[hifi] Search failed for {endpoint}: {exc}", file=sys.stderr)
|
||||
continue
|
||||
@@ -71,7 +75,7 @@ class HIFI(Provider):
|
||||
return []
|
||||
|
||||
data = payload.get("data") or {}
|
||||
items = data.get("items") or []
|
||||
items = self._extract_track_items(data)
|
||||
results: List[SearchResult] = []
|
||||
for item in items:
|
||||
if limit and len(results) >= limit:
|
||||
@@ -82,6 +86,57 @@ class HIFI(Provider):
|
||||
|
||||
return results[:limit]
|
||||
|
||||
def _get_api_client_for_base(self, base_url: str) -> Optional[HifiApiClient]:
|
||||
base = base_url.rstrip("/")
|
||||
for client in self.api_clients:
|
||||
if getattr(client, "base_url", "").rstrip("/") == base:
|
||||
return client
|
||||
return None
|
||||
|
||||
def _extract_track_items(self, data: Any) -> List[Dict[str, Any]]:
|
||||
if isinstance(data, list):
|
||||
return [item for item in data if isinstance(item, dict)]
|
||||
if not isinstance(data, dict):
|
||||
return []
|
||||
|
||||
items: List[Dict[str, Any]] = []
|
||||
direct = data.get("items")
|
||||
if isinstance(direct, list):
|
||||
items.extend(item for item in direct if isinstance(item, dict))
|
||||
|
||||
tracks_section = data.get("tracks")
|
||||
if isinstance(tracks_section, dict):
|
||||
track_items = tracks_section.get("items")
|
||||
if isinstance(track_items, list):
|
||||
items.extend(item for item in track_items if isinstance(item, dict))
|
||||
|
||||
top_hits = data.get("topHits")
|
||||
if isinstance(top_hits, list):
|
||||
for hit in top_hits:
|
||||
if not isinstance(hit, dict):
|
||||
continue
|
||||
hit_type = str(hit.get("type") or "").upper()
|
||||
if hit_type != "TRACKS":
|
||||
continue
|
||||
value = hit.get("value")
|
||||
if isinstance(value, dict):
|
||||
items.append(value)
|
||||
|
||||
seen: set[int] = set()
|
||||
deduped: List[Dict[str, Any]] = []
|
||||
for item in items:
|
||||
track_id = item.get("id") or item.get("trackId")
|
||||
try:
|
||||
track_int = int(track_id)
|
||||
except Exception:
|
||||
track_int = None
|
||||
if track_int is None or track_int in seen:
|
||||
continue
|
||||
seen.add(track_int)
|
||||
deduped.append(item)
|
||||
|
||||
return deduped
|
||||
|
||||
def _resolve_api_urls(self) -> List[str]:
|
||||
urls: List[str] = []
|
||||
raw = self.config.get("api_urls")
|
||||
@@ -210,10 +265,12 @@ class HIFI(Provider):
|
||||
detail = " | ".join(detail_parts)
|
||||
|
||||
columns: List[tuple[str, str]] = []
|
||||
if artist_display:
|
||||
columns.append(("Artist", artist_display))
|
||||
if title:
|
||||
columns.append(("Title", title))
|
||||
if album_title:
|
||||
columns.append(("Album", album_title))
|
||||
if artist_display:
|
||||
columns.append(("Artist", artist_display))
|
||||
duration_text = self._format_duration(item.get("duration"))
|
||||
if duration_text:
|
||||
columns.append(("Duration", duration_text))
|
||||
@@ -311,14 +368,12 @@ class HIFI(Provider):
|
||||
def _fetch_track_details(self, track_id: int) -> Optional[Dict[str, Any]]:
|
||||
if track_id <= 0:
|
||||
return None
|
||||
params = {"id": str(track_id)}
|
||||
for base in self.api_urls:
|
||||
endpoint = f"{base.rstrip('/')}/track/"
|
||||
try:
|
||||
resp = httpx.get(endpoint, params=params, timeout=10.0)
|
||||
resp.raise_for_status()
|
||||
payload = resp.json()
|
||||
data = payload.get("data")
|
||||
client = self._get_api_client_for_base(base)
|
||||
payload = client.track(track_id) if client else None
|
||||
data = payload.get("data") if isinstance(payload, dict) else None
|
||||
if isinstance(data, dict):
|
||||
return data
|
||||
except Exception as exc:
|
||||
|
||||
Reference in New Issue
Block a user