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>
Zweimal in Folge stand „es läuft nicht" gegen „bei mir ist es behoben",
ohne dass sich klären ließ, welcher Stand überhaupt auf dem Gerät liegt.
Das soll nicht noch einmal passieren.
Einstellungen → Diagnose zeigt jetzt:
- welcher Server und über welche Verbindung, mit Warnung bei der
gedrosselten Plex-Vermittlung
- den letzten Abspielversuch: Titel, gewählter Weg, Quelladresse
- jeden Schritt mit Zeitabstand zum Start. Der Abstand ist die
eigentliche Auskunft: liegt zwischen „Quelle gewählt" und „spielt"
eine Minute, hängt es an der Leitung; kommt „spielt" gar nicht, am
Motor.
- den Zeitpunkt, zu dem der laufende Build entstanden ist
Das Build-Datum kommt aus dem Änderungsdatum der eigenen Binärdatei —
kein Build-Skript, keine erzeugte Datei, und immer richtig.
Der Bericht lässt sich kopieren und enthält keinen Token: die
Quelladresse wird ohne Abfrageteil abgelegt, und dort steckt er.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nachladen
- DownloadRefiller wählt aus, WELCHE Folgen fehlen; wie viele, rechnet
die Regel-Engine. Getrennt, weil das Rechnen ohne Server auskommt und
damit prüfbar ist.
- In Ausstrahlungsreihenfolge, Specials in Staffel 0 bleiben außen vor.
- Läuft nach dem Ansehen und beim Start, nicht auf einem Zeitgeber: eine
App, die im Hintergrund unaufgefordert Gigabytes lädt, wäre eine
unangenehme Überraschung auf der Mobilfunkrechnung.
Startseiten-Layout
- Reihen ein-/ausblenden und per Bearbeiten-Modus umsortieren.
- Die Anordnungslogik liegt als HubArrangement in PlexKit statt im
App-Target — dort ist sie ohne Simulator testbar, und dort sitzen die
unangenehmen Fälle: neue Reihen vom Server landen am Ende statt zu
verschwinden, verschwundene aus der gespeicherten Liste stören nicht,
ein doppelter Eintrag stürzt nicht ab. 11 Tests.
126 Tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Engine
- Hintergrund-URLSession: läuft weiter, wenn die App zu ist. Der ganze
Zustand liegt in SwiftData, weil es nach einem Neustart kein anderes
Gedächtnis gibt.
- Pausieren über cancel(byProducingResumeData:) — nur so lässt sich
weiterladen statt neu zu beginnen. Bei 40 GB der Unterschied
zwischen brauchbar und unbrauchbar.
- Zwei Übertragungen gleichzeitig, Folgen in Staffel-/Folgenreihenfolge.
Alles parallel zu laden hieße: keine Folge wird fertig.
- Speicherlimit und Geräteplatz werden vor dem Annehmen geprüft, ein
Gigabyte bleibt als Puffer frei.
- Verwaiste Dateien werden beim Start entfernt; sie entstehen, wenn die
App genau beim Abschluss beendet wird.
- Downloads liegen in Application Support, nicht in Caches (iOS räumt
den eigenmächtig leer) und sind von der iCloud-Sicherung ausgenommen.
Oberfläche
- Download-Knopf auf Detailseiten mit vier Zuständen in einem Knopf.
- „Alle Folgen laden" für Staffel und Serie; ein abgelehnter Titel
stoppt den Stapel nicht.
- Downloads-Ansicht mit Belegung, WLAN-Schalter, Pausieren, Fortsetzen,
Löschen — nach Serie gruppiert.
Offline
- Der Player bevorzugt die lokale Datei, auch ohne erreichbaren Server.
- Beim Herunterladen wird ein Abzug der Serverangaben mitgesichert:
offline lässt sich nichts nachfragen, und der PlaybackDecider braucht
Container und Codecs.
Ein Fehler, den die Tests aufgedeckt haben: der Koordinator hielt nur
den ModelContext, nicht den ModelContainer. Ein ModelContext hält seinen
Container nicht am Leben — wird der anderswo freigegeben, stürzt jeder
Zugriff auf einen Eintrag ab, und die Meldung zeigt auf ModelContext.reset
statt auf die Ursache. Jetzt liegt die Zuständigkeit beim Koordinator.
102 Tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Decider brauchte keine Änderung — nur eine andere Richtlinie.
Genau dafür war er gebaut.
Transcoding
- TranscodeRequest baut die Parameter für /video/:/transcode/universal.
directStream=1 lässt Plex nur umpacken, wenn der Bildcodec passt,
statt pauschal neu zu kodieren.
- Vor dem Start wird der Server gefragt (decision); sagt er nein, steht
der Grund im Klartext da statt eines schwarzen Bildes.
- Beim Verlassen wird der Transcoder angehalten. Ohne dieses Signal
rechnet der Server minutenlang für niemanden weiter.
- Die adaptive Bitrate kommt mit HLS: AVPlayer wechselt sie selbst.
Qualitätseinstellungen
- Getrennt für WLAN und Mobilfunk, fünf spürbare Stufen.
Voreinstellung: zuhause Original, unterwegs 4 Mbit.
- NetworkConditions erkennt Mobilfunk über isExpensive — das deckt auch
den Hotspot ab, der technisch WLAN ist und trotzdem Volumen kostet.
Spuren und Marken
- Ton- und Untertitelwahl im Player, bevorzugte Sprache in den
Einstellungen, nachsichtiger Sprachvergleich (de/deu/ger/de-DE).
- Intro- und Abspann-Marken mit Überspringen-Knopf, optional
automatisch. Bereits übersprungene Marken werden gemerkt, sonst käme
man nach einem Rücksprung nie ins Intro zurück.
- Nächste Folge inkl. Staffelwechsel; Specials in Staffel 0 werden
nicht vorgezogen.
Fortschritt
- Alle zehn Sekunden an den Server, plus Schlussmeldung beim Verlassen.
Erst die nimmt den Titel aus „wird gerade abgespielt" heraus.
- markWatched/markUnwatched/rate/refreshLibrary stehen bereit.
86 Tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Datenschicht:
- plex.tv-Anmeldung über das PIN-Verfahren, Token im Schlüsselbund
- Serversuche und Verbindungsauswahl nach Rang (lokal vor direkt vor
Vermittlung), mit Abgleich der Server-Kennung gegen veraltete
plex.direct-Adressen
- PlexServer als einzige Stelle, an der die App Endpunkte kennt:
Mediatheken, Hubs, seitenweises Blättern mit Filtern, Metadaten,
Staffeln/Folgen, Suche
Die Oberfläche:
- Startseite mit Aufmacher und den Reihen vom Server
- Mediathek als Raster oder Liste, mit Filter- und Sortierblatt
- Detailseiten für Filme, Folgen, Serien und Staffeln inkl. Besetzung,
Fassungsauswahl und aufklappbaren technischen Angaben
- Suche mit gemerkten Anfragen
- Vollbildplayer mit eigenem Chrome
Der Player:
- AVPlayerEngine und VLCPlayerEngine hinter einem gemeinsamen Protokoll
- VLCKit liegt in einem eigenen Package (FlixyVLC), damit `swift test`
in FlixyKit nicht das 920-MB-Binärpaket mitzieht
Am echten plex.tv geprüft: der Anmeldecode kommt an. Dabei fiel auf,
dass `strong=true` einen dreißigstelligen Code liefert, der sich bei
plex.tv/link nicht eintippen lässt — jetzt der kurze.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>