using System.Globalization; namespace Flaro.Core.Library; /// Ein Anlass, zu dem eine eigene Reihe auf der Startseite steht. /// /// Was über der Reihe steht — „Zu Halloween". /// Tag im Jahr, ab dem sie erscheint, als „MM-TT". /// Tag im Jahr, bis zu dem sie bleibt, als „MM-TT". /// Stichwörter der Metadatenquelle, kleingeschrieben. /// Genres, falls Stichwörter allein zu wenig hergeben. /// /// /// /// 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. /// /// /// Stichwörter zuerst, Genres als Zugabe. „Stirb langsam" ist kein /// Familienfilm und trägt trotzdem „christmas" — eine Weihnachtsreihe nach /// Genres enthielte jeden Zeichentrickfilm und diesen Film nicht. /// /// public sealed record Saisonanlass( string Name, string Von, string Bis, IReadOnlyList Stichworte, IReadOnlyList Genres) { /// Was ohne eigene Einstellung dasteht. /// /// /// Vier, und bewusst nicht mehr. 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. /// public static IReadOnlyList 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"], []), ]; /// Ob dieser Anlass an diesem Tag gilt. /// /// /// Ü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. /// 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; } /// „12-24" wird zu 1224 — oder zu null, wenn es keiner ist. 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; } /// Ob der Anlass überhaupt etwas finden kann. public bool Brauchbar => !string.IsNullOrWhiteSpace(Name) && Tagnummer(Von) is not null && Tagnummer(Bis) is not null && (Stichworte.Count > 0 || Genres.Count > 0); }