Zwei Teile, ein Treffer — und einer verschwand

Du hast drei Filme vermisst, und die Zahlen sagten schon, wo sie sind: 448
Filme plus 13 zweite Fassungen sind genau die 461 Dateien. Es fehlte keine
Datei; drei Filme steckten als Fassung in einem anderen.

Gemessen, warum. Der Dateinamenleser ist unschuldig — „Teil 2" bleibt im
Titel. TMDB aber liefert für „Heiligtümer des Todes Teil 1" wie für „Teil 2"
denselben Treffer zuerst, sobald ohne Jahr gesucht werden muss. Und weil
zwei Einträge dieselbe Kennung nicht teilen dürfen, wurde der zweite
geschluckt.

Zwei Dateien, deren Namen verschiedene Jahre nennen, sind jetzt verschiedene
Filme. Der erste Anlauf hatte ein Jahr Abstand als Toleranz erlaubt — für
Dezember-Erstaufführungen — und verschluckte damit genau den Fall, um den es
geht: Teil 1 ist von 2010, Teil 2 von 2011.

Dazu sieht man endlich, was nicht zugeordnet werden konnte. „Nicht
zugeordnet" listete bisher nur Dateien ganz ohne Titel, und die gibt es bei
Filmen nie — deshalb standen dort nur Serien. Daneben eine Liste der Titel
mit mehreren Dateien: zwei Fassungen sind die Regel, zwei verschiedene Filme
der Fehler, und an den Dateinamen sieht man es sofort.

Der Bearbeiten-Dialog hat jetzt Reiter statt Knöpfe, die weitere Fenster
öffnen — ein Fenster über einem Fenster, und man wusste nicht mehr, was man
zumacht. „Titel ändern" und „Bilder bearbeiten" sind aus dem Kontextmenü
raus; über „Bearbeiten" kommt man an beides.

