Live-TV-Sender gefunden, Film-Schriftzüge ergänzt

Senderliste
  Plex liefert die Sender verschachtelt in der Antwort auf /livetv/dvrs
  mit — jeder Empfänger bringt seine eigenen unter `Device` → `Channel`.
  Mein getrennter Endpunkt /livetv/dvrs/{id}/channels war eine Vermutung
  und lieferte nichts. Bei einem Server mit über dreißig eingerichteten
  Sendern stand deshalb „Keine Sender".

  Die verschachtelte Liste hat jetzt Vorrang, der Endpunkt bleibt als
  Rückfalllinie. `ChannelMapping` wird als ältere Schreibweise ebenfalls
  gelesen, und der Empfänger-Schlüssel kommt je nach Serverfassung als
  Zahl oder als Zeichenkette.

  Bleibt die Liste leer, sagt die Ansicht jetzt welcher Weg was ergeben
  hat. In einem Bereich ohne offizielle Beschreibung ist das die Angabe,
  mit der sich der nächste Fehler finden lässt.

Schriftzüge
  Plex liefert bei vielen Filmen ein `clearLogo` — den Schriftzug in
  seiner eigenen Type, freigestellt. Der tritt jetzt im Aufmacher an die
  Stelle des gesetzten Titels.

  Dabei ein Fallstrick: /photo/:/transcode liefert JPEG, und JPEG kennt
  keine Transparenz. Über den Bild-Transcoder geladen wäre aus dem
  freigestellten Logo ein schwarzer Kasten geworden. Es wird deshalb
  unverändert geladen. Fehlt der Schriftzug oder scheitert das Laden,
  bleibt es beim Titel.

161 Tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Guido
2026-09-12 09:28:21 +02:00
co-authored by Claude Opus 5
parent 7cfc6e0667
commit ed84b5bf22
11 changed files with 381 additions and 17 deletions
@@ -10,6 +10,10 @@ public struct HeroBanner<Actions: View>: View {
private let metadata: String?
private let summary: String?
private let artworkURL: URL?
/// Der freigestellte Schriftzug des Films. Steht er zur Verfügung, tritt
/// er an die Stelle des gesetzten Titels — „Harry Potter" in seiner
/// eigenen Schrift ist wiedererkennbar, eine Systemschrift nicht.
private let logoURL: URL?
private let aspectRatio: CGFloat
private let actions: Actions
@@ -18,6 +22,7 @@ public struct HeroBanner<Actions: View>: View {
metadata: String? = nil,
summary: String? = nil,
artworkURL: URL?,
logoURL: URL? = nil,
// 16:9, weil Plex genau das als `art` liefert. Vorher stand hier
// 3:4 — mit `scaledToFill` wurde das Bild dadurch links und rechts
// kräftig beschnitten, und vom Aufmacher war nur ein Ausschnitt zu
@@ -29,10 +34,49 @@ public struct HeroBanner<Actions: View>: View {
self.metadata = metadata
self.summary = summary
self.artworkURL = artworkURL
self.logoURL = logoURL
self.aspectRatio = aspectRatio
self.actions = actions()
}
/// Schriftzug, wenn vorhanden — sonst gesetzter Titel.
///
/// Der Schriftzug wird ohne Bild-Transcoder geladen; er ist ein
/// freigestelltes PNG, und der Transcoder liefert JPEG. Aus dem
/// freigestellten Logo würde sonst ein schwarzer Kasten.
@ViewBuilder
private var titleView: some View {
if let logoURL {
AsyncImage(url: logoURL) { phase in
switch phase {
case .success(let image):
image
.resizable()
.scaledToFit()
// Nach oben begrenzt: manche Schriftzüge sind fast
// quadratisch, andere sehr breit. Ohne Deckel schöbe
// ein hohes Logo die Knöpfe aus dem Bild.
.frame(maxWidth: 260, maxHeight: 76, alignment: .leading)
default:
// Solange geladen wird — und wenn es scheitert — bleibt es
// beim gesetzten Titel. Ein leerer Platz wäre schlimmer
// als eine Systemschrift.
plainTitle
}
}
.accessibilityLabel(Text(title))
} else {
plainTitle
}
}
private var plainTitle: some View {
Text(title)
.font(.flixyHero)
.foregroundStyle(Color.flixyTextPrimary)
.lineLimit(2)
}
public var body: some View {
FlixyArtwork(url: artworkURL, aspectRatio: aspectRatio)
.overlay(alignment: .bottom) {
@@ -53,10 +97,7 @@ public struct HeroBanner<Actions: View>: View {
}
.overlay(alignment: .bottomLeading) {
VStack(alignment: .leading, spacing: FlixySpacing.snug) {
Text(title)
.font(.flixyHero)
.foregroundStyle(Color.flixyTextPrimary)
.lineLimit(2)
titleView
if let metadata {
Text(metadata)