dev: harden resolver bootstrap and simplify update settings
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<addon id="plugin.video.viewit" name="ViewIt" version="0.1.62-dev" provider-name="ViewIt">
|
||||
<addon id="plugin.video.viewit" name="ViewIt" version="0.1.63-dev" provider-name="ViewIt">
|
||||
<requires>
|
||||
<import addon="xbmc.python" version="3.0.0" />
|
||||
<import addon="script.module.requests" />
|
||||
<import addon="script.module.beautifulsoup4" />
|
||||
<import addon="script.module.resolveurl" />
|
||||
</requires>
|
||||
<extension point="xbmc.python.pluginsource" library="default.py">
|
||||
<provides>video</provides>
|
||||
|
||||
182
addon/default.py
182
addon/default.py
@@ -954,12 +954,6 @@ 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"
|
||||
@@ -976,6 +970,8 @@ UPDATE_CHANNEL_CUSTOM = 2
|
||||
AUTO_UPDATE_INTERVAL_SEC = 6 * 60 * 60
|
||||
UPDATE_HTTP_TIMEOUT_SEC = 8
|
||||
UPDATE_ADDON_ID = "plugin.video.viewit"
|
||||
RESOLVEURL_ADDON_ID = "script.module.resolveurl"
|
||||
RESOLVEURL_AUTO_INSTALL_INTERVAL_SEC = 6 * 60 * 60
|
||||
|
||||
|
||||
def _selected_update_channel() -> int:
|
||||
@@ -1030,10 +1026,7 @@ def _resolve_update_info_url() -> str:
|
||||
raw = _get_setting_string("update_repo_url")
|
||||
else:
|
||||
raw = _get_setting_string("update_repo_url_main")
|
||||
info_url = _normalize_update_info_url(raw)
|
||||
# Legacy-Setting beibehalten, damit bestehende Installationen und alte Builds weiterlaufen.
|
||||
_set_setting_string("update_repo_url", info_url)
|
||||
return info_url
|
||||
return _normalize_update_info_url(raw)
|
||||
|
||||
|
||||
def _read_text_url(url: str, *, timeout: int = UPDATE_HTTP_TIMEOUT_SEC) -> str:
|
||||
@@ -1247,25 +1240,10 @@ def _install_addon_version(info_url: str, version: str) -> bool:
|
||||
|
||||
def _sync_update_channel_status_settings() -> None:
|
||||
channel = _selected_update_channel()
|
||||
channel_label = _channel_label(channel)
|
||||
|
||||
selected_info_url = _resolve_update_info_url()
|
||||
main_info_url = _normalize_update_info_url(_get_setting_string("update_repo_url_main"))
|
||||
nightly_info_url = _normalize_update_info_url(_get_setting_string("update_repo_url_nightly"))
|
||||
|
||||
available_main = _fetch_repo_addon_version(main_info_url)
|
||||
available_nightly = _fetch_repo_addon_version(nightly_info_url)
|
||||
if channel == UPDATE_CHANNEL_MAIN:
|
||||
available_selected = available_main
|
||||
elif channel == UPDATE_CHANNEL_NIGHTLY:
|
||||
available_selected = available_nightly
|
||||
else:
|
||||
available_selected = _fetch_repo_addon_version(selected_info_url)
|
||||
|
||||
_set_setting_string("update_active_channel", channel_label)
|
||||
available_selected = _fetch_repo_addon_version(selected_info_url)
|
||||
_set_setting_string("update_active_channel", _channel_label(channel))
|
||||
_set_setting_string("update_active_repo_url", selected_info_url)
|
||||
_set_setting_string("update_available_main", available_main)
|
||||
_set_setting_string("update_available_nightly", available_nightly)
|
||||
_set_setting_string("update_available_selected", available_selected)
|
||||
|
||||
|
||||
@@ -1306,11 +1284,6 @@ def _update_repository_source(info_url: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _settings_key_for_plugin(name: str) -> str:
|
||||
safe = re.sub(r"[^a-z0-9]+", "_", (name or "").strip().casefold()).strip("_")
|
||||
return f"update_version_{safe}" if safe else "update_version_unknown"
|
||||
|
||||
|
||||
def _installed_addon_version_from_disk() -> str:
|
||||
if xbmcvfs is None:
|
||||
return "0.0.0"
|
||||
@@ -1328,6 +1301,96 @@ def _installed_addon_version_from_disk() -> str:
|
||||
return "0.0.0"
|
||||
|
||||
|
||||
def _is_addon_installed(addon_id: str) -> bool:
|
||||
addon_id = str(addon_id or "").strip()
|
||||
if not addon_id:
|
||||
return False
|
||||
has_addon = getattr(xbmc, "getCondVisibility", None)
|
||||
if callable(has_addon):
|
||||
try:
|
||||
return bool(has_addon(f"System.HasAddon({addon_id})"))
|
||||
except Exception:
|
||||
pass
|
||||
if xbmcvfs is None:
|
||||
return False
|
||||
try:
|
||||
addon_xml = xbmcvfs.translatePath(f"special://home/addons/{addon_id}/addon.xml")
|
||||
except Exception:
|
||||
return False
|
||||
return bool(addon_xml and os.path.exists(addon_xml))
|
||||
|
||||
|
||||
def _sync_resolveurl_status_setting() -> None:
|
||||
status = "Installiert" if _is_addon_installed(RESOLVEURL_ADDON_ID) else "Fehlt"
|
||||
_set_setting_string("resolveurl_status", status)
|
||||
|
||||
|
||||
def _install_kodi_addon(addon_id: str, *, wait_seconds: int) -> bool:
|
||||
if _is_addon_installed(addon_id):
|
||||
return True
|
||||
builtin = getattr(xbmc, "executebuiltin", None)
|
||||
if not callable(builtin):
|
||||
return False
|
||||
try:
|
||||
builtin(f"InstallAddon({addon_id})")
|
||||
builtin("UpdateLocalAddons")
|
||||
except Exception as exc:
|
||||
_log(f"InstallAddon fehlgeschlagen ({addon_id}): {exc}", xbmc.LOGWARNING)
|
||||
return False
|
||||
|
||||
if wait_seconds <= 0:
|
||||
return _is_addon_installed(addon_id)
|
||||
deadline = time.time() + max(1, int(wait_seconds))
|
||||
while time.time() < deadline:
|
||||
if _is_addon_installed(addon_id):
|
||||
return True
|
||||
time.sleep(1)
|
||||
return _is_addon_installed(addon_id)
|
||||
|
||||
|
||||
def _ensure_resolveurl_installed(*, force: bool, silent: bool) -> bool:
|
||||
if _is_addon_installed(RESOLVEURL_ADDON_ID):
|
||||
_sync_resolveurl_status_setting()
|
||||
return True
|
||||
if not force and not _get_setting_bool("resolveurl_auto_install", default=True):
|
||||
_sync_resolveurl_status_setting()
|
||||
return False
|
||||
|
||||
now = int(time.time())
|
||||
if not force:
|
||||
last_try = _get_setting_int("resolveurl_last_ts", default=0)
|
||||
if last_try > 0 and (now - last_try) < RESOLVEURL_AUTO_INSTALL_INTERVAL_SEC:
|
||||
return False
|
||||
_set_setting_string("resolveurl_last_ts", str(now))
|
||||
|
||||
wait_seconds = 20 if force else 0
|
||||
ok = _install_kodi_addon(RESOLVEURL_ADDON_ID, wait_seconds=wait_seconds)
|
||||
_sync_resolveurl_status_setting()
|
||||
|
||||
if not silent:
|
||||
if ok:
|
||||
xbmcgui.Dialog().notification(
|
||||
"ResolveURL",
|
||||
"script.module.resolveurl ist installiert.",
|
||||
xbmcgui.NOTIFICATION_INFO,
|
||||
4000,
|
||||
)
|
||||
else:
|
||||
xbmcgui.Dialog().notification(
|
||||
"ResolveURL",
|
||||
"Installation fehlgeschlagen. Bitte Repository/Netzwerk pruefen.",
|
||||
xbmcgui.NOTIFICATION_ERROR,
|
||||
5000,
|
||||
)
|
||||
return ok
|
||||
|
||||
|
||||
def _maybe_auto_install_resolveurl(action: str | None) -> None:
|
||||
if (action or "").strip():
|
||||
return
|
||||
_ensure_resolveurl_installed(force=False, silent=True)
|
||||
|
||||
|
||||
def _sync_update_version_settings() -> None:
|
||||
addon_version = _installed_addon_version_from_disk()
|
||||
if addon_version == "0.0.0":
|
||||
@@ -1337,24 +1400,8 @@ def _sync_update_version_settings() -> None:
|
||||
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)
|
||||
_set_setting_string("update_installed_version", addon_version)
|
||||
|
||||
versions = {
|
||||
"update_version_serienstream": "-",
|
||||
"update_version_aniworld": "-",
|
||||
"update_version_einschalten": "-",
|
||||
"update_version_topstreamfilm": "-",
|
||||
"update_version_filmpalast": "-",
|
||||
"update_version_doku_streams": "-",
|
||||
}
|
||||
for plugin in _discover_plugins().values():
|
||||
key = _settings_key_for_plugin(str(plugin.name))
|
||||
if key in versions:
|
||||
versions[key] = _plugin_version(plugin)
|
||||
for key, value in versions.items():
|
||||
_set_setting_string(key, value)
|
||||
|
||||
_sync_resolveurl_status_setting()
|
||||
_sync_update_channel_status_settings()
|
||||
|
||||
|
||||
@@ -3543,14 +3590,18 @@ def _show_version_selector() -> None:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
confirm_choice = xbmcgui.Dialog().select(
|
||||
"Version installieren",
|
||||
[
|
||||
f"Installieren: {version}",
|
||||
"Abbrechen",
|
||||
],
|
||||
)
|
||||
if confirm_choice != 0:
|
||||
dialog = xbmcgui.Dialog()
|
||||
try:
|
||||
confirmed = dialog.yesno(
|
||||
"Version installieren",
|
||||
f"Installiert: {installed}",
|
||||
f"Ausgewaehlt: {version}",
|
||||
yeslabel="Installieren",
|
||||
nolabel="Abbrechen",
|
||||
)
|
||||
except TypeError:
|
||||
confirmed = dialog.yesno("Version installieren", f"Installiert: {installed}", f"Ausgewaehlt: {version}")
|
||||
if not confirmed:
|
||||
return
|
||||
|
||||
xbmcgui.Dialog().notification("Updates", f"Installation gestartet: {version}", xbmcgui.NOTIFICATION_INFO, 2500)
|
||||
@@ -3609,6 +3660,10 @@ def _is_cloudflare_challenge_error(message: str) -> bool:
|
||||
return "cloudflare" in text or "challenge" in text or "attention required" in text
|
||||
|
||||
|
||||
def _is_resolveurl_missing_error(message: str) -> bool:
|
||||
return str(message or "").strip().casefold() == "resolveurl missing"
|
||||
|
||||
|
||||
def _play_final_link(
|
||||
link: str,
|
||||
*,
|
||||
@@ -3743,6 +3798,11 @@ def _play_episode(
|
||||
resolved_link = plugin.resolve_stream_link(link)
|
||||
if not resolved_link:
|
||||
err = _resolveurl_last_error()
|
||||
if _is_resolveurl_missing_error(err):
|
||||
_log("ResolveURL fehlt: versuche Auto-Installation.", xbmc.LOGWARNING)
|
||||
_ensure_resolveurl_installed(force=True, silent=True)
|
||||
resolved_link = plugin.resolve_stream_link(link)
|
||||
err = _resolveurl_last_error()
|
||||
if _is_cloudflare_challenge_error(err):
|
||||
_log(f"ResolveURL Cloudflare-Challenge: {err}", xbmc.LOGWARNING)
|
||||
xbmcgui.Dialog().notification(
|
||||
@@ -3853,6 +3913,11 @@ def _play_episode_url(
|
||||
resolved_link = plugin.resolve_stream_link(link)
|
||||
if not resolved_link:
|
||||
err = _resolveurl_last_error()
|
||||
if _is_resolveurl_missing_error(err):
|
||||
_log("ResolveURL fehlt: versuche Auto-Installation.", xbmc.LOGWARNING)
|
||||
_ensure_resolveurl_installed(force=True, silent=True)
|
||||
resolved_link = plugin.resolve_stream_link(link)
|
||||
err = _resolveurl_last_error()
|
||||
if _is_cloudflare_challenge_error(err):
|
||||
_log(f"ResolveURL Cloudflare-Challenge: {err}", xbmc.LOGWARNING)
|
||||
xbmcgui.Dialog().notification(
|
||||
@@ -3914,6 +3979,7 @@ def run() -> None:
|
||||
action = params.get("action")
|
||||
_log(f"Action: {action}", xbmc.LOGDEBUG)
|
||||
_maybe_run_auto_update_check(action)
|
||||
_maybe_auto_install_resolveurl(action)
|
||||
if action == "search":
|
||||
_show_search()
|
||||
elif action == "plugin_menu":
|
||||
@@ -3991,6 +4057,8 @@ def run() -> None:
|
||||
_apply_update_channel()
|
||||
elif action == "select_update_version":
|
||||
_show_version_selector()
|
||||
elif action == "install_resolveurl":
|
||||
_ensure_resolveurl_installed(force=True, silent=False)
|
||||
elif action == "seasons":
|
||||
_show_seasons(params.get("plugin", ""), params.get("title", ""), params.get("series_url", ""))
|
||||
elif action == "episodes":
|
||||
|
||||
@@ -23,6 +23,7 @@ def resolve(url: str) -> Optional[str]:
|
||||
try:
|
||||
import resolveurl # type: ignore
|
||||
except Exception:
|
||||
_LAST_RESOLVE_ERROR = "resolveurl missing"
|
||||
return None
|
||||
|
||||
try:
|
||||
@@ -36,7 +37,10 @@ def resolve(url: str) -> Optional[str]:
|
||||
resolver = getattr(hmf, "resolve", None)
|
||||
if callable(resolver):
|
||||
result = resolver()
|
||||
return str(result) if result else None
|
||||
if result:
|
||||
return str(result)
|
||||
_LAST_RESOLVE_ERROR = "unresolved"
|
||||
return None
|
||||
except Exception as exc:
|
||||
_LAST_RESOLVE_ERROR = str(exc or "")
|
||||
pass
|
||||
@@ -45,7 +49,10 @@ def resolve(url: str) -> Optional[str]:
|
||||
resolve_fn = getattr(resolveurl, "resolve", None)
|
||||
if callable(resolve_fn):
|
||||
result = resolve_fn(url)
|
||||
return str(result) if result else None
|
||||
if result:
|
||||
return str(result)
|
||||
_LAST_RESOLVE_ERROR = "unresolved"
|
||||
return None
|
||||
except Exception as exc:
|
||||
_LAST_RESOLVE_ERROR = str(exc or "")
|
||||
return None
|
||||
|
||||
@@ -40,24 +40,18 @@
|
||||
<setting id="apply_update_channel" type="action" label="Update-Kanal jetzt anwenden" action="RunPlugin(plugin://plugin.video.viewit/?action=apply_update_channel)" option="close" />
|
||||
<setting id="auto_update_enabled" type="bool" label="Automatische Updates (beim Start pruefen)" default="false" />
|
||||
<setting id="select_update_version" type="action" label="Version waehlen und installieren" action="RunPlugin(plugin://plugin.video.viewit/?action=select_update_version)" option="close" />
|
||||
<setting id="install_resolveurl" type="action" label="ResolveURL installieren/reparieren" action="RunPlugin(plugin://plugin.video.viewit/?action=install_resolveurl)" option="close" />
|
||||
<setting id="resolveurl_auto_install" type="bool" label="ResolveURL automatisch installieren (beim Start pruefen)" default="true" />
|
||||
<setting id="update_installed_version" type="text" label="Installierte Version" default="-" enable="false" />
|
||||
<setting id="update_available_selected" type="text" label="Verfuegbar (gewaehlter Kanal)" default="-" enable="false" />
|
||||
<setting id="update_available_main" type="text" label="Verfuegbar Main" default="-" enable="false" />
|
||||
<setting id="update_available_nightly" type="text" label="Verfuegbar Nightly" default="-" enable="false" />
|
||||
<setting id="resolveurl_status" type="text" label="ResolveURL Status" default="-" enable="false" />
|
||||
<setting id="update_active_channel" type="text" label="Aktiver Kanal" default="-" enable="false" />
|
||||
<setting id="update_active_repo_url" type="text" label="Aktive Repo URL" default="-" enable="false" />
|
||||
<setting id="update_info" type="text" label="Updates laufen ueber den normalen Kodi-Update-Mechanismus." default="" enable="false" />
|
||||
<setting id="update_repo_url_main" type="text" label="Main URL (addons.xml)" default="https://gitea.it-drui.de/viewit/ViewIT-Kodi-Repo/raw/branch/main/addons.xml" />
|
||||
<setting id="update_repo_url_nightly" type="text" label="Nightly URL (addons.xml)" default="https://gitea.it-drui.de/viewit/ViewIT-Kodi-Repo/raw/branch/nightly/addons.xml" />
|
||||
<setting id="update_repo_url" type="text" label="Custom URL (addons.xml)" default="https://gitea.it-drui.de/viewit/ViewIT-Kodi-Repo/raw/branch/nightly/addons.xml" />
|
||||
<setting id="auto_update_last_ts" type="text" label="Auto-Update letzte Pruefung (intern)" default="0" visible="false" />
|
||||
<setting id="update_version_addon" type="text" label="ViewIT Version" default="-" visible="false" />
|
||||
<setting id="update_version_serienstream" type="text" label="SerienStream Version" default="-" visible="false" />
|
||||
<setting id="update_version_aniworld" type="text" label="AniWorld Version" default="-" visible="false" />
|
||||
<setting id="update_version_einschalten" type="text" label="Einschalten Version" default="-" visible="false" />
|
||||
<setting id="update_version_topstreamfilm" type="text" label="TopStream Version" default="-" visible="false" />
|
||||
<setting id="update_version_filmpalast" type="text" label="Filmpalast Version" default="-" visible="false" />
|
||||
<setting id="update_version_doku_streams" type="text" label="Doku-Streams Version" default="-" visible="false" />
|
||||
<setting id="resolveurl_last_ts" type="text" label="ResolveURL letzte Pruefung (intern)" default="0" visible="false" />
|
||||
</category>
|
||||
|
||||
<category label="Debug Global">
|
||||
|
||||
Reference in New Issue
Block a user