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
+60
View File
@@ -110,6 +110,12 @@ public sealed class MetadataEnricher(
.Where(m => m.LibraryId == libraryId && m.TmdbId != null)
.ToDictionaryAsync(m => m.TmdbId!.Value, m => m.Id, ct);
// Welches Jahr im Dateinamen des schon zugeordneten stand — daran
// entscheidet sich, ob ein zweiter Treffer wirklich derselbe Film ist.
var jahreNachId = await db.Movies
.Where(m => m.LibraryId == libraryId && m.TmdbId != null)
.ToDictionaryAsync(m => m.Id, m => m.ParsedYear, ct);
var zusammenzulegen = new List<(Guid Sieger, Guid Verlierer)>();
foreach (var film in offen)
@@ -155,11 +161,41 @@ public sealed class MetadataEnricher(
// aus wie „die Spracheinstellung wirkt nicht".
if (vergeben.TryGetValue(gefunden.ProviderId, out var schonDa) && schonDa != film.Id)
{
// **Verschiedene Jahre heissen: verschiedene Filme.**
//
// „…Heiligtümer des Todes Teil 1 (2010)" und „Teil 2 (2011)"
// landen bei TMDB auf demselben Treffer, wenn ohne Jahr
// gesucht werden musste — die Suche liefert für beide Titel
// Teil 2 zuerst. Zusammengelegt verschwand damit ein ganzer
// Film als „zweite Fassung" des anderen, und niemand erfuhr
// davon. Gemessen am echten Bestand: 448 Filme und 13 zweite
// Fassungen bei 461 Dateien.
//
// Das Jahr aus dem Dateinamen ändert sich nie und ist deshalb
// der verlässlichste Unterschied, den es hier gibt. Kennt nur
// einer von beiden eines, sagt das nichts — dann bleibt es
// beim Zusammenlegen, denn „Despicable Me" und „Ich einfach
// unverbesserlich" sind wirklich derselbe Film.
if (JahreWidersprechen(film.ParsedYear, jahreNachId.GetValueOrDefault(schonDa)))
{
fortschritt?.Report(new Scanschritt(Scanphase.Vermerk,
$"„{film.ParsedTitle ?? film.Title}“ ({film.ParsedYear}) und ein anderer Titel "
+ $"führen beide auf {gefunden.ProviderId} — verschiedene Jahre, also nicht "
+ "zusammengelegt. Dieser bleibt ohne Zuordnung."));
durch++;
continue;
}
zusammenzulegen.Add((Sieger: schonDa, Verlierer: film.Id));
continue;
}
vergeben[gefunden.ProviderId] = film.Id;
// **Auch das Jahr, und zwar sofort.** Die beiden Tabellen müssen
// im Gleichschritt wachsen: wird nur `vergeben` fortgeschrieben,
// findet der zweite Film zwar den ersten, kennt aber dessen Jahr
// nicht — und legt wieder zusammen, was nicht zusammengehört.
jahreNachId[film.Id] = film.ParsedYear;
film.TmdbId = gefunden.ProviderId;
film.ImdbId = gefunden.ImdbId;
// **Ein Titel von Hand bleibt stehen.** Wie bei den Bildern: ohne
@@ -237,6 +273,30 @@ public sealed class MetadataEnricher(
return (new ProviderIds(ausNfo.Tmdb ?? ausPfad.Tmdb, ausNfo.Imdb ?? ausPfad.Imdb), Nfo.ReadLocked(nfo));
}
/// <summary>Ob zwei Jahre einander widersprechen.</summary>
///
/// <remarks>
/// <para>
/// <b>Nur wenn beide bekannt sind.</b> Eine Lücke ist keine Aussage: wer
/// seine Dateien ohne Jahr benennt, bekäme sonst nie eine Dublette
/// erkannt — und „Despicable Me" und „Ich einfach unverbesserlich"
/// gehören wirklich zusammen.
/// </para>
/// <para>
/// <b>Dafür schon ab einem Jahr Abstand, und das ist gemessen.</b> Erst
/// stand hier eine Toleranz von einem Jahr — für den Fall, dass eine
/// Erstaufführung im Dezember hier im Januar läuft. Genau die Toleranz
/// verschluckte den Fall, um den es geht: „Heiligtümer des Todes Teil 1"
/// ist von 2010, „Teil 2" von 2011. Zwei Dateien, deren Namen
/// verschiedene Jahre nennen, sind verschiedene Filme — und wenn doch
/// nicht, steht der zweite in der Liste der nicht zugeordneten Titel und
/// lässt sich in zwei Klicks geradeziehen. Das ist allemal besser, als
/// ihn lautlos verschwinden zu lassen.
/// </para>
/// </remarks>
private static bool JahreWidersprechen(int? eines, int? anderes) =>
eines is { } a && anderes is { } b && a != b;
private async Task<int> SerienZuordnen(
Guid libraryId, bool erneut, IProgress<Scanschritt>? fortschritt, CancellationToken ct,
string? nurSprache = null, IReadOnlySet<Guid>? nurDiese = null)