Zwei Titel je Film, und die Sprache lässt sich wählen
Die Mediathek sah zweisprachig aus — "Despicable Me" neben "Ich einfach unverbesserlich". Es gab nur ein Titelfeld, und welche Sprache darin landete, entschied die Einstellung zum Zeitpunkt des Scans. Movie und Series tragen jetzt zusätzlich OriginalTitle. Gesucht wird über beide: wer "Despicable Me" tippt, findet "Ich einfach unverbesserlich". Auf der Detailseite steht der Originaltitel unter dem übersetzten, wenn er abweicht. Die Sprache der Metadaten ist in der Verwaltung eine Auswahl statt eines Textfelds. Vorher musste man "de-DE" wissen, und ein Tippfehler darin nahm TMDB stillschweigend als Englisch an. Dazu eine eigene Sprache je Benutzer. Das Ehrliche daran steht im Dialog: die Daten liegen in einer Sprache vor, und wer eine andere wählt, bekommt, was übersetzt vorliegt — für den Rest die Serversprache, nicht ein leeres Feld. ItemTranslation hält die zweite Sprache, gefüllt über eine Sammelaktion. Nicht nebenbei beim Öffnen: das verteilte die Wartezeit über Wochen und träfe immer den, der gerade etwas sucht. Alle Sprachen für alle Titel vorzuhalten wäre der Bestand mal Sprachen an Abrufen und Speicher, für einen Haushalt mit zweien. Deshalb auf Ansage. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
f359807561
commit
921533050b
@@ -0,0 +1,35 @@
|
||||
namespace Flaro.Core.Library;
|
||||
|
||||
/// <summary>Ein Titel in einer anderen Sprache als der des Servers.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <b>Warum nicht einfach alles in allen Sprachen holen.</b> Das hiesse, den
|
||||
/// ganzen Bestand je Sprache abzurufen und zu speichern — für einen Haushalt
|
||||
/// mit zwei Sprachen ein Vielfaches an Abrufen und Speicher für etwas, das
|
||||
/// fast niemand ansieht.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <b>Also auf Abruf.</b> Öffnet jemand mit abweichender Sprache einen Titel,
|
||||
/// wird die Übersetzung einmal geholt und bleibt liegen. Was fehlt, erscheint
|
||||
/// in der Sprache des Servers — nicht leer.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public sealed class ItemTranslation
|
||||
{
|
||||
public Guid Id { get; init; } = Guid.CreateVersion7();
|
||||
|
||||
public Guid? MovieId { get; init; }
|
||||
public Guid? SeriesId { get; init; }
|
||||
public Guid? EpisodeId { get; init; }
|
||||
|
||||
/// <summary>Das Sprachkürzel, so wie es beim Abruf verwendet wurde.</summary>
|
||||
public required string Language { get; init; }
|
||||
|
||||
public string? Title { get; set; }
|
||||
public string? Overview { get; set; }
|
||||
public string? Tagline { get; set; }
|
||||
|
||||
/// <summary>Wann sie geholt wurde — für ein späteres Auffrischen.</summary>
|
||||
public DateTimeOffset FetchedAt { get; set; }
|
||||
}
|
||||
@@ -110,6 +110,17 @@ public sealed class Movie
|
||||
/// <summary>Ohne führenden Artikel — siehe <see cref="SortTitle"/>.</summary>
|
||||
public required string SortTitleValue { get; set; }
|
||||
|
||||
/// <summary>Der Titel in der Sprache des Originals.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <b>Damit die Mediathek nicht zweisprachig aussieht.</b> Vorher stand
|
||||
/// nur ein Titel da, und welcher es wurde, entschied die Sprache zum
|
||||
/// Zeitpunkt des Scans — „Despicable Me" neben „Ich einfach
|
||||
/// unverbesserlich". Mit beiden lässt sich zeigen, was passt, und über
|
||||
/// beide suchen.
|
||||
/// </remarks>
|
||||
public string? OriginalTitle { get; set; }
|
||||
|
||||
public int? Year { get; set; }
|
||||
public string? Overview { get; set; }
|
||||
|
||||
@@ -203,6 +214,17 @@ public sealed class Series
|
||||
|
||||
public required string Title { get; set; }
|
||||
public required string SortTitleValue { get; set; }
|
||||
|
||||
/// <summary>Der Titel in der Sprache des Originals.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <b>Damit die Mediathek nicht zweisprachig aussieht.</b> Vorher stand
|
||||
/// nur ein Titel da, und welcher es wurde, entschied die Sprache zum
|
||||
/// Zeitpunkt des Scans — „Despicable Me" neben „Ich einfach
|
||||
/// unverbesserlich". Mit beiden lässt sich zeigen, was passt, und über
|
||||
/// beide suchen.
|
||||
/// </remarks>
|
||||
public string? OriginalTitle { get; set; }
|
||||
public int? Year { get; set; }
|
||||
public string? Overview { get; set; }
|
||||
public int? TmdbId { get; set; }
|
||||
|
||||
@@ -53,7 +53,10 @@ public sealed record MovieMetadata(
|
||||
///
|
||||
/// Nicht jeder Titel hat eines. Fehlt es, steht der Titel als Text da.
|
||||
/// </remarks>
|
||||
RemoteImage? Logo = null);
|
||||
RemoteImage? Logo = null,
|
||||
|
||||
/// <summary>Der Titel in der Sprache des Originals.</summary>
|
||||
string? OriginalTitle = null);
|
||||
|
||||
public sealed record SeriesMetadata(
|
||||
int ProviderId, string Title, int? Year, string? Overview,
|
||||
@@ -74,7 +77,10 @@ public sealed record SeriesMetadata(
|
||||
///
|
||||
/// Nicht jeder Titel hat eines. Fehlt es, steht der Titel als Text da.
|
||||
/// </remarks>
|
||||
RemoteImage? Logo = null);
|
||||
RemoteImage? Logo = null,
|
||||
|
||||
/// <summary>Der Titel in der Sprache des Originals.</summary>
|
||||
string? OriginalTitle = null);
|
||||
|
||||
public sealed record EpisodeMetadata(string? Title, string? Overview, RemoteImage? Still);
|
||||
|
||||
@@ -119,8 +125,28 @@ public interface IMetadataProvider
|
||||
/// </remarks>
|
||||
Task<MovieMetadata?> GetMovieAsync(int providerId, CancellationToken ct = default);
|
||||
|
||||
/// <summary>Holt einen Titel in einer bestimmten Sprache.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <b>Für die Übersetzungstabelle, nicht für den Scan.</b> Der Scan nimmt
|
||||
/// die Sprache des Servers; dies hier füllt nach, was ein Benutzer mit
|
||||
/// abweichender Sprache sehen will.
|
||||
/// </remarks>
|
||||
/// <remarks>
|
||||
/// <b>Mit Vorgabe.</b> Ein Anbieter, der keine Sprachen kennt, liefert
|
||||
/// schlicht die des Servers — das ist ehrlicher als eine leere Antwort und
|
||||
/// erspart jedem Test-Doppelgänger eine Pflichtmethode, die er nicht
|
||||
/// braucht.
|
||||
/// </remarks>
|
||||
Task<MovieMetadata?> GetMovieAsync(int providerId, string sprache, CancellationToken ct = default) =>
|
||||
GetMovieAsync(providerId, ct);
|
||||
|
||||
Task<SeriesMetadata?> GetSeriesAsync(int providerId, CancellationToken ct = default);
|
||||
|
||||
/// <summary>Holt eine Serie in einer bestimmten Sprache.</summary>
|
||||
Task<SeriesMetadata?> GetSeriesAsync(int providerId, string sprache, CancellationToken ct = default) =>
|
||||
GetSeriesAsync(providerId, ct);
|
||||
|
||||
/// <summary>Mehrere Vorschläge zur Auswahl — für das Korrigieren von Hand.</summary>
|
||||
Task<IReadOnlyList<MovieMetadata>> SearchMoviesAsync(string title, int? year, CancellationToken ct = default);
|
||||
|
||||
|
||||
@@ -19,5 +19,16 @@ public sealed class User
|
||||
|
||||
public bool IsAdministrator { get; set; }
|
||||
|
||||
/// <summary>Die bevorzugte Sprache — <c>null</c> heisst: die des Servers.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <b>Und sie ist nicht kostenlos.</b> Metadaten werden in der Sprache des
|
||||
/// Servers geholt und gespeichert. Wer eine andere wählt, bekommt, was in
|
||||
/// der Übersetzungstabelle liegt — und für den Rest die Serversprache.
|
||||
/// Darauf wird beim Umstellen deutlich hingewiesen; es stillschweigend
|
||||
/// halb zu übersetzen wäre schlechter als gar nicht.
|
||||
/// </remarks>
|
||||
public string? Language { get; set; }
|
||||
|
||||
public DateTimeOffset CreatedAt { get; init; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user