From 18db89399d2da378c3b78a10308e0f050f9ec51b Mon Sep 17 00:00:00 2001 From: Scarriffle Date: Fri, 9 Oct 2026 16:02:29 +0200 Subject: [PATCH] Ein leeres Jahrfeld ist eine Angabe, kein Versehen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wer bei der Zuordnung kein Jahr einträgt, sagt damit, dass er keines weiss. Der Server reichte trotzdem eines nach — das aus dem Dateinamen —, und das leere Feld hatte überhaupt keine Wirkung. Gerade bei einem falsch benannten Film ist der Dateiname aber die unzuverlässigste Quelle, die es gibt: „Plan B (2010)" heisst bei TMDB „DivertiMento – Plan B" und ist von 2011. Mit dem nachgereichten 2010 kam nie ein Treffer, und es gab keinen Weg daran vorbei. Ohne Angabe wird jetzt ohne Jahr gesucht. Der Platzhalter sagt es auch. Auf der Detailseite stand im Feld bisher das Jahr der bestehenden Zuordnung — also genau der, die gerade korrigiert werden soll. „Doctor Strange" war auf ein Making-of von 2022 gelaufen; mit dessen Jahr konnte der richtige Film von 2016 gar nicht erscheinen. Das Feld bleibt jetzt leer, und leer heisst überall dasselbe. Co-Authored-By: Claude Opus 5 --- .../src/Flaro.Api/Endpoints/MatchEndpoints.cs | 26 +++++---- .../Flaro.Api.Tests/MatchCorrectionTests.cs | 54 ++++++++++++++++++- server/tests/Flaro.Api.Tests/MetadataTests.cs | 21 ++++++-- web/app/src/views/detail.ts | 23 +++++--- web/app/src/zuordnung.ts | 6 ++- 5 files changed, 105 insertions(+), 25 deletions(-) diff --git a/server/src/Flaro.Api/Endpoints/MatchEndpoints.cs b/server/src/Flaro.Api/Endpoints/MatchEndpoints.cs index 0c008e9..cce758a 100644 --- a/server/src/Flaro.Api/Endpoints/MatchEndpoints.cs +++ b/server/src/Flaro.Api/Endpoints/MatchEndpoints.cs @@ -253,15 +253,21 @@ public static class MatchEndpoints // — nicht der angezeigte Titel, der ja gerade der falsche ist. var vorschläge = await anbieter.SearchMoviesAsync( string.IsNullOrWhiteSpace(query) ? film.ParsedTitle : query.Trim(), - // **Das Jahr aus dem Dateinamen, nicht das aus der Zuordnung.** + // **Kein Jahr heisst: ohne Jahr suchen.** // - // Hier stand `film.Year` — und das kommt von genau der - // Zuordnung, die gerade korrigiert werden soll. „Doctor - // Strange" war fälschlich auf ein Making-of von 2022 - // gelaufen; die Suche hängte daraufhin `year=2022` an, und der - // richtige Film von 2016 konnte gar nicht mehr auftauchen. Ein - // falscher Treffer verhinderte so seine eigene Korrektur. - year ?? film.ParsedYear); + // Die Maske trägt das Jahr aus dem Dateinamen schon ein; wer + // es herausnimmt, sagt damit, dass er es nicht weiss. Hier + // stand ein Rückfall auf eben dieses Jahr — das leere Feld + // hatte also keine Wirkung, und ein falsch benannter Film + // liess sich nicht finden. „Plan B (2010)" heisst bei TMDB + // „DivertiMento – Plan B" und ist von 2011; mit dem Jahr aus + // dem Dateinamen kam nie ein Treffer. + // + // Davor stand hier `film.Year`, also das Jahr aus der + // Zuordnung, die gerade korrigiert werden soll — ein falscher + // Treffer verhinderte so seine eigene Korrektur. Auch das ist + // damit erledigt. + year); return Results.Ok(vorschläge.Select(v => new MatchCandidate(v.ProviderId, v.Title, v.Year, v.Overview, v.Poster?.Url)).ToList()); @@ -319,8 +325,8 @@ public static class MatchEndpoints var vorschläge = await anbieter.SearchSeriesAsync( string.IsNullOrWhiteSpace(query) ? serie.ParsedTitle : query.Trim(), - // Siehe oben: aus dem Dateinamen, nicht aus der Zuordnung. - year ?? serie.ParsedYear); + // Siehe oben: ein leeres Jahr ist eine Angabe, kein Fehlen. + year); return Results.Ok(vorschläge.Select(v => new MatchCandidate(v.ProviderId, v.Title, v.Year, v.Overview, v.Poster?.Url)).ToList()); diff --git a/server/tests/Flaro.Api.Tests/MatchCorrectionTests.cs b/server/tests/Flaro.Api.Tests/MatchCorrectionTests.cs index 8826c4b..e3a8e0e 100644 --- a/server/tests/Flaro.Api.Tests/MatchCorrectionTests.cs +++ b/server/tests/Flaro.Api.Tests/MatchCorrectionTests.cs @@ -65,8 +65,18 @@ public class MatchCorrectionTests public Task FindMovieAsync(string t, int? j, CancellationToken ct = default) => Task.FromResult(Falsch); - public Task> SearchMoviesAsync(string t, int? j, CancellationToken ct = default) => - Task.FromResult>([Falsch, Richtig]); + /// Womit zuletzt gesucht wurde — die Prüfungen unten lesen es. + public static int? ZuletztesJahr { get; private set; } + public static bool Gefragt { get; private set; } + + public Task> SearchMoviesAsync(string t, int? j, CancellationToken ct = default) + { + ZuletztesJahr = j; + Gefragt = true; + return Task.FromResult>([Falsch, Richtig]); + } + + public static void Vergessen() { ZuletztesJahr = null; Gefragt = false; } public Task GetMovieAsync(int id, CancellationToken ct = default) => Task.FromResult( @@ -133,6 +143,46 @@ public class MatchCorrectionTests Assert.That(vorschläge!.Select(v => v.Title), Does.Contain("Dark")); } + /// Ein leeres Jahrfeld heisst „ich weiss es nicht", nicht „nimm das vom Dateinamen". + /// + /// + /// Der Anlass. „Plan B (2010)" heisst bei TMDB „DivertiMento – + /// Plan B" und ist von 2011. Wer das Jahr aus der Maske herausnahm, um + /// ohne es zu suchen, bekam trotzdem keinen Treffer: der Server reichte + /// das Jahr aus dem Dateinamen nach. Das leere Feld hatte damit gar + /// keine Wirkung, und ein falsch benannter Film war von Hand nicht zu + /// finden. + /// + [Test] + public async Task Ohne_Jahr_wird_wirklich_ohne_Jahr_gesucht() + { + var (client, film) = await Eingelesen(beiwerkSchreiben: false); + ZweiTreffer.Vergessen(); + + await client.GetFromJsonAsync>( + $"/api/v1/movies/{film.Id}/matches?query=Plan%20B"); + + Assert.Multiple(() => + { + Assert.That(ZweiTreffer.Gefragt, Is.True, "die Suche muss überhaupt stattgefunden haben"); + Assert.That(ZweiTreffer.ZuletztesJahr, Is.Null, + "das Jahr aus dem Dateinamen darf nicht nachgereicht werden"); + }); + } + + /// Ein angegebenes Jahr geht unverändert weiter. + [Test] + public async Task Ein_angegebenes_Jahr_kommt_an() + { + var (client, film) = await Eingelesen(beiwerkSchreiben: false); + ZweiTreffer.Vergessen(); + + await client.GetFromJsonAsync>( + $"/api/v1/movies/{film.Id}/matches?query=Plan%20B&year=2011"); + + Assert.That(ZweiTreffer.ZuletztesJahr, Is.EqualTo(2011)); + } + [Test] public async Task Eine_Korrektur_greift_sofort() { diff --git a/server/tests/Flaro.Api.Tests/MetadataTests.cs b/server/tests/Flaro.Api.Tests/MetadataTests.cs index 11c0818..da268d2 100644 --- a/server/tests/Flaro.Api.Tests/MetadataTests.cs +++ b/server/tests/Flaro.Api.Tests/MetadataTests.cs @@ -885,15 +885,25 @@ public class MetadataTests /// Eine falsche Zuordnung darf ihre eigene Korrektur nicht verhindern. /// /// + /// /// Aus dem echten Bestand. „Doctor Strange" war fälschlich auf ein /// Making-of von 2022 gelaufen. Beim Korrigieren hängte die Suche /// year=2022 an — aus genau der Zuordnung, die gerade weg sollte — /// und lieferte nur noch Titel von 2022. Der richtige Film von 2016 konnte - /// gar nicht erscheinen. Gesucht wird deshalb mit dem Jahr aus dem - /// Dateinamen, nie mit dem aus dem Treffer. + /// gar nicht erscheinen. + /// + /// + /// Danach stand hier das Jahr aus dem Dateinamen, und auch das war + /// falsch. Ein leeres Jahrfeld heisst „ich weiss es nicht" — und + /// gerade bei einem falsch benannten Film ist der Dateiname die + /// unzuverlässigste Quelle, die es gibt. „Plan B (2010)" heisst bei TMDB + /// „DivertiMento – Plan B" und ist von 2011; mit dem nachgereichten 2010 + /// kam nie ein Treffer, und das leere Feld hatte keine Wirkung. Ohne + /// Angabe wird jetzt ohne Jahr gesucht. + /// /// [Test] - public async Task Die_Vorschlagssuche_nimmt_das_Jahr_aus_dem_Dateinamen() + public async Task Die_Vorschlagssuche_nimmt_ohne_Angabe_gar_kein_Jahr() { Datei("Doctor Strange (2016).mkv"); var anbieter = new VorgegebenerAnbieter @@ -916,8 +926,9 @@ public class MetadataTests await client.GetFromJsonAsync>( $"/api/v1/movies/{filme.Items[0].Id}/matches"); - Assert.That(anbieter.Gefragt, Does.Contain("suchFilm:Doctor Strange:2016"), - "Gesucht wird mit 2016 aus dem Dateinamen, nicht mit 2022 aus dem Treffer."); + Assert.That(anbieter.Gefragt, Does.Contain("suchFilm:Doctor Strange:"), + "Ohne Angabe wird ohne Jahr gesucht — weder mit 2022 aus dem Treffer " + + "noch mit 2016 aus dem Dateinamen."); } /// Zwei Dateien auf denselben Film zu legen ist kein Fehler. diff --git a/web/app/src/views/detail.ts b/web/app/src/views/detail.ts index a75420a..c6a402f 100644 --- a/web/app/src/views/detail.ts +++ b/web/app/src/views/detail.ts @@ -79,7 +79,7 @@ export function detailseite(art: Art, id: string, zurueck: () => void): HTMLElem dateiliste(eintrag.files, eintrag.id, eintrag.state), besetzung(eintrag.credits), aehnlichereihe(eintrag.id), - zuordnungsbereich(eintrag.title, eintrag.year)); + zuordnungsbereich(eintrag.title)); } else { const eintrag = await serieLaden(id); wurzel.innerHTML = ''; @@ -91,7 +91,7 @@ export function detailseite(art: Art, id: string, zurueck: () => void): HTMLElem kopfbereich(eintrag, eintrag.state, null), await staffeln(eintrag), besetzung(eintrag.credits), - zuordnungsbereich(eintrag.title, eintrag.year)); + zuordnungsbereich(eintrag.title)); } } catch (fehler) { wurzel.innerHTML = ''; @@ -842,7 +842,7 @@ export function detailseite(art: Art, id: string, zurueck: () => void): HTMLElem /* ---------- Zuordnung korrigieren ---------- */ - function zuordnungsbereich(titel: string, jahr: number | null): HTMLElement { + function zuordnungsbereich(titel: string): HTMLElement { const bereich = document.createElement('section'); if (!istAdmin()) return bereich; @@ -852,19 +852,28 @@ export function detailseite(art: Art, id: string, zurueck: () => void): HTMLElem oeffner.onclick = () => { oeffner.remove(); - bereich.appendChild(zuordnungsmaske(titel, jahr)); + bereich.appendChild(zuordnungsmaske(titel)); }; return bereich; } - function zuordnungsmaske(titel: string, jahr: number | null): HTMLElement { + function zuordnungsmaske(titel: string): HTMLElement { const maske = document.createElement('div'); maske.className = 'einstellungen'; const suche = feld('Anderer Suchbegriff'); suche.value = titel; - const jahrfeld = feld('Jahr', 'number'); - if (jahr) jahrfeld.value = String(jahr); + // **Das Feld bleibt leer, und das ist Absicht.** + // + // Hier stand das Jahr der bestehenden Zuordnung — also genau der + // Zuordnung, die gerade korrigiert werden soll. „Doctor Strange" war + // auf ein Making-of von 2022 gelaufen; mit dessen Jahr in der Suche + // konnte der richtige Film von 2016 gar nicht erscheinen. Ein falscher + // Treffer verhinderte so seine eigene Korrektur. + // + // Leer heisst jetzt überall dasselbe: ohne Jahr suchen. Der Server + // reicht keines mehr nach. + const jahrfeld = feld('Jahr — leer: unbekannt', 'number'); const suchen = knopf('Suchen', 'btn'); const reihe = document.createElement('div'); diff --git a/web/app/src/zuordnung.ts b/web/app/src/zuordnung.ts index baa4893..a78a88f 100644 --- a/web/app/src/zuordnung.ts +++ b/web/app/src/zuordnung.ts @@ -114,7 +114,11 @@ export function zuordnungsflaeche( // Leer heisst: der Server nimmt das Jahr aus dem Dateinamen. Hier etwas // vorzutragen, das aus der zu korrigierenden Zuordnung stammt, hiesse die // Suche auf genau den falschen Jahrgang einzugrenzen. - const jahrfeld = feld('Jahr (aus dem Dateinamen)', 'number'); + // **Leer heisst: unbekannt.** Das Jahr aus dem Dateinamen steht schon + // drin; wer es herausnimmt, sucht ohne Jahr. Der Server fiel hier + // früher auf eben dieses Jahr zurück — das leere Feld hatte damit + // keine Wirkung. + const jahrfeld = feld('Jahr — leer: unbekannt', 'number'); if (jahr) jahrfeld.value = String(jahr); const suchen = knopf('Suchen', 'btn');