Live-TV: die Sender waren da, zwei eigene Fehler haben sie verschluckt
Der Abzug vom Server zeigt beides schwarz auf weiß. Erstens: /media/grabbers/devices/1/channels antwortet mit 278 Sendern — unter dem Sammelnamen `DeviceChannel`. Die Hülle kannte nur `Channel` und hat die vollständige Liste als leer verworfen. Zweitens: das Programmraster antwortet, aber nicht auf `type=1`. Die 1 steht bei Plex für Film, und im Programm laufen auch Folgen, Sport und Nachrichten — der Filter hat das Raster geleert. Ohne ihn kommen die Sendungen samt Sendername, Nummer, Logo und Kennung. Das Raster hat jetzt Vorrang vor der Tunerliste, auch wenn beide antworten: nur dort gehören Sender und Programm zusammen, es enthält ohnehin nur die eingeschalteten Sender, und die Tunerliste führt alle 278. Einschalten läuft über die Adresse der laufenden Sendung beim Programmanbieter — Plex behandelt eine laufende Sendung wie einen Film. Die Adresse wird einmal entpackt, bevor sie in die Anfrage geht: sonst kodiert URLComponents ein zweites Mal, und aus %3A wird %253A. Die Tests stehen jetzt auf den echten Antworten aus dem Abzug, nicht auf erfundenen: DeviceChannel mit `name` und `key`, Rastereinträge mit channelVcn, channelID und einer Folge neben einem Film. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
7e36f37506
commit
2362865ba9
@@ -44,7 +44,9 @@ struct LiveTVGuideTests {
|
||||
let guide = await server.liveTVGuide(dvr: dvr)
|
||||
|
||||
#expect(guide.channels.count == 2)
|
||||
#expect(guide.channels.map(\.title) == ["SRF 1 HD", "SRF2"])
|
||||
// Nach Sendernummer, und ohne die Nummer noch einmal im Namen:
|
||||
// Plex schreibt sie dort mit hinein.
|
||||
#expect(guide.channels.map(\.title) == ["SRF2", "ZDFGERH (ZDF HD)"])
|
||||
}
|
||||
|
||||
@Test("Fehlt der Sendername, trägt das Kürzel den Sender")
|
||||
@@ -54,12 +56,10 @@ struct LiveTVGuideTests {
|
||||
])
|
||||
|
||||
let guide = await server.liveTVGuide(dvr: dvr)
|
||||
let second = try #require(guide.channels.last)
|
||||
let callSignOnly = try #require(guide.channels.first)
|
||||
|
||||
#expect(second.title == "SRF2")
|
||||
// Die Sendernummer kommt mal als Zahl, mal als Zeichenkette — beides
|
||||
// muss lesbar sein, sonst fehlt sie bei der Hälfte der Sender.
|
||||
#expect(second.channelIdentifier == "2")
|
||||
#expect(callSignOnly.title == "SRF2")
|
||||
#expect(callSignOnly.channelIdentifier == "002")
|
||||
}
|
||||
|
||||
@Test("Sendungen landen beim richtigen Sender, nach Anfangszeit sortiert")
|
||||
@@ -69,10 +69,12 @@ struct LiveTVGuideTests {
|
||||
])
|
||||
|
||||
let guide = await server.liveTVGuide(dvr: dvr)
|
||||
let first = try #require(guide.channels.first)
|
||||
let programs = try #require(guide.programs[first.id])
|
||||
let zdf = try #require(guide.channels.last)
|
||||
let programs = try #require(guide.programs[zdf.id])
|
||||
|
||||
#expect(programs.map(\.title) == ["Tagesschau", "Meteo"])
|
||||
// Auch die Folge ist dabei: mit `type=1` kam nur „Film" durch, und
|
||||
// das Raster blieb leer.
|
||||
#expect(programs.map(\.title) == ["Endlich Witwer", "heute journal"])
|
||||
#expect(guide.programs.count == 2)
|
||||
}
|
||||
|
||||
@@ -148,14 +150,47 @@ struct LiveTVGuideTests {
|
||||
#expect(lookup.trace.contains { $0.path == "/livetv/dvrs/2/channels" && $0.result.contains("Channel: 2") })
|
||||
}
|
||||
|
||||
@Test("Die Einschaltadresse reist mit dem Sender mit")
|
||||
func keepsTuneKey() async throws {
|
||||
@Test("Die Adresse der laufenden Sendung führt zum Strom")
|
||||
func tunesThroughTheProgram() async throws {
|
||||
// Das Raster nennt keine Teil-Adresse. Der Weg führt über die
|
||||
// Sendung selbst: Plex behandelt eine laufende Sendung wie einen Film.
|
||||
let server = server(routes: [
|
||||
"/tv.plex.providers.epg.cloud:2/grid": try fixture("livetv-grid"),
|
||||
])
|
||||
|
||||
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))
|
||||
let path = try #require(URLComponents(url: url, resolvingAgainstBaseURL: false)?
|
||||
.queryItems?.first { $0.name == "path" }?.value)
|
||||
|
||||
#expect(guide.channels.first?.key == "/livetv/channels/11")
|
||||
#expect(path == "/tv.plex.providers.epg.cloud:2/metadata/plex://movie/6254592919e23c64f6c5605d")
|
||||
// Doppelt kodiert fände der Server nichts — aus %3A würde %253A.
|
||||
#expect(!url.absoluteString.contains("%253A"))
|
||||
}
|
||||
|
||||
@Test("Die Sender des Tuners stehen unter DeviceChannel")
|
||||
func readsDeviceChannelKey() async throws {
|
||||
// Der Server lieferte 278 Sender, die Hülle verwarf sie: sie kannte
|
||||
// nur `Channel`. Der Tuner schreibt `DeviceChannel`.
|
||||
let json = """
|
||||
{"MediaContainer":{"size":2,"DeviceChannel":[
|
||||
{"drm":false,"favorite":false,"hd":true,"identifier":"300","key":"300","name":"ZDF HD"},
|
||||
{"hd":true,"identifier":"301","key":"301","name":"SRF 1 HD"}
|
||||
]}}
|
||||
"""
|
||||
let server = server(routes: ["/media/grabbers/devices/1/channels": json])
|
||||
let withTuner = PlexDVR(
|
||||
key: "2",
|
||||
devices: [PlexTunerDevice(key: "1")],
|
||||
epgIdentifier: "tv.plex.providers.epg.cloud:2"
|
||||
)
|
||||
|
||||
let lookup = await server.channels(inDVR: withTuner)
|
||||
|
||||
#expect(lookup.channels.map(\.title) == ["ZDF HD", "SRF 1 HD"])
|
||||
// Die Nummer steht beim Tuner schlicht im Schlüssel.
|
||||
#expect(lookup.channels.first?.channelIdentifier == "300")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user