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:
co-authored by
Claude Opus 5
parent
c854c4a09a
commit
557708b769
@@ -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>
|
||||
|
||||
@@ -350,6 +350,212 @@ public class PlaybackTests
|
||||
Assert.That(danach!.UnwatchedCount, Is.EqualTo(2));
|
||||
}
|
||||
|
||||
/// <summary>Eine Serie als gesehen markieren hakt jede Folge ab.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <b>Der Fall, der vorher stumm scheiterte.</b> Der Server kannte zu
|
||||
/// einer Serienkennung keinen Zustand und antwortete mit 404; die
|
||||
/// Oberfläche verschluckte die Ablehnung, und der Klick tat sichtbar
|
||||
/// nichts.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public async Task Eine_Serie_als_gesehen_markieren_hakt_alle_Folgen_ab()
|
||||
{
|
||||
Datei("Dark/Season 01/Dark - S01E01 - Geheimnisse.mkv");
|
||||
Datei("Dark/Season 01/Dark - S01E02 - Luegen.mkv");
|
||||
Datei("Dark/Season 02/Dark - S02E01 - Beginnings.mkv");
|
||||
|
||||
using var server = new FlaroServer();
|
||||
var client = await Eingelesen(server, "Shows");
|
||||
|
||||
var serien = await client.GetFromJsonAsync<Page<SeriesResponse>>("/api/v1/series");
|
||||
var serie = serien!.Items[0];
|
||||
|
||||
var antwort = await client.PutAsJsonAsync(
|
||||
$"/api/v1/items/{serie.Id}/watched", new WatchedRequest(true));
|
||||
|
||||
Assert.That(antwort.StatusCode, Is.EqualTo(HttpStatusCode.OK),
|
||||
"eine Serienkennung ist eine gültige Titelkennung");
|
||||
|
||||
var danach = await client.GetFromJsonAsync<SeriesResponse>($"/api/v1/series/{serie.Id}");
|
||||
var folgen = await client.GetFromJsonAsync<Page<EpisodeResponse>>(
|
||||
$"/api/v1/series/{serie.Id}/episodes");
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(danach!.UnwatchedCount, Is.Zero, "keine Folge steht mehr aus");
|
||||
Assert.That(danach.State?.Watched, Is.True, "und die Serie selbst trägt das Häkchen");
|
||||
Assert.That(folgen!.Items.Select(f => f.State?.Watched), Is.All.True,
|
||||
"jede einzelne Folge ist abgehakt, nicht nur die Serie");
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>Und wieder zurück — ohne Rest.</summary>
|
||||
[Test]
|
||||
public async Task Eine_Serie_als_ungesehen_markieren_nimmt_jedes_Haekchen_weg()
|
||||
{
|
||||
Datei("Dark/Season 01/Dark - S01E01 - Geheimnisse.mkv");
|
||||
Datei("Dark/Season 01/Dark - S01E02 - Luegen.mkv");
|
||||
|
||||
using var server = new FlaroServer();
|
||||
var client = await Eingelesen(server, "Shows");
|
||||
|
||||
var serien = await client.GetFromJsonAsync<Page<SeriesResponse>>("/api/v1/series");
|
||||
var serie = serien!.Items[0];
|
||||
|
||||
await client.PutAsJsonAsync($"/api/v1/items/{serie.Id}/watched", new WatchedRequest(true));
|
||||
await client.PutAsJsonAsync($"/api/v1/items/{serie.Id}/watched", new WatchedRequest(false));
|
||||
|
||||
var danach = await client.GetFromJsonAsync<SeriesResponse>($"/api/v1/series/{serie.Id}");
|
||||
var folgen = await client.GetFromJsonAsync<Page<EpisodeResponse>>(
|
||||
$"/api/v1/series/{serie.Id}/episodes");
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(danach!.UnwatchedCount, Is.EqualTo(2));
|
||||
Assert.That(danach.State?.Watched, Is.False);
|
||||
Assert.That(folgen!.Items.Select(f => f.State?.Watched), Is.All.False);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>Favorit an einer Serie — vorher ebenfalls eine stille 404.</summary>
|
||||
[Test]
|
||||
public async Task Eine_Serie_laesst_sich_zu_den_Favoriten_legen()
|
||||
{
|
||||
Datei("Dark/Season 01/Dark - S01E01 - Geheimnisse.mkv");
|
||||
|
||||
using var server = new FlaroServer();
|
||||
var client = await Eingelesen(server, "Shows");
|
||||
|
||||
var serien = await client.GetFromJsonAsync<Page<SeriesResponse>>("/api/v1/series");
|
||||
var serie = serien!.Items[0];
|
||||
|
||||
var antwort = await client.PutAsJsonAsync(
|
||||
$"/api/v1/items/{serie.Id}/favourite", new FavouriteRequest(true));
|
||||
antwort.EnsureSuccessStatusCode();
|
||||
|
||||
var liste = await client.GetFromJsonAsync<Page<SeriesResponse>>("/api/v1/series");
|
||||
Assert.That(liste!.Items[0].State?.Favourite, Is.True,
|
||||
"auch die Liste führt den Zustand mit — sonst wüsste die Kachel es nicht");
|
||||
}
|
||||
|
||||
/// <summary>Der Stand einer Serie gehört dem Benutzer, nicht dem Server.</summary>
|
||||
[Test]
|
||||
public async Task Der_Serienstand_gehoert_dem_Benutzer()
|
||||
{
|
||||
Datei("Dark/Season 01/Dark - S01E01 - Geheimnisse.mkv");
|
||||
|
||||
using var server = new FlaroServer();
|
||||
var ich = await Eingelesen(server, "Shows");
|
||||
|
||||
var serien = await ich.GetFromJsonAsync<Page<SeriesResponse>>("/api/v1/series");
|
||||
var serie = serien!.Items[0];
|
||||
await ich.PutAsJsonAsync($"/api/v1/items/{serie.Id}/watched", new WatchedRequest(true));
|
||||
|
||||
(await ich.PostAsJsonAsync("/api/v1/users",
|
||||
new CreateUserRequest("mitbewohner", "ein-langes-passwort", false))).EnsureSuccessStatusCode();
|
||||
var andere = server.AlsAngemeldeter(
|
||||
(await server.SignIn("mitbewohner", "ein-langes-passwort", "iPad", "geraet-2")).Token);
|
||||
|
||||
var seine = await andere.GetFromJsonAsync<SeriesResponse>($"/api/v1/series/{serie.Id}");
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(seine!.State?.Watched, Is.Not.True);
|
||||
Assert.That(seine.UnwatchedCount, Is.EqualTo(1));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>Viele auf einmal — eine Anfrage, nicht zweihundert.</summary>
|
||||
[Test]
|
||||
public async Task Eine_Sammelmarkierung_hakt_alles_Gewaehlte_ab()
|
||||
{
|
||||
Datei("Matrix (1999)/Matrix (1999).mkv");
|
||||
Datei("Alien (1979)/Alien (1979).mkv");
|
||||
Datei("Heat (1995)/Heat (1995).mkv");
|
||||
|
||||
using var server = new FlaroServer();
|
||||
var client = await Eingelesen(server);
|
||||
|
||||
var seite = await client.GetFromJsonAsync<Page<MovieResponse>>("/api/v1/movies");
|
||||
var zwei = seite!.Items.Take(2).Select(m => m.Id).ToList();
|
||||
|
||||
var antwort = await client.PutAsJsonAsync("/api/v1/items/watched",
|
||||
new BulkWatchedRequest(zwei, true));
|
||||
var ergebnis = await antwort.Content.ReadFromJsonAsync<BulkWatchedResponse>();
|
||||
|
||||
var danach = await client.GetFromJsonAsync<Page<MovieResponse>>("/api/v1/movies");
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ergebnis!.Changed, Is.EqualTo(2));
|
||||
Assert.That(ergebnis.Unknown, Is.Empty);
|
||||
Assert.That(danach!.Items.Count(m => m.State?.Watched == true), Is.EqualTo(2),
|
||||
"genau die zwei gewählten, nicht der dritte");
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>Was es nicht gibt, wird benannt statt verschwiegen.</summary>
|
||||
[Test]
|
||||
public async Task Eine_Sammelmarkierung_nennt_was_sie_nicht_gefunden_hat()
|
||||
{
|
||||
Datei("Matrix (1999)/Matrix (1999).mkv");
|
||||
|
||||
using var server = new FlaroServer();
|
||||
var client = await Eingelesen(server);
|
||||
var film = await ErsterFilm(client);
|
||||
var erfunden = Guid.CreateVersion7();
|
||||
|
||||
var antwort = await client.PutAsJsonAsync("/api/v1/items/watched",
|
||||
new BulkWatchedRequest([film, erfunden], true));
|
||||
var ergebnis = await antwort.Content.ReadFromJsonAsync<BulkWatchedResponse>();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ergebnis!.Changed, Is.EqualTo(1));
|
||||
Assert.That(ergebnis.Unknown, Is.EqualTo(new[] { erfunden }));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>Auch Serien gehören in eine Sammelmarkierung.</summary>
|
||||
[Test]
|
||||
public async Task Eine_Sammelmarkierung_zieht_die_Folgen_einer_Serie_mit()
|
||||
{
|
||||
Datei("Dark/Season 01/Dark - S01E01 - Geheimnisse.mkv");
|
||||
Datei("Dark/Season 01/Dark - S01E02 - Luegen.mkv");
|
||||
|
||||
using var server = new FlaroServer();
|
||||
var client = await Eingelesen(server, "Shows");
|
||||
|
||||
var serien = await client.GetFromJsonAsync<Page<SeriesResponse>>("/api/v1/series");
|
||||
var serie = serien!.Items[0];
|
||||
|
||||
await client.PutAsJsonAsync("/api/v1/items/watched",
|
||||
new BulkWatchedRequest([serie.Id], true));
|
||||
|
||||
var danach = await client.GetFromJsonAsync<SeriesResponse>($"/api/v1/series/{serie.Id}");
|
||||
Assert.That(danach!.UnwatchedCount, Is.Zero);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Eine_leere_Sammelmarkierung_aendert_nichts_und_scheitert_nicht()
|
||||
{
|
||||
Datei("Matrix (1999)/Matrix (1999).mkv");
|
||||
|
||||
using var server = new FlaroServer();
|
||||
var client = await Eingelesen(server);
|
||||
|
||||
var antwort = await client.PutAsJsonAsync("/api/v1/items/watched",
|
||||
new BulkWatchedRequest([], true));
|
||||
var ergebnis = await antwort.Content.ReadFromJsonAsync<BulkWatchedResponse>();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(antwort.StatusCode, Is.EqualTo(HttpStatusCode.OK));
|
||||
Assert.That(ergebnis!.Changed, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Die_naechste_Folge_richtet_sich_nach_Staffel_und_Nummer()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user