Eine Reihe, die nur zu ihrer Zeit dasteht
Zu Halloween, zur Weihnachtszeit, zum Jahreswechsel, im Sommer — und zu allem, was sonst jemand feiert. **Nach Stichwörtern, nicht nach Genres.** „Stirb langsam" ist kein Familienfilm und trägt trotzdem „christmas". Eine Weihnachtsreihe nach Genres enthielte jeden Zeichentrickfilm und diesen Film nicht. TMDB führt die Stichwörter ohnehin; sie kommen jetzt über `append_to_response` mit und landen in einer eigenen Tabelle, nach demselben Muster wie Genres. Kleingeschrieben abgelegt — TMDB liefert „Christmas" und „christmas" je nach Eintrag, und zwei Schreibweisen wären zwei Stichwörter. **Einstellbar und nicht eingebaut.** Halloween und Weihnachten kennt jeder; der 1. August ist Schweizer Nationalfeiertag, der 4. Juli amerikanischer, und der Geburtstag des Betreibers steht in keiner Bibliothek. Eine feste Liste im Quelltext hiesse: für jeden Anlass eine neue Fassung. Vier sind vorangelegt — als Beispiel, nicht als Meinung darüber, was jemand feiert. **Über den Jahreswechsel hinweg.** „28.12. bis 02.01." ist kein Fehler, sondern der Normalfall für Silvester; ein Vergleich, der nur „von ≤ heute ≤ bis" kennt, fände diesen Zeitraum nie — und die Reihe stünde genau in den Tagen nicht da, für die sie gedacht ist. Geprüft, Tag für Tag, samt der Zusicherung, dass sich die vorangelegten Anlässe an keinem Tag im Jahr überschneiden. **Leer heisst leer.** Gilt heute kein Anlass oder findet er nichts, kommt eine Reihe ohne Namen zurück und der Client zeigt gar keine — statt einer mit Überschrift und nichts darunter. Scheitert der Abruf ganz, fehlt eine Reihe und nicht die Startseite. Bedient wird sie als Text, eine Zeile je Anlass: Name, von, bis, Stichwörter, Genres. Ein Listeneditor mit Zeilen zum Hinzufügen, Verschieben und Löschen wäre viel Oberfläche für etwas, das man dreimal im Jahr anfasst — und es ist dieselbe Form, in der es gespeichert wird. Ein Anlass ohne Stichwort und ohne Genre wird abgewiesen statt stillschweigend geschluckt: er fände nie etwas, und wer ihn eingetragen hat, suchte den Fehler woanders. **Die Stichwörter kommen erst beim nächsten Auffrischen der Metadaten.** Vorhandene Titel tragen noch keine — bis dahin bleibt die Reihe leer. 764 Tests grün, davon 22 neue. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
c13d1e78d2
commit
e066f5fe87
@@ -97,3 +97,29 @@ public sealed class Fremdbewertung
|
||||
/// <summary>Was dastehen soll: „7,4", „87 %", „62".</summary>
|
||||
public required string Anzeige { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>Ein Stichwort der Metadatenquelle, einmal je Name.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <b>Feiner als ein Genre, und deshalb eine eigene Tabelle.</b> „Stirb
|
||||
/// langsam" ist kein Familienfilm und trägt trotzdem „christmas". Eine
|
||||
/// Weihnachtsreihe nach Genres enthielte jeden Zeichentrickfilm und diesen
|
||||
/// Film nicht — nach Stichwörtern stimmt es.
|
||||
///
|
||||
/// Kleingeschrieben abgelegt: TMDB liefert „Christmas" und „christmas" je
|
||||
/// nach Eintrag, und zwei Schreibweisen wären zwei Stichwörter.
|
||||
/// </remarks>
|
||||
public sealed class Stichwort
|
||||
{
|
||||
public Guid Id { get; init; } = Guid.CreateVersion7();
|
||||
public required string Name { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>Verbindet ein Stichwort mit einem Film oder einer Serie.</summary>
|
||||
public sealed class Stichwortlink
|
||||
{
|
||||
public Guid Id { get; init; } = Guid.CreateVersion7();
|
||||
public required Guid StichwortId { get; init; }
|
||||
public Guid? MovieId { get; init; }
|
||||
public Guid? SeriesId { get; init; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace Flaro.Core.Library;
|
||||
|
||||
/// <summary>Ein Anlass, zu dem eine eigene Reihe auf der Startseite steht.</summary>
|
||||
///
|
||||
/// <param name="Name">Was über der Reihe steht — „Zu Halloween".</param>
|
||||
/// <param name="Von">Tag im Jahr, ab dem sie erscheint, als „MM-TT".</param>
|
||||
/// <param name="Bis">Tag im Jahr, bis zu dem sie bleibt, als „MM-TT".</param>
|
||||
/// <param name="Stichworte">Stichwörter der Metadatenquelle, kleingeschrieben.</param>
|
||||
/// <param name="Genres">Genres, falls Stichwörter allein zu wenig hergeben.</param>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <b>Einstellbar und nicht eingebaut.</b> Halloween und Weihnachten kennt
|
||||
/// jeder; der 1. August ist Schweizer Nationalfeiertag, der 4. Juli
|
||||
/// amerikanischer, und der Geburtstag des Betreibers steht in keiner
|
||||
/// Bibliothek. Eine feste Liste im Quelltext hiesse: für jeden Anlass eine
|
||||
/// neue Fassung.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <b>Stichwörter zuerst, Genres als Zugabe.</b> „Stirb langsam" ist kein
|
||||
/// Familienfilm und trägt trotzdem „christmas" — eine Weihnachtsreihe nach
|
||||
/// Genres enthielte jeden Zeichentrickfilm und diesen Film nicht.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public sealed record Saisonanlass(
|
||||
string Name,
|
||||
string Von,
|
||||
string Bis,
|
||||
IReadOnlyList<string> Stichworte,
|
||||
IReadOnlyList<string> Genres)
|
||||
{
|
||||
/// <summary>Was ohne eigene Einstellung dasteht.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <b>Vier, und bewusst nicht mehr.</b> Eine lange Vorgabeliste wäre
|
||||
/// eine Meinung darüber, was jemand feiert. Diese vier sind weit genug
|
||||
/// verbreitet, um als Beispiel zu taugen, und zeigen zugleich die drei
|
||||
/// Formen: ein Zeitraum im Jahr, einer über den Jahreswechsel, und
|
||||
/// einer, der sich auf Genres stützt.
|
||||
/// </remarks>
|
||||
public static IReadOnlyList<Saisonanlass> Vorgabe { get; } =
|
||||
[
|
||||
new("Zu Halloween", "10-01", "11-01",
|
||||
["halloween", "haunted house", "witch", "slasher", "zombie"],
|
||||
["Horror"]),
|
||||
new("Zur Weihnachtszeit", "12-01", "12-27",
|
||||
["christmas", "santa claus", "christmas eve"],
|
||||
[]),
|
||||
new("Zum Jahreswechsel", "12-28", "01-02",
|
||||
["new year's eve", "new year"],
|
||||
[]),
|
||||
new("Für den Sommer", "06-15", "08-31",
|
||||
["summer", "beach", "summer vacation", "road trip"],
|
||||
[]),
|
||||
];
|
||||
|
||||
/// <summary>Ob dieser Anlass an diesem Tag gilt.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <b>Über den Jahreswechsel hinweg.</b> „28.12. bis 02.01." ist kein
|
||||
/// Fehler, sondern der Normalfall für Silvester — ein Vergleich, der nur
|
||||
/// „von ≤ heute ≤ bis" kennt, fände diesen Zeitraum nie.
|
||||
/// </remarks>
|
||||
public bool Gilt(DateTimeOffset tag)
|
||||
{
|
||||
if (Tagnummer(Von) is not { } von || Tagnummer(Bis) is not { } bis) return false;
|
||||
|
||||
var heute = tag.Month * 100 + tag.Day;
|
||||
return von <= bis
|
||||
? heute >= von && heute <= bis
|
||||
: heute >= von || heute <= bis;
|
||||
}
|
||||
|
||||
/// <summary>„12-24" wird zu 1224 — oder zu <c>null</c>, wenn es keiner ist.</summary>
|
||||
private static int? Tagnummer(string roh)
|
||||
{
|
||||
var teile = (roh ?? "").Split('-');
|
||||
if (teile.Length != 2) return null;
|
||||
if (!int.TryParse(teile[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var monat)) return null;
|
||||
if (!int.TryParse(teile[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var tag)) return null;
|
||||
if (monat is < 1 or > 12 || tag is < 1 or > 31) return null;
|
||||
|
||||
return monat * 100 + tag;
|
||||
}
|
||||
|
||||
/// <summary>Ob der Anlass überhaupt etwas finden kann.</summary>
|
||||
public bool Brauchbar =>
|
||||
!string.IsNullOrWhiteSpace(Name)
|
||||
&& Tagnummer(Von) is not null && Tagnummer(Bis) is not null
|
||||
&& (Stichworte.Count > 0 || Genres.Count > 0);
|
||||
}
|
||||
@@ -51,6 +51,15 @@ public sealed record MovieMetadata(
|
||||
/// <summary>Die Altersfreigabe des eingestellten Landes, etwa „16".</summary>
|
||||
string? ContentRating = null,
|
||||
IReadOnlyList<string>? Genres = null,
|
||||
/// <summary>Stichwörter der Quelle, kleingeschrieben — „christmas", „halloween".</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <b>Feiner als Genres.</b> „Stirb langsam" ist kein Familienfilm und
|
||||
/// steht trotzdem unter dem Stichwort „christmas" — nach Genres liesse
|
||||
/// sich eine Weihnachtsreihe nicht bauen, die diesen Film enthält und
|
||||
/// nicht jeden Zeichentrickfilm.
|
||||
/// </remarks>
|
||||
IReadOnlyList<string>? Keywords = null,
|
||||
IReadOnlyList<CreditMetadata>? Credits = null,
|
||||
/// <summary>Der Schriftzug des Titels, freigestellt auf durchsichtigem Grund.</summary>
|
||||
///
|
||||
@@ -86,6 +95,15 @@ public sealed record SeriesMetadata(
|
||||
string? Tagline = null,
|
||||
string? ContentRating = null,
|
||||
IReadOnlyList<string>? Genres = null,
|
||||
/// <summary>Stichwörter der Quelle, kleingeschrieben — „christmas", „halloween".</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <b>Feiner als Genres.</b> „Stirb langsam" ist kein Familienfilm und
|
||||
/// steht trotzdem unter dem Stichwort „christmas" — nach Genres liesse
|
||||
/// sich eine Weihnachtsreihe nicht bauen, die diesen Film enthält und
|
||||
/// nicht jeden Zeichentrickfilm.
|
||||
/// </remarks>
|
||||
IReadOnlyList<string>? Keywords = null,
|
||||
IReadOnlyList<CreditMetadata>? Credits = null,
|
||||
/// <summary>Der Schriftzug des Titels, freigestellt auf durchsichtigem Grund.</summary>
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user