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
+2 -1
View File
@@ -67,7 +67,8 @@ struct PlayableDetailView: View {
path: item.art ?? item.grandparentArt ?? item.thumb,
width: 900,
height: 1200
)
),
logoURL: session.server?.rawImageURL(path: item.clearLogoPath)
) {
Button {
playback.play(item, mediaIndex: selectedVersion)
+2 -1
View File
@@ -45,7 +45,8 @@ struct SeriesDetailView: View {
path: item.art ?? item.thumb,
width: 900,
height: 1200
)
),
logoURL: session.server?.rawImageURL(path: item.clearLogoPath)
) {
DownloadAllButton(container: item)
}
+2 -1
View File
@@ -19,7 +19,8 @@ struct HeroSection: View {
path: item.art ?? item.grandparentArt ?? item.thumb,
width: 900,
height: 1200
)
),
logoURL: session.server?.rawImageURL(path: item.clearLogoPath)
) {
Button {
playback.play(item)
+17 -2
View File
@@ -12,6 +12,8 @@ struct LiveTVView: View {
@State private var availability: LiveTVAvailability?
@State private var channels: [PlexChannel] = []
/// Woher die Senderliste kam — steht in der leeren Ansicht.
@State private var channelSource: String?
@State private var programs: [String: [PlexProgram]] = [:]
@State private var isTuning: String?
@@ -47,7 +49,17 @@ struct LiveTVView: View {
ContentUnavailableView {
Label("liveTV.noChannels.title", systemImage: "tv")
} description: {
Text("liveTV.noChannels.description")
VStack(spacing: FlixySpacing.snug) {
Text("liveTV.noChannels.description")
if let channelSource {
// Ohne diese Angabe ist „keine Sender" eine
// Sackgasse: es sagt nicht, ob der Server nichts
// hergibt oder ob die App am falschen Ort sucht.
Text(channelSource)
.font(.system(.caption2, design: .monospaced))
.foregroundStyle(Color.flixyTextMuted)
}
}
} actions: {
Button("action.retry") { Task { await load() } }
}
@@ -86,7 +98,10 @@ struct LiveTVView: View {
self.availability = availability
guard case .available(let dvrs) = availability, let dvr = dvrs.first else { return }
channels = (try? await server.channels(inDVR: dvr)) ?? []
let lookup = await server.channels(inDVR: dvr)
channels = lookup.channels
channelSource = lookup.description
// Der Programmführer kommt getrennt: er kann ausfallen, ohne dass
// deshalb das Umschalten unmöglich wäre. Eine Senderliste ohne