Files
rippy/docker/api/test_prescan_helpers.py
T
Hitonabi 0c269a97ee fix(metadaten): exakt schlaegt unscharf - Jikan beendet die Kette nur bei Treffer
Der SAVEPOINT v3.16 vermutete, das Aehnlichkeits-Gate 0,55 sei "grosszuegig" und
Jikan stehe in der Kette zu frueh (vor OMDb). Nachgerechnet - titel_aehnlichkeit
ist eine reine Funktion - ergibt sich ein anderes Bild als vermutet:

  "Alien"           vs. "Alien 9"           -> 0,83  TRIFFT
  "Inception"        vs. "Deception"         -> 0,78  TRIFFT
  "Hero"             vs. "Heroman"           -> 0,73  TRIFFT
  "The Dark Knight"  vs. "Dark Knight Rises" -> 0,69  TRIFFT

Ein Kinofilm, den TMDB verpasst, bekam damit Anime-Metadaten mit Confidence
0,85 - und OMDb, das ihn kennt, wurde nie gefragt.

Bemerkenswert dabei, und das widerlegt die Vermutung "einfach zu niedrig": Fuer
den Fall, fuer den Jikan ueberhaupt eingebaut wurde, ist das Gate sogar zu HOCH.
"Evangelion 2.22" gegen den MAL-Titel "Evangelion: 2.0 You Can (Not) Advance"
ergibt 0,51 und faellt durch. Eine einzelne Zahl kann beides nicht leisten.

Deshalb zwei Schwellen statt Umsortieren (Reihenfolge bleibt, AGENTS Regel B):
Nur ein praktisch exakter Titel (>= 0,9) beendet die Kette. Ein unscharfer
Treffer wird GEMERKT, dann wird OMDb gefragt - und erst wenn OMDb nichts hat,
kommt er als VORSCHLAG mit Confidence 0,6 zum Zug. Damit gewinnt "exakt" immer
gegen "unscharf", egal aus welcher Quelle.

Antwort auf die Commander-Frage "JIKAN ist drin - wird das genutzt?": ja, und ab
jetzt an der richtigen Stelle.

Ehrlicher Vorbehalt: Live gegengeprueft ist das nicht - MyAnimeList war waehrend
dieser Sitzung durchweg weg (Jikan antwortete HTTP 504 auf jede Anfrage). Die
Arithmetik des Gates ist davon unberuehrt und in test_jikan_helpers.py
festgehalten, die Kettenlogik in test_prescan_helpers.py.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 12:59:26 +02:00

