„Schon durchsucht" und „hat eine Marke" sind zwei verschiedene Dinge

Genau dazwischen fehlte die Unterscheidung. Ein Film, bei dem die Suche
einmal nichts fand, trägt einen Vermerk und keine Marke — und war damit
für jeden weiteren Lauf erledigt, obwohl er der interessanteste Fall ist.
Es gab nur alles oder nichts, und der Knopf bei der Mediathek schickte
immer „alles": 453 Filme mal zwanzig Minuten Schlüsselbilder, auch für
die vierhundert, bei denen längst etwas stand.

Aus `bool erneut` wird `Markenumfang` mit drei Werten. `Neue` ist, was
der Scan tut, und ändert sich nicht. `Luecken` nimmt sich vor, wo keine
Marke steht — gleich ob dort schon einmal gesucht wurde. `Alles` ist der
alte Holzhammer.

Bei der Mediathek jetzt zwei Knöpfe, weil es zwei Fragen sind: „Fehlende
Marken suchen" ist die alltägliche, „Alles neu durchsuchen" die seltene
und teure, und deren Rückfrage nennt die Zahl der Titel. Auf der
Detailseite bleibt es bei einem Knopf mit „alles" — wer ihn bei genau
diesem Titel drückt, ist mit genau diesem Titel unzufrieden.

Bei einer Serie wird eine Staffel ganz gelesen, sobald einer ihrer
Folgen etwas fehlt. Billiger ginge es nur, indem man die Lücke gar nicht
erst angeht, und genau dafür drückt jemand den Knopf.

Vier Prüfungen am Endpunkt, die messen, ob der Lauf den Film anfasst:
`Neue` überspringt den Durchsuchten, `Luecken` nimmt ihn sich vor,
`Alles` sowieso, und ein Film mit Marke bleibt bei `Luecken` in Ruhe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-15 14:20:47 +02:00
co-authored by Claude Opus 5
parent f2752e6c05
commit f79ecf2757
6 changed files with 271 additions and 54 deletions
@@ -893,11 +893,12 @@ public static class LibraryContentEndpoints
// Hintergrundlauf statt einer Antwort, auf die jemand wartet.
// Dasselbe für einen Film — dort sucht der Server im Bild.
app.MapPost("/api/v1/movies/{id:guid}/marken", async (
Guid id, FlaroContext db, Markenerkennung erkennung, bool erneut = false) =>
Guid id, FlaroContext db, Markenerkennung erkennung,
Markenumfang umfang = Markenumfang.Alles) =>
{
if (!await db.Movies.AsNoTracking().AnyAsync(x => x.Id == id)) return Results.NotFound();
_ = erkennung.FilmAsync(id, erneut);
_ = erkennung.FilmAsync(id, umfang);
return Results.Accepted();
}).RequireAuthorization(FlaroPolicies.Administrator);
@@ -914,12 +915,17 @@ public static class LibraryContentEndpoints
return weg > 0 ? Results.NoContent() : Results.NotFound();
}).RequireAuthorization(FlaroPolicies.Administrator);
// **Bei einem einzelnen Titel ist „alles" die Vorgabe.** Wer den
// Knopf bei genau dieser Serie drückt, ist mit genau dieser Serie
// unzufrieden; ihn dann nach Lücken suchen zu lassen hiesse, ihm
// die Antwort zu verweigern, die er haben will.
app.MapPost("/api/v1/series/{id:guid}/marken", async (
Guid id, FlaroContext db, Markenerkennung erkennung, bool erneut = false) =>
Guid id, FlaroContext db, Markenerkennung erkennung,
Markenumfang umfang = Markenumfang.Alles) =>
{
if (!await db.Series.AsNoTracking().AnyAsync(x => x.Id == id)) return Results.NotFound();
return erkennung.Starten(id, erneut)
return erkennung.Starten(id, umfang)
? Results.Accepted()
: Einwand.Belegt("Für diese Serie werden gerade Marken gesucht.");
}).RequireAuthorization(FlaroPolicies.Administrator);
@@ -930,12 +936,13 @@ public static class LibraryContentEndpoints
// einmal. Der Lauf kann Stunden dauern und läuft deshalb im
// Hintergrund weiter; die Antwort kommt sofort.
app.MapPost("/api/v1/libraries/{id:guid}/marken", async (
Guid id, FlaroContext db, Markenerkennung erkennung, bool erneut = false) =>
Guid id, FlaroContext db, Markenerkennung erkennung,
Markenumfang umfang = Markenumfang.Neue) =>
{
if (!await db.Libraries.AsNoTracking().AnyAsync(x => x.Id == id))
return Results.NotFound();
erkennung.MediathekStarten(id, erneut);
erkennung.MediathekStarten(id, umfang);
return Results.Accepted();
}).RequireAuthorization(FlaroPolicies.Administrator);