dev: umfangreiches Refactoring, Trakt-Integration und Code-Review-Fixes (0.1.69-dev)
Core & Architektur: - Neues Verzeichnis addon/core/ mit router.py, trakt.py, metadata.py, gui.py, playstate.py, plugin_manager.py, updater.py - Tests-Verzeichnis hinzugefügt (24 Tests, pytest + Coverage) Trakt-Integration: - OAuth Device Flow, Scrobbling, Watchlist, History, Calendar - Upcoming Episodes, Weiterschauen (Continue Watching) - Watched-Status in Episodenlisten - _trakt_find_in_plugins() mit 5-Min-Cache Serienstream-Suche: - API-Ergebnisse werden immer mit Katalog-Cache ergänzt (serverseitiges 10-Treffer-Limit) - Katalog-Cache wird beim Addon-Start im Daemon-Thread vorgewärmt - Notification nach Cache-Load via xbmc.executebuiltin() (thread-sicher) Bugfixes (Code-Review): - Race Condition auf _TRAKT_WATCHED_CACHE: _TRAKT_WATCHED_CACHE_LOCK hinzugefügt - GUI-Dialog aus Daemon-Thread: xbmcgui -> xbmc.executebuiltin() - ValueError in Trakt-Watchlist-Routen abgesichert - Token expires_at==0 Check korrigiert - get_setting_bool() Kontrollfluss in gui.py bereinigt - topstreamfilm_plugin: try-finally um xbmcvfs.File.close() Cleanup: - default.py.bak und refactor_router.py entfernt - .gitignore: /tests/ Eintrag entfernt - Type-Hints vereinheitlicht (Dict/List/Tuple -> dict/list/tuple)
This commit is contained in:
@@ -557,3 +557,51 @@ def lookup_tv_season(
|
||||
continue
|
||||
result[ep_number] = TmdbEpisodeMeta(plot=plot, thumb=thumb, runtime_minutes=runtime_minutes)
|
||||
return result or None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# External IDs (IMDb, TVDb) – für Trakt-Integration
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TmdbExternalIds:
|
||||
imdb_id: str # z.B. "tt1234567"
|
||||
tvdb_id: int # TheTVDB-ID
|
||||
|
||||
|
||||
def fetch_external_ids(
|
||||
*,
|
||||
kind: str,
|
||||
tmdb_id: int,
|
||||
api_key: str,
|
||||
timeout: int = 15,
|
||||
log: Callable[[str], None] | None = None,
|
||||
log_responses: bool = False,
|
||||
) -> Optional[TmdbExternalIds]:
|
||||
"""Ruft IMDb-ID und TVDb-ID via /movie/{id}/external_ids oder /tv/{id}/external_ids ab."""
|
||||
if requests is None or not tmdb_id:
|
||||
return None
|
||||
api_key = (api_key or "").strip()
|
||||
if not api_key:
|
||||
return None
|
||||
kind = (kind or "").strip()
|
||||
if kind not in ("movie", "tv"):
|
||||
return None
|
||||
params = {"api_key": api_key}
|
||||
url = f"{TMDB_API_BASE}/{kind}/{tmdb_id}/external_ids?{urlencode(params)}"
|
||||
status, payload, body_text = _tmdb_get_json(
|
||||
url=url, timeout=timeout, log=log, log_responses=log_responses,
|
||||
)
|
||||
if callable(log):
|
||||
log(f"TMDB RESPONSE /{kind}/{{id}}/external_ids status={status}")
|
||||
if status != 200 or not isinstance(payload, dict):
|
||||
return None
|
||||
imdb_id = (payload.get("imdb_id") or "").strip()
|
||||
tvdb_id = 0
|
||||
try:
|
||||
tvdb_id = int(payload.get("tvdb_id") or 0)
|
||||
except (ValueError, TypeError):
|
||||
tvdb_id = 0
|
||||
if not imdb_id and not tvdb_id:
|
||||
return None
|
||||
return TmdbExternalIds(imdb_id=imdb_id, tvdb_id=tvdb_id)
|
||||
|
||||
Reference in New Issue
Block a user