from __future__ import annotations import re from plugin_interface import BasisPlugin from tmdb import TmdbCastMember METADATA_MODE_AUTO = 0 METADATA_MODE_SOURCE = 1 METADATA_MODE_TMDB = 2 METADATA_MODE_MIX = 3 def metadata_setting_id(plugin_name: str) -> str: safe = re.sub(r"[^a-z0-9]+", "_", (plugin_name or "").strip().casefold()).strip("_") return f"{safe}_metadata_source" if safe else "metadata_source" def plugin_supports_metadata(plugin: BasisPlugin) -> bool: try: return plugin.__class__.metadata_for is not BasisPlugin.metadata_for except Exception: return False def metadata_policy( plugin_name: str, plugin: BasisPlugin, *, allow_tmdb: bool, get_setting_int=None, ) -> tuple[bool, bool, bool]: if not callable(get_setting_int): return plugin_supports_metadata(plugin), allow_tmdb, bool(getattr(plugin, "prefer_source_metadata", False)) mode = get_setting_int(metadata_setting_id(plugin_name), default=METADATA_MODE_AUTO) supports_source = plugin_supports_metadata(plugin) if mode == METADATA_MODE_SOURCE: return supports_source, False, True if mode == METADATA_MODE_TMDB: return False, allow_tmdb, False if mode == METADATA_MODE_MIX: return supports_source, allow_tmdb, True prefer_source = bool(getattr(plugin, "prefer_source_metadata", False)) return supports_source, allow_tmdb, prefer_source def collect_plugin_metadata( plugin: BasisPlugin, titles: list[str], ) -> dict[str, tuple[dict[str, str], dict[str, str], list[TmdbCastMember] | None]]: getter = getattr(plugin, "metadata_for", None) if not callable(getter): return {} collected: dict[str, tuple[dict[str, str], dict[str, str], list[TmdbCastMember] | None]] = {} for title in titles: try: labels, art, cast = getter(title) except Exception: continue if isinstance(labels, dict) or isinstance(art, dict) or cast: label_map = {str(k): str(v) for k, v in dict(labels or {}).items() if v} art_map = {str(k): str(v) for k, v in dict(art or {}).items() if v} collected[title] = (label_map, art_map, cast if isinstance(cast, list) else None) return collected def needs_tmdb(labels: dict[str, str], art: dict[str, str], *, want_plot: bool, want_art: bool) -> bool: if want_plot and not labels.get("plot"): return True if want_art and not (art.get("thumb") or art.get("poster") or art.get("fanart") or art.get("landscape")): return True return False def merge_metadata( title: str, tmdb_labels: dict[str, str] | None, tmdb_art: dict[str, str] | None, tmdb_cast: list[TmdbCastMember] | None, plugin_meta: tuple[dict[str, str], dict[str, str], list[TmdbCastMember] | None] | None, ) -> tuple[dict[str, str], dict[str, str], list[TmdbCastMember] | None]: labels = dict(tmdb_labels or {}) art = dict(tmdb_art or {}) cast = tmdb_cast if plugin_meta is not None: meta_labels, meta_art, meta_cast = plugin_meta labels.update({k: str(v) for k, v in dict(meta_labels or {}).items() if v}) art.update({k: str(v) for k, v in dict(meta_art or {}).items() if v}) if meta_cast is not None: cast = meta_cast if "title" not in labels: labels["title"] = title return labels, art, cast