Der Vorrat steigt jetzt auch eine Ebene tiefer

Bei „Auto\" bestellen wir eine Liste von Stufen; die Schnipsel stehen eine
Ebene darunter. Der Speicher erkannte das zwar, stieg dann aber aus und
reichte die Liste mit relativen Adressen durch — die zeigten danach auf den
lokalen Server, wo es sie nicht gibt. Es wurde nichts vorgeholt, und
beinahe waere auch nichts mehr gelaufen.

Jetzt wird auch die Stufenliste umgeschrieben. Holt der Player eine Stufe,
kommt er wieder bei uns an, und dort beginnt das Vorauslaufen — bei der
Stufe, fuer die er sich entschieden hat.

Dazu eine Zeile im Qualitaetsblatt, die sagt, ob der Vorrat laeuft und wie
weit er voraus ist. Von aussen ist das nicht zu sehen: laeuft er nicht,
spielt es trotzdem, nur ohne Vorsprung — und genau so sieht auch ein
Vorrat aus, der laeuft und nichts bekommt. Ohne diese Zeile sind die beiden
Faelle nicht zu unterscheiden, und ich haette wieder geraten.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-28 20:29:20 +02:00
co-authored by Claude Opus 5
parent 134dc82927
commit bbd1c3b572
6 changed files with 225 additions and 13 deletions
@@ -24,11 +24,28 @@ public actor LocalStreamServer {
private static let segmentPrefix = "/s/"
/// Der Pfad der Abspielliste selbst.
private static let playlistPath = "/playlist.m3u8"
/// Der Pfad einer Stufe, die eine Ebene tiefer liegt.
///
/// Die Endung muss stimmen: AVPlayer entscheidet am Namen, ob er eine
/// Abspielliste oder Bild erwartet.
private static let levelPrefix = "/level.m3u8"
/// Wie eine Adresse aus der Abspielliste beim Server heisst.
///
/// Der ursprüngliche Pfad wandert dabei in die Abfrage, damit Schrägstriche
/// und Punkte darin nichts anrichten.
/// Wie eine Stufe aus der Stufenliste beim Server heisst.
///
/// Vollständig, nicht relativ: eine Stufe liegt beim Server unter einem
/// ganz anderen Pfad als bei uns, und relativ aufgelöst zeigte sie ins
/// Leere.
public nonisolated static func localPlaylistPath(for absolute: String) -> String {
var teile = URLComponents()
teile.path = levelPrefix
teile.queryItems = [URLQueryItem(name: "u", value: absolute)]
return teile.string ?? levelPrefix
}
public nonisolated static func localPath(for original: String) -> String {
var teile = URLComponents()
teile.path = segmentPrefix
@@ -134,6 +151,18 @@ public actor LocalStreamServer {
let pfadTeil = anfrage.components(separatedBy: " ").dropFirst().first
else { return finish(verbindung, status: 400, body: Data()) }
if pfadTeil.hasPrefix(Self.levelPrefix) {
guard let teile = URLComponents(string: pfadTeil),
let adresse = teile.queryItems?.first(where: { $0.name == "u" })?.value,
let inhalt = await cache.playlist(at: adresse)
else { return finish(verbindung, status: 404, body: Data()) }
return finish(
verbindung, status: 200, body: Data(inhalt.utf8),
type: "application/vnd.apple.mpegurl"
)
}
if pfadTeil.hasPrefix(Self.playlistPath) {
let inhalt = Data((playlist ?? "").utf8)
return finish(