Compare commits
1 Commits
v0.1.91.0-
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 7df6bc61c4 |
@@ -1,3 +1,7 @@
|
||||
## 0.1.91.0-dev - 2026-04-10
|
||||
|
||||
- dev: bump to 0.1.90.5 pre-commit Hook synchronisiert Changelog-Version mit ZIP-Version
|
||||
|
||||
## 0.1.90.5-dev - 2026-04-10
|
||||
|
||||
- dev: bump to 0.1.90.0 Changelog und Release-Prozess fix
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
## 0.1.91.0
|
||||
## 0.1.91.5
|
||||
|
||||
**TMDb Helper Integration**
|
||||
- SerienStream-Player: Staffel- und Episodennummer werden jetzt korrekt an ViewIT übergeben
|
||||
- Direkte Episodenwiedergabe über TMDb Helper funktioniert jetzt zuverlässig
|
||||
|
||||
**Autoplay / Hoster**
|
||||
- Bevorzugter Hoster wird jetzt korrekt ausgelesen und angewendet
|
||||
- Gesperrte Hoster: Einstellungen → Tools → „Gesperrte Hoster konfigurieren" – ausgewählte Hoster werden bei der Wiedergabe übersprungen
|
||||
|
||||
**Allgemein**
|
||||
- Changelog und Release-Prozess fix.
|
||||
- Changelog aktualisiert.
|
||||
|
||||
|
||||
## 0.1.90.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<addon id="plugin.video.viewit" name="ViewIt" version="0.1.91.0-dev" provider-name="ViewIt">
|
||||
<addon id="plugin.video.viewit" name="ViewIt" version="0.1.91.5-dev" provider-name="ViewIt">
|
||||
<requires>
|
||||
<import addon="xbmc.python" version="3.0.0" />
|
||||
<import addon="script.module.requests" />
|
||||
|
||||
@@ -119,6 +119,7 @@ from metadata_utils import (
|
||||
from tmdb import TmdbCastMember, TmdbExternalIds, fetch_external_ids, fetch_tv_episode_credits, lookup_movie, lookup_tv_season, lookup_tv_season_summary, lookup_tv_show
|
||||
from core.metadata import _resolve_tmdb_api_key
|
||||
from core.router import Router
|
||||
from hosters import ALL_HOSTERS, normalize_hoster_name
|
||||
|
||||
_router = Router()
|
||||
|
||||
@@ -618,18 +619,69 @@ def _get_setting_int(setting_id: str, *, default: int = 0) -> int:
|
||||
return default
|
||||
|
||||
|
||||
_PREFERRED_HOSTERS_LIST = [
|
||||
"voe", "streamtape", "doodstream", "vidoza", "mixdrop", "supervideo", "dropload",
|
||||
]
|
||||
_PREFERRED_HOSTERS_LIST = [h["id"] for h in ALL_HOSTERS]
|
||||
|
||||
|
||||
def _get_preferred_hoster() -> str:
|
||||
"""Liest preferred_hoster (enum-Index) und gibt den Hosternamen zurueck."""
|
||||
raw = _get_setting_string("preferred_hoster").strip()
|
||||
raw_int = _get_setting_int("preferred_hoster", default=-1)
|
||||
_log(f"preferred_hoster raw_string='{raw}' raw_int={raw_int}", xbmc.LOGINFO)
|
||||
# getSettingString liefert bei enum den Display-Wert (z.B. "voe"), nicht den Index.
|
||||
# Prüfe ob raw bereits ein bekannter Hoster-Name ist.
|
||||
if raw.casefold() in [h.casefold() for h in _PREFERRED_HOSTERS_LIST]:
|
||||
return raw
|
||||
# Fallback: Index-basiert über getSettingInt
|
||||
if raw_int >= 0:
|
||||
try:
|
||||
return _PREFERRED_HOSTERS_LIST[raw_int]
|
||||
except IndexError:
|
||||
pass
|
||||
# Fallback: Index aus String
|
||||
try:
|
||||
return _PREFERRED_HOSTERS_LIST[int(raw)]
|
||||
except (ValueError, IndexError):
|
||||
return raw # Fallback: Textwert direkt verwenden
|
||||
return raw
|
||||
|
||||
|
||||
def _get_blocked_hosters() -> set[str]:
|
||||
"""Gibt die Menge der gesperrten Hoster-IDs zurück."""
|
||||
raw = _get_setting_string("blocked_hosters").strip()
|
||||
if not raw:
|
||||
return set()
|
||||
return {h.strip().casefold() for h in raw.split(",") if h.strip()}
|
||||
|
||||
|
||||
def _filter_hosters(hosters: list[str], blocked: set[str]) -> list[str]:
|
||||
"""Entfernt gesperrte Hoster aus der Liste. Unbekannte Hoster bleiben erhalten."""
|
||||
if not blocked:
|
||||
return hosters
|
||||
result = []
|
||||
for h in hosters:
|
||||
hid = normalize_hoster_name(h)
|
||||
if hid and hid.casefold() in blocked:
|
||||
_log(f"Hoster '{h}' ist gesperrt und wird entfernt.", xbmc.LOGDEBUG)
|
||||
continue
|
||||
result.append(h)
|
||||
return result
|
||||
|
||||
|
||||
def _configure_blocked_hosters_dialog() -> None:
|
||||
"""Multi-Select-Dialog zum Sperren/Entsperren von Hostern."""
|
||||
blocked = _get_blocked_hosters()
|
||||
labels = [h["display"] for h in ALL_HOSTERS]
|
||||
preselected = [i for i, h in enumerate(ALL_HOSTERS) if h["id"].casefold() in blocked]
|
||||
|
||||
result = xbmcgui.Dialog().multiselect("Gesperrte Hoster auswaehlen", labels, preselect=preselected)
|
||||
if result is None:
|
||||
return # Abgebrochen
|
||||
|
||||
blocked_ids = sorted(ALL_HOSTERS[i]["id"] for i in result)
|
||||
_set_setting_string("blocked_hosters", ",".join(blocked_ids))
|
||||
count = len(blocked_ids)
|
||||
msg = f"{count} Hoster gesperrt" if count else "Keine Hoster gesperrt"
|
||||
xbmcgui.Dialog().notification("Hoster-Sperrung", msg, xbmcgui.NOTIFICATION_INFO, 3000)
|
||||
_log(f"Gesperrte Hoster gespeichert: {blocked_ids}", xbmc.LOGINFO)
|
||||
|
||||
|
||||
def _metadata_policy(
|
||||
@@ -1258,7 +1310,28 @@ RESOLVEURL_ADDON_ID = "script.module.resolveurl"
|
||||
RESOLVEURL_AUTO_INSTALL_INTERVAL_SEC = 6 * 60 * 60
|
||||
YTDLP_ADDON_ID = "script.module.yt-dlp"
|
||||
TMDB_HELPER_ADDON_ID = "plugin.video.themoviedb.helper"
|
||||
TMDB_HELPER_PLAYERS_DIR = Path.home() / ".kodi" / "addons" / TMDB_HELPER_ADDON_ID / "resources" / "players"
|
||||
|
||||
|
||||
def _kodi_userdata_dir() -> Path:
|
||||
"""Ermittelt das Kodi-Userdata-Verzeichnis plattformübergreifend."""
|
||||
import platform
|
||||
system = platform.system()
|
||||
if system == "Windows":
|
||||
appdata = os.environ.get("APPDATA") or os.environ.get("LOCALAPPDATA") or ""
|
||||
if appdata:
|
||||
return Path(appdata) / "Kodi" / "userdata"
|
||||
if system == "Darwin":
|
||||
return Path.home() / "Library" / "Application Support" / "Kodi" / "userdata"
|
||||
# Linux, LibreELEC, OSMC, Flatpak-Fallback → ~/.kodi/userdata
|
||||
flatpak = Path.home() / ".var" / "app" / "tv.kodi.Kodi" / "data" / "userdata"
|
||||
if flatpak.exists():
|
||||
return flatpak
|
||||
return Path.home() / ".kodi" / "userdata"
|
||||
|
||||
|
||||
def _tmdb_helper_players_dir() -> Path:
|
||||
"""Gibt das players/-Verzeichnis im TMDb-Helper-Addon-Data-Ordner zurück."""
|
||||
return _kodi_userdata_dir() / "addon_data" / TMDB_HELPER_ADDON_ID / "players"
|
||||
|
||||
|
||||
def _selected_update_channel() -> int:
|
||||
@@ -1768,10 +1841,11 @@ def _install_tmdb_helper_players() -> None:
|
||||
if not source_files:
|
||||
xbmcgui.Dialog().notification("TMDb Helper", "Keine Player-Dateien gefunden.", xbmcgui.NOTIFICATION_WARNING, 4000)
|
||||
return
|
||||
TMDB_HELPER_PLAYERS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
dest_dir = _tmdb_helper_players_dir()
|
||||
dest_dir.mkdir(parents=True, exist_ok=True)
|
||||
import shutil
|
||||
for src in source_files:
|
||||
shutil.copy2(src, TMDB_HELPER_PLAYERS_DIR / src.name)
|
||||
shutil.copy2(src, dest_dir / src.name)
|
||||
_log(f"TMDb Helper Player installiert: {[f.name for f in source_files]}")
|
||||
xbmcgui.Dialog().notification("TMDb Helper", f"{len(source_files)} Player installiert.", xbmcgui.NOTIFICATION_INFO, 3000)
|
||||
except Exception as exc:
|
||||
@@ -4543,6 +4617,9 @@ def _play_episode(
|
||||
forced_hoster = (forced_hoster or "").strip()
|
||||
autoplay = _get_setting_bool("autoplay_enabled", default=False)
|
||||
preferred = _get_preferred_hoster()
|
||||
blocked = _get_blocked_hosters()
|
||||
available_hosters = _filter_hosters(available_hosters, blocked)
|
||||
_log(f"Autoplay={autoplay}, preferred='{preferred}', blocked={blocked}, hosters={available_hosters}", xbmc.LOGINFO)
|
||||
if available_hosters:
|
||||
if forced_hoster:
|
||||
for hoster in available_hosters:
|
||||
@@ -4671,6 +4748,9 @@ def _play_episode_url(
|
||||
selected_hoster: str | None = None
|
||||
autoplay = _get_setting_bool("autoplay_enabled", default=False)
|
||||
preferred = _get_preferred_hoster()
|
||||
blocked = _get_blocked_hosters()
|
||||
available_hosters = _filter_hosters(available_hosters, blocked)
|
||||
_log(f"Autoplay={autoplay}, preferred='{preferred}', blocked={blocked}, hosters={available_hosters}", xbmc.LOGINFO)
|
||||
if available_hosters:
|
||||
if autoplay and preferred:
|
||||
pref_lower = preferred.casefold()
|
||||
@@ -5518,6 +5598,11 @@ def _route_install_tmdb_helper_players(params: dict[str, str]) -> None:
|
||||
_install_tmdb_helper_players()
|
||||
|
||||
|
||||
@_router.route("configure_blocked_hosters")
|
||||
def _route_configure_blocked_hosters(params: dict[str, str]) -> None:
|
||||
_configure_blocked_hosters_dialog()
|
||||
|
||||
|
||||
@_router.route("choose_source")
|
||||
def _route_choose_source(params: dict[str, str]) -> None:
|
||||
_show_choose_source(params.get("title", ""), params.get("plugins", ""))
|
||||
|
||||
33
addon/hosters.py
Normal file
33
addon/hosters.py
Normal file
@@ -0,0 +1,33 @@
|
||||
"""Zentrale Hoster-Definitionen für ViewIT."""
|
||||
|
||||
ALL_HOSTERS: list[dict] = [
|
||||
{"id": "voe", "display": "VOE", "aliases": ["voe", "voe.sx"]},
|
||||
{"id": "streamtape", "display": "Streamtape", "aliases": ["streamtape", "streamtape.com"]},
|
||||
{"id": "doodstream", "display": "Doodstream", "aliases": ["doodstream", "dood", "ds2play", "playmogo"]},
|
||||
{"id": "vidoza", "display": "Vidoza", "aliases": ["vidoza", "vidoza.net"]},
|
||||
{"id": "mixdrop", "display": "Mixdrop", "aliases": ["mixdrop", "mixdrop.co"]},
|
||||
{"id": "supervideo", "display": "Supervideo", "aliases": ["supervideo", "supervideo.tv"]},
|
||||
{"id": "dropload", "display": "Dropload", "aliases": ["dropload", "dropload.io"]},
|
||||
]
|
||||
|
||||
|
||||
def get_hoster_ids() -> list[str]:
|
||||
return [h["id"] for h in ALL_HOSTERS]
|
||||
|
||||
|
||||
def get_display_names() -> list[str]:
|
||||
return [h["display"] for h in ALL_HOSTERS]
|
||||
|
||||
|
||||
def normalize_hoster_name(name: str) -> str | None:
|
||||
"""Wandelt Display-Name oder Alias in Hoster-ID um. Gibt None zurück wenn unbekannt."""
|
||||
key = (name or "").casefold().strip()
|
||||
for h in ALL_HOSTERS:
|
||||
if key == h["id"].casefold():
|
||||
return h["id"]
|
||||
if any(key == a.casefold() for a in h["aliases"]):
|
||||
return h["id"]
|
||||
# Substring-Fallback: "Voe Stream" → "voe"
|
||||
if key and h["id"].casefold() in key:
|
||||
return h["id"]
|
||||
return None
|
||||
BIN
addon/icon.png
BIN
addon/icon.png
Binary file not shown.
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 858 KiB |
@@ -7,15 +7,9 @@
|
||||
"assert" : {
|
||||
"play_movie": ["title"],
|
||||
"play_episode": ["showname", "season", "episode"],
|
||||
"search_movie": ["title"],
|
||||
"search_episode": ["showname"]
|
||||
"search_movie": ["title"]
|
||||
},
|
||||
"play_movie" : "plugin://plugin.video.viewit/?action=play_direct&plugin=Serienstream&type=movie&query={title_url}",
|
||||
"play_episode" : "plugin://plugin.video.viewit/?action=play_direct&plugin=Serienstream&type=episode&query={showname_url}&season={season}&episode={episode}",
|
||||
"search_movie" : [
|
||||
"plugin://plugin.video.viewit/?action=plugin_search&plugin=Serienstream&query={title_url}"
|
||||
],
|
||||
"search_episode" : [
|
||||
"plugin://plugin.video.viewit/?action=plugin_search&plugin=Serienstream&query={showname_url}"
|
||||
]
|
||||
"play_movie" : "plugin://plugin.video.viewit/?action=play_direct&plugin=Serienstream&type=movie&query={title}",
|
||||
"play_episode" : "plugin://plugin.video.viewit/?action=play_direct&plugin=Serienstream&type=episode&query={showname}&season={season}&episode={episode}",
|
||||
"search_movie" : "plugin://plugin.video.viewit/?action=plugin_search&plugin=Serienstream&query={title}"
|
||||
}
|
||||
|
||||
@@ -142,6 +142,9 @@
|
||||
</category>
|
||||
|
||||
<category label="Tools">
|
||||
<setting id="blocked_hosters" type="text" label="" default="" visible="false" />
|
||||
<setting id="configure_blocked_hosters" type="action" label="Gesperrte Hoster konfigurieren" action="RunPlugin(plugin://plugin.video.viewit/?action=configure_blocked_hosters)" option="close" />
|
||||
<setting type="lsep" label="TMDb Helper" />
|
||||
<setting id="tmdb_helper_status" type="text" label="TMDb Helper Status" default="-" enable="false" />
|
||||
<setting id="install_tmdb_helper_players" type="action" label="TMDb Helper Player installieren" action="RunPlugin(plugin://plugin.video.viewit/?action=install_tmdb_helper_players)" option="close" enable="eq(-1,Installiert)" />
|
||||
</category>
|
||||
|
||||
Reference in New Issue
Block a user