feat: Komplettierung der aktuellen Rippy-Etappe
Ampel / ampel (push) Failing after 29s

- Versionsanzeige für den Windows-Worker im UI inkl. Prüfung
- Absicherung der install.sh gegen fehlendes systemd
- Serien-Episoden-Erkennung und Laufzeitabgleich anhand TMDB-Daten (Heuristik)
- Umstellung der Windows-Worker-Installation auf SchTasks (Dienst-Ersatz)
- Kodi-Bibliotheks-Refresh über JSON-RPC integriert
This commit is contained in:
Hitonabi
2026-07-26 21:13:27 +02:00
parent d15900d1eb
commit e165e2a0d3
9 changed files with 179 additions and 78 deletions
+46 -4
View File
@@ -777,6 +777,18 @@ async def create_job(request: JobCreateRequest):
if request.series and request.series.strip():
meta_dict["series"] = request.series.strip()
meta_dict["season"] = max(1, int(request.season or 1))
# TMDB-Laufzeiten der Episoden holen (für die Erkennung im Worker)
if meta_dict.get("id") and meta_dict.get("type") == "tv":
try:
from clients.tmdb import TMDBClient
staffel = TMDBClient().get_tv_season(meta_dict["id"], meta_dict["season"])
if staffel and "episodes" in staffel:
meta_dict["episode_runtimes"] = [
ep.get("runtime") for ep in staffel["episodes"] if ep.get("runtime")
]
except Exception as e:
print(f"Fehler beim Holen der Staffel-Laufzeiten: {e}")
if request.main_feature_only is not None:
meta_dict["main_feature_only"] = request.main_feature_only
if request.titles:
@@ -1230,7 +1242,10 @@ async def capabilities():
zeile["node"] = node
return zeilen
return {"workers": await asyncio.to_thread(sammle)}
return {
"workers": await asyncio.to_thread(sammle),
"server_version": os.getenv("RIPPY_VERSION", "dev")
}
@app.get("/presets")
@@ -1291,8 +1306,8 @@ class MediaServerRefreshRequest(BaseModel):
@app.post("/mediaserver/refresh")
async def mediaserver_refresh(request: MediaServerRefreshRequest):
"""Bibliotheks-Scan von Jellyfin/Emby anstoßen — auch als Verbindungs-Test
aus den Einstellungen (POST /Library/Refresh, Header X-Emby-Token)."""
"""Bibliotheks-Scan von Jellyfin/Emby/Kodi anstoßen — auch als Verbindungs-Test
aus den Einstellungen."""
import requests as _requests
url = request.url.strip().rstrip("/")
@@ -1300,6 +1315,24 @@ async def mediaserver_refresh(request: MediaServerRefreshRequest):
raise HTTPException(status_code=422, detail="Server-URL muss mit http(s):// beginnen")
def anstossen():
# Fallback für die reine API-Test-Funktion, die den Server-Typ nicht kennt:
# Wir versuchen Kodi (JSON-RPC) und danach Emby/Jellyfin.
# Wenn der User Kodi auswählt, hat er oft Basic Auth konfiguriert.
auth = None
if ":" in request.api_key:
user, pw = request.api_key.split(":", 1)
auth = (user, pw)
try:
# Kodi JSON-RPC
payload = {"jsonrpc": "2.0", "method": "VideoLibrary.Scan", "id": 1}
res = _requests.post(url + "/jsonrpc", json=payload, auth=auth, timeout=5)
if res.status_code < 300:
return res
except:
pass
# Emby / Jellyfin
return _requests.post(
url + "/Library/Refresh",
headers={"X-Emby-Token": request.api_key.strip()}, timeout=15,
@@ -1748,9 +1781,12 @@ async def worker_setup_paket():
if name.endswith(".py") and not name.startswith(("test_", "conftest")):
z.write(os.path.join("worker_dist", name), name)
# requirements.txt für die venv, rippy.ico für die Verknüpfung
# auf dem Desktop (sonst trägt sie das Batch-Standardsymbol).
elif name in ("requirements.txt", "rippy.ico"):
z.write(os.path.join("worker_dist", name), name)
# Write RIPPY_VERSION to version.txt
version_str = os.getenv("RIPPY_VERSION", "dev")
z.writestr("version.txt", version_str)
return puffer.getvalue()
inhalt = await asyncio.to_thread(baue)
@@ -1762,6 +1798,12 @@ async def worker_setup_paket():
)
@app.get("/system/version")
async def system_version():
"""Gibt die aktuelle Rippy-Version des Servers zurück (aus deploy.sh)."""
return {"version": os.getenv("RIPPY_VERSION", "dev")}
@app.get("/system/info")
async def system_info():
"""System-Selbstauskunft (Einstellungen → System): Werkzeug-Versionen der