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');