Ein Klick, der nichts tat, und niemand sagte warum

Eine Serienkachel kannte der Server als Titel nicht: „als gesehen markieren"
lief in eine 404, und weil das Kontextmenü die Ablehnung verschluckte, geschah
sichtbar gar nichts. Dasselbe beim Favoriten. UserItemState bekommt eine
Serienkennung, das Häkchen zieht alle Folgen mit, und was wirft, erscheint als
Meldung statt in der Browserkonsole.

Dazu eine Mehrfachauswahl in der Mediathek — gesehen, ungesehen, Metadaten
neu holen für das Gewählte, in einer Anfrage statt in zweihundert. Ein neues
Plakat steht sofort auf der Kachel, und ein Titel, den es nicht mehr gibt,
endet nicht mehr in einer Sackgasse.

Gemessen: ein POST auf /refresh ohne Rumpf antwortete nach der Erweiterung mit
404 — also genau der Aufruf „alles auffrischen", den es länger gibt als die
Auswahl. Der Rumpf wird jetzt von Hand gelesen, und beide Formen stehen in
einer Prüfung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-05 18:28:33 +02:00
co-authored by Claude Opus 5
parent c854c4a09a
commit 557708b769
21 changed files with 2085 additions and 78 deletions
@@ -316,6 +316,67 @@ public class MetadataTests
Assert.That(nachher!.Items[0].Title, Is.EqualTo("Von Hand"));
}
/// <summary>Auffrischen nimmt eine Auswahl entgegen — und geht auch ohne.</summary>
///
/// <remarks>
/// <b>Gemessen, nachdem es einmal brach.</b> Als die Auswahl als
/// <c>RefreshRequest?</c> im Kopf der Methode stand, lehnte der Server
/// jede Anfrage ohne Rumpf mit 404 ab — also den Knopf „Metadaten neu
/// holen" für die ganze Mediathek, den es länger gibt als die Auswahl.
/// Beide Formen gehören deshalb in eine Prüfung.
/// </remarks>
[Test]
public async Task Auffrischen_nimmt_eine_Auswahl_entgegen_und_geht_auch_ohne()
{
Datei("101 Dalmatians (1996)/101 Dalmatians (1996).mkv");
var anbieter = new VorgegebenerAnbieter
{
Film = new MovieMetadata(8741, "101 Dalmatiner", 1996, "Deutsch.", null, null)
{
Language = "de-DE",
},
};
using var server = MitAnbieter(anbieter);
var (client, bibliothek) = await Einrichten(server, "Movies");
await Scannen(client, bibliothek);
var filme = await client.GetFromJsonAsync<Page<MovieResponse>>("/api/v1/movies");
var kennung = filme!.Items[0].Id;
// Ohne Rumpf: der alte Weg, und er muss weiter gehen.
var ohne = await client.PostAsync($"/api/v1/libraries/{bibliothek}/refresh", null);
Assert.That(ohne.StatusCode, Is.EqualTo(HttpStatusCode.Accepted),
"ein fehlender Rumpf heisst alles, nicht nicht-gefunden");
await Fertig(client, bibliothek);
// Mit Auswahl: nur dieser eine Titel.
var mit = await client.PostAsJsonAsync(
$"/api/v1/libraries/{bibliothek}/refresh", new RefreshRequest([kennung]));
Assert.That(mit.StatusCode, Is.EqualTo(HttpStatusCode.Accepted));
var stand = await Fertig(client, bibliothek);
Assert.Multiple(() =>
{
Assert.That(stand.Metadata?.MoviesMatched, Is.EqualTo(1));
Assert.That(stand.FilesFound, Is.Null,
"bei einer Auswahl wird nicht noch einmal das Dateisystem abgelaufen");
});
}
private static async Task<ScanStatus> Fertig(HttpClient client, Guid bibliothek)
{
for (var i = 0; i < 200; i++)
{
var stand = await client.GetFromJsonAsync<ScanStatus>($"/api/v1/libraries/{bibliothek}/scan");
if (stand!.State == "finished") return stand;
if (stand.State == "failed") Assert.Fail($"Gescheitert: {stand.Error}");
await Task.Delay(50);
}
Assert.Fail("Nicht fertig geworden.");
return null!;
}
/// <summary>Eine falsche Zuordnung darf ihre eigene Korrektur nicht verhindern.</summary>
///
/// <remarks>