Files
Xstream-Standalone/DOKUMENTATION.md
Task-Orchestrator 28b9afb234 DAP-74: Technische Dokumentation der xStream Kodi-Addons erstellt
Analysiert und dokumentiert:
- plugin.video.xstream: Startup-Sequenz, URL-Routing, Site-Plugin-Konvention,
  Browsing- und Hoster-Auflösungsflow, globale Suche
- script.module.xstreamscraper: automatische TMDB-basierte Stream-Suche
- HTTP-Request-Handler: Caching, Cookie-Verwaltung, Anti-Bot-Mechanismen
- Plugin-Handler, GUI-Schicht, Einstellungsreferenz, Abhängigkeiten

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-17 21:30:12 +02:00

18 KiB
Raw Blame History

xStream Technische Dokumentation

Version: plugin.video.xstream 2026.02.11 / script.module.xstreamscraper 2025.08.14
Erstellt: 2026-08-17


1. Übersicht

Das Projekt besteht aus zwei voneinander abhängigen Kodi-Addons:

Addon Zweck
plugin.video.xstream Vollständiges Video-Plugin: Browser-GUI, Site-Plugins, Hoster-Auflösung, Download
script.module.xstreamscraper Companion-Modul: automatische Suche und Stream-Auflösung via TMDB-ID, für externe Aufrufer

