- 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:
@@ -348,13 +348,45 @@ def rip_titel_auswahl(device_path: str, output_dir: str, titel_liste: list,
|
||||
return {"status": "success", "output_dir": output_dir, "files": alle_dateien}
|
||||
|
||||
|
||||
def laengster_titel(dauern: dict):
|
||||
"""Titel-Nummer mit der längsten Laufzeit — der Hauptfilm (pure Funktion)."""
|
||||
def laengster_titel(dauern: dict, meta: dict = None):
|
||||
"""Titel-Nummer für den Hauptfilm (pure Funktion).
|
||||
|
||||
Mit meta['runtime'] wird heuristisch der Titel gesucht, dessen Laufzeit am nächsten
|
||||
an der TMDB-Laufzeit liegt (vermeidet 'Play All'-Tracks, die länger als der Film sind).
|
||||
Ohne runtime wird klassisch der längste Titel gewählt.
|
||||
"""
|
||||
if not dauern:
|
||||
return None
|
||||
|
||||
ziel_s = (meta.get("runtime") or 0) * 60 if meta else 0
|
||||
if ziel_s > 0:
|
||||
bester = min(dauern, key=lambda t: abs(dauern[t] - ziel_s))
|
||||
if abs(dauern[bester] - ziel_s) <= 20 * 60:
|
||||
return bester
|
||||
|
||||
return max(dauern, key=dauern.get)
|
||||
|
||||
|
||||
def episoden_titel(dauern: dict, meta: dict) -> list:
|
||||
"""Findet Episoden-Titel anhand der TMDB-Episoden-Laufzeiten.
|
||||
|
||||
Toleranz: +/- 10 Minuten (600 Sekunden) zum Durchschnitt.
|
||||
Gibt eine sortierte Liste der gefundenen Titelnummern zurück.
|
||||
"""
|
||||
if not dauern or not meta or not meta.get("episode_runtimes"):
|
||||
return []
|
||||
|
||||
runtimes_s = [r * 60 for r in meta["episode_runtimes"]]
|
||||
avg_runtime = sum(runtimes_s) / len(runtimes_s)
|
||||
|
||||
gefundene_titel = []
|
||||
for titel, dauer in dauern.items():
|
||||
if abs(dauer - avg_runtime) <= 10 * 60:
|
||||
gefundene_titel.append(int(titel))
|
||||
|
||||
return sorted(gefundene_titel)
|
||||
|
||||
|
||||
def lies_titel_dauern(device_path: str, timeout: int = 300) -> dict:
|
||||
"""Fragt die Titel-Laufzeiten der Disc ab (makemkvcon info, Robot-Mode)."""
|
||||
try:
|
||||
@@ -832,15 +864,14 @@ def run_makemkv(device_path: str, output_dir: str, progress_cb=None, titel: str
|
||||
|
||||
def rip_video(device_path: str, disc_id: str, disc_type: str = "dvd", progress_cb=None,
|
||||
output_dir: str = None, nur_hauptfilm: bool = False,
|
||||
titel_liste: list = None, log_cb=None) -> dict:
|
||||
titel_liste: list = None, log_cb=None, meta: dict = None) -> dict:
|
||||
"""Rippt eine DVD oder Blu-ray verlustfrei mit MakeMKV.
|
||||
|
||||
Bewusst KEIN eigener Celery-Task: der einzige Task ist worker.tasks.rip_disc,
|
||||
der hier mit seinem eigenen Fortschritts-Callback durchgreift. output_dir
|
||||
überschreibt das Ziel (Transcode-Fall: Roh-Rip nach /app/temp).
|
||||
titel_liste: exakte Titel-Auswahl aus dem UI (schlägt nur_hauptfilm).
|
||||
nur_hauptfilm: Vorab-Info-Lauf, dann nur den LÄNGSTEN Titel rippen —
|
||||
das löst das eingestellte (vorher wirkungslose) mainFeatureOnly ein.
|
||||
nur_hauptfilm: Vorab-Info-Lauf, dann heuristisch den besten Titel rippen.
|
||||
"""
|
||||
if output_dir is None:
|
||||
output_dir = os.path.join(RIP_OUTPUT_DIR, disc_type, disc_id)
|
||||
@@ -849,10 +880,18 @@ def rip_video(device_path: str, disc_id: str, disc_type: str = "dvd", progress_c
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
return rip_titel_auswahl(device_path, output_dir, titel_liste, progress_cb, log_cb)
|
||||
|
||||
# Serien-Erkennung: Wenn keine Titel explizit gewählt wurden und es eine Serie ist
|
||||
if meta and meta.get("series") and meta.get("episode_runtimes"):
|
||||
dauern = lies_titel_dauern(device_path)
|
||||
episoden = episoden_titel(dauern, meta)
|
||||
if episoden:
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
return rip_titel_auswahl(device_path, output_dir, episoden, progress_cb, log_cb)
|
||||
|
||||
titel = "all"
|
||||
if nur_hauptfilm:
|
||||
dauern = lies_titel_dauern(device_path)
|
||||
haupt = laengster_titel(dauern)
|
||||
haupt = laengster_titel(dauern, meta)
|
||||
if haupt is not None:
|
||||
titel = str(haupt)
|
||||
# Kein Titel ermittelbar → ehrlich auf 'all' zurückfallen statt raten
|
||||
|
||||
Reference in New Issue
Block a user