63c664e5a9ab3f47cdde4eb9fad3b8f590ebed7e
4
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
19c9dc843c |
„Aus Weiterschauen entfernen" tut jetzt etwas — und man kann es sehen
Der Knopf war wirkungslos, und zwar aus zwei Gründen, die beide auf
dasselbe hinauslaufen: er war nie geprüft worden.
**Der Weg war falsch.** Die Methode las erst ein Benutzerdatenblatt über
`GET /Users/{id}/Items/{id}/UserData`, änderte es und schrieb es zurück.
Diese Stelle war die **einzige im ganzen Projekt**, die ein solches Blatt
eigens liest — überall sonst kommt es am Titel mit. Es gab also kein
zweites Beispiel, an dem der Weg je funktioniert hätte, und ein 404
beendete die Sache, bevor überhaupt etwas geschrieben wurde.
Jetzt wird das Blatt **gebaut**, nicht erfragt: „gesehen", „Favorit" und
die Zählung stehen am Titel, den der Aufrufer ohnehin in der Hand hat —
deshalb nimmt `removeFromContinueWatching` jetzt den Titel statt nur
seiner Kennung. Gelesen wird trotzdem noch, aber unverbindlich: gelingt
es, bleiben auch Felder erhalten, die diese App gar nicht kennt. Und
geschrieben wird über beide Wege — erst der gebündelte
`/UserItems/{id}/UserData`, bei einem 404 der ältere. Welcher gilt, hängt
an der Serverfassung.
**Und man konnte es nicht sehen.** Die Attrappe kannte die Route nicht;
ihr Auffangzweig antwortete auf jeden Schreibversuch mit Status 200, und
die Weiterschauen-Reihe war fest verdrahtet. Der Aufruf gelang also immer
und änderte nie etwas — genau das Bild eines kaputten Knopfes, nur aus
einem anderen Grund. Genau deshalb ist der Fehler durchgerutscht.
Sie führt jetzt echte Benutzerdatenblätter, beantwortet beide Wege und
liefert unter „Weiterschauen" nur noch, was eine gemerkte Stelle grösser
null hat. Unter `/__userdata` steht, was geschrieben wurde und wohin.
Gemessen im Simulator, nach einem Tipp auf den Eintrag:
/UserItems/m2/UserData
{"Played":false,"IsFavorite":false,"PlaybackPositionTicks":0,…}
Danach ist „Weiterschauen" leer und die Reihe verschwindet von der
Startseite.
**Zwei Dinge, die danach trotzdem auffallen können**, und beide sind
keine Fehler: Jellyfins „Als Nächstes" führt angefangene Folgen mit, eine
entfernte Folge kann dort wieder auftauchen. Und bei zusammengelegten
Reihen stehen auch Folgen ohne gemerkte Stelle — dort gibt es nichts zu
entfernen, und der Eintrag fehlt.
Plex bleibt unberührt: der Weg dort war in Ordnung und bekommt nur die
neue Form.
iOS und tvOS bauen, 469 Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
b0db4f8f5f |
Bei VLC sass das Bild nie richtig — und der Knopf wirkte nie
Zwei Fehler, die dieselbe Ursache haben: alles, was über VLC läuft, ging
an der Bildebene vorbei, an der die App gedreht hat.
**Das Bild sass nicht mittig.** Nicht ein paar Punkte daneben — gemessen
eine Anzeigefläche von 1200×480 Punkt in einer Zeichenfläche von 711×400,
unten rechts angeschlagen, im falschen Seitenverhältnis. Der Grund steht
im Vertrag von `VLCDrawable`: VLCKit fragt die Grösse **einmal** beim
Anlegen ab und überlässt seine Anzeigefläche danach der
Autoresizing-Maske. Eine Maske hält aber den Unterschied fest, nicht das
Verhältnis — was beim Anlegen zu gross war, bleibt für immer um denselben
Betrag zu gross. Und angelegt wird sie mitten in der Drehung ins
Querformat, während SwiftUI sie einblendet: also regelmässig falsch.
Die Zeichenfläche ist jetzt eine eigene Klasse, die ihrer Anzeigefläche
bei jedem Layout wieder die eigene Grösse gibt. Danach gemessen: 695,7 ×
400 Punkt, Rand links 130,0, rechts 130,3 — mittig.
**Der Knopf für einpassen/füllen tat nichts.** Er schrieb `videoGravity`
auf eine `AVPlayerLayer`, die bei VLC gar nicht im Baum hängt. Die
Einstellung geht deshalb jetzt durch die Engine: `setVideoFit` am
Protokoll, beim Systemplayer eine Voreinstellung, die nichts tut — dort
macht es die Bildebene —, bei VLC `videoFitMode`. `smaller` heisst bei
libvlc „fit inside", `larger` „fit outside".
Gemessen, im Querformat auf einem Pro Max, über VLC:
eingepasst 695,7 × 400 pt Rand l/r 130,0/130,3 o/u 20,0/20,0
füllend 935,3 × 440 pt Rand l/r 10,3/ 10,3 o/u 0,0/ 0,0
**Zurückgenommen:** im Kommentar an `videoFit` stand, ein `didSet` auf
einer `@Observable`-Klasse werde nicht gemeldet. Das stimmt nicht —
`HomeLayoutSettings` lebt davon. Ein Kommentar, der einen falschen
Mechanismus behauptet, schickt den nächsten in die falsche Richtung;
jetzt steht der belegte Grund dort.
Dazu, damit dieser Weg überhaupt prüfbar ist: die Attrappe meldet mit
`--vlc` DTS-Ton. AVFoundation kann das nicht, also fällt die App auf
VLCKit zurück. Die Beispieldatei bleibt dieselbe — geprüft wird der Weg,
nicht der Ton. Ohne diesen Schalter ist der VLC-Zweig im Simulator gar
nicht zu erreichen, und genau deshalb lagen beide Fehler so lange da.
Ebenfalls dabei: `EdgeInsets.symmetrical` mit fünf Tests und das Polster
im Player, das damit nicht mehr verschiebt statt einrückt.
iOS und tvOS bauen, 465 Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
fb418c842d |
Wiedergabe: der Player spricht nicht mehr mit Plex, sondern mit dem Vertrag
Bis hierher konnte man sich bei Jellyfin anmelden und stöbern, aber nichts abspielen. Der Player war die letzte große Stelle, die Plex unmittelbar kannte. Drei Mitglieder kommen dafür in den Vertrag: eine Wiedergabe vorbereiten, sie beenden, den Fortschritt melden. Die Entscheidung **ob** umgerechnet wird, fällt weiterhin vorher im `PlaybackDecider` — der Server führt sie nur aus. Genau diese Trennung fehlte: der Player hat Plex' Transcoder angesprochen und konnte deshalb mit nichts anderem reden. `MediaBackendError` bekommt einen siebten Fall: `refused(reason:)`. Der Server hat verstanden und sagt nein, in eigenen Worten. Bei Plex war genau dieser Satz die einzige brauchbare Spur, und er ging tagelang verloren, weil es dafür keinen Fall gab. Bei Jellyfin kommt die Adresse einer umgerechneten Fassung vom Server selbst (`PlaybackInfo` → `TranscodingUrl`), nicht von uns. Er weiß, welche Spuren er kopieren kann und welche er neu rechnen muss. Drei Dinge, die beim Hinsehen auffielen: - **`startTimeTicks` gehört nicht in die Anfrage.** Sonst entscheiden zwei Stellen über den Startpunkt: der Server ließe den Strom dort beginnen, und der Player spränge noch einmal um dieselbe Strecke vor. Bei einundzwanzig Minuten Fortschritt landet man bei zweiundvierzig. - **Der erste Bericht braucht einen eigenen Endpunkt.** Ohne ihn erscheint der Titel bei Jellyfin nirgends als „läuft gerade". Er fiel zunächst aus, weil er die Laufzeit verlangte — und die steht erst Sekunden nach dem Öffnen fest. Jetzt tut es für die erste Meldung die des Servers. - **In der Download-Adresse standen Titel und Fassung vertauscht.** Bei einem Film mit einer Fassung sind beide Kennungen dieselbe und nichts fällt auf; bei zweien schon. `MediaFile` sagt jetzt, zu welchem Titel sie gehört. Live-TV bleibt bei Plex und wird als Einziges noch unmittelbar durchgereicht. Ein Tuner ist ein Stück Hardware, und die fünfhundert Zeilen, die es gekostet hat, ihn zu bändigen, gehören in keinen gemeinsamen Vertrag. Nachgesehen, nicht nur gebaut: gegen die Attrappe läuft ein echtes Video, der Beginn wird gemeldet, der Fortschritt kommt in Ticks mit Sitzung und Fassung an. Was die Attrappe **nicht** beantworten kann, ist, ob ein echter Jellyfin das Geräteprofil annimmt und eine Umrechnung anbietet — das entscheidet erst ein richtiger Server. 257 Tests grün. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
370f7f94f1 |
Startseite: der Aufmacher wechselt, die Neuzugänge stimmen
Vier Dinge aus dem ersten Blick auf einen echten Jellyfin-Server.
**„Zuletzt hinzugefügt" waren nicht die Neuzugänge**, sondern eine
alphabetische Liste. Die Reihe kommt jetzt von `/Users/{id}/Items/Latest` —
dem Endpunkt, den Jellyfin dafür hat. Das behebt zwei Fehler auf einmal: die
Sortierung nach Anlegedatum kam alphabetisch zurück, und selbst wenn sie
gegriffen hätte, wäre sie falsch gewesen. Das Anlegedatum einer Serie ist der
Tag, an dem sie in die Mediathek kam; eine Serie, die seit zwei Jahren dort
steht und gestern eine neue Folge bekommen hat, wäre nie aufgetaucht. Die
Antwort ist dort ein nacktes Feld ohne `Items`-Hülle — dafür gibt es einen
Test, sonst bliebe die Startseite eines Tages stumm leer.
**Der Aufmacher war einer und blieb es.** Jetzt sind es bis zu fünf, die alle
sieben Sekunden weiterwandern und sich auch von Hand durchblättern lassen.
Der Zeitgeber hängt an der aktuellen Seite und fängt bei jedem Wechsel von
vorn an — sonst rutscht der Aufmacher genau dann weiter, wenn man sich einen
Titel ansieht. Wer Bewegung abgestellt hat, blättert selbst. Titel ohne
Hintergrundbild werden übersprungen, solange es andere gibt: eine graue
Fläche mit Text ist keine Bühne.
**Die Seitenleiste ist durchscheinend** statt undurchsichtig, und der
Schleier darunter dunkelt schwächer ab — ein voller Schleier hätte aus dem
Milchglas wieder eine Wand gemacht.
**Der Suchlauf ist aus der Mediathek verschwunden.** Er stand im
Dreipunktmenü, einen Tipp neben „Filter" und „Ansicht wechseln", und
beschäftigt den Server minutenlang. Er steht jetzt in den Einstellungen neben
der Mediathek, zu der er gehört.
Dazu eine Jellyfin-Attrappe unter Tools/: ein Server, der gerade genug kann,
dass sich die Oberfläche ansehen lässt. Damit ist diese Runde tatsächlich
angeschaut worden — Anmeldung per Code, Startseite, wandernder Aufmacher,
Seitenleiste, Einstellungen — ohne einen echten Server anzufassen.
Was weiter aussteht: die Seitenleiste oben statt seitlich, und ihre Einträge
selbst zusammenzustellen. Das ist die nächste Runde, nicht diese.
250 Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|