Zusammenfassung der Funktion: xStream ist eine Kodi-Suchmaschine für Filme und Serien. Es lädt Inhalte von verschiedenen Streaming-Webseiten (sogenannte „Site-Plugins"), löst die gefundenen Hoster-Links über das resolveurl-Addon auf und spielt den Stream in Kodi ab. Das Scraper-Modul ergänzt dies um eine vollautomatische Suche, die auf TMDB-IDs basiert.


2. Komponentenstruktur

Xstream-Standalone/
├── plugin.video.xstream/
│   ├── addon.xml                    # Addon-Metadaten und Abhängigkeiten
│   ├── default.py                   # Einstiegspunkt (Kodi ruft dies auf)
│   ├── service.py                   # Kodi-Service (läuft beim Kodi-Start)
│   ├── xstream.py                   # URL-Router und Hauptlogik
│   ├── sites/                       # Site-Plugins (eine Datei pro Webseite)
│   │   ├── kinox.py
│   │   ├── aniworld.py
│   │   ├── burningseries.py
│   │   └── ...
│   └── resources/
│       └── lib/
│           ├── config.py            # Addon-Einstellungen (Wrapper um xbmcaddon)
│           ├── tools.py             # Logger, Parser, Cache-Hilfsfunktionen
│           ├── gui/
│           │   ├── gui.py           # Kodi-GUI-Abstraktion (Listeneinträge, Ansichten)
│           │   ├── guiElement.py    # Einzelner Listeneintrag (Titel, Thumbnail, Metadaten)
│           │   ├── hoster.py        # Hoster-GUI: Abspielen, Download, Weiterleiten
│           │   └── contextElement.py# Kontextmenü-Einträge
│           └── handler/
│               ├── pluginHandler.py # Erkennung und Verwaltung der Site-Plugins
│               ├── requestHandler.py# HTTP-Client mit Cache, Cookies, Anti-Bot
│               ├── ParameterHandler.py # URL-Parameter lesen/schreiben
│               ├── jdownloaderHandler.py
│               ├── jdownloader2Handler.py
│               ├── myjdownloaderHandler.py
│               └── pyLoadHandler.py
└── script.module.xstreamscraper/
    ├── addon.xml
    ├── main.py                      # Einstiegspunkt des Scraper-Moduls
    ├── service.py                   # Service des Scraper-Moduls
    └── resources/lib/
        ├── scraper.py               # Kernlogik: Suche, Hoster-Auflösung, Wiedergabe
        ├── settings.py              # Globaler Zustand (collectMode, aDirectory)
        ├── tools.py
        ├── gui/                     # GUI-Klassen (Subset von plugin.video.xstream)
        └── handler/                 # Request- und Parameter-Handler (Subset)

3. Ablauf: plugin.video.xstream

3.1 Startup-Sequenz (Service)

service.py wird von Kodi beim Start als separater Service-Prozess ausgeführt.

Kodi-Start
   └─► service.py: main()
         1. cCache: setze '{addon_id}_main' = 'running'
         2. Resolver-Update von GitHub prüfen/ausführen (updateManager.resolverUpdate)
         3. Abhängigkeiten prüfen (checkDependence)  fehlende Addons installieren
         4. Domain-Prüfung aller Site-Plugins parallel (cPluginHandler.checkDomain)
              → HTTP-Request an domain des jeweiligen Site-Plugins
              → Status 200/3xx: Domain aktiv, globale Suche aktiviert
              → Status 403503: globale Suche deaktiviert, Link gesperrt
         5. PluginDB aktualisieren (falls neue Einstellungen vorhanden)
         6. cCache: setze '{addon_id}_main' = 'finished'
         7. Changelog-Popup anzeigen (falls konfiguriert)
         8. Alten HTML-Cache löschen (alle N Tage, konfigurierbar)

showMainMenu() in xstream.py wartet aktiv (max. 60 Sekunden / 0,5-Sekunden-Schleifen) auf das Signal 'finished', bevor das Hauptmenü aufgebaut wird.


3.2 Browsing-Flow (Plugin-Aufruf)

Kodi ruft default.py mit einer Plugin-URL der Form
plugin://plugin.video.xstream/?site=kinox&function=showMovieMenu&... auf.

default.py: main()
   └─► Systempfade einrichten (sites/, lib/, art/sites/)
   └─► xstream.py: parseUrl()
         ├── ParameterHandler: URL-Parameter lesen
         ├── Sonderfunktionen: clearCache, viewInfo, searchAlter, searchTMDB, ...
         ├── Kein 'site'-Parameter → showMainMenu()
         │     └── alle aktivierten Site-Plugins als Listeneinträge hinzufügen
         ├── site = 'cHosterGui' → showHosterGui()
         ├── site = 'globalSearch' → searchGlobal()
         ├── site = 'xStream' → xStream-Einstellungen öffnen
         ├── site = 'resolver' → Resolver-Einstellungen öffnen
         └── site = '<plugin-name>'
               └── plugin = __import__('<plugin-name>')
               └── function = getattr(plugin, sFunction)
               └── function()   ← Site-Plugin übernimmt

3.3 Site-Plugin-Konvention

Jede Datei in sites/ ist ein eigenständiges Python-Modul. Es muss folgende Modul-Variablen und Funktionen bereitstellen:

Name Pflicht Beschreibung
SITE_IDENTIFIER Ja Eindeutiger Bezeichner (= Dateiname ohne .py)
SITE_NAME Ja Anzeigename im Menü
SITE_ICON Nein Dateiname des Icons in resources/art/sites/
DOMAIN Nein Standarddomain; kann per Einstellung überschrieben werden
SITE_GLOBAL_SEARCH Nein True/False; steuert globale Suche
load() Ja Einstiegspunkt baut Hauptmenü des Sites auf
_search(oGui, sSearchText) Nein Globale Suche; befüllt oGui mit Ergebnissen
showHosters() Typisch Gibt Hoster-Liste zurück (list of dicts + Funktionsname am Ende)
getHosterUrl(sUrl) Typisch Löst einen Hoster-Link zur Stream-URL auf

Beispiel (kinox.py, vereinfacht):

SITE_IDENTIFIER = 'kinox'
SITE_NAME = 'KinoX'
DOMAIN = 'ww22.kinoz.to'

def load():          # Hauptmenü: News, Filme, Serien, Dokumentationen, Suche
def showMovieMenu(): # Untermenü: Kino, A-Z, Genre, Beliebt, Neu
def showHosters():   # Gibt Liste der Hoster-Dicts + 'getHosterUrl' zurück
def getHosterUrl():  # Löst Hoster-URL auf, gibt {'streamUrl':..., 'resolved':...} zurück
def _search(oGui, sSearchText):  # Globale Suche, befüllt oGui

3.4 Hoster-Auflösungsflow

User klickt auf Film/Episode
   └─► xstream.py: parseUrl() erkennt 'playMode'
         ├── hosterSelect = 'Auto' → cHosterGui.streamAuto()
         └── sonst             → cHosterGui.stream()

cHosterGui.stream(playMode, siteName, function):
   1. Site-Plugin laden, Hoster-Funktion aufrufen → Hoster-Liste
   2. Hoster nach Priorität sortieren (__getPriorities)
        → resolveurl.HostedMediaFile(url=...).get_resolvers()
        → Priorität nach Resolver-Ranking + Qualität + Sprache
   3. Auswahl:
        ├── hosterSelect = 'List' → Hoster als Ordner anzeigen (showHosterFolder)
        ├── Mehrere Hoster       → Dialog zur Auswahl (_chooseHoster)
        └── Genau ein Hoster     → direkt weiter
   4. getHosterUrl(hoster['link']) aufrufen → {'streamUrl': ..., 'resolved': bool}
   5. cHosterGui.play / download / addToPlaylist / sendToJD / ...

cHosterGui.play(siteResult):
   1. resolveurl.resolve(streamUrl) → direkter Stream-Link
   2. xbmcgui.ListItem mit Link erstellen
   3. m3u8/mpd → inputstream.adaptive aktivieren
   4. xbmcplugin.setResolvedUrl(handle, True, listItem)

3.5 Globale Suche

searchGlobal(sSearchText):
   1. cGui im collectMode = True (Ergebnisse werden im Speicher gesammelt)
   2. ThreadPoolExecutor (max. 10 Workers):
        → alle aktivierten Plugins mit globalsearch != 'false'
        → plugin._search(oGui, sSearchText) parallel aufrufen
   3. Fortschrittsdialog aktualisieren (050 %)
   4. collectMode = False
   5. Ergebnisse nach Site-Name sortiert als Listeneinträge hinzufügen (50100 %)

searchAlter (Kontextmenü „Weitere Quellen"):
   - Wie searchGlobal, aber mit Titel-Normalisierung (Jahr, Staffelkennung entfernen)
   - Ergebnisse werden nach Titel, Jahr und IMDB-ID gefiltert

searchTMDB (aus TMDB-Kontext aufgerufen):
   - Wie searchGlobal, ohne zusätzliche Filterung

4. HTTP-Request-Handler (requestHandler.py)

cRequestHandler ist der zentrale HTTP-Client des Plugins.

Initialisierung (wichtige Parameter)

Parameter Standard Bedeutung
caching True HTML-Cache aktivieren
ignoreErrors False HTTP-Fehler still ignorieren
method 'GET' HTTP-Methode
compression True gzip/deflate anfordern
bypass_dns False DNS-over-HTTPS verwenden

Caching

Zwei Cache-Ebenen, konfigurierbar per Einstellung:

Ebene Speicherort Aktivierung
Persistent {profile}/htmlcache/{md5(url)} Standard
Volatil (In-Memory) cCache (Wörterbuch) Einstellung volatileHtmlCache = true

Cache-Lebensdauer: konfigurierbar, Standard 6 Stunden (360 min × 60 s).

Anti-Bot-Mechanismen

Schutzmechanismus Erkennung Behandlung
Cloudflare cloudflare im Response-Header Fehlermeldung an Nutzer, kein Retry
DDOS-Guard DDOS-GUARD im Response-Body Automatischer Cookie-Challenge via check.ddos-guard.net
Blazingfast lazingfast im Response-Body AES-Entschlüsselung via pyaes, Cookie-Setzung
DNS-Sperre (CUII) Redirect zu notice.cuii.info Fehlerdialog; Bypass via DoH (Cloudflare) wenn aktiviert

DNS-over-HTTPS (DoH)

Wenn bypass_dns = True und Einstellung bypassDNSlock = true:
→ DNS-Auflösung via https://cloudflare-dns.com/dns-query statt System-DNS
→ IP-Adresse wird direkt für TCP-Verbindung genutzt; SNI-Header enthält weiterhin den Hostnamen
→ IP-Ergebnis wird im volatilen Cache gespeichert

Pro Domain wird eine eigene Cookie-Datei im LWP-Format gespeichert:
{profile}/cookies/{domain_mit_unterstrichen}.txt


5. Plugin-Handler (pluginHandler.py)

Verwaltet die Erkennung und den Zustand der Site-Plugins.

PluginDB

Eine JSON-Datei unter {profile}/pluginDB. Sie enthält für jedes Site-Plugin:

{
  "kinox": {
    "name": "KinoX",
    "identifier": "kinox",
    "icon": "kinox.png",
    "domain": "ww22.kinoz.to",
    "globalsearch": "true",
    "modified": 1700000000.0
  }
}

Die DB wird aktualisiert, wenn:

  • Eine neue .py-Datei im sites/-Ordner gefunden wird
  • Eine vorhandene Datei seit dem letzten Einlesen geändert wurde
  • Die globale Sucheinstellung für ein Plugin geändert wurde

Domain-Prüfung (checkDomain)

Wird beim Kodi-Start vom Service aufgerufen. Für jedes aktivierte Plugin:

  1. HTTP-Request an http://{domain}/
  2. Status-Code wird in der Einstellung plugin_{id}_status gespeichert
  3. Bei Redirect (3xx): neue Domain aus dem Location-Header übernehmen
  4. Bei 403503: globale Suche für das Plugin deaktivieren

6. GUI-Schicht (gui.py, guiElement.py)

cGui

Abstraktion über Kodis xbmcplugin-API. Wesentliche Konzepte:

collectMode: Wenn True, werden Listeneinträge nicht an Kodi gesendet, sondern in self.searchResults gesammelt. Wird für die globale Suche verwendet, damit alle Plugins ihre Ergebnisse in eine gemeinsame Liste schreiben können.

TMDB-Metadaten: Wenn die Einstellung TMDBMETA = true, wird für jeden Eintrag automatisch guiElement.getMeta() aufgerufen (via TMDB-API), bevor er angezeigt wird.

Kontext-Menü-Einträge (automatisch für alle Einträge):

  • Trailer (wenn Addon script.module.xstream.trailer installiert)
  • Erweiterte Info (TMDB-Infobox)
  • Weitere Quellen (searchAlter)
  • Playlist hinzufügen
  • Download
  • An JDownloader / JDownloader2 / My.JDownloader / pyLoad senden
  • Manueller Hoster-Auswahldialog (wenn Auto-Modus aktiv)

cGuiElement

Repräsentiert einen einzelnen Listeneintrag. Wesentliche Felder:

Feld Methode Beschreibung
Titel setTitle Anzeigename
Site-Name setSiteName Zugehöriges Site-Plugin
Funktion setFunction Aufzurufende Funktion beim Klick
Thumbnail setThumbnail Vorschaubild-URL
Fanart setFanart Hintergrundbild-URL
Medientyp setMediaType movie, tvshow, season, episode
Sprache setLanguage Sprach-Code (z. B. DE, EN)
Qualität setQuality z. B. 1080p, 720p
Jahr setYear Erscheinungsjahr
Staffel/Episode setSeason/setEpisode Serieninformationen

7. script.module.xstreamscraper

Das Scraper-Modul ist für den Fall gedacht, dass externe Tools (z. B. über Kodi-Addons, die TMDB-IDs kennen) einen Film oder eine Serie automatisch abspielen wollen, ohne durch das xStream-Menü navigieren zu müssen.

Haupt-API: scraper.play(_type, _id, season, episode)

play("movie", "123456", None, None)
play("tv",    "78910",  "2",  "5")   # Staffel 2, Episode 5

Ablauf:

play(_type, _id, season, episode):
   1. TMDB-API: Film-/Seriendaten laden (Name, Erscheinungsdatum, alternative Titel)
   2. Optional: vavoo-Integration prüfen (direkter Stream ohne Scraping)
   3. searchGlobal(name, searchtitles, isSerie, ...) aufrufen
        → alle aktivierten Site-Plugins parallel durchsuchen (ThreadPoolExecutor)
        → Ergebnisse filtern:
             - Sprache muss Deutsch sein
             - Medientyp muss passen (Film ≠ Serie)
             - Bei Serien: Staffelnummer prüfen
             - Jahresabgleich (±0 bei Filmen)
             - Titelabgleich (normalisiert: Sonderzeichen entfernt)
   4. get_hosters(sources, isSerie, season, episode) aufrufen
        → Bei Serien: get_episodes() navigiert zu korrekter Episode
        → site-plugin.getHosterUrl() für jeden Treffer
   5. Jeden Hoster der Reihe nach testen:
        → resolveurl.resolve(streamUrl) aufrufen
        → HTTP-HEAD-Request prüfen (Content-Type muss Video sein)
        → Erster gültiger Link → _play(url)
   6. _play(url):
        → xbmcgui.ListItem mit URL
        → m3u8 → inputstream.adaptive
        → xbmcplugin.setResolvedUrl()

Unterschied zur manuellen Nutzung via plugin.video.xstream

Aspekt plugin.video.xstream script.module.xstreamscraper
Einstieg Nutzer-Navigation TMDB-ID als Parameter
Hoster-Auswahl Manuell oder nach Priorität Vollautomatisch, erster funktionierender
Stream-Validierung Keiner HTTP-HEAD-Request vor Wiedergabe
Sprach-/Jahresfilter Keine automatische Filterung Automatisch (nur Deutsch, korrektes Jahr)
Zielgruppe Endnutzer in Kodi-GUI Andere Addons / Automatisierung

8. Einstellungen (Auszug)

Alle Einstellungen befinden sich in resources/settings.xml und werden über cConfig gelesen.

Einstellung Bedeutung
plugin_{id} Site-Plugin aktiviert (true/false)
plugin_{id}.domain Überschreibt Standard-Domain des Plugins
plugin_{id}_status Letzter HTTP-Status-Code der Domain
plugin_{id}_checkdomain Domain-Prüfung für dieses Plugin aktiviert
global_search_{id} Globale Suche für dieses Plugin aktiviert
hosterSelect Auto (automatisch) oder List (manuelle Auswahl)
cacheTime HTML-Cache-Lebensdauer in Minuten (Standard: 360)
requestTimeout HTTP-Timeout in Sekunden (Standard: 10)
volatileHtmlCache In-Memory-Cache aktivieren
bypassDNSlock DNS-over-HTTPS für gesperrte Domains
TMDBMETA TMDB-Metadaten für Listeneinträge laden
metaOverwrite TMDB-Daten ersetzen statt ergänzen
prefLanguage Bevorzugte Sprache (1 = Deutsch, 2 = Englisch)
preferedQuality Bevorzugte Videoqualität für Hoster-Sortierung
presortHoster Hoster nach Resolver-Priorität vorsortieren
maxHoster Maximale Anzahl Hoster in der Liste
jd_enabled / jd2_enabled / myjd_enabled / pyload_enabled Download-Manager aktivieren
githubUpdateResolver Resolver bei Kodi-Start aktualisieren
cacheDeltaDay HTML-Cache alle N Tage beim Start löschen
popup.update.notification Changelog-Popup beim Start anzeigen

9. Abhängigkeiten

plugin.video.xstream

Addon Pflicht Zweck
script.module.requests Ja HTTP (via scraper-Modul)
script.module.resolveurl ≥ 5.1.173 Ja Hoster-Auflösung
script.module.six ≥ 1.11.0 Ja Python-2/3-Kompatibilität
script.module.pyaes Ja AES-Entschlüsselung (Blazingfast-Bypass)
script.module.inputstreamhelper ≥ 0.3.3 Optional HLS/DASH über inputstream.adaptive
repository.resolveurl Optional Resolver-Repository
script.module.pydevd / script.module.web-pdb Optional Debugging

script.module.xstreamscraper

Zusätzlich zu den obigen:

Addon Pflicht Zweck
plugin.video.xstream Ja Nutzt dessen Site-Plugins direkt
plugin.video.vavooto Ja Vavoo-Stream-Integration

10. Bekannte Einschränkungen

  • Cloudflare: Seiten mit aktivem Cloudflare-Schutz werden nicht automatisch umgangen. Der Nutzer erhält eine Fehlermeldung.
  • Domain-Wechsel: Wenn eine Streaming-Seite ihre Domain ändert, muss entweder der Kodi-Start abgewartet werden (Domain-Prüfung aktualisiert die Einstellung automatisch via Redirect-Erkennung) oder die Domain muss manuell in den xStream-Einstellungen angepasst werden.
  • Thread-Safety in Global Search: Die Site-Plugins werden parallel in Threads ausgeführt. Plugins, die globalen Zustand modifizieren, können Race-Conditions verursachen.
  • scraper.py plugin_ Funktion: Der Scraper importiert Site-Plugins dynamisch und setzt settings.urlparams als globalen Zustand dies ist nicht thread-sicher und kann bei paralleler Nutzung zu Problemen führen.
  • Kodi-Version: Der Code enthält explizite Versionsprüfungen (kodi_version[:2] < '20' usw.). Unter Kodi 19 wird setInfo statt getVideoInfoTag() verwendet.