dev: YouTube HD via inputstream.adaptive, DokuStreams Suche fix

This commit is contained in:
2026-03-14 23:34:09 +01:00
parent d51505e004
commit ea9ceec34c
6 changed files with 416 additions and 95 deletions

View File

@@ -286,7 +286,7 @@ class DokuStreamsPlugin(BasisPlugin):
soup = _get_soup(search_url, session=session)
except Exception:
return []
return _parse_listing_hits(soup, query=query)
return _parse_listing_hits(soup)
def capabilities(self) -> set[str]:
return {"genres", "popular_series", "tags", "random"}
@@ -455,15 +455,24 @@ class DokuStreamsPlugin(BasisPlugin):
art = {"thumb": poster, "poster": poster}
return info, art, None
def series_url_for_title(self, title: str) -> Optional[str]:
return self._title_to_url.get((title or "").strip())
def remember_series_url(self, title: str, url: str) -> None:
title = (title or "").strip()
url = (url or "").strip()
if title and url:
self._title_to_url[title] = url
def seasons_for(self, title: str) -> List[str]:
title = (title or "").strip()
if not title or title not in self._title_to_url:
if not title:
return []
return ["Stream"]
def episodes_for(self, title: str, season: str) -> List[str]:
title = (title or "").strip()
if not title or title not in self._title_to_url:
if not title:
return []
return [title]
@@ -537,6 +546,14 @@ class DokuStreamsPlugin(BasisPlugin):
"""Folgt Redirects und versucht ResolveURL fuer Hoster-Links."""
if not link:
return None
# YouTube-URLs via yt-dlp aufloesen
from ytdlp_helper import extract_youtube_id, resolve_youtube_url
yt_id = extract_youtube_id(link)
if yt_id:
resolved = resolve_youtube_url(yt_id)
if resolved:
return resolved
return None
from plugin_helpers import resolve_via_resolveurl
resolved = resolve_via_resolveurl(link, fallback_to_link=False)
if resolved:

View File

@@ -135,7 +135,7 @@ def _videos_from_search_data(data: dict) -> List[str]:
def _search_with_ytdlp(query: str, count: int = 20) -> List[str]:
"""Sucht YouTube-Videos via yt-dlp ytsearch-Extraktor."""
if not _ensure_ytdlp_in_path():
if not ensure_ytdlp_in_path():
return []
try:
from yt_dlp import YoutubeDL # type: ignore
@@ -174,95 +174,7 @@ def _fetch_search_videos(url: str) -> List[str]:
return []
def _fix_strptime() -> None:
"""Kodi-Workaround: datetime.strptime ist manchmal None."""
import datetime as _dt
import time as _time
if not callable(getattr(_dt.datetime, "strptime", None)):
_dt.datetime.strptime = lambda s, f: _dt.datetime(*(_time.strptime(s, f)[0:6]))
def _ensure_ytdlp_in_path() -> bool:
"""Fuegt script.module.yt-dlp/lib zum sys.path hinzu falls noetig."""
_fix_strptime()
try:
import yt_dlp # type: ignore # noqa: F401
return True
except ImportError:
pass
try:
import sys, os
import xbmcvfs # type: ignore
lib_path = xbmcvfs.translatePath("special://home/addons/script.module.yt-dlp/lib")
if lib_path and os.path.isdir(lib_path) and lib_path not in sys.path:
sys.path.insert(0, lib_path)
import yt_dlp # type: ignore # noqa: F401
return True
except Exception:
pass
return False
def _get_quality_format() -> str:
"""Liest YouTube-Qualitaet aus den Addon-Einstellungen."""
_QUALITY_MAP = {
"0": "best[ext=mp4]/best",
"1": "bestvideo[height<=1080][ext=mp4]+bestaudio[ext=m4a]/best[height<=1080][ext=mp4]/best",
"2": "bestvideo[height<=720][ext=mp4]+bestaudio[ext=m4a]/best[height<=720][ext=mp4]/best",
"3": "bestvideo[height<=480][ext=mp4]+bestaudio[ext=m4a]/best[height<=480][ext=mp4]/best",
"4": "bestvideo[height<=360][ext=mp4]+bestaudio[ext=m4a]/best[height<=360][ext=mp4]/best",
}
try:
import xbmcaddon # type: ignore
val = xbmcaddon.Addon().getSetting("youtube_quality") or "0"
return _QUALITY_MAP.get(val, _QUALITY_MAP["0"])
except Exception:
return _QUALITY_MAP["0"]
def _resolve_with_ytdlp(video_id: str) -> Optional[str]:
"""Loest Video-ID via yt-dlp zu direkter Stream-URL auf."""
if not _ensure_ytdlp_in_path():
_log("[YouTube] yt-dlp nicht verfuegbar (script.module.yt-dlp fehlt)")
try:
import xbmcgui
xbmcgui.Dialog().notification(
"yt-dlp fehlt",
"Bitte yt-dlp in den ViewIT-Einstellungen installieren.",
xbmcgui.NOTIFICATION_ERROR,
5000,
)
except Exception:
pass
return None
try:
from yt_dlp import YoutubeDL # type: ignore
except ImportError:
return None
url = f"https://www.youtube.com/watch?v={video_id}"
fmt = _get_quality_format()
ydl_opts: Dict[str, Any] = {
"format": fmt,
"quiet": True,
"no_warnings": True,
"extract_flat": False,
}
try:
with YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(url, download=False)
if not info:
return None
# Einzelnes Video
direct = info.get("url")
if direct:
return direct
# Formatauswahl
formats = info.get("formats", [])
if formats:
return formats[-1].get("url")
except Exception as exc:
_log(f"[YouTube] yt-dlp Fehler fuer {video_id}: {exc}")
return None
from ytdlp_helper import ensure_ytdlp_in_path, resolve_youtube_url
# ---------------------------------------------------------------------------
@@ -306,7 +218,7 @@ class YoutubePlugin(BasisPlugin):
video_id = _decode_id(episode) or _decode_id(title)
if not video_id:
return None
return _resolve_with_ytdlp(video_id)
return resolve_youtube_url(video_id)
def resolve_stream_link(self, link: str) -> Optional[str]:
return link # bereits direkte URL