Vier Punkte aus dem Praxistest
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>
This commit is contained in:
@@ -39,7 +39,9 @@ struct DownloadRefiller {
|
||||
// ließe sich weder das Speicherlimit prüfen noch ein
|
||||
// Fortschritt anzeigen.
|
||||
let detailed = (try? await server.metadata(ratingKey: episode.ratingKey)) ?? episode
|
||||
guard let plan = service.plan(for: detailed) else { continue }
|
||||
// Folgen ohne abrufbare Datei still überspringen: das Nachladen
|
||||
// läuft im Hintergrund, da hilft keine Fehlermeldung.
|
||||
guard let plan = try? service.plan(for: detailed) else { continue }
|
||||
if (try? coordinator.enqueue(plan)) != nil { added += 1 }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,16 +14,26 @@ struct DownloadService {
|
||||
|
||||
/// Baut den Auftrag für einen einzelnen Titel.
|
||||
///
|
||||
/// `nil`, wenn es keine abspielbare Datei gibt — bei einem Titel, den der
|
||||
/// Server noch nicht analysiert hat, etwa.
|
||||
func plan(for item: PlexItem, mediaIndex: Int = 0) -> DownloadPlan? {
|
||||
guard let server else { return nil }
|
||||
/// Wirft mit Begründung, statt still `nil` zurückzugeben. Der Unterschied
|
||||
/// ist nicht akademisch: mit `nil` sah der Download-Knopf aus, als täte er
|
||||
/// nichts, obwohl der Grund bekannt war — etwa ein Titel, den der Server
|
||||
/// noch nicht analysiert hat.
|
||||
func plan(for item: PlexItem, mediaIndex: Int = 0) throws(DownloadRefusal) -> DownloadPlan {
|
||||
guard let server else {
|
||||
throw .noDownloadableFile(reason: String(localized: "downloads.refused.noServer"))
|
||||
}
|
||||
let media = item.media.indices.contains(mediaIndex)
|
||||
? item.media[mediaIndex]
|
||||
: item.preferredMedia
|
||||
guard let media, let part = media.parts.first,
|
||||
let url = server.downloadURL(part: part)
|
||||
else { return nil }
|
||||
guard let media else {
|
||||
throw .noDownloadableFile(reason: String(localized: "downloads.refused.noMedia"))
|
||||
}
|
||||
guard let part = media.parts.first else {
|
||||
throw .noDownloadableFile(reason: String(localized: "downloads.refused.noPart"))
|
||||
}
|
||||
guard let url = server.downloadURL(part: part) else {
|
||||
throw .noDownloadableFile(reason: String(localized: "downloads.refused.noURL"))
|
||||
}
|
||||
|
||||
return DownloadPlan(
|
||||
ratingKey: item.ratingKey,
|
||||
@@ -43,9 +53,8 @@ struct DownloadService {
|
||||
|
||||
/// Lädt einen einzelnen Titel.
|
||||
@discardableResult
|
||||
func download(_ item: PlexItem, mediaIndex: Int = 0) throws(DownloadRefusal) -> DownloadItem? {
|
||||
guard let plan = plan(for: item, mediaIndex: mediaIndex) else { return nil }
|
||||
return try coordinator.enqueue(plan)
|
||||
func download(_ item: PlexItem, mediaIndex: Int = 0) throws(DownloadRefusal) -> DownloadItem {
|
||||
try coordinator.enqueue(try plan(for: item, mediaIndex: mediaIndex))
|
||||
}
|
||||
|
||||
/// Lädt alle Folgen einer Staffel oder Serie.
|
||||
@@ -78,14 +87,14 @@ struct DownloadService {
|
||||
}
|
||||
|
||||
let detailed = (try? await server.metadata(ratingKey: episode.ratingKey)) ?? episode
|
||||
guard let plan = plan(for: detailed) else {
|
||||
unavailable += 1
|
||||
continue
|
||||
}
|
||||
|
||||
do {
|
||||
_ = try coordinator.enqueue(plan)
|
||||
_ = try coordinator.enqueue(try plan(for: detailed))
|
||||
accepted += 1
|
||||
} catch DownloadRefusal.noDownloadableFile {
|
||||
// Einzelne Folgen ohne Datei stoppen den Stapel nicht — sie
|
||||
// werden am Ende nur gezählt.
|
||||
unavailable += 1
|
||||
} catch {
|
||||
refused.append((episode, error))
|
||||
// Beim Speicherlimit hat es keinen Sinn, die übrigen Folgen
|
||||
|
||||
Reference in New Issue
Block a user