dev: bump to 0.1.66 and harden resolveurl + serienstream

This commit is contained in:
2026-02-25 16:35:16 +01:00
parent 74d15cb25e
commit 73f07d20b4
20 changed files with 522 additions and 232 deletions

View File

@@ -1,9 +1,15 @@
"""Template fuer ein neues ViewIt-Plugin (Basis: serienstream_plugin).
"""Template fuer ein neues ViewIt-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.
Vorgehen fuer ein neues Plugin:
1. Datei kopieren/umbenennen (ohne fuehrenden Unterstrich), z.B. `my_site_plugin.py`
2. `name`, `ADDON_ID`, `BASE_URL` und Header anpassen
3. `search_titles`, `seasons_for`, `episodes_for` gemaess Zielseite implementieren
4. Optional weitere Methoden wie `stream_link_for`, `resolve_stream_link`,
`popular_series`, `genres`, `titles_for_genre`, `available_hosters_for` etc.
implementieren siehe `docs/PLUGIN_DEVELOPMENT.md` und bestehende Plugins.
"""
from __future__ import annotations
@@ -48,20 +54,33 @@ HEADERS = {
"Connection": "keep-alive",
}
ProgressCallback = Optional[Callable[[str, Optional[int]], Any]]
@dataclass(frozen=True)
class TitleHit:
"""Ein Suchtreffer mit Titel und Detail-URL."""
"""Ein einfacher Suchtreffer mit Titel und Detail-URL."""
title: str
url: str
class TemplatePlugin(BasisPlugin):
"""Vorlage fuer eine Streamingseiten-Integration.
"""Vorlage fuer eine HTML-basierte Streamingseiten-Integration.
Optional kann ein Plugin Capabilities deklarieren (z.B. `popular_series`),
damit der Router passende Menüpunkte anbieten kann.
Dieses Template zeigt nur die MINIMALE, aber reale Schnittstelle:
Pflicht:
- `async search_titles(query, progress_callback=None) -> list[str]`
- `seasons_for(title) -> list[str]`
- `episodes_for(title, season) -> list[str]`
Empfohlen (optional, je nach Use-Case):
- `capabilities()` mit z.B. `popular_series`, `genres`, `latest_episodes`
- `popular_series()`, `titles_for_genre()`, `titles_for_genre_page()`
- `stream_link_for(...)` und/oder `stream_link_for_url(...)`
- `resolve_stream_link(link)` fuer Hosters/Redirects
- `metadata_for(title)` fuer eigene Metadaten (siehe bestehende Plugins)
"""
name = "Template"
@@ -71,15 +90,25 @@ class TemplatePlugin(BasisPlugin):
@property
def is_available(self) -> bool:
"""Signalisiert dem Router, ob das Plugin nutzbar ist (z.B. Abhaengigkeiten vorhanden)."""
return REQUESTS_AVAILABLE
@property
def unavailable_reason(self) -> str:
"""Optionaler Grund, warum `is_available` false ist (z.B. fehlende Pakete)."""
if REQUESTS_AVAILABLE:
return ""
return f"requests/bs4 nicht verfuegbar: {REQUESTS_IMPORT_ERROR}"
def _get_session(self) -> RequestsSession:
"""Gibt eine vorkonfigurierte `requests.Session` zurueck.
In echten Plugins kann hier auch `http_session_pool.get_requests_session(...)`
genutzt werden, wenn mehrere Module sich Sessions teilen sollen.
"""
if requests is None:
raise RuntimeError(self.unavailable_reason)
if self._session is None:
@@ -91,41 +120,72 @@ class TemplatePlugin(BasisPlugin):
async def search_titles(
self,
query: str,
progress_callback: Optional[Callable[[str, Optional[int]], Any]] = None,
progress_callback: ProgressCallback = None,
) -> List[str]:
"""TODO: Suche auf der Zielseite implementieren."""
"""Sucht Titel auf der Zielseite und liefert eine Liste an Titel-Strings.
Best Practices:
- Nur passende Titel liefern (wortbasiert, keine Zufallstreffer).
- `progress_callback(message, percent)` sparsam nutzen, um lange Suchen anzuzeigen.
- HTTP-Requests robust kapseln (Timeouts, Fehlerbehandlung, optionales Logging).
"""
_ = (query, progress_callback)
return []
def seasons_for(self, title: str) -> List[str]:
"""TODO: Staffeln fuer einen Titel liefern."""
"""Liefert alle Staffeln fuer einen Titel, z.B. `['Staffel 1', 'Staffel 2']`.
Fuer reine Film-Provider kann stattdessen z.B. `['Film']` zurueckgegeben werden
(siehe \"Film Provider Standard\" in `docs/PLUGIN_DEVELOPMENT.md`).
"""
_ = title
return []
def episodes_for(self, title: str, season: str) -> List[str]:
"""TODO: Episoden fuer Titel+Staffel liefern."""
"""Liefert Episoden-Labels fuer einen Titel und eine Staffel.
Beispiele:
- `['Episode 1', 'Episode 2']`
- `['Episode 1: Pilot', 'Episode 2: Finale']`
"""
_ = (title, season)
return []
def capabilities(self) -> set[str]:
"""Optional: Deklariert higkeiten dieses Plugins.
"""Optional: Deklariert die Faehigkeiten dieses Plugins.
Beispiele:
- `popular_series`: Plugin kann beliebte Serien liefern
- `genres`: Plugin unterstützt Genre-Browser
- `popular_series`: Plugin kann beliebte Titel liefern
- `genres`: Plugin unterstuetzt Genre-Browser
- `latest_episodes`: Plugin liefert eine Liste neuer Episoden
"""
return set()
def popular_series(self) -> List[str]:
"""Optional: Liste beliebter Serien (nur wenn `popular_series` gesetzt ist)."""
"""Optional: Liste beliebter Titel (wenn `popular_series` in `capabilities()` gesetzt ist)."""
return []
def stream_link_for(self, title: str, season: str, episode: str) -> Optional[str]:
"""Optional: Embed-/Hoster-Link fuer eine Episode."""
"""Optional: Embed-/Hoster-Link fuer eine Episode.
Der Router ruft diese Methode nur auf, wenn sie existiert. Der Rueckgabewert
ist entweder ein finaler Stream-Link oder ein Hoster-/Embed-Link, der spaeter
ueber `resolve_stream_link` oder ResolveURL weiter aufgeloest werden kann.
"""
_ = (title, season, episode)
return None
def resolve_stream_link(self, link: str) -> Optional[str]:
"""Optional: Redirect-/Mirror-Aufloesung."""
"""Optional: Redirect-/Mirror-Aufloesung fuer Hoster-Links.
Falls nicht ueberschrieben, kann der Router (oder ResolveURL) den Link
direkt verwenden. Plugins koennen hier z.B. HTTP-Redirects verfolgen.
"""
return link