Compare commits

..

4 Commits

10 changed files with 194 additions and 19 deletions

View File

@@ -1,3 +1,19 @@
## 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
## 0.1.90.0-dev - 2026-04-10
- dev: bump to 0.1.89.5 Changelog aktualisiert
## 0.1.89.5-dev - 2026-04-10
- dev: bump to 0.1.89.0 Changelog komplett
## 0.1.89.0-dev - 2026-04-10
- dev: bump to 0.1.88.5 Changelog fuer aktuelle Version

View File

@@ -1,4 +1,38 @@
## 0.1.89.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.
## 0.1.90.0
**TMDb Helper Integration**
- Einstellungen → Tools: Player-Dateien für TMDb Helper direkt aus ViewIT installierbar
- Zwei Player mitgeliefert: SerienStream (direkte Episodenwiedergabe) und Globale Suche
- Menüpunkt ist ausgegraut wenn TMDb Helper nicht installiert ist
**Metadaten / Poster**
- Poster und Infos werden jetzt korrekt geladen wenn kein eigener TMDb-API-Key eingetragen ist
- „Neueste Episoden" (SerienStream, Aniworld) zeigt jetzt Poster und Serieninfos
**Topstreamfilm**
- „Neueste Titel" entfernt das Feature existiert auf der aktuellen Domain nicht
**Filmpalast**
- Hoster „Veev HD" wird jetzt erkannt und in der Hoster-Liste angezeigt
**Kosmetik**
- Menü-Icons für Hauptmenü, Plugin-Menüs und Trakt-Untermenü
## 0.1.89.5
**TMDb Helper Integration**
- Einstellungen → Tools: Player-Dateien für TMDb Helper direkt aus ViewIT installierbar

View File

@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<addon id="plugin.video.viewit" name="ViewIt" version="0.1.89.5-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" />

View File

@@ -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
View 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 858 KiB

View File

@@ -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}"
}

View File

@@ -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>

View File

@@ -35,6 +35,7 @@ ZIP_NAME="${ADDON_ID}-${ADDON_VERSION}.zip"
ZIP_PATH="${INSTALL_DIR}/${ZIP_NAME}"
CHANGELOG_USER="${SRC_ADDON_DIR}/CHANGELOG-USER.md"
python3 "${ROOT_DIR}/scripts/update_user_changelog.py" --fill "${ADDON_XML}" "${CHANGELOG_USER}" >&2
python3 "${ROOT_DIR}/scripts/update_user_changelog.py" --check "${ADDON_XML}" "${CHANGELOG_USER}" >&2 || exit 1
ADDON_DIR="$("${ROOT_DIR}/scripts/build_install_addon.sh" >/dev/null; echo "${INSTALL_DIR}/${ADDON_ID}")"

View File

@@ -51,4 +51,13 @@ fi
sed -i "s/version=\"${current}\"/version=\"${new_version}\"/" addon/addon.xml
git add addon/addon.xml
# Changelog-Abschnitt von alter auf neue Version umbenennen (nur erstes Vorkommen)
old_clean=$(echo "$version_only")
new_clean=$(echo "$new_version" | sed 's/-[a-zA-Z].*$//')
CHANGELOG="addon/CHANGELOG-USER.md"
if [[ -f "$CHANGELOG" ]]; then
sed -i "0,/^## ${old_clean}$/s//## ${new_clean}/" "$CHANGELOG"
git add "$CHANGELOG"
fi
echo "[hook] Version: $current → $new_version"