Beim Prüfen gefunden: ein Dialog blieb nach einem Seitenwechsel über der
neuen Seite stehen. Er hängt an body, nicht am Inhaltsbereich.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-06 13:21:42 +02:00
co-authored by Claude Opus 5
parent fcf40e4394
commit c3124ba27c
12 changed files with 626 additions and 78 deletions
@@ -377,6 +377,141 @@ public class MetadataTests
return null!;
}
/* ---------- Zwei Teile, ein Treffer ---------- */
/// <summary>Zwei Filme verschiedener Jahre werden nicht zusammengelegt.</summary>
///
/// <remarks>
/// <para>
/// <b>Aus dem echten Bestand, und es kostete drei Filme.</b> „Harry Potter
/// und die Heiligtümer des Todes Teil 1" und „Teil 2" landen bei TMDB auf
/// demselben Treffer, sobald ohne Jahr gesucht werden muss — gemessen:
/// die Suche liefert für <i>beide</i> Titel Teil 2 zuerst. Weil zwei
/// Einträge dieselbe Kennung nicht teilen dürfen, wurde der zweite als
/// „zweite Fassung" des ersten geschluckt. In der Übersicht standen dann
/// 448 Filme und 13 zweite Fassungen, in Plex 451 Filme — und nirgends
/// stand, welche drei fehlen.
/// </para>
/// <para>
/// Das Jahr aus dem Dateinamen ändert sich nie. Widersprechen sich zwei,
/// sind es verschiedene Filme, und dann bleibt der zweite lieber ohne
/// Zuordnung — sichtbar in der Liste der nicht zugeordneten Titel — als
/// lautlos verschwunden.
/// </para>
/// </remarks>
[Test]
public async Task Zwei_Teile_mit_verschiedenen_Jahren_bleiben_zwei_Filme()
{
Datei("Heiligtuemer des Todes Teil 1 (2010)/Heiligtuemer des Todes Teil 1 (2010).mkv");
Datei("Heiligtuemer des Todes Teil 2 (2011)/Heiligtuemer des Todes Teil 2 (2011).mkv");
// Die Quelle liefert für jede Suche denselben Film — genau wie TMDB
// es ohne Jahr tut.
var anbieter = new VorgegebenerAnbieter
{
Film = new MovieMetadata(12445, "Heiligtümer des Todes – Teil 2", 2011, null, null, null),
};
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");
Assert.That(filme!.Items, Has.Count.EqualTo(2),
"zwei Dateien, zwei Jahre — also zwei Filme, nicht einer mit zwei Fassungen");
var ohne = await client.GetFromJsonAsync<List<OhneZuordnung>>(
$"/api/v1/libraries/{bibliothek}/unmatched");
Assert.That(ohne, Has.Count.EqualTo(1),
"der zweite bleibt ohne Zuordnung — und steht dafür in der Liste");
}
/// <summary>Derselbe Film in zwei Ordnern wird weiterhin zusammengelegt.</summary>
///
/// <remarks>
/// <b>Die Gegenprobe, und sie ist wichtiger als sie aussieht.</b> „Despicable
/// Me" und „Ich einfach unverbesserlich" sind wirklich derselbe Film —
/// gleiches Jahr, zwei Ordner. Diesen Fall mit zu verbieten hiesse, einen
/// Fehler durch einen anderen zu ersetzen.
/// </remarks>
[Test]
public async Task Derselbe_Film_in_zwei_Ordnern_wird_weiter_zusammengelegt()
{
Datei("Despicable Me (2010)/Despicable Me (2010).mkv");
Datei("Ich einfach unverbesserlich (2010)/Ich einfach unverbesserlich (2010).mkv");
var anbieter = new VorgegebenerAnbieter
{
Film = new MovieMetadata(20352, "Ich einfach unverbesserlich", 2010, null, null, null),
};
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");
Assert.Multiple(() =>
{
Assert.That(filme!.Items, Has.Count.EqualTo(1), "ein Film");
Assert.That(filme.Items[0].Files, Has.Count.EqualTo(2), "mit zwei Dateien");
});
}
/// <summary>Ohne Jahr im Namen wird weiter zusammengelegt.</summary>
///
/// <remarks>
/// <b>Eine Lücke ist keine Aussage.</b> Wer seine Dateien ohne Jahr
/// benennt, bekäme sonst nie eine Dublette erkannt — und zwei Ordner
/// desselben Films blieben für immer zwei Einträge.
/// </remarks>
[Test]
public async Task Ohne_Jahr_im_Namen_wird_weiter_zusammengelegt()
{
Datei("Despicable Me/Despicable Me.mkv");
Datei("Ich einfach unverbesserlich/Ich einfach unverbesserlich.mkv");
var anbieter = new VorgegebenerAnbieter
{
Film = new MovieMetadata(20352, "Ich einfach unverbesserlich", 2010, null, null, null),
};
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");
Assert.That(filme!.Items, Has.Count.EqualTo(1));
}
/// <summary>Titel ohne Zuordnung stehen in einer Liste — mit Dateinamen.</summary>
[Test]
public async Task Nicht_zugeordnete_Filme_stehen_in_der_Liste()
{
Datei("Ein Mitschnitt ohne Titel/Ein Mitschnitt ohne Titel.mkv");
// Die Quelle findet nichts.
var anbieter = new VorgegebenerAnbieter { Film = null };
using var server = MitAnbieter(anbieter);
var (client, bibliothek) = await Einrichten(server, "Movies");
await Scannen(client, bibliothek);
var ohne = await client.GetFromJsonAsync<List<OhneZuordnung>>(
$"/api/v1/libraries/{bibliothek}/unmatched");
Assert.That(ohne, Has.Count.EqualTo(1));
Assert.Multiple(() =>
{
Assert.That(ohne![0].Art, Is.EqualTo("movie"));
Assert.That(ohne[0].Dateien, Is.EqualTo(1));
Assert.That(ohne[0].Beispiel, Does.EndWith(".mkv"));
Assert.That(ohne[0].Beispiel, Does.Not.Contain("/"), "nur der Dateiname, nicht der Pfad");
});
}
/// <summary>Eine falsche Zuordnung darf ihre eigene Korrektur nicht verhindern.</summary>
///
/// <remarks>