Wrapper-Site Auflösung für meinecloud.click implementiert

- _resolve_wrapper_site() erkennt meinecloud.click und parst data-link Attribute
- Rekursive Auflösung: Wrapper -> Hoster -> Streaming-API
- Streaming-API 404 Fallback: URL direkt zurückgeben wenn API nicht existiert
- HTML-Erkennung bei Downloads bleibt aktiv für Hosts die trotzdem HTML zurückgeben
- STATUS.md aktualisiert
This commit is contained in:
2026-07-07 22:19:23 +02:00
parent 041b60c771
commit 8a82974e64
3 changed files with 6210 additions and 823 deletions
+4 -1
View File
@@ -1,6 +1,6 @@
# xStream Downloader Projektstatus
Stand: 7.7.2026, 16:56
Stand: 7.7.2026, 20:17
## Ziel
Web-Wrapper für das xstream Kodi-Addon, mit dem man Filme suchen, finden
@@ -53,6 +53,8 @@ xstreamDownloader/
12. **HLS/m3u8 Download** via ffmpeg
13. **HTML-Erkennung** verhindert 16KB HTML-Files als "fertige Downloads"
14. **Streaming-Site Auflösung** vidara.to etc. via API (filecode → m3u8)
15. **Wrapper-Site Auflösung** meinecloud.click etc. via HTML-Parsing (data-link Attribute)
16. **Rekursive Auflösung** Wrapper → Hoster → Streaming-API (z.B. meinecloud → dr0pstream → m3u8)
## Navigation (Menü → Inhalte)
@@ -82,6 +84,7 @@ Beim Klick auf einen Menüpunkt:
| 14 | Port 8769 belegt | Geändert auf Port 8770 | 6.7.2026 |
| 15 | Download 16KB HTML statt Video (VOE etc.) | HTML-Erkennung in _run_direct() | 7.7.2026 |
| 16 | Streaming-Sites liefern HTML statt m3u8 | _resolve_streaming_api() für vidara.to etc. | 7.7.2026 |
| 17 | Wrapper-Site meinecloud.click gibt HTML zurück | _resolve_wrapper_site() parst data-link Attribute | 7.7.2026 |
## Verbleibende Aufgaben
+86 -3
View File
@@ -542,13 +542,88 @@ def _resolve_streaming_api(url):
m3u8_url = data.get('streaming_url')
if m3u8_url:
return (m3u8_url, None)
return (None, 'streaming_url nicht in API-Antwort')
# API responded but no streaming_url - might be direct embed
# Return URL for direct handling instead of failing
return (url, None)
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
# API endpoint doesn't exist - this is likely a direct embed URL
# Return the URL for direct handling
return (url, None)
return (None, f'Streaming-API Fehler: {e}')
except Exception as e:
return (None, f'Streaming-API Fehler: {e}')
def _resolve_wrapper_site(url):
"""Löst Wrapper-Sites (meinecloud.click etc.) auf: Fetches HTML und parsed data-link Attribute.
Wrapper-Sites wie meinecloud.click geben keine direkten Video-URLs zurück, sondern
HTML-Seiten mit eingebetteten Hoster-URLs in data-link Attributen.
"""
import re
from urllib.parse import urlparse
# Prüfe ob es eine bekannte Wrapper-Site ist
parsed = urlparse(url)
host = parsed.netloc.lower()
# Wrapper-Site Patterns
WRAPPER_PATTERNS = [
r'meinecloud\.click',
r'meinedownload\.',
r'mycloud\.',
]
is_wrapper = any(re.search(p, host) for p in WRAPPER_PATTERNS)
if not is_wrapper:
return (None, None) # Keine Wrapper-Site
# Futtern Sie die HTML-Seite und parsen data-link Attribute
try:
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7',
}
resp = requests.get(url, headers=headers, timeout=15)
resp.raise_for_status()
html = resp.text
# Parse data-link Attribute
# Pattern: data-link="https://host.com/e/filecode" oder data-link="//host.com/e/filecode"
links = re.findall(r'data-link="([^"]+)"', html)
if not links:
return (None, f'Keine data-link URLs in Wrapper-HTML gefunden')
# Filtere leere und interne Links
valid_links = []
for link in links:
if not link or 'meinecloud' in link.lower():
continue
# Protokoll-relativ beheben
if link.startswith('//'):
link = 'https:' + link
valid_links.append(link)
if not valid_links:
return (None, f'Keine validen Hoster-URLs in Wrapper gefunden')
# Gebe die erste brauchbare URL zurück (bevorzugt VOE wenn verfügbar)
for link in valid_links:
if 'voe' in link.lower():
return (link, None)
return (valid_links[0], None)
except Exception as e:
return (None, f'Wrapper-Aufloesung Fehler: {e}')
def _resolve_url(url):
# Erst prüfen ob es eine bekannte Streaming-Site ist
# 1. Prüfe ob es eine bekannte Streaming-Site ist (/e/<filecode> API Pattern)
m3u8_url, err = _resolve_streaming_api(url)
if m3u8_url:
return (m3u8_url, None)
@@ -556,7 +631,15 @@ def _resolve_url(url):
# Streaming-Site erkannt aber Fehler
return (None, err)
# Falls resolveurl nicht verfügbar, URL direkt zurückgeben
# 2. Prüfe ob es eine Wrapper-Site ist (meinecloud.click etc.)
wrapper_url, wrapper_err = _resolve_wrapper_site(url)
if wrapper_url:
return _resolve_url(wrapper_url) # Rekursiv auflösen (könnte wieder Streaming-Site sein)
if wrapper_err:
# Wrapper erkannt aber Fehler
return (None, wrapper_err)
# 3. Falls resolveurl nicht verfügbar, URL direkt zurückgeben
# (viele URLs sind bereits direkte Stream-URLs)
try:
import resolveurl
+6114 -813
View File
File diff suppressed because one or more lines are too long