Prüfen, ob wir uns die Leiter selbst bauen können
Der Wortlaut der Master-Playlist zeigt, woraus Jellyfins eigene Leiter bestünde: dieselbe `main.m3u8`-Adresse, mehrfach, mit anderem `VideoBitrate`. Eine Master-Playlist ist nur ein Menü. Liefert der Server diese Unter-Playlists auch dann, wenn **wir** die Zahl ändern, brauchen wir seine Zustimmung gar nicht — dann schreiben wir das Menü selbst, und die Frage, warum er es verweigert, ist gegenstandslos. Die Probe versucht deshalb drei Stufen von Hand: halbe Bitrate, ein Viertel, und ein Viertel zusammen mit `maxHeight=480`. Das letzte ist der interessante Fall — Jellyfins eigene Leiter lässt die Auflösung stehen und dreht nur an der Bitrate. Eine Stufe, die auch kleiner rechnet, sieht bei wenig Bandbreite deutlich besser aus als dieselbe Auflösung mit zu wenig Daten. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
6e18fda4aa
commit
f48eb55f35
@@ -321,7 +321,10 @@ func jellyfinLeiter(host: String) async {
|
||||
)
|
||||
print(mitABR)
|
||||
|
||||
if mitABR.contains("1 Stufe:") { erklärungWarumKeineLeiter() }
|
||||
if mitABR.contains("1 Stufe:") {
|
||||
erklärungWarumKeineLeiter()
|
||||
await prüfeSelbstgebauteLeiter(master: master, kopfzeilen: kopf)
|
||||
}
|
||||
|
||||
// Aufräumen: die Aushandlung hat am Server eine Sitzung angelegt, und
|
||||
// ohne dieses Signal rechnet der Transcoder weiter, obwohl niemand
|
||||
@@ -354,3 +357,59 @@ func erklärungWarumKeineLeiter() {
|
||||
print(" Kam dieser Aufruf von zuhause, ist Punkt 1 die Erklärung — und dann")
|
||||
print(" sagt die Messung nichts darüber, was von unterwegs käme.")
|
||||
}
|
||||
|
||||
/// Prüft, ob wir uns die Leiter **selbst** bauen könnten.
|
||||
///
|
||||
/// Eine Master-Playlist ist nur ein Menü: eine Liste von Adressen mit Angaben
|
||||
/// dazu. Jellyfins eigene Leiter besteht aus derselben `main.m3u8`-Adresse,
|
||||
/// nur mit anderem `VideoBitrate`. Liefert der Server diese Unter-Playlists
|
||||
/// auch dann, wenn **wir** die Zahl ändern, dann braucht es seine Zustimmung
|
||||
/// gar nicht — dann schreiben wir das Menü.
|
||||
///
|
||||
/// Zusätzlich mit `maxHeight`: Jellyfins eigene Leiter lässt die Auflösung
|
||||
/// stehen und dreht nur an der Bitrate. Eine Stufe, die auch kleiner rechnet,
|
||||
/// sieht bei wenig Bandbreite deutlich besser aus.
|
||||
func prüfeSelbstgebauteLeiter(master: URL, kopfzeilen: [String: String]) async {
|
||||
print("")
|
||||
print("=== Ginge eine selbstgebaute Leiter? ===")
|
||||
|
||||
guard let (daten, _) = try? await URLSession.shared.data(for: anfrage(master, kopfzeilen)),
|
||||
let zeile = String(decoding: daten, as: UTF8.self)
|
||||
.split(separator: "\n")
|
||||
.first(where: { $0.hasPrefix("main.m3u8") }),
|
||||
let unter = URL(string: String(zeile), relativeTo: master)?.absoluteURL
|
||||
else {
|
||||
print(" Keine Unter-Playlist im Menü gefunden.")
|
||||
return
|
||||
}
|
||||
|
||||
let versuche: [(String, Int, Int?)] = [
|
||||
("halbe Bitrate", 3_000_000, nil),
|
||||
("ein Viertel", 1_500_000, nil),
|
||||
("ein Viertel + 480p", 1_500_000, 480),
|
||||
]
|
||||
|
||||
for (name, bitrate, höhe) in versuche {
|
||||
var ziel = setzend("VideoBitrate", auf: String(bitrate), in: unter)
|
||||
if let höhe { ziel = setzend("maxHeight", auf: String(höhe), in: ziel) }
|
||||
|
||||
if let (roh, antwort) = try? await URLSession.shared.data(for: anfrage(ziel, kopfzeilen)) {
|
||||
let status = (antwort as? HTTPURLResponse)?.statusCode ?? 0
|
||||
let text = String(decoding: roh, as: UTF8.self)
|
||||
let schnipsel = text.split(separator: "\n").count { $0.hasPrefix("#EXTINF") }
|
||||
print(" \(name): HTTP \(status), \(schnipsel) Schnipsel")
|
||||
} else {
|
||||
print(" \(name): nicht erreichbar")
|
||||
}
|
||||
}
|
||||
|
||||
print("")
|
||||
print(" Kommen hier überall Schnipsel zurück, brauchen wir Jellyfins")
|
||||
print(" Zustimmung nicht — dann schreiben wir das Menü selbst.")
|
||||
}
|
||||
|
||||
private func anfrage(_ url: URL, _ kopfzeilen: [String: String]) -> URLRequest {
|
||||
var request = URLRequest(url: url)
|
||||
for (name, wert) in kopfzeilen { request.setValue(wert, forHTTPHeaderField: name) }
|
||||
return request
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user