Diagnose zeigt den Aufbau der Live-TV-Antwort
Die Sender bleiben leer, und ich habe jetzt zweimal geraten, wo sie stehen könnten — beim ersten Mal ein eigener Endpunkt, beim zweiten die Verschachtelung unter Device. Beides war eine Vermutung, weil dieser Teil der Plex-API keine offizielle Beschreibung hat. Statt ein drittes Mal zu raten: Einstellungen → Diagnose → „Live-TV- Antwort ansehen" fragt den Server und zeigt den Aufbau der Antwort. Schlüssel, Anzahl und Sendernamen, keine Werte und keine Zugangsdaten — genug, um den richtigen Schlüssel zu finden. Von Listen wird nur der erste Eintrag ausgeklappt; bei dreißig Sendern wäre die vollständige Ausgabe unlesbar, und alle haben denselben Aufbau. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -137,6 +137,66 @@ extension PlexServer {
|
||||
}
|
||||
}
|
||||
|
||||
extension PlexServer {
|
||||
/// Der Aufbau der Antwort auf `/livetv/dvrs`, zum Ansehen.
|
||||
///
|
||||
/// Nicht zum Anzeigen im Alltag, sondern zum Nachsehen: die
|
||||
/// Live-TV-Endpunkte von Plex haben keine offizielle Beschreibung, und
|
||||
/// ohne die tatsächliche Antwort bleibt jede Vermutung darüber, wo die
|
||||
/// Sender stehen, eine Vermutung. Diese Ausgabe beendet das Raten.
|
||||
///
|
||||
/// Werte werden nicht gezeigt, nur Struktur und Anzahl — das genügt, um
|
||||
/// den richtigen Schlüssel zu finden, und nichts davon ist vertraulich.
|
||||
public func liveTVStructure() async -> String {
|
||||
let data: Data
|
||||
do {
|
||||
data = try await client.send(PlexRequest(path: "/livetv/dvrs", timeout: .seconds(10)))
|
||||
} catch {
|
||||
return "Abfrage gescheitert: \(error)"
|
||||
}
|
||||
|
||||
guard let object = try? JSONSerialization.jsonObject(with: data) else {
|
||||
return "Antwort ist kein JSON (\(data.count) Bytes)"
|
||||
}
|
||||
return Self.outline(object).joined(separator: "\n")
|
||||
}
|
||||
|
||||
/// Beschreibt den Aufbau eines JSON-Werts, ohne die Werte selbst.
|
||||
///
|
||||
/// Ausnahme sind Titel und Sendernummern: die stehen ohnehin im
|
||||
/// Programmführer und sind beim Suchen die nützlichste Angabe.
|
||||
private static func outline(_ value: Any, indent: Int = 0) -> [String] {
|
||||
let padding = String(repeating: " ", count: indent)
|
||||
|
||||
switch value {
|
||||
case let dictionary as [String: Any]:
|
||||
return dictionary.keys.sorted().flatMap { key -> [String] in
|
||||
let child = dictionary[key]!
|
||||
if ["title", "channelIdentifier", "lineupTitle"].contains(key),
|
||||
let text = child as? String {
|
||||
return ["\(padding)\(key): \(text)"]
|
||||
}
|
||||
switch child {
|
||||
case is [Any], is [String: Any]:
|
||||
return ["\(padding)\(key):"] + outline(child, indent: indent + 1)
|
||||
default:
|
||||
return ["\(padding)\(key): \(type(of: child))"]
|
||||
}
|
||||
}
|
||||
|
||||
case let array as [Any]:
|
||||
guard let first = array.first else { return ["\(padding)(leer)"] }
|
||||
// Nur das erste Element ausklappen — bei dreißig Sendern wäre die
|
||||
// vollständige Ausgabe unlesbar, und alle haben denselben Aufbau.
|
||||
return ["\(padding)[\(array.count) Einträge, erster:]"]
|
||||
+ outline(first, indent: indent + 1)
|
||||
|
||||
default:
|
||||
return ["\(padding)\(type(of: value))"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Woher die Senderliste kam.
|
||||
public struct ChannelLookup: Sendable {
|
||||
public enum Source: Sendable, Equatable {
|
||||
|
||||
Reference in New Issue
Block a user