Files
ViewIT/addon/plugins/_template_plugin.py

128 lines
3.9 KiB
Python

"""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