Fragen statt starten — die Probe überfuhr den Server
Beim letzten Lauf scheiterte auch die Anfrage, die vorher funktioniert hatte. Kein neuer Befund, sondern mein Messfehler: die Probe warf sechs Transcode-Sitzungen in Folge an, und danach lehnt Plex alles mit nackten 400ern ab — auch das, was vorher ging. Jede Anfrage an `start.m3u8` startet einen Transcoder. Für eine Parameterreihe ist das das falsche Werkzeug. Der **Entscheider** sagt, was der Server täte, ohne etwas zu tun: Auflösung, Bitrate, und ob umgerechnet oder umgepackt wird. Die Reihe läuft jetzt darüber. Die zwei verbleibenden echten Sitzungen bekommen Abstand voneinander. Der Wert wird aus der Antwort gesucht statt geparst — Plex antwortet je nach Kopfzeile als XML oder JSON, und es geht um eine Anzeige, nicht um Daten, mit denen weitergerechnet wird. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
b861ca0599
commit
d2237c29cd
@@ -204,18 +204,26 @@ if CommandLine.arguments.contains("--leiter") {
|
||||
resolution: auflösung,
|
||||
isLocal: connection.local
|
||||
)
|
||||
guard let url = server.transcodeURL(for: probe) else { continue }
|
||||
let antwort = await prüfePlaylist(url)
|
||||
let zeile = antwort
|
||||
.split(separator: "\n")
|
||||
.first { $0.contains("Mbit/s") }
|
||||
.map { $0.trimmingCharacters(in: .whitespaces) } ?? "keine Stufe"
|
||||
print(" \(name): \(zeile)")
|
||||
await server.stopTranscode(sessionIdentifier: probe.sessionIdentifier)
|
||||
// **Über den Entscheider, nicht über start.m3u8.** Jede Anfrage dort
|
||||
// wirft einen Transcoder an; sechs in Folge bringen den Server dazu,
|
||||
// auch das abzulehnen, was vorher ging. Der Entscheider sagt, was er
|
||||
// täte, ohne etwas zu tun.
|
||||
let wortlaut = await server.decisionText(for: probe)
|
||||
let auflösung = herausziehen("videoResolution", aus: wortlaut)
|
||||
?? herausziehen("height", aus: wortlaut)
|
||||
let bitrate = herausziehen("bitrate", aus: wortlaut)
|
||||
let entscheidung = herausziehen("transcodeDecisionText", aus: wortlaut)
|
||||
?? herausziehen("generalDecisionText", aus: wortlaut)
|
||||
print(" \(name):")
|
||||
print(" Auflösung \(auflösung ?? "–") · Bitrate \(bitrate ?? "–")")
|
||||
if let entscheidung { print(" \(entscheidung)") }
|
||||
}
|
||||
print()
|
||||
|
||||
// Zwischen den beiden echten Sitzungen Luft lassen: Plex nimmt eine
|
||||
// schnelle Folge von Transcode-Starts übel und lehnt danach alles ab.
|
||||
for (name, anfrage) in [("ohne autoAdjustQuality", ohne), ("mit autoAdjustQuality=1", mit)] {
|
||||
try? await Task.sleep(for: .seconds(3))
|
||||
print("=== \(name) ===")
|
||||
guard let url = server.transcodeURL(for: anfrage) else {
|
||||
print(" Keine Adresse zu bauen.\n")
|
||||
@@ -321,3 +329,26 @@ func storedClientIdentifier() -> String {
|
||||
UserDefaults.standard.set(created, forKey: key)
|
||||
return created
|
||||
}
|
||||
|
||||
|
||||
/// Zieht einen Wert aus der Antwort des Entscheiders.
|
||||
///
|
||||
/// Plex antwortet je nach Kopfzeile als XML oder JSON; beide Formen tragen
|
||||
/// den Wert als `name="wert"` bzw. `"name":"wert"`. Statt zwei Parser zu
|
||||
/// bauen, wird hier gesucht — es geht um eine Anzeige, nicht um Daten, mit
|
||||
/// denen weitergerechnet wird.
|
||||
func herausziehen(_ name: String, aus text: String) -> String? {
|
||||
for muster in ["\(name)=\"", "\"\(name)\":\""] {
|
||||
guard let bereich = text.range(of: muster) else { continue }
|
||||
let rest = text[bereich.upperBound...]
|
||||
let wert = String(rest.prefix { $0 != "\"" })
|
||||
if !wert.isEmpty { return wert }
|
||||
}
|
||||
// JSON-Zahlen stehen ohne Anführungszeichen.
|
||||
if let bereich = text.range(of: "\"\(name)\":") {
|
||||
let rest = text[bereich.upperBound...].drop { $0 == " " }
|
||||
let wert = String(rest.prefix { $0.isNumber })
|
||||
if !wert.isEmpty { return wert }
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user