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>
Zwei Dinge, die beide dasselbe Missverständnis erzeugt haben.
Der Regler blieb beim Spulen liegen, wo er war, und rückte erst nach, wenn
das erste Bild von der neuen Stelle da war — über das Netz Sekunden später.
Das liest sich als „der Sprung ist nicht angekommen", und man spult noch
einmal. Der Sprung ist aber angekommen, in dem Moment, in dem man ihn
auslöst; alles Weitere ist Warten auf Daten, und dafür gibt es den Kreisel.
Die Stelle steht jetzt sofort. Nachzügler von der alten Stelle werden
verworfen, sonst zöge die letzte Meldung den Regler wieder zurück.
Und bis wohin geladen ist, stand nirgends. Dafür ist der `Slider` gewichen:
er hat genau eine Spur, und die gehört dem Fortschritt. Etwas dahinter zu
zeichnen und auf gleiche Innenabstände zu hoffen ginge so lange gut, bis
Apple sie ändert. Der neue Regler zeichnet drei Schichten aus derselben
Rechnung — Grund, Geladen, Gespielt — und hat einen Griff, den ein Finger
trifft.
Der Vorrat wird dabei abgelegt statt ausgerechnet. Eine berechnete
Eigenschaft wird nur gelesen, wenn ohnehin neu gezeichnet wird, und das
geschieht, weil die Abspielstelle weiterläuft. Im pausierten Zustand läuft
sie nicht — und ausgerechnet da will man zusehen, wie der Vorrat wächst.
Die Schleife, die ihn nachführt, lief bisher ausserdem nur bei
„automatisch": wer eine Stufe von Hand gewählt hatte, hätte nie gesehen,
wie weit geladen ist.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Im Spurenblatt stand „CC" und sonst nichts — derselbe Fehler wie beim Ton:
das ist AVFoundations Name für den einen Untertitel, den ein umgerechneter
Stream mitbringt. Zur Auswahl steht jetzt, was in der Datei liegt, und die
Nummer geht als `subtitleStreamIndex` mit in die Anfrage.
`-1` heisst dabei ausdrücklich „keine". Das ist nicht dasselbe wie nichts zu
schicken: dann sucht der Server sich einen aus, und es steht plötzlich ein
Untertitel im Bild, den niemand bestellt hat.
Und der Klick ins Bild: Anhalten ging, Fortsetzen nicht. Der Abdunkler
hinter der Bedienung deckt das ganze Fenster ab und lag über dem Film —
solange die Bedienung zu sehen war, landete jeder Klick auf ihm. Auffallen
konnte das nur an einer Stelle: nach dem Pausieren bleibt die Bedienung
stehen, also traf der Klick, der wieder starten sollte, nie das Bild. Der
Abdunkler ist jetzt unantastbar; er dunkelt ab, mehr nicht.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Seit die Bedienung dauerhaft montiert ist, zeichnet der Scrubber darin im
Sekundentakt neu. `onContinuousHover` meldet nicht nur bei Bewegung, sondern
auch bei jedem Neuzeichnen — also setzte die Ausblendfrist sich endlos
selbst zurück. Die Bedienung blieb für immer stehen, und die Überblendung,
die dadurch nie stattfand, sah aus wie eine kaputte Animation. Sie war nie
das Problem; das war sie schon beim letzten Anlauf nicht.
Jetzt gilt der Zeiger nur als bewegt, wenn er an einer anderen Stelle ist
als zuletzt.
Und der Klick in den schwarzen Rand: ich habe zweimal ausgerechnet, wo das
Bild aufhört, und lag zweimal daneben. Jetzt rechnet das Layout. Die
Bildfläche ist auf ihr Seitenverhältnis zugeschnitten und hat ihren eigenen
Griff; der schwarze Rand ist schlicht der Hintergrund dahinter. Was am
Player ankommt, ist damit per Definition daneben gegangen — es muss niemand
mehr feststellen.
Damit fallen `videoRect`, `videoFrame`, `playerSize`, der benannte
Koordinatenraum und die Abfrage der `AVPlayerLayer` ersatzlos weg.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Im Spurenblatt stand eine einzige Zeile: „Unbekannt". Das ist der Name, den
AVFoundation einer namenlosen Spur gibt — und bei einem umgerechneten
Stream liefert der Server genau eine. Der Player hatte nichts zur Auswahl,
weil die Wahl längst gefallen war, bevor er gefragt wurde.
Gewählt wird jetzt aus den Spuren, die **in der Datei** stehen, und zwar
bevor der Stream ausgehandelt wird. Die Nummer geht als `audioStreamIndex`
mit hinaus; wer mitten im Film umstellt, bekommt den Stream neu — ausser
bei unveränderter Wiedergabe, wo der Player ohne Unterbrechung umschaltet.
Die Abwägung selbst macht `AudioTrackChooser`: gemerkte Spur, dann
Wunschsprache, dann Rangliste, dann Standardspur — und Audiodeskription
mit deutlichem Abzug statt Ausschluss, damit eine Sprache, die es nur so
gibt, immer noch besser ist als Stille.
Drei Ebenen in `LanguagePreferences`: Serie, Mediathek, allgemein. Gefragt
wird von unten nach oben. Die Mediathek wird nur nachgeschlagen, wenn
überhaupt jemand eine Sprache je Mediathek gesetzt hat — sonst kostete jede
Wiedergabe eine Anfrage für eine Ebene, die niemand benutzt.
Wer von Hand umstellt, dessen Wahl wird für die Serie gemerkt, ohne
Nachfrage. Der Dialog „für diese Serie merken?" ist genau die Art, die man
nach dem dritten Mal wegklickt. Sichtbar ist es trotzdem: das Spurenblatt
zeigt es und lässt es löschen.
Dazu die Rangliste in den Einstellungen, ziehbar, und der Schalter
„Audiodeskription meiden".
Und die Player-Oberfläche blendet endlich als Ganzes über. Die Kopfzeile
hatte gar keine Überblendung — sie sprang herein, während die Bedienung
darunter verblasste. Jetzt steht die Animation an einer Stelle statt an
sechs, und sie läuft über Deckkraft statt über Einfügen und Entfernen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Er hat weiterhin angehalten statt ein- und auszublenden, und der Grund
steckte in der Rechnung: der schwarze Rand wurde aus der Fenstergrösse
ausgerechnet, das Bild liegt aber in einer Fläche mit `ignoresSafeArea()`.
Auf dem Mac ist der Einzug der Fensterleiste genau der Unterschied
zwischen beiden — die Rechnung lag um diesen Betrag daneben.
Jetzt wird die Bildfläche gemessen statt angenommen, und beide Zahlen
stehen in einem gemeinsamen, benannten Koordinatenraum. Vor allem aber
wird zuerst `AVPlayerLayer.videoRect` gefragt: der Player weiss selbst,
wo Bild steht. Die eigene Rechnung bleibt für den Moment vor dem ersten
Bild und für VLC, das keine solche Ebene hat.
Dazu zwei Worte: „Nachschub" heisst jetzt „Nachladen", und „Blatt" heisst
wieder „Sheet" — das ist ein Fachbegriff und bleibt englisch.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
**Das Raster sagt jetzt, ob noch etwas kommt.** Eine Mediathek lädt
seitenweise nach, und wer unten ankam, sah ein Raster, das aufhört — ohne
unterscheiden zu können, ob das alles war oder gerade nachgeladen wird.
Beides sah gleich aus.
Beide Server nennen die Gesamtzahl (Jellyfin `TotalRecordCount`, Plex
`totalSize`), und wir lesen sie längst. Also stehen die nächsten Kacheln
schon da, in der Form, die sie haben werden — gedeckelt auf ein Dutzend,
weil zweihundert Platzhalter niemandem helfen. Ist wirklich alles da,
steht es am Ende ausdrücklich: „Alle 252 Titel geladen".
Gegen die Attrappe mit 252 Titeln durchgeblättert und nachgesehen: die
Zeile steht da, und alle 252 sind angekommen.
**Herein sanft, hinaus zügig.** Das Einblenden der Bedienung begleitet
eine Bewegung des Zeigers und soll wirken, als käme sie der Hand
entgegen; zwei Zehntel wirkten wie ein Aufblitzen. Das Ausblenden
dagegen ist ein Aufräumen, und dabei muss niemand zusehen.
**Ein Klick ins Schwarze blendet um, statt anzuhalten.** Ein Film füllt
das Fenster fast nie ganz aus — die Balken daneben gehören nicht zum
Film, und dort zu klicken ist die natürliche Geste für „zeig mir die
Bedienung". Wo das Bild aufhört, wird aus `presentationSize` gerechnet,
also aus dem, was wirklich ankommt. Fehlen die Maße, verhält es sich wie
bisher.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
**Die Wiedergabe sprang von selbst wieder an.** Auf dem Mac pausiert ein
Klick ins Bild — und der Klick, mit dem man ein Fenster nach vorn holt,
kommt ebenfalls dort an. Man aktiviert das Fenster und drückt dabei auf
Play. Klicks innerhalb einer Viertelsekunde nach dem Aktivieren zählen
deshalb nicht: länger braucht niemand bis zum ersten gemeinten Klick,
kürzer erwischt den Fall nicht.
**Schwarzbild mit Ton nach dem Vergrössern.** Kachel und Vollbild
bestehen beim Wechsel kurz gleichzeitig, und beide holten sich dieselbe
Bildfläche in ihre Hülle. Eine Ansicht hat aber nur einen Vorgesetzten —
wer zuletzt aktualisiert, gewinnt, und das war nicht verlässlich die
richtige. Blieb die Fläche bei der Kachel, die gleich darauf verschwand,
lief im Vollbild der Ton weiter und das Bild blieb schwarz.
Die Hülle allein genügte nicht: sie verhindert, dass das Abräumen der
einen Ansicht der anderen etwas wegnimmt, entscheidet aber nicht, wer
die Fläche bekommen **soll**. Das sagt jetzt `isActive` — abgeleitet aus
`playback.presentation`, also aus derselben Quelle, die auch bestimmt,
welche Ansicht überhaupt zu sehen ist.
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>
**Die Schlüssel.** Im Quelltext steht `"season.number \(season)"`, der
Schlüssel heißt damit `season.number %lld`. Im Katalog stand er ohne
Platzhalter — also traf er nie, und die App zeigte den Schlüssel selbst:
„The 50 · season.number 1 · episode.number 1". Beide umbenannt. Ein
Überbleibsel `episode.number %@` ohne eine einzige Übersetzung ist
mitgegangen, und aus „Episode" wurde „Folge", wie überall sonst im Haus.
**Die Kreisel.** Die Abdeckung beim Wiederherstellen der Stelle ist eine
ganze Seite, kein Schleier — nur lag das Übrige weiter darüber. Zu sehen
waren Bedienelemente mitten im Satz, ein Kreisel in der Abdeckung und ein
zweiter im Abspielknopf, den man in dem Moment ohnehin nicht drücken
soll. Jetzt ist die Abdeckung ausschließlich. Die Kopfzeile bleibt: sie
ist der Weg zurück.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Kein Hänger, sondern ein Absturz, der nicht durchkam. Der Stapel des
eingefrorenen Prozesses endet in `_assertionFailure` beim Lesen eines
`@Environment`-Werts — mitten in `SheetBridge.present`, also während das
Blatt aufgebaut wird. Weil der Player in diesem Moment in einem
Layoutdurchlauf steckt, erschien nie eine Meldung: das Fenster stand
still.
`@Environment(PlaybackSettings.self)` ohne Fragezeichen ist keine Bitte,
sondern eine Behauptung — fehlt der Gegenstand, hält Swift die Anwendung
an. Und ein Blatt hängt an einem eigenen Darstellungsbaum. Auf dem iPad
kam die Umgebung des Players dort bisher an, auf dem Mac nicht.
Zwei Änderungen, beide nötig:
- Der Player reicht `PlaybackSettings` und den Akzent ausdrücklich in
seine Blätter hinein, statt sich auf Vererbung zu verlassen.
- `QualitySheet` liest die Einstellungen als Optional. Ein Vergessen
kostet künftig eine fehlende Zeile im Blatt statt der ganzen App.
Dazu ein Test, der genau diesen Weg geht: abspielen, Qualitätsknopf,
Blatt da? Er lief schon vor der Korrektur durch — der Unterschied
zwischen iPad und Mac ist mit einem Simulator nicht zu fassen. Er hält
trotzdem fest, dass der Weg überhaupt gegangen werden kann.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Player deckt das ganze Fenster ab, und auf dem Mac zeichnet das
System seine Ampelknöpfe darüber. Die Kopfzeile lag damit nicht nur
optisch unter ihnen — der Streifen gehört der Fensterleiste, und die
nimmt jeden Klick für sich. Verkleinern, Schließen, Tonspur, Untertitel
und die Qualitätsstufe waren dort tot, und ein Doppelklick auf dieselbe
Stelle legte das Fenster ins Dock.
Jetzt beginnt die Kopfzeile auf dem Mac achtundzwanzig Punkte tiefer.
Dazu: Tabulator springt in der Jellyfin-Anmeldung vom Namen zum Passwort
und zurück. „Name, Tab, Passwort, Eingabe" ist der Weg, den jeder mit
einem Passwortspeicher nimmt; SwiftUI schiebt den Fokus dort nicht von
selbst weiter.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Bedienung mit Zeiger und Tastatur hing an
`#if targetEnvironment(macCatalyst)`. Das ist in dem Bau, der tatsächlich
benutzt wird, **falsch**: „für iPad angepasst" ist buchstäblich der
iOS-Bau, der auf Apple Silicon startet, und dort ist die Abfrage nicht
erfüllt. Klick-zum-Anhalten, Leertaste und die Pfeiltasten waren damit
genau dort abgeschaltet, wo sie gebraucht werden.
Jetzt beantwortet `FlixyPlatform.isMac` die Frage zur Laufzeit und kennt
beide Wege. Die Ansicht bleibt dabei eine einzige: `focusable(_:)` nimmt
den Schalter entgegen, die Tastenhandler geben sonst `.ignored` zurück.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Während der Player auf Daten wartete, stand im mittleren Knopf das
Abspieldreieck und der Ladekreis lag dahinter. Das las sich als
„angehalten": man drückte auf Abspielen, und es geschah nichts — es lief
ja bereits, es kam nur nichts an.
Jetzt sitzt der Kreisel **im** Knopf, dort wo sonst das Symbol steht. Der
freistehende Kreisel in der Bildmitte bleibt für den Fall, dass die
Bedienelemente ausgeblendet sind. Zwei übereinander gibt es nicht mehr.
`togglePlayPause` zählt das Warten jetzt zum Laufen. Vorher führte ein
Tipp in diesem Moment zu `play()` auf etwas, das schon spielte.
Dazu auf dem Mac, wie im Browser auch:
- Ein Klick ins Bild hält an, statt erst die Bedienelemente zu holen. Die
kommen dort von allein, sobald sich der Zeiger regt.
- Leertaste hält an, Pfeil links und rechts springen.
Mit dem Finger bleibt es beim Alten: ohne Zeiger gibt es keine Bewegung
ohne Berührung, und ein Tipp, der sofort anhält, nähme den einzigen Weg
zu Scrubber, Tonspur und Qualität.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Und dein Argument dafür war das beste: auf dem Mac kann ich selbst hinsehen.
Kein Simulator-Tunnel, der mitten im Prüfen abstürzt — `screencapture` auf das
Fenster der App, und zwar nur auf ihres, nicht auf den Bildschirm.
**Ein eigenes Ziel, nicht ein gemeinsames.** Die Info.plist der iOS-App ist
voller iOS-Angaben: Startbildschirm, erlaubte Ausrichtungen, Live Activities.
Die alle bedingt zu machen hieße, dass jede spätere Änderung an der iOS-Seite
über eine Stelle geht, die auch den Mac betrifft. Zwei Ziele sind ein paar
Zeilen mehr und eine Sorge weniger.
**Was den Unterschied ausmacht, steht an einer Stelle.** Ein neuer
`PlatformShims` in FlixyDesign übersetzt, was auf beiden Seiten verschieden
heißt: schmale Titelzeile, halbhohes Blatt, Eingabefelder ohne
Großschreibung, die Plätze in der Werkzeugleiste, die Zwischenablage. Zwanzig
Ansichten benutzen ihn, statt zwanzigmal `#if os(iOS)` zu tragen — sonst
wandert die Fallunterscheidung in jede neue Datei und wird beim übernächsten
Bildschirm vergessen.
Wirklich verschieden sind nur fünf Stellen: die Bildfläche (`UIView` gegen
`NSView`), der AirPlay-Knopf, die Ausrichtungssperre (auf dem Mac gibt es
nichts zu sperren), der App-Delegat für Hintergrund-Downloads und das
Anmeldefenster, das ein anderes Fenster als Anker braucht.
**Das Karussell blättert jetzt mit einem einrastenden Streifen** statt mit
`TabView(.page)` — den Seitenstil gibt es auf dem Mac nicht. Das ist nebenbei
die bessere Lösung: das verschachtelte TabView hatte die Eigenschaft, beim
Wechsel kurz zwei Seiten gleichzeitig zu zeigen.
**Was auf dem Mac fehlt und warum:** VLC. Das Binärpaket ist auf iOS
festgelegt; sein xcframework enthält zwar Mac-Teile, aber das ist eine eigene
Runde. Solange fällt die Wiedergabe dort auf den Systemplayer zurück — MKV und
DTS gehen also noch nicht. Live Activities gibt es auf dem Mac nicht, Bild-in-
Bild startet von Hand statt beim Verlassen der App.
Gesehen: die App startet, der Anmeldebildschirm steht, beide Wege sind da.
Angemeldet habe ich mich auf dem Mac **nicht** — das ginge nur, indem ich
einen Token in deinen Schlüsselbund schreibe, und dann fragt macOS dich beim
ersten Zugriff nach dem Passwort. Das machst du mit einem Klick selbst.
iOS baut unverändert, 263 Tests grün.
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>
Deine Einstellungs-Bilder sind eine lange Liste. Ich habe sie durchgegangen
und getrennt: was etwas steuert, ist gebaut; was eine Einstellung für eine
Sache wäre, die es nicht gibt, ist nicht gebaut. Ein Schalter, der nichts
bewirkt, ist schlimmer als kein Schalter.
**Die Einstellungen sind jetzt eine Übersicht.** Vorher stand alles
untereinander auf einem Bildschirm — Serverangaben, Qualität, Wiedergabe, drei
Verweise, Downloads, Version, Abmelden. Das war beim Bauen bequem und beim
Suchen anstrengend. Jetzt führt jede Zeile in einen Bildschirm, der zu einer
Frage gehört: Server, Erscheinungsbild, Startseite, Wiedergabe, Ton &
Untertitel, Downloads, Diagnose.
**Neu, und jedes davon greift irgendwo:**
- Zurück- und Vorspulen getrennt einstellbar. Die Knöpfe im Player und die
Doppeltipp-Flächen tragen danach auch das passende Symbol.
- Startgeschwindigkeit — die Engine kann es längst, gefragt wurde nie.
- „Im Querformat sperren" abschaltbar. Für die allermeisten Filme richtig, für
den, der im Bett auf der Seite liegt, das Gegenteil.
- „Gewählte Qualität merken": die Stufe gilt dann auch für den nächsten Titel.
Aufbewahrt wird eine **Zahl**, keine Sprosse — welche Sprossen es gibt, hängt
von der Quelle ab, und eine 720p-Datei kennt keine Zwanzig-Megabit-Stufe.
Dann kommt die nächstgelegene, nicht „automatisch".
- „Bitrate im Qualitätsmenü zeigen".
- Gleichzeitige Downloads. Der Wert gab es schon in der Engine, nur ohne
Bedienung und ohne dass er einen Neustart überlebte.
- Aufmacher: wie viele Titel, und ob sie aus Angefangenem oder nur aus
Neuzugängen kommen.
- „Weiterschauen und Als Nächstes zusammenlegen" und „Gesehenes aus
Neuzugängen ausblenden" — beides in der Ansicht, nicht im Server: das sind
Fragen der Darstellung, und so gelten sie für Plex und Jellyfin gleich.
**Verkleinert herunterladen geht jetzt auch bei Jellyfin.** Da hatte ich zu
früh aufgegeben: ich hatte nur nach der Adresse zum *Abspielen* gesucht, und
die ist eine Abspielliste mit hunderten Schnipseln — als Datei unbrauchbar.
`/Videos/{id}/stream.mp4` gibt dieselbe Umrechnung als eine Datei heraus. Die
Größe bleibt eine Schätzung; eine Umrechnung, die erst beim Abruf beginnt,
kennt ihre eigene Länge nicht.
**Die Kontozeile ist jetzt eine Karte, die nach oben aufklappt**, kein
Systemmenü mehr. Ein Menü legt sich als eigene Ebene über alles und springt
dorthin, wo Platz ist; die Karte bleibt, wo sie ist, und lässt die Zeile mit
dem Namen stehen — man sieht also weiter, um wessen Konto es geht.
**Nicht gebaut, mit Grund:** Trailer im Karussell, Poster- und Sammlungsstil,
Untertitel-Aussehen, sekundäre Untertitel, lokale Intros, Modular Home,
App-Symbol. Für all das fehlt das, was die Einstellung steuern würde — es gibt
in Flixy weder Trailer noch Sammlungen, und der Player zeichnet Untertitel
nicht selbst.
263 Tests grün. **Nicht angesehen**: der Simulator-Tunnel ist weiterhin
abgestürzt und ließ sich nicht wieder aufbauen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ein frisch angeforderter Stream beginnt vorn, puffert und springt erst
danach an die Stelle, an der man war. Zehn Sekunden lang lief sichtbar
der Filmanfang — und der Eindruck, die Stelle sei weg und man müsse sie
wiederfinden.
Der Umstieg wird jetzt abgedeckt, solange der Player noch nicht dort ist,
und die Abdeckung nennt die Stelle ausdrücklich. Genau darum geht es:
nicht, dass es schneller wird, sondern dass niemand denkt, er habe etwas
verloren.
Aufgehoben wird sie, sobald der Player innerhalb von zwei Sekunden um die
Stelle liegt. Dazu eine Notbremse nach dreißig Sekunden — springt er nie
dorthin, bliebe sonst für immer eine schwarze Fläche über dem Bild.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ein Überzug liegt in SwiftUI zwangsläufig obenauf. Ich hatte die
Doppeltipp-Flächen als `.overlay` über den ganzen Player gelegt, also
eine durchsichtige Fläche vor jeden Knopf — Pause, Scrubber, Qualität,
Kopfzeile, alles wirkungslos. Im Stapel entscheidet dagegen die
Reihenfolge, und dort liegen sie jetzt: über dem Bild, unter den
Bedienelementen.
Dazu kleiner. Volle Bildschirmhälften decken die Mitte ab, wo der
Pause-Knopf sitzt, und den oberen Rand mit der Kopfzeile — beim Zielen
auf einen Knopf träfe man zuerst die Fläche. Jetzt sind es zwei Streifen
von je dreißig Prozent Breite in der mittleren Höhe, mit Abstand zu oben
und unten.
Tippen außerhalb zeigt und verbirgt die Bedienelemente wie zuvor.
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>
Drei Sachen aus dem Feldtest.
Der Griff zum Größerziehen war wirkungslos, und zwar durch meinen Fehler:
die Drehung lag auf dem ganzen Überzug statt auf dem Symbol. Bei zwei der
vier Ecken kippte damit die gesamte Trefferfläche weg, und man griff ins
Leere. Jetzt sitzt der Griff über `overlay(alignment:)`, nur der Pfeil
dreht sich, und das Ziehen hat Vorrang vor dem Verschieben der Kachel —
sonst gewinnt das Verschieben, das am selben Ort hängt.
Senderlogos sind Schriftzüge und fast nie quadratisch. Formatfüllend in
einem Quadrat fehlten links und rechts genau die Teile, an denen man den
Sender erkennt. Sie bekommen jetzt eine breitere Fläche und werden
eingepasst statt beschnitten — `FlixyArtwork` kann beides, und welches
gilt, entscheidet der Aufrufer.
Und im Player steht bei Live-TV, was gerade läuft. Der Name reist mit dem
Einschalten mit, denn nachzuschlagen ist er nicht — ein Sender hat keine
Metadaten in der Mediathek. Beim Aufdecken der Bedienelemente wird er
nachgeholt, aber nur, wenn die alte Sendung wirklich abgelaufen ist:
sonst stünde derselbe Name den ganzen Abend, und das wäre derselbe
Fehler, der eben erst im Programm behoben wurde.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Wer im Fernsehen etwas sieht und nebenher nachsehen will, was sonst
läuft, musste bisher abbrechen. Plex' eigene Handy-Apps können das auch
nicht — kein Grund, es hier genauso zu machen.
Der eigentliche Umbau ist nicht die Kachel, sondern der Besitz. Die
Wiedergabe hing an der Sichtbarkeit der Ansicht, und zwar dreifach: das
Modell war `@State` im Player, `onDisappear` hat den Motor abgeräumt, und
die Bildebene entstand in `makeUIView` neu. Zurückgehen hieß deshalb:
Motor tot, Transcoder aus, beim Live-TV der Tuner freigegeben.
Jetzt gehört das Modell der Wurzelansicht, die immer da ist. Verkleinern
und Vergrößern wechseln nur noch die Darstellung; beendet wird die
Wiedergabe an genau einer Stelle, und zwar weil jemand es will.
Die Bildebene hält das Modell selbst — dasselbe Muster, das VLC seit
jeher verwendet. Dieselbe `UIView` wandert zwischen Kachel und Vollbild,
statt neu zu entstehen; sonst setzte das Bild bei jedem Wechsel neu an.
Bild-in-Bild wandert mit und bekommt endlich einen Delegaten: bisher war
es eine Einbahnstraße, aus der man nicht in die App zurückkam.
Die Kachel schwebt und lässt sich in jede Ecke ziehen, statt als Leiste
unten zu kleben — eine Leiste nähme jeder Liste Platz weg und müsste in
jedem Bildschirm bedacht werden. Die Eckenberechnung steht in
MiniPlayerPlacement und ist geprüft: in einer View wäre eine Kachel, die
halb aus dem Bild ragt, erst auf dem Gerät aufgefallen.
Der Pfeil oben verkleinert, ein neuer Knopf daneben beendet wirklich.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Player hing sich auf
Die Qualitätsauswahl war ein Menu. Schloss man es durch einen Tipp ins
Bild, blieb eine unsichtbare Ebene zurück, die alle weiteren Tipps
schluckte — die Bedienelemente kamen nicht mehr, pausieren ging nicht
mehr. Jetzt ein confirmationDialog, der sich selbst wegräumt. Nach dem
Schließen werden die Bedienelemente eingeblendet und die Ausblendfrist
neu gestartet.
Downloads galten als fertig, waren aber leer
Zwei Fehler übereinander. Erstens gilt ein URLSessionDownloadTask auch
bei 404 oder 500 als erfolgreich und legt die Fehlerseite als Datei ab.
Zweitens überschrieb ich danach die erwartete Größe mit der empfangenen
— womit die Anzeige auf hundert Prozent stand und der Beweis weg war.
873 MB waren in einer Sekunde „fertig", und beim Abspielen kam nur
„Wiedergabe wurde unterbrochen".
Jetzt wird der Statuscode geprüft, die erwartete Größe bleibt stehen,
und eine unplausible Datei wird verworfen statt verbucht: unter 100 KB
ist keine Videodatei, unter der Hälfte der angekündigten Größe ist eine
abgebrochene Übertragung. Sechs Tests dazu.
Stufenliste ergab keinen Sinn
Für einen 720p-Inhalt standen Original, Full HD und HD mit derselben
geschätzten Größe untereinander — das sah aus, als wäre die Schätzung
kaputt. Sie war es nicht, die Stufen waren es: hochrechnen bringt nur
eine größere Datei. Angeboten wird jetzt nur noch, was unter der
Auflösung der Datei liegt, und beim Original steht dabei, was es ist:
„Original · 720p · 873 MB".
Kopfleiste
Kein Hintergrund mehr statt eines weichgezeichneten — die Knöpfe
bringen ihre eigene Glasfläche mit. Der Titel ist weg: der Name der App
gehört auf den Homescreen, nicht über jeden Bildschirm.
145 Tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
iPad meldete sich nie an
Die Ursache ist unangenehm speziell: Wer im Browser schon bei Plex
angemeldet ist, wird von app.plex.tv/auth sofort auf watch.plex.tv
weitergeschickt — OHNE dass der Code verknüpft wird. Man sieht sich
angemeldet, die App wartet vergeblich, und es gibt keinerlei Hinweis.
Jetzt wird plex.tv/link mit eingetragenem Code geöffnet. Diese Seite
tut nur eine Sache: den Code bestätigen. Die Gerätekennung steckt
ohnehin schon im PIN.
Dazu ein Ausweg: bleibt es nach fünfzehn Sekunden ohne Token, erscheint
der Code im Anmeldebildschirm zum Abtippen. Schließt man das Fenster
ohne Erfolg, bleibt er stehen statt abzumelden — er gilt weiter.
Download fragte nicht nach der Qualität
Jetzt Original, Full HD, HD oder Sparsam, jeweils mit geschätzter
Größe. Die Größe ist das eigentliche Entscheidungskriterium — „Full HD"
allein sagt nicht, ob es aufs Telefon passt.
Die komprimierten Stufen laufen über den Universal-Transcoder und sind
weiterhin NICHT am Server geprüft; steht so im Quelltext.
Schwarzes Bild ohne Anzeige
Der Player kannte nur „spielt" und „spielt nicht". Wartete er auf
Daten, stand man vor einem Standbild ohne Hinweis. Es gibt jetzt einen
eigenen Pufferzustand mit Anzeige.
Aufmacher war beschnitten
Er stand auf 3:4, Plex liefert als `art` aber 16:9 — mit scaledToFill
ging links und rechts je ein Viertel verloren, ohne dass man es dem
Bild ansah. Die Seitenverhältnisse liegen jetzt an einer Stelle in
FlixyAspectRatio.
Schwarze Leiste über dem Aufmacher
.ultraThinMaterial statt undurchsichtigem Grund: das Bild läuft
unscharf hinter der Leiste weiter, statt an einer harten Kante zu
enden. Weichgezeichnet, nicht abgedunkelt.
139 Tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
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>
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>
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>