"""Template fuer ein neues ViewIt-Plugin (Basis: serienstream_plugin). Diese Datei wird NICHT automatisch geladen (Dateiname beginnt mit `_`). Zum Verwenden: 1) Kopiere/benenne die Datei um (ohne fuehrenden Unterstrich), z.B. `my_site_plugin.py` 2) Passe `name`, `BASE_URL` und die Implementierungen an. """ from __future__ import annotations from dataclasses import dataclass from typing import TYPE_CHECKING, Any, List, Optional try: # pragma: no cover - optional dependency import requests from bs4 import BeautifulSoup # type: ignore[import-not-found] except ImportError as exc: # pragma: no cover - optional dependency requests = None BeautifulSoup = None REQUESTS_AVAILABLE = False REQUESTS_IMPORT_ERROR = exc else: REQUESTS_AVAILABLE = True REQUESTS_IMPORT_ERROR = None try: # pragma: no cover - optional Kodi helpers import xbmcaddon # type: ignore[import-not-found] except ImportError: # pragma: no cover - allow running outside Kodi xbmcaddon = None from plugin_interface import BasisPlugin if TYPE_CHECKING: # pragma: no cover from requests import Session as RequestsSession from bs4 import BeautifulSoup as BeautifulSoupT # type: ignore[import-not-found] else: # pragma: no cover RequestsSession = Any BeautifulSoupT = Any ADDON_ID = "plugin.video.viewit" BASE_URL = "https://example.com" DEFAULT_TIMEOUT = 20 HEADERS = { "User-Agent": "Mozilla/5.0 (Kodi; ViewIt) AppleWebKit/537.36 (KHTML, like Gecko)", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "de-DE,de;q=0.9,en;q=0.8", "Connection": "keep-alive", } @dataclass(frozen=True) class TitleHit: """Ein Suchtreffer mit Titel und Detail-URL.""" title: str url: str class TemplatePlugin(BasisPlugin): """Vorlage fuer eine Streamingseiten-Integration. Optional kann ein Plugin Capabilities deklarieren (z.B. `popular_series`), damit der Router passende Menüpunkte anbieten kann. """ name = "Template" def __init__(self) -> None: self._session: RequestsSession | None = None @property def is_available(self) -> bool: return REQUESTS_AVAILABLE @property def unavailable_reason(self) -> str: if REQUESTS_AVAILABLE: return "" return f"requests/bs4 nicht verfuegbar: {REQUESTS_IMPORT_ERROR}" def _get_session(self) -> RequestsSession: if requests is None: raise RuntimeError(self.unavailable_reason) if self._session is None: session = requests.Session() session.headers.update(HEADERS) self._session = session return self._session async def search_titles(self, query: str) -> List[str]: """TODO: Suche auf der Zielseite implementieren.""" _ = query return [] def seasons_for(self, title: str) -> List[str]: """TODO: Staffeln fuer einen Titel liefern.""" _ = title return [] def episodes_for(self, title: str, season: str) -> List[str]: """TODO: Episoden fuer Titel+Staffel liefern.""" _ = (title, season) return [] def capabilities(self) -> set[str]: """Optional: Deklariert Fähigkeiten dieses Plugins. Beispiele: - `popular_series`: Plugin kann beliebte Serien liefern - `genres`: Plugin unterstützt Genre-Browser """ return set() def popular_series(self) -> List[str]: """Optional: Liste beliebter Serien (nur wenn `popular_series` gesetzt ist).""" return [] def stream_link_for(self, title: str, season: str, episode: str) -> Optional[str]: """Optional: Embed-/Hoster-Link fuer eine Episode.""" _ = (title, season, episode) return None def resolve_stream_link(self, link: str) -> Optional[str]: """Optional: Redirect-/Mirror-Aufloesung.""" return link