import MediaKit /// Welcher Titel und welches Bild auf eine Kachel gehören. /// /// **Hier und nicht bei einer Ansicht.** Das stand in `MediaRow.swift` — und /// damit in einer Datei, die nur das Telefon übersetzt. Der Fernseher zeigt /// dieselben Kacheln mit denselben Rückfallketten; sie dort noch einmal /// hinzuschreiben hiesse, zwei Stellen gleich zu halten, an denen die Fehler /// erst nach Wochen auffallen: ein Plakat, das bei einer Staffel grau bleibt, /// sieht nicht nach einem Fehler aus, sondern nach einem Server ohne Bild. /// /// Reine Ableitungen aus `MediaItem`, keine Ansicht — deshalb neben den /// übrigen Modellen und nicht in FlixyDesign, das `MediaItem` gar nicht kennt. extension MediaItem { /// Der Titel auf einer Kachel in einer Reihe. /// /// Groß steht, worum es geht: bei einer Folge ihr eigener Titel, bei /// einer Staffel der Name der Serie. Die Einordnung — Serie, Staffel — /// gehört darunter. „Staffel 10" allein als Überschrift sagt nichts /// darüber, welche Serie gemeint ist. var rowTitle: String { switch kind { case .episode: title // Die Serie steht je nach Antwort mal unter `parentTitle`, mal unter // `seriesTitle`. Fehlt beides, bleibt „Staffel 2" — besser als // gar keine Beschriftung. case .season: parentTitle ?? seriesTitle ?? title default: title } } /// Welches Bild auf die Querformat-Kachel gehört. /// /// Bei Folgen ist `thumb` das Szenenbild der Folge — genau richtig. Bei /// Filmen ist `thumb` das Hochkant-Plakat, das im Querformat beschnitten /// würde; dort ist `art` (das Hintergrundbild) die bessere Wahl. var rowArtworkPath: String? { switch kind { case .episode: thumb ?? seriesThumb // Eine Staffel hat bei Jellyfin oft gar kein eigenes Bild — sie leiht // sich das der Serie. Ohne diesen Rückfall blieb „Nachtstreife, // Staffel 7" eine graue Fläche, obwohl die Serie ein Plakat hat. case .season: art ?? thumb ?? seriesArt ?? seriesThumb default: art ?? thumb } } /// Welches Bild auf die Hochkant-Kachel gehört. /// /// Bei Folgen das Plakat der Serie statt des Szenenbilds: ein 16:9-Bild /// hochkant beschnitten zeigt einen zufälligen Ausschnitt und ist zum /// Wiedererkennen wertlos. var posterArtworkPath: String? { switch kind { case .episode: seriesThumb ?? parentThumb ?? thumb // Das eigene Staffelplakat zuerst: es zeigt die Staffel. Gibt es // keines, ist das der Serie allemal besser als nichts. case .season: thumb ?? seriesThumb default: thumb } } } /// Laufzeiten als Text. /// /// Aus derselben Ansichtsdatei hierher geholt wie die Kachel-Ableitungen /// darüber: am Fernseher steht dieselbe Zeile unter demselben Aufmacher. extension Duration { /// Laufzeit als „2 Std 46 Min" bzw. „46 Min". var runtimeLabel: String { let totalMinutes = Int(components.seconds / 60) let hours = totalMinutes / 60 let minutes = totalMinutes % 60 if hours > 0 { return String(localized: "runtime.hoursMinutes \(hours) \(minutes)") } return String(localized: "runtime.minutes \(minutes)") } }