Add configurable update source and update-only version display
This commit is contained in:
129
addon/default.py
129
addon/default.py
@@ -16,6 +16,7 @@ import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import xml.etree.ElementTree as ET
|
||||
from pathlib import Path
|
||||
from types import ModuleType
|
||||
from urllib.parse import parse_qs, urlencode
|
||||
@@ -401,6 +402,27 @@ def _get_setting_bool(setting_id: str, *, default: bool = False) -> bool:
|
||||
return default
|
||||
|
||||
|
||||
def _set_setting_string(setting_id: str, value: str) -> None:
|
||||
if xbmcaddon is None:
|
||||
return
|
||||
addon = _get_addon()
|
||||
if addon is None:
|
||||
return
|
||||
setter = getattr(addon, "setSettingString", None)
|
||||
if callable(setter):
|
||||
try:
|
||||
setter(setting_id, str(value))
|
||||
return
|
||||
except TypeError:
|
||||
return
|
||||
setter = getattr(addon, "setSetting", None)
|
||||
if callable(setter):
|
||||
try:
|
||||
setter(setting_id, str(value))
|
||||
except TypeError:
|
||||
return
|
||||
|
||||
|
||||
def _apply_video_info(item, info_labels: dict[str, object] | None, cast: list[TmdbCastMember] | None) -> None:
|
||||
"""Setzt Metadaten bevorzugt via InfoTagVideo (Kodi v20+), mit Fallback auf deprecated APIs."""
|
||||
|
||||
@@ -883,6 +905,84 @@ def _add_directory_item(
|
||||
xbmcplugin.addDirectoryItem(handle=handle, url=url, listitem=item, isFolder=is_folder)
|
||||
|
||||
|
||||
def _plugin_version(plugin: BasisPlugin) -> str:
|
||||
raw = getattr(plugin, "version", "0.0.0")
|
||||
text = str(raw or "").strip()
|
||||
return text or "0.0.0"
|
||||
|
||||
|
||||
def _normalize_update_info_url(raw: str) -> str:
|
||||
value = str(raw or "").strip()
|
||||
default = "http://127.0.0.1:8080/repo/addons.xml"
|
||||
if not value:
|
||||
return default
|
||||
if value.endswith("/addons.xml"):
|
||||
return value
|
||||
return value.rstrip("/") + "/addons.xml"
|
||||
|
||||
|
||||
def _repo_addon_xml_path() -> str:
|
||||
if xbmcvfs is None:
|
||||
return ""
|
||||
try:
|
||||
return xbmcvfs.translatePath("special://home/addons/repository.viewit/addon.xml")
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
|
||||
def _update_repository_source(info_url: str) -> bool:
|
||||
path = _repo_addon_xml_path()
|
||||
if not path:
|
||||
return False
|
||||
if not os.path.exists(path):
|
||||
return False
|
||||
try:
|
||||
tree = ET.parse(path)
|
||||
root = tree.getroot()
|
||||
dir_node = root.find(".//dir")
|
||||
if dir_node is None:
|
||||
return False
|
||||
info = dir_node.find("info")
|
||||
checksum = dir_node.find("checksum")
|
||||
datadir = dir_node.find("datadir")
|
||||
if info is None or checksum is None or datadir is None:
|
||||
return False
|
||||
base = info_url[: -len("/addons.xml")] if info_url.endswith("/addons.xml") else info_url.rstrip("/")
|
||||
info.text = info_url
|
||||
checksum.text = f"{base}/addons.xml.md5"
|
||||
datadir.text = f"{base}/"
|
||||
tree.write(path, encoding="utf-8", xml_declaration=True)
|
||||
return True
|
||||
except Exception as exc:
|
||||
_log(f"Repository-URL konnte nicht gesetzt werden: {exc}", xbmc.LOGWARNING)
|
||||
return False
|
||||
|
||||
|
||||
def _sync_update_version_settings() -> None:
|
||||
addon = _get_addon()
|
||||
addon_version = "0.0.0"
|
||||
if addon is not None:
|
||||
try:
|
||||
addon_version = str(addon.getAddonInfo("version") or "0.0.0")
|
||||
except Exception:
|
||||
addon_version = "0.0.0"
|
||||
_set_setting_string("update_version_addon", addon_version)
|
||||
|
||||
versions = {
|
||||
"update_version_serienstream": "-",
|
||||
"update_version_aniworld": "-",
|
||||
"update_version_einschalten": "-",
|
||||
"update_version_topstreamfilm": "-",
|
||||
"update_version_filmpalast": "-",
|
||||
}
|
||||
for plugin in _discover_plugins().values():
|
||||
key = f"update_version_{str(plugin.name).strip().lower()}"
|
||||
if key in versions:
|
||||
versions[key] = _plugin_version(plugin)
|
||||
for key, value in versions.items():
|
||||
_set_setting_string(key, value)
|
||||
|
||||
|
||||
def _show_root_menu() -> None:
|
||||
handle = _get_handle()
|
||||
_log("Root-Menue wird angezeigt.")
|
||||
@@ -890,8 +990,7 @@ def _show_root_menu() -> None:
|
||||
|
||||
plugins = _discover_plugins()
|
||||
for plugin_name in sorted(plugins.keys(), key=lambda value: value.casefold()):
|
||||
display = f"{plugin_name}"
|
||||
_add_directory_item(handle, display, "plugin_menu", {"plugin": plugin_name}, is_folder=True)
|
||||
_add_directory_item(handle, plugin_name, "plugin_menu", {"plugin": plugin_name}, is_folder=True)
|
||||
|
||||
_add_directory_item(handle, "Einstellungen", "settings")
|
||||
xbmcplugin.endOfDirectory(handle)
|
||||
@@ -2245,10 +2344,34 @@ def _open_settings() -> None:
|
||||
"""Oeffnet das Kodi-Addon-Settings-Dialog."""
|
||||
if xbmcaddon is None: # pragma: no cover - outside Kodi
|
||||
raise RuntimeError("xbmcaddon ist nicht verfuegbar (KodiStub).")
|
||||
_sync_update_version_settings()
|
||||
addon = xbmcaddon.Addon()
|
||||
addon.openSettings()
|
||||
|
||||
|
||||
def _run_update_check() -> None:
|
||||
"""Stoesst Kodi-Repo- und Addon-Updates an und informiert den Benutzer."""
|
||||
if xbmc is None: # pragma: no cover - outside Kodi
|
||||
return
|
||||
try:
|
||||
info_url = _normalize_update_info_url(_get_setting_string("update_repo_url"))
|
||||
_set_setting_string("update_repo_url", info_url)
|
||||
_sync_update_version_settings()
|
||||
_update_repository_source(info_url)
|
||||
builtin = getattr(xbmc, "executebuiltin", None)
|
||||
if callable(builtin):
|
||||
builtin("UpdateAddonRepos")
|
||||
builtin("UpdateLocalAddons")
|
||||
builtin("ActivateWindow(addonbrowser,addons://updates/)")
|
||||
xbmcgui.Dialog().notification("ViewIT Update", "Update-Pruefung gestartet.", xbmcgui.NOTIFICATION_INFO, 4000)
|
||||
except Exception as exc:
|
||||
_log(f"Update-Pruefung fehlgeschlagen: {exc}", xbmc.LOGWARNING)
|
||||
try:
|
||||
xbmcgui.Dialog().notification("ViewIT Update", "Update-Pruefung fehlgeschlagen.", xbmcgui.NOTIFICATION_ERROR, 4000)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _extract_first_int(value: str) -> int | None:
|
||||
match = re.search(r"(\d+)", value or "")
|
||||
if not match:
|
||||
@@ -2599,6 +2722,8 @@ def run() -> None:
|
||||
)
|
||||
elif action == "settings":
|
||||
_open_settings()
|
||||
elif action == "check_updates":
|
||||
_run_update_check()
|
||||
elif action == "seasons":
|
||||
_show_seasons(params.get("plugin", ""), params.get("title", ""), params.get("series_url", ""))
|
||||
elif action == "episodes":
|
||||
|
||||
@@ -11,6 +11,7 @@ class BasisPlugin(ABC):
|
||||
"""Abstrakte Basisklasse fuer alle Integrationen."""
|
||||
|
||||
name: str
|
||||
version: str = "0.0.0"
|
||||
|
||||
@abstractmethod
|
||||
async def search_titles(self, query: str) -> List[str]:
|
||||
|
||||
@@ -691,6 +691,7 @@ def search_animes(query: str) -> List[SeriesResult]:
|
||||
|
||||
class AniworldPlugin(BasisPlugin):
|
||||
name = "Aniworld"
|
||||
version = "1.0.0"
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._anime_results: Dict[str, SeriesResult] = {}
|
||||
|
||||
@@ -507,6 +507,7 @@ class EinschaltenPlugin(BasisPlugin):
|
||||
"""Metadata-Plugin für eine autorisierte Quelle."""
|
||||
|
||||
name = "Einschalten"
|
||||
version = "1.0.0"
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.is_available = REQUESTS_AVAILABLE
|
||||
|
||||
@@ -219,6 +219,7 @@ def _get_soup(url: str, *, session: Optional[RequestsSession] = None) -> Beautif
|
||||
|
||||
class FilmpalastPlugin(BasisPlugin):
|
||||
name = "Filmpalast"
|
||||
version = "1.0.0"
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._title_to_url: Dict[str, str] = {}
|
||||
|
||||
@@ -784,6 +784,7 @@ class SerienstreamPlugin(BasisPlugin):
|
||||
"""Downloader-Plugin, das Serien von s.to ueber requests/bs4 bereitstellt."""
|
||||
|
||||
name = "Serienstream"
|
||||
version = "1.0.0"
|
||||
POPULAR_GENRE_LABEL = "⭐ Beliebte Serien"
|
||||
|
||||
def __init__(self) -> None:
|
||||
|
||||
@@ -123,6 +123,7 @@ class TopstreamfilmPlugin(BasisPlugin):
|
||||
"""Integration fuer eine HTML-basierte Suchseite."""
|
||||
|
||||
name = "Topstreamfilm"
|
||||
version = "1.0.0"
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._session: RequestsSession | None = None
|
||||
|
||||
@@ -61,4 +61,15 @@
|
||||
<setting id="tmdb_log_requests" type="bool" label="TMDB API Requests loggen" default="false" />
|
||||
<setting id="tmdb_log_responses" type="bool" label="TMDB API Antworten loggen" default="false" />
|
||||
</category>
|
||||
<category label="Update">
|
||||
<setting id="update_repo_url" type="text" label="Update-URL (addons.xml)" default="http://127.0.0.1:8080/repo/addons.xml" />
|
||||
<setting id="run_update_check" type="action" label="Jetzt auf Updates pruefen" action="RunPlugin(plugin://plugin.video.viewit/?action=check_updates)" option="close" />
|
||||
<setting id="update_info" type="text" label="Kodi-Repository-Updates werden ueber den Kodi-Update-Mechanismus verarbeitet." default="" enable="false" />
|
||||
<setting id="update_version_addon" type="text" label="ViewIT Addon Version" default="-" enable="false" />
|
||||
<setting id="update_version_serienstream" type="text" label="Serienstream Plugin Version" default="-" enable="false" />
|
||||
<setting id="update_version_aniworld" type="text" label="Aniworld Plugin Version" default="-" enable="false" />
|
||||
<setting id="update_version_einschalten" type="text" label="Einschalten Plugin Version" default="-" enable="false" />
|
||||
<setting id="update_version_topstreamfilm" type="text" label="Topstreamfilm Plugin Version" default="-" enable="false" />
|
||||
<setting id="update_version_filmpalast" type="text" label="Filmpalast Plugin Version" default="-" enable="false" />
|
||||
</category>
|
||||
</settings>
|
||||
|
||||
Reference in New Issue
Block a user