Der Server lieferte sie, die Spur lag im Stream, ausgewaehlt war sie auch —
und angezeigt wurde trotzdem nichts.
Der Grund ist eine Eigenschaft, die von Haus aus auf `true` steht:
`appliesMediaSelectionCriteriaAutomatically`. Der Player richtet sich damit
nach den Untertiteleinstellungen des Systems, und die stehen in aller Regel
auf „aus\". Er nahm also jede Wahl, die wir trafen, wieder zurueck —
lautlos, und erst nachdem wir sie gesetzt hatten.
Beim Ton aendert das Abschalten nichts: welche Spur klingt, ist laengst
beim Aushandeln entschieden, und bei einem umgerechneten Stream kommt
ohnehin nur eine an.
Dazu eine zweite Absicherung: bei einer Abspielliste laedt AVFoundation die
Nebenspuren nachtraeglich. Meldet sie beim ersten Mal noch keine, ginge der
bestellte Untertitel verloren — deshalb wird im Sekundentakt nachgefasst,
solange nichts ausgewaehlt ist.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Groesse in vier Stufen, Schrift und Hintergrund als fuenf feste Paare —
Weiss, Weiss auf Schwarz, Schwarz auf Weiss, Gelb, Gelb auf Schwarz. Feste
Paare statt zweier Regler, weil unabhaengige Achsen unlesbare Mischungen
zulassen: Schwarz auf durchsichtig ueber einer Nachtszene ist eine
gueltige Einstellung und eine wertlose.
Die Uebersetzung nach AVFoundation ist eine Tabelle aus Schluesseln, bei
der jeder Fehler lautlos ist — ein falscher Schluessel laesst den
Initialisierer `nil` zurueckgeben, und dann gibt es gar keine Regel. Auf
dem Bildschirm sieht „keine Regel\" genauso aus wie „Regel ohne Wirkung\".
Zehn Tests decken das ab, darunter die drei Fallen: Alpha zuerst in der
Farbe, Prozentwert statt Punktgroesse, und der Hintergrund auch fuer
„durchsichtig\" ausdruecklich gesetzt statt weggelassen — weggelassen gilt
sonst, was Jellyfins WebVTT selbst mitbringt, und das ist oft ein
schwarzer Kasten.
Als Protokollmethode, nicht als Feld an `PlaybackSource`: die wird einmal
beim Oeffnen gelesen, und eine Einstellung, die erst beim naechsten Film
wirkt, haelt jeder fuer kaputt. Angewandt wird an zwei Stellen — am
laufenden Gegenstand und am frisch angelegten. Nur das erste zu tun hiesse,
dass die naechste Folge wieder in der Vorgabe erscheint.
VLC erbt die leere Vorgabe. Die Einstellungsseite sagt beides: dass es fuer
den Standardplayer gilt, und dass eingebrannte Bilduntertitel von Blu-rays
sich nicht gestalten lassen, weil es dort keinen Text gibt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Fehlstart im Zug hat den eigentlichen Mangel gezeigt: die ganze neue
Regelung misst **ab dem ersten Bild**. Kommt nie eines, misst sie nichts,
greift nichts — und „Auto" hat sich als das erwiesen, was es wörtlich
heisst: „nimm, was in den Einstellungen steht". Steht dort „Original",
bittet die App über eine Zugverbindung um eine 4K-Datei und wartet
vierzig Sekunden auf etwas, das nie kommen kann.
Statt aufzugeben geht der Watchdog jetzt eine Sprosse tiefer und baut
neu auf — bei Filmen über `restart()`, bei Sendern über den Tuner-Abbau.
Gezählt gegen dasselbe Budget wie die Sicherheitsleine, sonst schickt
eine tote Leitung die App endlos im Kreis.
Scheitert auch das, nennt die Meldung jetzt den Grund und den Weg statt
nur „keine Daten mehr": wer ohne Grenze angefragt hat, soll erfahren,
dass es daran liegt und wo es sich ändern lässt.
Und „Strom" heisst Stream. Zweiunddreissig Stellen, dazu das
Gedächtnis ergänzt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Eingedeutschte Fachbegriffe in den Kommentaren — „Wachhund" für
Watchdog, „Motor" für Engine. Das liest sich albern und ist unklarer als
das Original; niemand sagt Wachhund, wenn er einen Watchdog meint.
Acht Stellen berichtigt. Gewöhnliche Sprache bleibt deutsch, der Stil
der Kommentare ändert sich nicht.
Dazu die Plex-Leiter messbar gemacht: `--leiter` baut dieselbe Anfrage
zweimal, mit und ohne `autoAdjustQuality=1`, und zählt die Stufen. Die
Zeile steht seit dem Umbau im Code und war nie geprüft — genau die Art
ungeprüfter Annahme über Serververhalten, die bei Jellyfin vier Runden
gekostet hat.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bisher hieß `PlayerQuality.automatic` wörtlich: nimm die Zahl, die für
WLAN oder Mobilfunk hinterlegt ist. Keine Messung, kein Nachregeln — die
Entscheidung fiel einmal beim Start und galt bis zum Ende.
`StreamHealth` beurteilt den Strom jetzt fortlaufend aus Proben im
Sekundentakt. Ein reiner Typ: kein AVFoundation, keine Uhr, kein Netz.
Damit lässt sich eine schlechte Zugfahrt als Zahlenreihe hinschreiben
und nachsehen, was sie auslöst — zehn Tests tun genau das.
**Welches Signal wann meldet**, ist der eigentliche Inhalt. Der
Pufferverlauf ist der einzige echte Frühwarner: schrumpft er schneller,
als die Zeit vergeht, kommt weniger herein als hinausgeht, und das sieht
man zehn bis zwanzig Sekunden vor dem Rückler. `isLikelyToKeepUp` ist
früh, aber sprunghaft — es zählt erst, wenn es anhält. Der Rücklerzähler
meldet zu spät zum Regeln und bleibt trotzdem der Massstab, an dem sich
hinterher ablesen lässt, ob es besser wurde. Die **gemessene** Bitrate
steht bewusst nicht drin: auf einer kleinen Sprosse holt der Player
wenig, ohne dass die Leitung schlecht wäre.
Ausdrücklich kein Bandbreitentest. Der kostet Daten, ist beim Vorliegen
veraltet und misst die Vergangenheit. Der Pufferverlauf ist die bessere
Messung, weil er die einzige Größe misst, auf die es ankommt: lädt es
schneller, als es läuft.
Gehandelt wird über `preferredPeakBitRate` — der billige Hebel, der ohne
Neuaufbau wirkt. Gezielt wird dabei auf eine Sprosse, **die es in
`AVAsset.variants` wirklich gibt**: ein Wert zwischen zweien wählt
dieselbe wie die untere und machte jede Anzeige darüber zur Lüge.
Absichtlich unsymmetrisch — runter sofort, hinauf frühestens nach einer
Minute Ruhe.
Und getrennt von `quality`: die Automatik ruft **nicht** `select(quality:)`.
Die Methode schreibt `rememberedQuality` fort und setzte eine manuelle
Stufe — womit die Automatik sich selbst abschaltete und eine schlechte
Zugfahrt dauerhaft das Wohnzimmer verschlechterte.
Hat die Playlist nur eine Stufe, greift der Hebel ins Leere. Das ist kein
Fehler, sondern der Fall, für den die Sicherheitsleine gebaut wird — bis
dahin steht er wenigstens im Protokoll.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`timeControlStatus` meldet zwei verschiedene Dinge als `.paused`: das
Anhalten durch den Nutzer und den Fall, dass `play()` gerufen wurde, der
Player aber nicht losläuft — weil die Quelle nicht bereit ist oder weil
nichts ankommt. Die Engine hat beides als „pausiert" weitergegeben.
Sichtbar war das als Player mit Abspieldreieck und Scrubber auf 0:00,
während in Wahrheit auf Daten gewartet wurde. Wer dann tippte, drückte
auf Play bei etwas, das längst laufen sollte.
Die Engine führt jetzt mit, ob überhaupt jemand spielen wollte.
Stillstand mit Absicht ist Pause, Stillstand ohne Absicht ist Warten.
Dazu die Anzeigeregel, wie gewünscht: **der Kreisel gilt immer**, mit
oder ohne eingeblendete Bedienung. Er ist keine Verzierung der Knöpfe,
sondern die Auskunft „es kommt gleich weiter" — und die braucht man
gerade dann, wenn nichts eingeblendet ist und man vor einem stehenden
Bild sitzt. Das Play-Pause-Symbol erscheint dagegen nur mit der übrigen
Bedienung, und an seiner Stelle bleibt beim Laden eine Lücke, damit der
Kreisel hindurchscheint statt zwei Anzeigen übereinanderzulegen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zwei Änderungen, die an der Wiedergabe selbst etwas tun — beide ohne
Abhängigkeit davon, ob die Server je eine Leiter liefern.
**Vorrat.** Ohne Angabe legt AVPlayer so viel an, wie es für einen
zügigen Start braucht, und keinen Meter mehr. Das ist richtig, solange
die Leitung trägt, und falsch, sobald sie aussetzt: ein Loch von fünf
Sekunden trifft dann auf einen Puffer von fünf Sekunden, und das Bild
steht. Fünfundzwanzig Sekunden sind ein Anfangswert, kein Messergebnis.
Nur für Filme und Folgen über das Netz. **Nicht für Sender** — dort
hieße ein halbminütiger Vorrat eine halbe Minute Verzug und ein zähes
Umschalten. Und nicht für Dateien von der Platte, die brauchen keinen.
Wer das entscheidet, muss mehr wissen als der Motor, deshalb reist die
Zahl mit der Quelle statt dass die Engine rät.
**VLC hat das Stocken nie gemeldet.** `VLCMediaPlayerState` kennt keinen
Wert dafür — die Aufzählung führt nur `opening`, `playing`, `paused`,
`stopped`, `error`. Der Puffer-Fortschritt kommt über
`mediaPlayerBufferingChanged:`, und die Methode fehlte. Folge:
`.buffering` ging dort **nie** an, der Wachhund im Player löste nie aus,
und ein hängender Strom lief stumm ins Nichts — ohne Kreisel, ohne
Meldung, ohne Abbruch. Ausgerechnet auf dem Weg, der die großen Remuxe
spielt, bei denen eine schwache Leitung am ehesten scheitert.
Gewertet wird nur aus dem Spielen heraus: laut Dokumentation kommt vor
jeder Wiedergabe einmal 0,0 und einmal 1,0, und dieses anfängliche
Füllen ist der Start, kein Rückler.
Dazu meldet VLC jetzt überhaupt Statistik. `variantCount` bleibt dabei
`nil` und nicht `1` — eine Datei hat keine Leiter, und „gibt es nicht"
ist etwas anderes als „gibt es einmal". Bei der Bitrate steht die
Annahme im Kommentar statt im Nebel: libvlc führt `inputBitrate`
vermutlich in Byte je Sekunde, daher der Faktor acht.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bisher gab es über eine laufende Wiedergabe zwei Zahlen — gemessene
Bitrate und verworfene Bilder —, und die standen nur zur Anzeige da. Die
Frage „trägt die Leitung das gerade" war nicht zu beantworten, weder für
den Nutzer noch für die App.
**Die wichtigste neue Zahl ist `variantCount`.** Sie kommt aus
`AVAsset.variants`, also vom Parser des Players, und beantwortet die
Frage, ob es überhaupt etwas zum Umschalten gibt. Steht dort 1, greift
jedes Nachregeln ins Leere — und genau das ist heute der Fall, weil die
App bei beiden Servern eine Playlist mit einer Stufe bestellt.
Dazu der Pufferstand aus `loadedTimeRanges`: der einzige echte
Frühwarner. Schrumpft er schneller, als die Zeit vergeht, kommt weniger
herein als hinausgeht — zehn bis zwanzig Sekunden, bevor das Bild steht.
Alles andere meldet sich erst danach.
**Verworfene Bilder werden jetzt über alle Protokolleinträge summiert.**
Das Zugriffsprotokoll legt bei jedem Stufenwechsel einen neuen an, dessen
Zähler bei null beginnt; wer nur `last` liest, hält eine Wiedergabe für
makellos, die schon zwanzigmal Bilder verworfen hat.
**Der Wachhund war blind für den häufigsten Fall.** Vierzig Sekunden am
Stück ohne Daten brechen ab — aber er setzte sich bei jedem kurzen
Erholen zurück, und zehn Rückler à dreißig Sekunden lösten ihn nie aus.
`StallLedger` zählt daneben mit, wie viel Zeit im gleitenden Fenster
fürs Warten draufging. Es bricht nichts ab, es stellt nur fest — und ist
ein reiner Typ ohne Uhr und ohne AVFoundation, damit sich eine Folge von
Rücklern als Zahlenreihe hinschreiben und das Urteil prüfen lässt.
Sieben Tests, darunter genau der Fall, an dem der alte Wachhund
vorbeisah.
Gezählt wird nur der Weg vom Spielen ins Warten. Das anfängliche Puffern
ist der Start, kein Rückler; würde es mitgezählt, hätte jede Wiedergabe
eine Vorstrafe.
Und zwei Kommentare sind berichtigt. Sie behaupteten, AVPlayer wechsle
die Bitrate von selbst und das sei „die zugesagte automatische
Qualitätsanpassung". Umschalten kann er nur zwischen Varianten, die in
der Liste stehen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
**Eine Taste zum Vergrößern** unten rechts auf der Kachel. Das Antippen der
Fläche vergrößert weiterhin, aber auf derselben Fläche liegen schon das Ziehen
und das Aufziehen — und was dabei danebengeht, sieht aus wie „reagiert nicht".
Ein Knopf geht nicht daneben.
**Ton und Untertitel getrennt.** Es sind zwei verschiedene Fragen: die Tonspur
stellt man einmal am Anfang um, die Untertitel mitten im Film. In einem
gemeinsamen Blatt scrollte man jedes Mal an der anderen Liste vorbei. Das
Untertitel-Symbol ist gefüllt, solange welche laufen — so sieht man es, ohne
das Blatt zu öffnen. Und eine Auswahl schließt das Blatt jetzt selbst.
**AirPlay.** Nicht nachgebaut, sondern die Systemstelle: sie kennt Geräte, die
eine App nie aufzählen könnte. Der Knopf erscheint nur beim Systemplayer — VLC
zeichnet selbst und kann kein AirPlay, und ein Knopf, der dort ins Leere
führte, wäre schlimmer als keiner.
**Die Qualität steht als Text da**, nicht als drei Schieberegler: „1080p",
„720p", „Auto". Bei „automatisch" steht dort, was gerade tatsächlich ankommt —
das weiß nur der Player, und ihn zu fragen ist ehrlicher, als „Auto"
hinzuschreiben und die Antwort schuldig zu bleiben.
Dazu die Einstellungen mit farbigen Symbolen und einer Kopfkarte je Bereich.
Das ist nicht nur Zierde: in einer Liste aus zehn gleich aussehenden Zeilen
findet das Auge nichts wieder, und „das mit dem blauen Zahnrad" ist eine
brauchbare Beschreibung. Die Farben sind fest und ausdrücklich **nicht** die
Akzentfarbe — trüge alles dieselbe, unterschiede sie nichts mehr.
Und der Aufmacher läuft jetzt unter der Seitenleiste weiter
(`backgroundExtensionEffect`): die Ränder werden gespiegelt und weich
fortgeschrieben, während Titel und Knöpfe stehen bleiben. Vorher endete das
Bild an der Kante der Leiste, und beim Weiterwandern schob sich das nächste an
einer harten Linie ins Bild.
263 Tests grün. Player-Knöpfe und Einstellungen angesehen; den Aufmacher hinter
der Leiste konnte ich an den einfarbigen Flächen der Attrappe nicht sicher
beurteilen — der Simulator ist dabei erneut abgestürzt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Erster Schritt zu Jellyfin, und er besteht vor allem aus Wegnehmen.
`PlaybackDecider` nahm bisher Plex-Modelle entgegen und las daraus sechs
Felder. Das band die Entscheidung an einen bestimmten Server, obwohl an
der Frage „kann iOS das öffnen?" nichts serverspezifisch ist. Jetzt nimmt
er ein `MediaProfile` — Container, Codecs, Bitrate, ob die Datei
untersucht ist.
Wie ernst die Kopplung war, zeigte der Player selbst: für die
Offline-Wiedergabe baute er sich **erfundene** Plex-Werte zusammen — eine
Media mit Kennung 0, ein Part mit dem Dateinamen als Schlüssel,
zusammengesetzte Spurlisten —, nur damit die Signatur passte. Für eine
Datei, die längst auf dem Gerät lag und mit Plex nichts mehr zu tun
hatte. Dieser Hack ist weg.
Neu ist das Target `MediaKit`: Typen und Rechnungen, die für jeden Server
gelten, ohne eine einzige Abhängigkeit. Darin `MediaProfile` und die
`Duration`-Brücke, die bisher in PlexKit stand — „weil es die unterste
Schicht ist". Das stimmte, solange es nur einen Server gab.
Damit kennen Wiedergabe und Downloads Plex nicht mehr. Zwei der
Abhängigkeiten waren ohnehin tot; die dritte trug nur diese Brücke.
Die wichtigste Testtabelle des Projekts ist mitgewandert und dabei
kürzer geworden: dort steht jetzt, worauf es ankommt, statt vollständiger
Modelle mit Kennungen und Dateipfaden, von denen niemand etwas las.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die vier erfundenen Stufen weichen der Leiter, die der Server selbst
meldet: 64, 96, 208, 320, 720, 1500, 2000, 3000, 4000, 8000, 10000,
12000, 20000 kbps mit den Auflösungen, die Plex dafür vorsieht. Eine
eigene Leiter hieße, Stufen anzubieten, die der Transcoder nicht kennt —
er rundet dann still auf die nächste, und die Anzeige log.
Angeboten wird nur, was zur Quelle passt. Eine 720p-Datei auf 1080p
hochzurechnen bringt kein Bild dazu, und die Stufen sähen alle gleich aus.
Oben im Blatt steht, was tatsächlich über die Leitung kommt — gemessene
Bitrate, Auflösung, verworfene Bilder. Der Unterschied zur gewählten
Stufe ist keine Haarspalterei: die eine sagt, was erlaubt ist, die andere,
was ankommt. Ruckelt es trotz hoher Stufe, steht die Antwort dort.
„Nur Ton" gibt es, aber ehrlich beschriftet: Plex kennt für Videos keinen
reinen Tonstrom, also wird die unterste Sprosse geholt und das Bild
ausgeblendet.
Dazu Doppeltipp links und rechts für zehn Sekunden zurück und vor. Die
Reihenfolge der Gesten ist entscheidend — das einfache Tippen verschluckt
sonst das doppelte.
Die Kachel hängt nicht mehr in vier Ecken fest, sondern klebt links oder
rechts und ist in der Höhe frei. Vier Ecken sind schnell gebaut, aber im
Weg: steht sie über einem Knopf, bleiben drei Orte, die ebenso stören.
Größer wird sie durch Zusammen- und Auseinanderziehen; der Griff ist weg,
er saß zwangsläufig auf dem Bild und stritt sich mit dem Verschieben.
Und die Begriffe: „Motor" für engine sagt kein deutscher Entwickler.
Fachwörter, die im Deutschen englisch bleiben, bleiben jetzt englisch.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Crashlog vom Gerät:
_dispatch_assert_queue_fail
_swift_task_checkIsolatedSwift
MainActor.assumeIsolated
VLCPlayerEngine.mediaPlayerStateChanged(_:)
VLCKit input_thread_Events
Im Code stand als Begründung für assumeIsolated, VLCKit stelle seine
Rückrufe über die Hauptwarteschlange zu. Das ist falsch — es ruft den
Delegaten von seinem eigenen Input-Thread. Die App brach deshalb hart
ab, sobald VLC den ersten Zustandswechsel meldete, also unmittelbar
beim Drücken auf Play.
Alle drei Delegat-Methoden springen jetzt mit Task { @MainActor in }
sauber hinüber. Die Reihenfolge bleibt erhalten: die Aufgaben werden aus
demselben Thread nacheinander eingereiht.
Dieselbe Annahme steckte im AVPlayer-Motor in den KVO-Beobachtern —
KVO meldet auf dem Thread, der die Änderung ausgelöst hat, und AVPlayer
ändert seinen Zustand auch aus internen Threads. Ebenfalls umgestellt.
Die beiden Rückrufe mit ausdrücklichem queue: .main behalten
assumeIsolated: dort ist die Annahme belegt statt geraten, und der
Zeitbeobachter feuert viermal je Sekunde.
Dazu die Anmeldung: Plex führt den Rücksprung über forwardUrl nicht
zuverlässig aus. Auf dem iPad landet der Browser nach dem Anmelden auf
watch.plex.tv und bleibt stehen — der Token liegt bereit, aber die App
wartete auf einen Rückruf, der nie kam. Das Fenster wird jetzt geöffnet,
ohne darauf zu warten; parallel wird im Sekundentakt beim Server
nachgefragt. Der Rücksprung ist damit eine Annehmlichkeit, keine
Voraussetzung.
132 Tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Kein Video lief jemals an
AVPlayerEngine.load() wartete auf asset.load(.duration) und die
Spurenliste, BEVOR es zurückkehrte — und erst danach rief das Modell
play(). AVFoundation muss für die Dauer aber so viel von der Datei
holen, bis es den Index findet, und der sitzt bei MP4 wie MKV oft am
Ende. Über eine langsame Leitung sind das Minuten, in denen nur ein
Ladekreis zu sehen war, obwohl der Player längst hätte anfangen können.
Jetzt kehrt load() zurück, sobald das Item hängt; Dauer und Spuren
kommen nach und melden sich über den Ereignisstrom.
Dazu AVURLAssetPreferPreciseDurationAndTimingKey: false — sonst
durchsucht AVFoundation bei manchen Formaten die ganze Datei.
Zweiter Fund an derselben Stelle: VLCMedia(url:) ist nullable. Ging es
schief, blieb media still nil, play() tat nichts und es gab keinen
Fehler — nur einen Ladekreis ohne Ende. Wird jetzt gemeldet.
Kein Querformat im Player
requestGeometryUpdate allein dreht nicht: das System dreht sofort
zurück, solange die erlaubten Ausrichtungen es nicht hergeben. Die
Erlaubnis kommt nur über den App-Delegaten, deshalb OrientationLock
als Brücke. Player dreht ins Querformat, beim Verlassen zurück. iPad
bleibt frei — dort ist Querformat beim Blättern der Normalfall.
Uhrzeit über dem Film
Die Statusleiste war nur ausgeblendet, solange die Bedienelemente weg
waren. Jetzt immer.
Sehr langer Start
Zwei Ursachen. Erstens legte der Initialisierer der App die
Hintergrund-URLSession an — die spricht über XPC mit nsurlsessiond und
verzögerte den allerersten Bildaufbau. Jetzt erst bei Bedarf, und wer
keine Downloads hat, braucht sie nie. Zweitens fragte jeder Start erst
plex.tv nach der Serverliste und suchte die Verbindung neu. Die zuletzt
funktionierende wird jetzt gemerkt (Server-Token im Schlüsselbund) und
mit kurzer Zeitgrenze zuerst probiert; die vollständige Suche greift
nur noch, wenn sie nicht mehr antwortet — etwa wenn man von zuhause
weggeht.
Dazu ein Hinweis im Player, wenn die Verbindung über die gedrosselte
Plex-Vermittlung läuft. Sonst sucht man den Fehler in der App.
132 Tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Anmelde-Adresse wurde doppelt kodiert
URLComponents.fragment kodiert beim Setzen erneut, aus %5B wurde
%255B. Plex antwortete mit „Diese Anfrage konnte nicht abgeschlossen
werden". Die Adresse wird jetzt von Hand zusammengesetzt.
Verbindungssuche hing bis zu anderthalb Minuten
probeTimeout war deklariert, aber nirgends angewendet — es galt der
URLSession-Standard von 60 Sekunden. Zusammen mit der Prüfung Rang
für Rang kostete eine schweigende lokale Adresse die volle Zeit,
bevor der direkte Weg überhaupt begann. Jetzt laufen alle Adressen
gleichzeitig, mit Zeitgrenze, und die Rangordnung entscheidet unter
den erreichbaren.
Kein Zurück während des Ladens
Die Kopfzeile mit dem Schließen-Knopf wurde nur im Zustand .playing
gezeichnet. Bei langsamer Verbindung saß man ohne Ausweg vor einem
Ladekreis. Sie liegt jetzt als eigene Ebene darüber und erscheint
auch beim Vorbereiten — samt Titel, damit erkennbar bleibt, worauf
gewartet wird.
Sechs neue Tests, darunter drei, die die Zeitgrenze der
Verbindungssuche an einer schweigenden Adresse nachstellen.
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>