143 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Tests für die puren Pre-Scan-/OMDb-Helfer (Label-Normalisierung, Parsing)."""
from clients.omdb import parse_runtime_minutes, parse_year
from prescan.prescan import normalize_disc_label, parse_udf_dstring
def test_udf_dstring_latin1():
# d-string: [comp_id=8]["MEIN_FILM"][padding][len=10]
daten = bytes([8]) + b"MEIN_FILM" + bytes(21) + bytes([10])
assert parse_udf_dstring(daten) == "MEIN_FILM"
def test_udf_dstring_utf16():
text = "FILM".encode("utf-16-be")
daten = bytes([16]) + text + bytes(32 - 2 - len(text)) + bytes([1 + len(text)])
assert parse_udf_dstring(daten) == "FILM"
def test_udf_dstring_kaputt_gibt_leer():
assert parse_udf_dstring(b"") == ""
assert parse_udf_dstring(bytes(32)) == "" # Länge 0
daten = bytes([8]) + b"X" + bytes(29) + bytes([99]) # Länge > Puffer
assert parse_udf_dstring(daten) == ""
def test_label_normalisierung():
# Disc-Labels sind fast immer GROSS_MIT_UNTERSTRICHEN
assert normalize_disc_label("PULP_FICTION") == "Pulp Fiction"
assert normalize_disc_label("DIE_HARD_4.0_DE") == "Die Hard 4 0 De"
assert normalize_disc_label(" doppel raum ") == "doppel raum"
assert normalize_disc_label("") == ""
def test_label_mit_gemischter_schreibung_bleibt():
# Wer schon sauber benannt hat, wird nicht plattgewalzt
assert normalize_disc_label("Inception") == "Inception"
def test_omdb_runtime_parsing():
assert parse_runtime_minutes("142 min") == 142
assert parse_runtime_minutes("N/A") == 0
assert parse_runtime_minutes("") == 0
def test_omdb_jahr_parsing():
assert parse_year("1999") == 1999
assert parse_year("20052012") == 2005 # Serien-Zeitspanne
assert parse_year("N/A") is None
assert parse_year("") is None
# --- Reihenfolge der Metadaten-Quellen: exakt schlägt unscharf ---------------
#
# Änderung vom 26.07.2026. Vorher galt der erste Jikan-Treffer über dem Gate
# 0,55 sofort als sicherer Fund, und OMDb kam nie dran — ein Kinofilm, den TMDB
# verpasst, bekam damit Anime-Metadaten. Die Messwerte dazu stehen in
# test_jikan_helpers.py („Alien" gegen „Alien 9" = 0,83).
class _StummerClient:
"""Ein Client, der auf jede Frage dasselbe antwortet — und mitzählt."""
def __init__(self, antwort=None):
self.antwort = antwort
self.aufrufe = 0
def lookup(self, *a, **k):
self.aufrufe += 1
return self.antwort
def search_movie(self, *a, **k):
return []
def search_tv(self, *a, **k):
return []
def get_movie_details(self, *a, **k):
return None
def find_by_imdb(self, *a, **k):
return None
def _scanner(monkeypatch, jikan_antwort, omdb_antwort):
"""PreScan ohne __init__ (das bräuchte DB + API-Keys), Cache stillgelegt."""
from prescan import prescan as modul
monkeypatch.setattr(modul, "get", lambda k: None)
monkeypatch.setattr(modul, "cache_set", lambda *a, **k: None)
scan = modul.PreScan.__new__(modul.PreScan)
scan.tmdb = _StummerClient()
scan.jikan = _StummerClient(jikan_antwort)
scan.omdb = _StummerClient(omdb_antwort)
return scan
def _jikan(score):
return {"type": "movie", "id": "mal-1", "title": "Alien 9",
"source": "jikan", "match_score": score}
def _omdb():
return {"type": "movie", "id": "tt0078748", "title": "Alien",
"source": "omdb", "year": 1979}
def test_unscharfer_jikan_treffer_laesst_omdb_zum_zug(monkeypatch):
"""Der eigentliche Fehler: „Alien" traf mit 0,83 auf den Anime „Alien 9",
und der Film wurde nie gesucht."""
scan = _scanner(monkeypatch, _jikan(0.83), _omdb())
ergebnis = scan._scan_video("/dev/sr0", {"title": "Alien", "disc_type": "Blu-ray"})
assert ergebnis.metadata["source"] == "omdb"
assert ergebnis.confidence == 0.8
assert scan.omdb.aufrufe > 0
def test_exakter_jikan_treffer_gewinnt_sofort(monkeypatch):
"""Der Fall, für den Jikan gebaut wurde, darf NICHT verlorengehen
(AGENTS Regel B): Bei einem sicheren Treffer wird OMDb nicht mehr gefragt."""
scan = _scanner(monkeypatch, _jikan(1.0), _omdb())
ergebnis = scan._scan_video("/dev/sr0", {"title": "Alien 9", "disc_type": "Blu-ray"})
assert ergebnis.metadata["source"] == "jikan"
assert ergebnis.confidence == 0.85
assert scan.omdb.aufrufe == 0
def test_unscharfer_jikan_treffer_bleibt_als_vorschlag(monkeypatch):
"""Hat OMDb nichts (kein Key, kein Treffer), ist der unscharfe Jikan-Treffer
besser als nichts — aber er wird als VORSCHLAG ausgewiesen (0,6), nicht als
sicherer Fund."""
scan = _scanner(monkeypatch, _jikan(0.83), None)
ergebnis = scan._scan_video("/dev/sr0", {"title": "Alien", "disc_type": "Blu-ray"})
assert ergebnis.metadata["source"] == "jikan"
assert ergebnis.confidence == 0.6
def test_ohne_jede_quelle_bleibt_es_unbekannt(monkeypatch):
scan = _scanner(monkeypatch, None, None)
ergebnis = scan._scan_video("/dev/sr0", {"title": "Nix Da", "disc_type": "DVD"})
assert ergebnis.confidence == 0.0
assert ergebnis.metadata == {}