Download-Knopf tat nichts DownloadService.plan gab still nil zurück, wenn es keinen Auftrag bauen konnte, und download() reichte das als nil weiter. Der Knopf sah aus, als wäre er kaputt, dabei war der Grund jedes Mal bekannt. Es gibt jetzt einen eigenen Ablehnungsgrund mit vier unterschiedlichen Begründungen — keine Verbindung, keine Datei, kein abrufbarer Teil, keine Adresse. Eine Funktion, die kommentarlos nichts tut, ist selbst der Fehler. Live-TV galt als „nicht eingerichtet" Plex legt die Empfängerliste unter dem Schlüssel `Dvr` ab, die Hülle kannte aber nur Metadata, Directory und Hub. Sie las eine leere Liste und zog daraus die falsche Schlussfolgerung — auf einem Server, auf dem ein Empfänger eingerichtet war. Dasselbe galt für die Anbieterliste unter `MediaProvider`, ohne die es keinen Programmführer gibt. Beim Umbau wäre beinahe die Fehlerdiagnose verloren gegangen: mit `try?` über alle Schlüssel verschwände auch ein echter Dekodierfehler und ergäbe stillschweigend eine leere Liste. Aus „ein Feld heißt jetzt anders" würde „die Mediathek ist leer". Jetzt wird erst geprüft, ob der Schlüssel da ist, und dann ohne try? dekodiert. Fünf Tests halten beides fest. Qualität im Player wählbar Automatisch, Original, 1080p, 720p, 480p. Der Eingriff wird genau dann gebraucht, wenn es ruckelt — dafür will niemand den Film verlassen. Ein Wechsel baut den Strom neu auf (die Stufe steckt in der Adresse), merkt sich die Stelle und fährt sie wieder an. Der alte Transcoder wird vorher angehalten, sonst rechnet der Server zwei Ströme für einen Zuschauer. AVPlayer-Anzeige entfernt Sie war eine Prüfhilfe aus Phase 1. Dieselbe Angabe steht weiterhin unter Einstellungen → Diagnose, wo sie hingehört. 137 Tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
72 lines
2.3 KiB
Swift
72 lines
2.3 KiB
Swift
import Foundation
|
|
|
|
/// Eine im Player wählbare Qualitätsstufe.
|
|
///
|
|
/// Getrennt von den Einstellungen unter „Qualität": dort steht, was
|
|
/// üblicherweise gelten soll; hier greift man für diesen einen Film ein — weil
|
|
/// es gerade ruckelt oder weil man ausnahmsweise das Original will.
|
|
public enum PlayerQuality: String, Sendable, CaseIterable, Identifiable {
|
|
/// Was in den Einstellungen für die aktuelle Verbindung hinterlegt ist.
|
|
case automatic
|
|
/// Die Datei unverändert, ohne Umrechnung.
|
|
case original
|
|
case fullHD
|
|
case hd
|
|
case low
|
|
|
|
public var id: String { rawValue }
|
|
|
|
/// Obergrenze in Kilobit. `nil` bei `automatic` und `original`.
|
|
public var maximumBitrate: Int? {
|
|
switch self {
|
|
case .automatic, .original: nil
|
|
case .fullHD: 8_000
|
|
case .hd: 4_000
|
|
case .low: 2_000
|
|
}
|
|
}
|
|
|
|
public var resolution: String? {
|
|
switch self {
|
|
case .automatic, .original: nil
|
|
case .fullHD: "1920x1080"
|
|
case .hd: "1280x720"
|
|
case .low: "854x480"
|
|
}
|
|
}
|
|
|
|
/// Ob diese Stufe eine Umrechnung erzwingt.
|
|
///
|
|
/// `original` erzwingt das Gegenteil: keine Umrechnung, auch wenn die
|
|
/// Einstellungen eine Grenze vorsehen.
|
|
public var forcesTranscode: Bool {
|
|
switch self {
|
|
case .automatic, .original: false
|
|
case .fullHD, .hd, .low: true
|
|
}
|
|
}
|
|
|
|
/// Die Richtlinie für diese Stufe.
|
|
///
|
|
/// `automatic` reicht durch, was ohnehin gilt. Die übrigen überschreiben
|
|
/// sie — das ist der Zweck eines Eingriffs im Player.
|
|
public func policy(basedOn base: PlaybackPolicy) -> PlaybackPolicy {
|
|
switch self {
|
|
case .automatic:
|
|
base
|
|
case .original:
|
|
// Keine Grenze und kein Umrechnen: ausdrücklich das Original.
|
|
PlaybackPolicy(allowsTranscoding: false, allowsFallbackEngine: true, maximumBitrate: nil)
|
|
case .fullHD, .hd, .low:
|
|
// Ohne Ersatzmotor, damit die Entscheidung zwangsläufig beim
|
|
// Transcoder landet — sonst spielte VLC die Datei direkt ab und
|
|
// die gewählte Stufe bliebe wirkungslos.
|
|
PlaybackPolicy(
|
|
allowsTranscoding: true,
|
|
allowsFallbackEngine: false,
|
|
maximumBitrate: maximumBitrate
|
|
)
|
|
}
|
|
}
|
|
}
|