diff --git a/docker/api/prescan/prescan.py b/docker/api/prescan/prescan.py index 890afe6..b4b86ef 100644 --- a/docker/api/prescan/prescan.py +++ b/docker/api/prescan/prescan.py @@ -6,11 +6,11 @@ lieferte seitdem immer „Unknown Disc". Dies ist die echte Logik, bereinigt. """ import os -import shutil import subprocess from typing import Dict, List, Optional from rippy import drives as _laufwerks_schicht +from rippy.tools import katalog as werkzeug_katalog from clients.tmdb import TMDBClient from clients.jikan import JikanClient from clients.musicbrainz import MusicBrainzClient @@ -346,10 +346,19 @@ class PreScan: if label: toc["title"] = normalize_disc_label(label) - # Titel-Quelle 2 (optional, falls makemkvcon doch da ist): - if shutil.which("makemkvcon"): + # Titel-Quelle 3: die Titelliste von makemkvcon (optional). + # + # ⚠️ Über den Werkzeug-Katalog, NICHT über `shutil.which` + # (Befund 28.08.2026). `which` sucht nur im PATH — unter + # Windows liegen Programme in „Programme", nicht im PATH. + # Gemessen: `shutil.which("makemkvcon")` gibt dort auch bei + # installiertem MakeMKV None zurück, und dieser Zweig lief + # NIE. Genau derselbe Fehler, für den es `tools/katalog.py` + # gibt. + makemkv = werkzeug_katalog.finden("makemkv") + if makemkv: result = subprocess.run( - ["makemkvcon", "-r", "--noscan", "--minlength=300", "info", f"dev:{device_path}"], + [makemkv, "-r", "--noscan", "--minlength=300", "info", f"dev:{device_path}"], capture_output=True, text=True, timeout=120 diff --git a/docker/api/test_prescan_helpers.py b/docker/api/test_prescan_helpers.py index 6222360..2d63565 100644 --- a/docker/api/test_prescan_helpers.py +++ b/docker/api/test_prescan_helpers.py @@ -144,3 +144,72 @@ def test_ohne_jede_quelle_bleibt_es_unbekannt(monkeypatch): assert ergebnis.confidence == 0.3 assert ergebnis.metadata["type"] == "unknown" assert ergebnis.title == "Nix Da" + + +# ── Was auf FREMDEN Rechnern gilt (Befund 28.08.2026) ─────────────────── +# +# Der Commander: "du hast jetzt nur mein laufwerk analysiert oder? wenn ich +# rippy weitergebe wie laeuft es dort?" +# +# Berechtigt. Gemessen wurde an EINEM Laufwerk (LG BU40N) und EINER Disc +# (BD-50 mit BDMV/META). Diese Tests halten fest, was bei ANDEREN Discs +# passieren muss -- ohne dass eine davon vorhanden sein muss. +def test_bluray_ohne_metadaten_gibt_ehrlich_nichts_zurueck(tmp_path): + """Sehr viele Blu-rays haben kein BDMV/META. Dann greift der Rueckfall + auf das Volume-Label -- aber diese Funktion darf nichts erfinden.""" + from prescan.prescan import titel_aus_bdmt + + (tmp_path / "BDMV" / "STREAM").mkdir(parents=True) + assert titel_aus_bdmt(str(tmp_path)) is None + + +def test_dvd_hat_kein_bdmv(tmp_path): + from prescan.prescan import titel_aus_bdmt + + (tmp_path / "VIDEO_TS").mkdir() + assert titel_aus_bdmt(str(tmp_path)) is None + + +def test_bdmt_wird_gelesen_wenn_da(tmp_path): + """Der Weg, der bei der Disc des Commanders 'Evangelion 2.22' lieferte — + hier ohne Disc nachgestellt.""" + from prescan.prescan import titel_aus_bdmt + + meta = tmp_path / "BDMV" / "META" / "DL" + meta.mkdir(parents=True) + (meta / "bdmt_deu.xml").write_text( + '' + 'Evangelion 2.22' + '', encoding="utf-8") + assert titel_aus_bdmt(str(tmp_path)) == "Evangelion 2.22" + + +def test_englisch_wird_bevorzugt(tmp_path): + """Die APIs suchen mit englischen Titeln besser.""" + from prescan.prescan import titel_aus_bdmt + + meta = tmp_path / "BDMV" / "META" / "DL" + meta.mkdir(parents=True) + for datei, name in (("bdmt_deu.xml", "Deutscher Titel"), + ("bdmt_eng.xml", "English Title")): + (meta / datei).write_text( + "%s" % name, encoding="utf-8") + assert titel_aus_bdmt(str(tmp_path)) == "English Title" + + +def test_makemkvcon_wird_ueber_den_katalog_gesucht(): + """DER Fehler: `shutil.which("makemkvcon")` gibt unter Windows auch bei + installiertem MakeMKV None zurueck -- Windows-Programme liegen in + „Programme", nicht im PATH. Dieser Zweig lief dort also NIE.""" + import os + + hier = os.path.dirname(os.path.abspath(__file__)) + with open(os.path.join(hier, "prescan", "prescan.py"), encoding="utf-8") as f: + # NUR Code, keine Kommentare: Der erste Anlauf dieses Tests fiel ueber + # den eigenen Erklaertext, in dem der alte Aufruf zitiert wird. Ein + # Waechter, der an einer Erklaerung scheitert, prueft das Falsche. + code = [z for z in f if not z.strip().startswith("#")] + quelle = "".join(code) + assert "shutil.which(" not in quelle, ( + "shutil.which findet unter Windows keine Programme aus 'Programme'") + assert 'werkzeug_katalog.finden("makemkv")' in quelle