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
|
## 0.1.90.5-dev - 2026-04-10
|
||||||
|
|
||||||
- dev: bump to 0.1.90.0 Changelog und Release-Prozess fix
|
- 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**
|
**Allgemein**
|
||||||
- Changelog und Release-Prozess fix.
|
- Changelog und Release-Prozess fix.
|
||||||
- Changelog aktualisiert.
|
|
||||||
|
|
||||||
|
|
||||||
## 0.1.90.0
|
## 0.1.90.0
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?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>
|
<requires>
|
||||||
<import addon="xbmc.python" version="3.0.0" />
|
<import addon="xbmc.python" version="3.0.0" />
|
||||||
<import addon="script.module.requests" />
|
<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 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.metadata import _resolve_tmdb_api_key
|
||||||
from core.router import Router
|
from core.router import Router
|
||||||
|
from hosters import ALL_HOSTERS, normalize_hoster_name
|
||||||
|
|
||||||
_router = Router()
|
_router = Router()
|
||||||
|
|
||||||
@@ -618,18 +619,69 @@ def _get_setting_int(setting_id: str, *, default: int = 0) -> int:
|
|||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
_PREFERRED_HOSTERS_LIST = [
|
_PREFERRED_HOSTERS_LIST = [h["id"] for h in ALL_HOSTERS]
|
||||||
"voe", "streamtape", "doodstream", "vidoza", "mixdrop", "supervideo", "dropload",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def _get_preferred_hoster() -> str:
|
def _get_preferred_hoster() -> str:
|
||||||
"""Liest preferred_hoster (enum-Index) und gibt den Hosternamen zurueck."""
|
"""Liest preferred_hoster (enum-Index) und gibt den Hosternamen zurueck."""
|
||||||
raw = _get_setting_string("preferred_hoster").strip()
|
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:
|
try:
|
||||||
return _PREFERRED_HOSTERS_LIST[int(raw)]
|
return _PREFERRED_HOSTERS_LIST[int(raw)]
|
||||||
except (ValueError, IndexError):
|
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(
|
def _metadata_policy(
|
||||||
@@ -1258,7 +1310,28 @@ RESOLVEURL_ADDON_ID = "script.module.resolveurl"
|
|||||||
RESOLVEURL_AUTO_INSTALL_INTERVAL_SEC = 6 * 60 * 60
|
RESOLVEURL_AUTO_INSTALL_INTERVAL_SEC = 6 * 60 * 60
|
||||||
YTDLP_ADDON_ID = "script.module.yt-dlp"
|
YTDLP_ADDON_ID = "script.module.yt-dlp"
|
||||||
TMDB_HELPER_ADDON_ID = "plugin.video.themoviedb.helper"
|
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:
|
def _selected_update_channel() -> int:
|
||||||
@@ -1768,10 +1841,11 @@ def _install_tmdb_helper_players() -> None:
|
|||||||
if not source_files:
|
if not source_files:
|
||||||
xbmcgui.Dialog().notification("TMDb Helper", "Keine Player-Dateien gefunden.", xbmcgui.NOTIFICATION_WARNING, 4000)
|
xbmcgui.Dialog().notification("TMDb Helper", "Keine Player-Dateien gefunden.", xbmcgui.NOTIFICATION_WARNING, 4000)
|
||||||
return
|
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
|
import shutil
|
||||||
for src in source_files:
|
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]}")
|
_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)
|
xbmcgui.Dialog().notification("TMDb Helper", f"{len(source_files)} Player installiert.", xbmcgui.NOTIFICATION_INFO, 3000)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
@@ -4543,6 +4617,9 @@ def _play_episode(
|
|||||||
forced_hoster = (forced_hoster or "").strip()
|
forced_hoster = (forced_hoster or "").strip()
|
||||||
autoplay = _get_setting_bool("autoplay_enabled", default=False)
|
autoplay = _get_setting_bool("autoplay_enabled", default=False)
|
||||||
preferred = _get_preferred_hoster()
|
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 available_hosters:
|
||||||
if forced_hoster:
|
if forced_hoster:
|
||||||
for hoster in available_hosters:
|
for hoster in available_hosters:
|
||||||
@@ -4671,6 +4748,9 @@ def _play_episode_url(
|
|||||||
selected_hoster: str | None = None
|
selected_hoster: str | None = None
|
||||||
autoplay = _get_setting_bool("autoplay_enabled", default=False)
|
autoplay = _get_setting_bool("autoplay_enabled", default=False)
|
||||||
preferred = _get_preferred_hoster()
|
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 available_hosters:
|
||||||
if autoplay and preferred:
|
if autoplay and preferred:
|
||||||
pref_lower = preferred.casefold()
|
pref_lower = preferred.casefold()
|
||||||
@@ -5518,6 +5598,11 @@ def _route_install_tmdb_helper_players(params: dict[str, str]) -> None:
|
|||||||
_install_tmdb_helper_players()
|
_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")
|
@_router.route("choose_source")
|
||||||
def _route_choose_source(params: dict[str, str]) -> None:
|
def _route_choose_source(params: dict[str, str]) -> None:
|
||||||
_show_choose_source(params.get("title", ""), params.get("plugins", ""))
|
_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" : {
|
"assert" : {
|
||||||
"play_movie": ["title"],
|
"play_movie": ["title"],
|
||||||
"play_episode": ["showname", "season", "episode"],
|
"play_episode": ["showname", "season", "episode"],
|
||||||
"search_movie": ["title"],
|
"search_movie": ["title"]
|
||||||
"search_episode": ["showname"]
|
|
||||||
},
|
},
|
||||||
"play_movie" : "plugin://plugin.video.viewit/?action=play_direct&plugin=Serienstream&type=movie&query={title_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_url}&season={season}&episode={episode}",
|
"play_episode" : "plugin://plugin.video.viewit/?action=play_direct&plugin=Serienstream&type=episode&query={showname}&season={season}&episode={episode}",
|
||||||
"search_movie" : [
|
"search_movie" : "plugin://plugin.video.viewit/?action=plugin_search&plugin=Serienstream&query={title}"
|
||||||
"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}"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,6 +142,9 @@
|
|||||||
</category>
|
</category>
|
||||||
|
|
||||||
<category label="Tools">
|
<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="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)" />
|
<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>
|
</category>
|
||||||
|
|||||||
Reference in New Issue
Block a user