Live-TV bekommt einen neutralen Vertrag

Zwei Protokolle statt eines: LiveTVBackend für Sender, Programm und
Einschalten, LiveTVRecordingBackend für Aufnahmen. Getrennt, weil Plex
das eine kann und das andere nicht — ein as? sagt die Wahrheit, eine
Methode, die bei Plex nur wirft, verspricht etwas und bricht es dann.

Plex zieht um, ohne umgebaut zu werden. Der Suchlauf, der die
Senderliste findet, bleibt Zeile für Zeile, wo er ist; davor liegt jetzt
ein Actor, der sich Empfänger und Sender merkt. Nötig, weil PlexBackend
ein struct ist und tune() den echten PlexChannel braucht — ohne
Gedächtnis liefe der Suchlauf bei jedem Antippen neu.

Jellyfin ist neu und deutlich kürzer, weil es dort nichts zu suchen
gibt. Die Endpunkte stammen aus der OpenAPI-Spec des Servers. Beim
Vormerken wird die Vorlage des Servers roh weitergereicht statt
entschlüsselt und neu zusammengesetzt: welche Felder Pflicht sind, sagt
die Beschreibung nicht, und ein verlorenes fiele erst an einer Aufnahme
auf, die nicht startet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-14 06:17:10 +02:00
co-authored by Claude Opus 5
parent 9df58ed5a6
commit 24765a5afc
10 changed files with 1153 additions and 14 deletions
@@ -2,7 +2,7 @@ import Foundation
import MediaKit
/// Was beim Live-TV herauskommen kann.
public enum LiveTVAvailability: Sendable, Equatable {
public enum PlexLiveTVAvailability: Sendable, Equatable {
/// Es gibt einen Empfänger und Sender.
case available(dvrs: [PlexDVR])
/// Der Server läuft, hat aber keinen Empfänger eingerichtet.
@@ -16,7 +16,7 @@ public enum LiveTVAvailability: Sendable, Equatable {
extension PlexServer {
/// Prüft, ob der Server überhaupt Live-TV kann.
public func liveTVAvailability() async -> LiveTVAvailability {
public func liveTVAvailability() async -> PlexLiveTVAvailability {
do {
let container = try await client.send(
PlexRequest(path: "/livetv/dvrs", timeout: .seconds(10)),
@@ -405,7 +405,7 @@ extension PlexServer {
program: PlexProgram? = nil,
dvr: PlexDVR? = nil,
maximumBitrate: Int?
) async -> LiveTuneResult {
) async -> PlexTuneResult {
let session = UUID().uuidString
var attempts = 0
@@ -448,7 +448,7 @@ extension PlexServer {
)
trace.append(contentsOf: outcome.probes)
if let url = outcome.url {
return LiveTuneResult(
return PlexTuneResult(
url: url,
sessionIdentifier: session,
subscriptionKey: outcome.subscription,
@@ -464,7 +464,7 @@ extension PlexServer {
// Und hier aufhören. Dass das Belegen klappt, beantwortet die
// Frage nach dem Weg — die übrigen zwanzig Abfragen sind dann
// nur noch Lärm im Bericht und Last für den Server.
return LiveTuneResult(
return PlexTuneResult(
url: nil,
sessionIdentifier: session,
subscriptionKey: nil,
@@ -488,7 +488,7 @@ extension PlexServer {
)
trace.append(outcome.probe)
if let url = outcome.url {
return LiveTuneResult(url: url, sessionIdentifier: session, trace: trace)
return PlexTuneResult(url: url, sessionIdentifier: session, trace: trace)
}
}
@@ -515,7 +515,7 @@ extension PlexServer {
)
trace.append(outcome.probe)
if let url = outcome.url {
return LiveTuneResult(url: url, sessionIdentifier: session, trace: trace)
return PlexTuneResult(url: url, sessionIdentifier: session, trace: trace)
}
}
}
@@ -540,7 +540,7 @@ extension PlexServer {
)
trace.append(outcome.probe)
if let url = outcome.url {
return LiveTuneResult(url: url, sessionIdentifier: session, trace: trace)
return PlexTuneResult(url: url, sessionIdentifier: session, trace: trace)
}
}
}
@@ -601,7 +601,7 @@ extension PlexServer {
)
trace.append(outcome.probe)
if let url = outcome.url {
return LiveTuneResult(url: url, sessionIdentifier: session, trace: trace)
return PlexTuneResult(url: url, sessionIdentifier: session, trace: trace)
}
}
}
@@ -609,7 +609,7 @@ extension PlexServer {
// Kein Weg hat mit 200 geantwortet. Den Transcoder anhalten, sonst
// rechnet der Server für eine Wiedergabe weiter, die es nicht gibt.
await stopTranscode(sessionIdentifier: session)
return LiveTuneResult(url: nil, sessionIdentifier: session, trace: trace)
return PlexTuneResult(url: nil, sessionIdentifier: session, trace: trace)
}
/// Schlägt eine Sendung beim Programmanbieter nach.
@@ -1442,7 +1442,7 @@ public struct LiveTVGuide: Sendable {
}
/// Was beim Einschalten herauskam.
public struct LiveTuneResult: Sendable {
public struct PlexTuneResult: Sendable {
public let url: URL?
public let sessionIdentifier: String
/// Womit der Tuner wieder freigegeben wird.