Live-TV: das Programm zeigte die falsche Sendung als laufend
Der Fehler steckte in der Abfrage, und er ist grob:
beginsAt> = jetzt − 1 Std.
endsAt< = jetzt + 6 Std.
Beide Grenzen schließen genau das aus, was man sehen will. Ein
Zweistünder, der um halb vier begann, war um Viertel nach fünf
unsichtbar — und angezeigt wurde stattdessen die nächste Sendung, die
durch den Filter passte. Deshalb wich die Anzeige von Plex' eigener ab.
Jetzt wird nur der **Anfang** eingegrenzt, mit sechs Stunden Vorlauf für
lange Sendungen, und keine Grenze auf das Ende. Zurück kommt, was den
Zeitraum berührt, statt was vollständig hineinpasst.
Gefiltert wird danach nur das Programm, nicht die Senderliste: ein Sender
ohne frische Daten soll „kein Programm" sagen, statt zu verschwinden.
Dazu zwei Wünsche aus dem Feldtest:
Die Kachel lässt sich in der Größe ziehen. Der Griff sitzt in der Ecke,
die zur Bildschirmmitte zeigt — am äußeren Rand läge er halb außerhalb
des Daumens. Gespeichert wird die begrenzte Breite, nicht die gezogene,
sonst bliebe eine einmal zu weit gezogene Kachel für immer zu groß.
Und eine Senderauswahl. Über zwanzig Sender zu zeichnen und ihr Programm
zu holen kostet Zeit, und die meisten sieht man nie an. Eine leere
Auswahl heißt weiterhin „alle" — sonst stünde man beim ersten Öffnen vor
einer leeren Liste.
Die Zeiten im Raster-Abzug liegen jetzt in der Zukunft. Mit den echten
Zeitstempeln von damals wäre er ab dem Tag nach der Aufnahme leer
gewesen, sobald auf Frische gefiltert wird.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
26c909a2e2
commit
af45bebceb
@@ -9,9 +9,32 @@ import Testing
|
||||
/// keine Vermutung: die Weboberfläche von Plex zeichnet ihren Guide daraus,
|
||||
/// und jeder Eintrag trägt den Sender mit sich. Diese Tests halten fest, dass
|
||||
/// die Sender dort auch dann herauskommen, wenn sonst nichts antwortet.
|
||||
/// Hält fest, womit tatsächlich gefragt wurde.
|
||||
///
|
||||
/// Ein Actor, weil der Transport aus einem anderen Zusammenhang schreibt und
|
||||
/// Swift 6 das sonst zu Recht verweigert.
|
||||
private actor QueryRecorder {
|
||||
private(set) var items: [URLQueryItem] = []
|
||||
func note(_ new: [URLQueryItem]) { items = new }
|
||||
}
|
||||
|
||||
@Suite("Senderliste aus dem Programmraster")
|
||||
struct LiveTVGuideTests {
|
||||
|
||||
private func server(transport: FakeTransport) -> PlexServer {
|
||||
PlexServer(
|
||||
resource: PlexResource(
|
||||
name: "Test",
|
||||
clientIdentifier: "srv",
|
||||
accessToken: "token",
|
||||
connections: [PlexConnection(uri: "http://server:32400", local: true)]
|
||||
),
|
||||
connection: PlexConnection(uri: "http://server:32400", local: true),
|
||||
identity: .test,
|
||||
transport: transport
|
||||
)!
|
||||
}
|
||||
|
||||
private func server(routes: [String: String]) -> PlexServer {
|
||||
PlexServer(
|
||||
resource: PlexResource(
|
||||
@@ -26,6 +49,9 @@ struct LiveTVGuideTests {
|
||||
)!
|
||||
}
|
||||
|
||||
// Die Zeiten in `livetv-grid.json` liegen bewusst weit in der Zukunft:
|
||||
// das Programm wird auf Frische gefiltert, und ein Abzug mit den echten
|
||||
// Zeitstempeln von damals wäre ab dem Tag nach der Aufnahme leer gewesen.
|
||||
private func fixture(_ name: String) throws -> String {
|
||||
let url = try #require(Bundle.module.url(forResource: "Fixtures/\(name)", withExtension: "json"))
|
||||
return try String(contentsOf: url, encoding: .utf8)
|
||||
@@ -78,6 +104,39 @@ struct LiveTVGuideTests {
|
||||
#expect(guide.programs.count == 2)
|
||||
}
|
||||
|
||||
@Test("Die laufende Sendung fällt nicht aus dem Fenster")
|
||||
func keepsTheRunningProgramme() async throws {
|
||||
// Der Fehler, der das Programm sichtbar falsch machte: gefiltert wurde
|
||||
// auf „endet vor Fensterende" und „beginnt nach Fensteranfang". Ein
|
||||
// Zweistünder ab 15:30 war damit um 17:18 unsichtbar, und angezeigt
|
||||
// wurde die nächste Sendung, die durch den Filter passte.
|
||||
let body = try fixture("livetv-grid-overlap")
|
||||
let recorder = QueryRecorder()
|
||||
let server = server(transport: FakeTransport { request in
|
||||
await recorder.note(
|
||||
URLComponents(url: request.url!, resolvingAgainstBaseURL: false)?.queryItems ?? []
|
||||
)
|
||||
return (Data(body.utf8), FakeTransport.response(for: request, status: 200))
|
||||
})
|
||||
|
||||
// 17:18 — mitten im langen Film.
|
||||
let now = Date(timeIntervalSince1970: 1_789_211_880)
|
||||
let entries = try await server.guide(
|
||||
providerIdentifier: "tv.plex.providers.epg.cloud:2",
|
||||
from: now,
|
||||
to: now.addingTimeInterval(6 * 3_600)
|
||||
)
|
||||
|
||||
#expect(entries.map(\.program.title).contains("Der lange Film"))
|
||||
#expect(entries.first?.program.isRunning(at: now) == true)
|
||||
|
||||
// Und der Grund dafür steht in der Abfrage: nur der Anfang wird
|
||||
// eingegrenzt, mit Vorlauf — keine Grenze auf das Ende.
|
||||
let seen = await recorder.items
|
||||
#expect(seen.contains { $0.name == "beginsAt<" })
|
||||
#expect(!seen.contains { $0.name == "endsAt<" })
|
||||
}
|
||||
|
||||
@Test("Ein Sender ohne Namen taucht nicht als Strich auf")
|
||||
func skipsNamelessChannels() async throws {
|
||||
let json = """
|
||||
|
||||
Reference in New Issue
Block a user