Eine zweite Bildquelle, weil TMDB nicht alles hat

„365 Tage" stand mit polnischem Plakat da. Nachgesehen: TMDB hat zu diesem
Film 26 Plakate und kein einziges deutsches. Die Auswahl von gestern nimmt
seither das sprachlose statt des polnischen — erfinden kann sie keines.

fanart.tv ist die Quelle, bei der jedes Plakat seine Sprache mitführt, und
die Gemeinschaft dort pflegt landessprachliche Fassungen. OMDb wäre keine
Hilfe gewesen: es liefert das Plakat von IMDb, und das ist in aller Regel
das amerikanische.

**Ausdrücklich keine zweite Metadatenquelle.** `IBildquelle` liefert
Bilder, sonst nichts. Titel, Beschreibung und Besetzung kommen weiterhin
von einer Stelle — zwei Anbieter für dieselbe Angabe wären zwei Wahrheiten.

**Gefragt wird nur, wenn es lohnt.** `MovieMetadata` trägt jetzt die
Sprache des gewählten Plakats mit. Hat TMDB schon eines in der
eingestellten Sprache, geht keine Anfrage hinaus — bei achthundert Titeln
ist das der Unterschied zwischen „läuft nebenher" und „hängt am fremden
Dienst". Und nur ein landessprachliches sticht: ein sprachloses von
fanart.tv ist nicht besser als ein sprachloses von TMDB.

**Die Rangfolge liegt jetzt im Kern**, nicht im TMDB-Client. Sie gilt für
alle Quellen, sonst kämen die Bilder zweier Anbieter in zwei Reihenfolgen
zusammen. Im Bilderdialog stehen beide Quellen gemeinsam geordnet: ein
deutsches Plakat von fanart.tv vor einem sprachlosen von TMDB.

**Nur Filme.** Der Serienweg von fanart.tv verlangt eine TVDB-Kennung, und
die führt Flaro nicht. Eine halbe Lösung, die bei Serien stillschweigend
nichts tut, wäre schlechter als eine, die sagt, worauf sie sich beschränkt.

**Kein mitgelieferter Schlüssel.** Bei TMDB gibt es einen als Rückfall;
fanart.tv verlangt einen persönlichen, und einen fremden mitzuliefern
hiesse, ihn fremd zu benutzen. Ohne eigenen Schlüssel geht keine Anfrage
hinaus — geprüft. Einzutragen unter Einstellungen → Übersicht → Metadaten.

Dass „00" dort „ohne Sprache" heisst, wird beim Lesen übersetzt: sonst
führte die gemeinsame Rangfolge ein sprachloses Plakat als Sprache „00"
und setzte es hinter Englisch statt davor.

732 Tests grün, davon sieben neue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-08 21:18:27 +02:00
co-authored by Claude Opus 5
parent 2bd13f0f19
commit 97edb49564
13 changed files with 545 additions and 32 deletions
@@ -28,6 +28,15 @@ public enum CreditKind { Actor, Director, Writer }
public sealed record MovieMetadata(
int ProviderId, string Title, int? Year, string? Overview,
RemoteImage? Poster, RemoteImage? Backdrop, string? ImdbId = null,
/// <summary>In welcher Sprache das gewählte Plakat ist — <c>null</c> heisst sprachlos.</summary>
///
/// <remarks>
/// <b>Damit eine zweite Quelle nur dann gefragt wird, wenn sie lohnt.</b>
/// Hat TMDB schon ein deutsches Plakat, braucht niemand fanart.tv — und
/// bei achthundert Titeln sind achthundert vermiedene Anfragen der
/// Unterschied zwischen „läuft nebenher" und „hängt am fremden Dienst".
/// </remarks>
string? PosterLanguage = null,
/// <summary>Laufzeit in Minuten, wie die Quelle sie nennt.</summary>
///
/// <remarks>
@@ -248,5 +257,65 @@ public interface IImageReader
/// <b>Mit Vorschau und Sprache.</b> Wer ein Plakat aussucht, sucht meist eins
/// in seiner Sprache, und er will es sehen, bevor er es nimmt — nicht danach.
/// </remarks>
/// <param name="Quelle">Woher es stammt — „tmdb" oder „fanart".</param>
public sealed record Bildkandidat(
string Kind, string Url, string ThumbUrl, string? Language, double? Vote);
string Kind, string Url, string ThumbUrl, string? Language, double? Vote,
string Quelle = "tmdb");
/// <summary>Eine Quelle, die nur Bilder liefert — keine Metadaten.</summary>
///
/// <remarks>
/// <b>Bewusst nicht <see cref="IMetadataProvider"/>.</b> Dessen Methoden
/// liefern ganze Titelangaben; zwei Anbieter für Titel und Beschreibung
/// wären zwei Wahrheiten. Hier geht es nur um Plakate, und dort ist eine
/// zweite Quelle genau richtig: TMDB hat für manche Filme kein deutsches,
/// fanart.tv schon.
/// </remarks>
public interface IBildquelle
{
/// <summary>Ob sie überhaupt eingerichtet ist.</summary>
Task<bool> EingerichtetAsync(CancellationToken ct = default);
/// <summary>Alle Bilder zu einem Film, mit Sprachangabe.</summary>
Task<IReadOnlyList<Bildkandidat>> FilmbilderAsync(int tmdbId, CancellationToken ct = default);
}
/// <summary>Wie Bilder nach Sprache geordnet werden.</summary>
///
/// <remarks>
/// <para>
/// <b>Eine Rangfolge für alle Quellen.</b> Eingestellte Sprache, dann
/// sprachlos, dann Englisch, dann der Rest. Sie stand erst nur im
/// TMDB-Client; seit es eine zweite Bildquelle gibt, muss sie an einer
/// Stelle liegen, sonst kämen die Bilder zweier Quellen in zwei
/// Reihenfolgen zusammen.
/// </para>
/// <para>
/// <b>Sprachlos vor Englisch.</b> Ein Bild ohne Sprachkennung trägt keinen
/// Text — ein Plakat ohne Titel, ein Hintergrund ohne eingebrannten
/// Schriftzug. Für einen deutschen Bestand ist das besser als dasselbe mit
/// englischem Titel darüber.
/// </para>
/// </remarks>
public static class Bildrang
{
public static int Nach(string? sprache, string gewuenscht) =>
string.Equals(sprache, gewuenscht, StringComparison.OrdinalIgnoreCase) ? 0
: string.IsNullOrEmpty(sprache) ? 1
: string.Equals(sprache, "en", StringComparison.OrdinalIgnoreCase) ? 2
: 3;
/// <summary>Ordnet Kandidaten: erst die Sprache, dann die Stimmen.</summary>
///
/// <remarks>
/// <b>Die Quelle entscheidet nicht mit.</b> Ein deutsches Plakat von
/// fanart.tv steht vor einem sprachlosen von TMDB — das ist der Grund,
/// warum es die zweite Quelle überhaupt gibt. Bei gleichem Rang gewinnt,
/// was mehr Zustimmung hat.
/// </remarks>
public static IEnumerable<Bildkandidat> Geordnet(
IEnumerable<Bildkandidat> kandidaten, string sprache) =>
kandidaten
.OrderBy(b => Nach(b.Language, sprache))
.ThenByDescending(b => b.Vote ?? 0);
}