"""Optionales ResolveURL-Backend für das Kodi-Addon. Wenn `script.module.resolveurl` installiert ist, kann damit eine Hoster-URL zu einer abspielbaren Media-URL (inkl. evtl. Header-Suffix) aufgelöst werden. """ from __future__ import annotations import importlib import os import sys from typing import Optional _LAST_RESOLVE_ERROR = "" def _debug_log(message: str) -> None: line = f"[ViewIt][ResolveURL] {message}" try: import xbmc # type: ignore xbmc.log(line, xbmc.LOGDEBUG) except Exception: return def _append_addon_lib_path(addon_id: str) -> bool: try: import xbmcaddon # type: ignore import xbmcvfs # type: ignore addon = xbmcaddon.Addon(addon_id) addon_path = addon.getAddonInfo("path") lib_path = xbmcvfs.translatePath(os.path.join(addon_path, "lib")) if lib_path and lib_path not in sys.path: sys.path.append(lib_path) return bool(lib_path) except Exception: return False def get_last_error() -> str: return str(_LAST_RESOLVE_ERROR or "") def _import_resolveurl(): try: return importlib.import_module("resolveurl") except Exception as exc: _debug_log(f"import resolveurl failed (direct): {exc}") # Kodi should load transitive deps, but some runtimes miss sys.path entries. _append_addon_lib_path("script.module.resolveurl") _append_addon_lib_path("script.module.kodi-six") _append_addon_lib_path("script.module.six") try: return importlib.import_module("resolveurl") except Exception as exc: _debug_log(f"import resolveurl failed (with addon lib paths): {exc}") return None def resolve(url: str) -> Optional[str]: global _LAST_RESOLVE_ERROR _LAST_RESOLVE_ERROR = "" if not url: _debug_log("resolve() skipped (empty url)") return None _debug_log(f"input: {url}") resolveurl = _import_resolveurl() if resolveurl is None: _LAST_RESOLVE_ERROR = "resolveurl missing" _debug_log("result: (resolveurl missing)") return None try: hosted = getattr(resolveurl, "HostedMediaFile", None) if callable(hosted): hmf = hosted(url) valid = getattr(hmf, "valid_url", None) if callable(valid) and not valid(): _LAST_RESOLVE_ERROR = "invalid url" _debug_log("result: (invalid url for HostedMediaFile)") return None resolver = getattr(hmf, "resolve", None) if callable(resolver): result = resolver() if result: _debug_log(f"result: {result}") return str(result) _LAST_RESOLVE_ERROR = "unresolved" _debug_log("result: (HostedMediaFile unresolved)") return None except Exception as exc: _LAST_RESOLVE_ERROR = str(exc or "") _debug_log(f"HostedMediaFile error: {_LAST_RESOLVE_ERROR}") try: resolve_fn = getattr(resolveurl, "resolve", None) if callable(resolve_fn): result = resolve_fn(url) if result: _debug_log(f"result: {result}") return str(result) _LAST_RESOLVE_ERROR = "unresolved" _debug_log("result: (resolve() unresolved)") return None except Exception as exc: _LAST_RESOLVE_ERROR = str(exc or "") _debug_log(f"resolve() error: {_LAST_RESOLVE_ERROR}") return None _debug_log("result: (no resolver path)") return None