Live-TV: erst den Tuner belegen, dann umrechnen lassen
Der übersprungene Schritt. Ich habe die Sendung direkt an den Transcoder gegeben — ohne dass jemand den Tuner belegt hätte. Der Server fing an, merkte, dass er nichts zu senden hat, und brach ab: „die Wiedergabe wurde unterbrochen", ohne weitere Angabe. Jetzt zwei Schritte. Erst eine Live-Sitzung eröffnen, dann die Adresse dieser Sitzung umrechnen lassen — nicht die des Senders und nicht die der Sendung. mediaIndex und partIndex sind dabei -1: ein laufender Sender hat keine Fassungen zur Auswahl. Unter welchem Schlüssel sich die Sitzung eröffnen lässt, unterscheidet sich je nach Anbieter, deshalb werden die in Frage kommenden der Reihe nach probiert — der Raster-Schlüssel zuerst, weil er den Sender genauso bezeichnet wie die Liste, aus der er stammt. Dazu zwei Stellen, an denen Gründe bisher verschwanden: Vor dem Abspielen wird der Server gefragt, ob er den Strom überhaupt zulässt. Er antwortet im Klartext; der Player meldet nur, dass es nicht ging. Und wenn der Motor scheitert, steht sein Grund ab jetzt auf dem Bildschirm statt nur im Protokoll. „Die Wiedergabe wurde unterbrochen" allein sagt weder, ob der Server ablehnt, noch ob der Motor das Format nicht mag — und genau diese Unterscheidung hat diese Runde gekostet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
bbe47b83be
commit
861ca805a5
@@ -161,7 +161,10 @@ struct LiveTVGuideTests {
|
||||
let guide = await server.liveTVGuide(dvr: dvr)
|
||||
let zdf = try #require(guide.channels.last)
|
||||
let program = try #require(guide.programs[zdf.id]?.first)
|
||||
let url = try #require(await server.tune(channel: zdf, program: program, maximumBitrate: nil))
|
||||
// Hier antwortet keine Sitzung; dann bleibt der direkte Weg über die
|
||||
// Sendung — auf Servern, die den Tuner selbst belegen, genügt er.
|
||||
let result = await server.tune(channel: zdf, program: program, maximumBitrate: nil)
|
||||
let url = try #require(result.url)
|
||||
let path = try #require(URLComponents(url: url, resolvingAgainstBaseURL: false)?
|
||||
.queryItems?.first { $0.name == "path" }?.value)
|
||||
|
||||
@@ -170,6 +173,48 @@ struct LiveTVGuideTests {
|
||||
#expect(!url.absoluteString.contains("%253A"))
|
||||
}
|
||||
|
||||
@Test("Erst den Tuner belegen, dann umrechnen lassen")
|
||||
func opensSessionBeforeTranscoding() async throws {
|
||||
// Der übersprungene Schritt: ohne belegten Tuner beginnt die
|
||||
// Wiedergabe und stirbt sofort — „die Wiedergabe wurde unterbrochen".
|
||||
let session = """
|
||||
{"MediaContainer":{"size":1,"Metadata":[
|
||||
{"ratingKey":"live-1","key":"/livetv/sessions/abc","type":"clip","title":"ZDF HD",
|
||||
"Media":[{"id":1,"Part":[{"id":1,"key":"/livetv/sessions/abc/stream"}]}]}
|
||||
]}}
|
||||
"""
|
||||
// Nur unter dem Raster-Schlüssel antwortet eine Sitzung.
|
||||
let server = server(routes: ["/gk-5": session])
|
||||
let channel = PlexChannel(id: "5", title: "ZDF HD", key: "5", gridKey: "gk-5")
|
||||
|
||||
let result = await server.tune(channel: channel, maximumBitrate: nil)
|
||||
let url = try #require(result.url)
|
||||
let items = try #require(URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems)
|
||||
|
||||
#expect(items.first { $0.name == "path" }?.value == "/livetv/sessions/abc/stream")
|
||||
// Ein laufender Sender hat keine Fassungen zur Auswahl.
|
||||
#expect(items.first { $0.name == "mediaIndex" }?.value == "-1")
|
||||
}
|
||||
|
||||
@Test("Der Raster-Schlüssel wird zuerst versucht, und nie ein ganzer Pfad")
|
||||
func sessionKeyOrder() {
|
||||
let channel = PlexChannel(id: "hash-5", title: "ZDF HD", key: "5", gridKey: "gk-5")
|
||||
let program = PlexProgram(
|
||||
id: "p1",
|
||||
title: "heute",
|
||||
startsAt: .now,
|
||||
endsAt: .now.addingTimeInterval(1800),
|
||||
metadataKey: "/tv.plex.providers.epg.cloud:2/metadata/plex%3A%2F%2Fmovie%2Fabc"
|
||||
)
|
||||
|
||||
let keys = PlexServer.sessionKeys(channel: channel, program: program)
|
||||
|
||||
#expect(keys.first == "gk-5")
|
||||
// An `/livetv/sessions/<uuid>/` gehört ein Schlüssel, kein zweiter Pfad.
|
||||
#expect(keys.allSatisfy { !$0.contains("/") })
|
||||
#expect(keys.contains("5"))
|
||||
}
|
||||
|
||||
@Test("Die Sender des Tuners stehen unter DeviceChannel")
|
||||
func readsDeviceChannelKey() async throws {
|
||||
// Der Server lieferte 278 Sender, die Hülle verwarf sie: sie kannte
|
||||
|
||||
Reference in New Issue
Block a user