Ein Film kommt je Mediathek genau einmal vor
Der Scan verglich den Titel aus dem Dateinamen zeichengenau. Ein Punkt Unterschied — Dr. Dolittle 2 gegen Dr Dolittle 2 —, oder eine Datei mit Jahresangabe neben einer ohne, und es entstanden zwei Einträge. Die Metadaten ordneten beide demselben TMDB-Eintrag zu, beide bekamen denselben Titel, dasselbe Jahr, dasselbe Plakat, und nichts führte sie je wieder zusammen. Drei Ebenen, weil eine nicht trägt. Titelschluessel vergleicht ohne Satzzeichen, ohne Akzente und ohne Grossschreibung; ein fehlendes Jahr passt auf jedes, zwei bekannte verschiedene trennen. Bewusst nicht aggressiver: Spider-Man und Spiderman bleiben getrennt, und die beiden Dune von 1984 und 2021 sowieso. Ein zusammengelegter Film lässt sich nicht mehr trennen, ohne zu wissen, welche Datei wohin gehörte. Ein gefilterter Eindeutigkeitsindex auf (LibraryId, TmdbId) stellt die Regel in die Datenbank statt in Code, der sie einhalten soll. Gefiltert, weil ohne Metadaten alle Einträge null tragen. Zusammenlegung räumt auf, was kein Vergleich erkennen könnte: Ich einfach unverbesserlich und Despicable Me sind derselbe Film, und das verrät allein die TMDB-Kennung. Läuft nach jedem Scan, und von Hand über einen Knopf in der Verwaltung. Der Sehfortschritt wird gefaltet, nicht umgehängt — die weitere Stelle gewinnt, gesehen gewinnt, weggelegt gewinnt nicht. Die Migration räumt zuerst auf und legt dann erst den Index an. Andersherum scheiterte sie auf jeder Datenbank mit Dubletten, und zwar beim Start im Container, wo die Meldung niemand sieht. Gemessen an einer Datenbank mit zwei Dubletten und zwei Sehständen: 3 Filme auf 2, beide Dateien erhalten, Position 1800 statt 300 behalten. Dazu Fassungen. MediaFile.VersionLabel liest Mobil, 4K oder Director's Cut aus dem Namen, sonst aus der gemessenen Bildhöhe. Die Liste ist geschlossen, damit eine Fassung nicht YIFY heisst. Und der Fassungsname beendet jetzt den Titel wie jedes andere Beiwerk — vorher wurde aus "The Matrix (1999) - Mobil.mp4" der Film "The Matrix - Mobil", also ein zweiter Eintrag neben dem Original. Genau die Dublette, um die es ging. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
d01c5d43f4
commit
63c7ebb6d5
@@ -154,6 +154,64 @@ public class ScanTests
|
||||
Is.EqualTo(120));
|
||||
}
|
||||
|
||||
/// <summary>Schreibvarianten desselben Titels ergeben einen Eintrag.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <b>Der Fall, der die Mediathek doppelt aussehen liess.</b> Der Scan
|
||||
/// verglich den Titel aus dem Dateinamen zeichengenau — ein Punkt
|
||||
/// Unterschied, und es wurden zwei Filme, die anschliessend beide
|
||||
/// denselben TMDB-Eintrag bekamen und ununterscheidbar nebeneinander
|
||||
/// standen.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public async Task Schreibvarianten_ergeben_einen_Film()
|
||||
{
|
||||
Datei("Dr. Dolittle 2 (2001).mkv");
|
||||
Datei("Dr Dolittle 2.mkv");
|
||||
|
||||
using var server = new FlaroServer();
|
||||
var (client, bibliothek) = await MitBibliothek(server, "Movies");
|
||||
await Scannen(client, bibliothek);
|
||||
|
||||
var filme = await client.GetFromJsonAsync<Page<MovieResponse>>("/api/v1/movies");
|
||||
Assert.That(filme!.Total, Is.EqualTo(1));
|
||||
Assert.That(filme.Items[0].Files, Has.Count.EqualTo(2));
|
||||
Assert.That(filme.Items[0].Year, Is.EqualTo(2001),
|
||||
"Das Jahr der einen Datei gilt auch, wenn die andere keines trägt.");
|
||||
}
|
||||
|
||||
/// <summary>Eine mobile Fassung ist kein eigener Film.</summary>
|
||||
[Test]
|
||||
public async Task Eine_optimierte_Fassung_bleibt_beim_Film()
|
||||
{
|
||||
Datei("The Matrix (1999).mkv");
|
||||
Datei("The Matrix (1999) - Mobil.mp4");
|
||||
|
||||
using var server = new FlaroServer();
|
||||
var (client, bibliothek) = await MitBibliothek(server, "Movies");
|
||||
await Scannen(client, bibliothek);
|
||||
|
||||
var filme = await client.GetFromJsonAsync<Page<MovieResponse>>("/api/v1/movies");
|
||||
Assert.That(filme!.Total, Is.EqualTo(1), "Sonst stünde ein zweiter Film ‚The Matrix - Mobil‘ daneben.");
|
||||
Assert.That(filme.Items[0].Title, Is.EqualTo("The Matrix"));
|
||||
Assert.That(filme.Items[0].Files, Has.Count.EqualTo(2));
|
||||
}
|
||||
|
||||
/// <summary>Gleicher Name, anderes Jahr — zwei Filme, und das muss so bleiben.</summary>
|
||||
[Test]
|
||||
public async Task Zwei_Verfilmungen_bleiben_zwei_Filme()
|
||||
{
|
||||
Datei("Dune (1984).mkv");
|
||||
Datei("Dune (2021).mkv");
|
||||
|
||||
using var server = new FlaroServer();
|
||||
var (client, bibliothek) = await MitBibliothek(server, "Movies");
|
||||
await Scannen(client, bibliothek);
|
||||
|
||||
var filme = await client.GetFromJsonAsync<Page<MovieResponse>>("/api/v1/movies");
|
||||
Assert.That(filme!.Total, Is.EqualTo(2));
|
||||
}
|
||||
|
||||
/// <summary>4K und 1080p sind ein Film mit zwei Dateien, nicht zwei Filme.</summary>
|
||||
[Test]
|
||||
public async Task Zwei_Fassungen_desselben_Films_bleiben_ein_Eintrag()
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
using Flaro.Core.Library;
|
||||
|
||||
namespace Flaro.Core.Tests;
|
||||
|
||||
/// <summary>Welche Schreibweisen denselben Film meinen — und welche nicht.</summary>
|
||||
public class TitelschluesselTests
|
||||
{
|
||||
[TestCase("Dr. Dolittle 2", "Dr Dolittle 2")]
|
||||
[TestCase("Spider-Man", "Spider Man")]
|
||||
[TestCase("WALL·E", "WALL-E")]
|
||||
[TestCase("Amélie", "Amelie")]
|
||||
[TestCase("The Matrix", "the matrix")]
|
||||
[TestCase("Ich einfach unverbesserlich!", "Ich einfach unverbesserlich")]
|
||||
public void Gleiche_Titel_trotz_anderer_Schreibweise(string a, string b) =>
|
||||
Assert.That(Titelschluessel.Von(a), Is.EqualTo(Titelschluessel.Von(b)), $"„{a}" + $"\" und „{b}\"");
|
||||
|
||||
/// <summary>Hier endet die Toleranz — und das ist Absicht.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Ein zusammengelegter Film lässt sich nicht mehr trennen, ohne zu
|
||||
/// wissen, welche Datei wohin gehörte. Zwei Einträge für einen Film sind
|
||||
/// ärgerlich; ein Eintrag für zwei Filme ist Datenverlust.
|
||||
/// </remarks>
|
||||
[TestCase("Spider-Man", "Spiderman")]
|
||||
[TestCase("Der Pate", "Der Pate 2")]
|
||||
[TestCase("Dune", "Dune Part Two")]
|
||||
public void Verschiedene_Titel_bleiben_verschieden(string a, string b) =>
|
||||
Assert.That(Titelschluessel.Von(a), Is.Not.EqualTo(Titelschluessel.Von(b)));
|
||||
|
||||
[Test]
|
||||
public void Ein_fehlendes_Jahr_passt_auf_jedes() =>
|
||||
Assert.That(Titelschluessel.Gleich("Descendants 2", null, "Descendants 2", 2017), Is.True);
|
||||
|
||||
/// <summary>Die beiden „Dune" dürfen nie verschmelzen.</summary>
|
||||
[Test]
|
||||
public void Zwei_bekannte_Jahre_trennen() =>
|
||||
Assert.That(Titelschluessel.Gleich("Dune", 1984, "Dune", 2021), Is.False);
|
||||
|
||||
[Test]
|
||||
public void Leeres_passt_auf_nichts()
|
||||
{
|
||||
Assert.That(Titelschluessel.Von(""), Is.Empty);
|
||||
Assert.That(Titelschluessel.Gleich("", null, "", null), Is.False,
|
||||
"Zwei namenlose Einträge sind nicht derselbe Film.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Welche Fassung eine Datei ist — 4K, Mobil, Director's Cut.</summary>
|
||||
public class FassungTests
|
||||
{
|
||||
[TestCase("The Matrix (1999) - Mobil.mp4", "Mobil")]
|
||||
[TestCase("The Matrix (1999) - optimiert.mp4", "Mobil")]
|
||||
[TestCase("The Matrix (1999) - 2160p.mkv", "2160p")]
|
||||
[TestCase("The Matrix (1999) {edition-Director's Cut}.mkv", "Director's Cut")]
|
||||
[TestCase("Mobil/The Matrix (1999).mp4", "Mobil")]
|
||||
[TestCase("The Matrix (1999) - Extended.mkv", "Extended")]
|
||||
public void Erkennt_die_Fassung(string pfad, string erwartet) =>
|
||||
Assert.That(FileNames.Fassung(pfad), Is.EqualTo(erwartet));
|
||||
|
||||
/// <summary>Eine Veröffentlichungsgruppe ist keine Fassung.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Nähme man jedes Wort hinter dem letzten Bindestrich, hiesse eine
|
||||
/// Fassung „YIFY" oder „GRP". Lieber kein Name als ein falscher — dann
|
||||
/// greift der Rückfall über die Bildhöhe.
|
||||
/// </remarks>
|
||||
[TestCase("The Matrix (1999) - YIFY.mkv")]
|
||||
[TestCase("The Matrix (1999).mkv")]
|
||||
[TestCase("Filme/The Matrix (1999).mkv")]
|
||||
public void Raet_nicht(string pfad) => Assert.That(FileNames.Fassung(pfad), Is.Null);
|
||||
|
||||
[TestCase(2160, "4K")]
|
||||
[TestCase(1080, "1080p")]
|
||||
[TestCase(720, "720p")]
|
||||
[TestCase(480, "SD")]
|
||||
[TestCase(null, null)]
|
||||
public void Bildet_die_Fassung_aus_der_Hoehe(int? hoehe, string? erwartet) =>
|
||||
Assert.That(FileNames.FassungAusHoehe(hoehe), Is.EqualTo(erwartet));
|
||||
|
||||
/// <summary>Der Fassungszusatz darf nie im Titel landen.</summary>
|
||||
[Test]
|
||||
public void Die_Fassung_bleibt_aus_dem_Titel_heraus()
|
||||
{
|
||||
Assert.That(FileNames.ParseMovie("The Matrix (1999) - Mobil.mp4").Title, Is.EqualTo("The Matrix"));
|
||||
Assert.That(FileNames.ParseMovie("The Matrix (1999) - 2160p.mkv").Title, Is.EqualTo("The Matrix"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user