Commit Graph
95 Commits
Author SHA1 Message Date
ScarriffleandClaude Opus 5 ce4da992ea Einen Knopf je Serie ist bei fünfundneunzig kein Angebot
Es gab ihn: auf der Serienseite, das Uhrsymbol. Nur gilt er für genau
eine Serie — und nach jeder Änderung an der Erkennung will man ohnehin
alles noch einmal. Der Weg dorthin fehlte da, wo man ihn sucht: bei der
Mediathek, neben „Scannen" und „Metadaten auffrischen".

Der Lauf selbst war schon da. `NachScanAsync` macht genau das, Serien
über den Tonabgleich und Filme über das Bild — er hing bloss am Scan und
liess sich nicht von Hand anstossen. Jetzt nimmt er ein „erneut" entgegen
und ist über einen Endpunkt erreichbar. Die Antwort kommt sofort: über
einen grossen Bestand dauert das Stunden, und eine Anfrage so lange offen
zu halten hiesse, sie in ein Zeitlimit laufen zu lassen. Wie weit es ist,
steht im Protokoll von heute.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-13 21:01:11 +02:00
ScarriffleandClaude Opus 5 1340176bf0 Beim Staffelfinale klingt der Abspann anders
Und genau daran fiel er durch. Der Tonabgleich lebt davon, dass der
Abspann in jeder Folge derselbe ist; beim Finale ist er es oft nicht —
anderer Schluss, andere Musik, kein Treffer. In jeder Staffel fehlte
deshalb genau eine Marke, immer die letzte, und wer dort weitersah, sah
keinen Knopf. Das war der ganze Fehler. Der Spieler war nie schuld, und
meine Schranken-Vermutung von eben war falsch.

Was der Ton nicht findet, sucht jetzt das Bild — derselbe Weg wie bei
einem Film: dunkel werden und bis zum Ende durchhalten. Das Verfahren
lag fertig in `FilmAsync` und war nur dort eingebaut; es steht jetzt für
sich und wird von beiden benutzt. Nur für die Lücken: bei einer Staffel
ohne fehlende Marke läuft der Abtaster gar nicht.

**Drei Punkte heissen „mehr davon", nicht „tu etwas".** Bei einer Folge
taten sie etwas — wegräumen aus „Fortsetzen", ohne Rückfrage. Jeder, der
sie sah, hat ein Menü erwartet, draufgetippt, und dann baute die Seite
sich neu auf und die Punkte waren weg. Jetzt ein Kreuz, und eine Zeile,
die sagt, was geschehen ist.

Und die Markenanzeige nennt die Zeiten, nicht nur die Namen: dass eine
Marke da ist, sagt noch nicht, dass sie an der richtigen Stelle steht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-13 20:49:50 +02:00
ScarriffleandClaude Opus 5 74643b8242 Gefunden und gleich wieder weggeworfen
**Stream, nicht Strom.** Mein Fehler, und die Regel kenne ich: Fachbegriffe
bleiben englisch. Betroffen war eine Meldung im Spieler und vier Zeilen im
Tagesprotokoll.

**Der Abspann fiel durch die eigene Schranke.** `Hoechstlaenge` von fünf
Minuten galt für Vorspann und Abspann gleichermassen. Fünf Minuten sind
für einen Abspann aber keine Obergrenze, sondern die Regel — eine deutsche
Serienproduktion listet Sprecher, Synchronregie und Studio hinterher, und
sechs Minuten kommen vor. Der Tonabgleich fand das Stück, und die Zeile
darunter warf es weg. Von aussen sah das aus wie „nichts gefunden".
Der Abspann darf jetzt so lang sein wie sein Suchfenster; weiter reicht
eine Marke ohnehin nie.

**Vermutung, nicht Messung** — das Stück steht auf einem Server, an den ich
nicht komme. Deshalb dasselbe Commit:

**Man kann jetzt nachsehen.** Neben jeder Folge steht für Verwalter, was
die Erkennung gefunden hat: „Vorspann + Abspann", „Vorspann" oder „keine
Marken". Ob eine Marke fehlt oder bloss nicht angezeigt wird, war von
aussen nicht zu unterscheiden — und beides hat eine andere Ursache. Die
Angabe kostet nichts: sie steht längst in der Antwort des Servers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-13 20:33:52 +02:00
ScarriffleandClaude Opus 5 a360bed02b Vier Stellen, an denen eine Angabe unterwegs verlorenging
**Der Aufmacher wusste nur die Serie.** `Heroeintrag.titel` ist bei einer
angefangenen Folge der Name der Serie — richtig, denn der Aufmacher zeigt
die Serie. Wer von dort startete, las über dem Spieler „Biohackers" und
nicht, welche Folge läuft. Staffel, Nummer und Folgentitel reisen jetzt
mit. Dasselbe im Aufmacher selbst: „Staffel 1 · Folge 2" statt „S1 · F2".

**Der Abspann ist kein Angebot, sondern eine Frage.** Die Acht-Sekunden-
Frist von gestern war für das Intro gedacht und traf den Abspann mit:
„Nächste Folge" verschwand genau dort, wo man hinsieht. Ein Intro-Knopf
geht, wenn man ihn nicht nimmt; der Abspann-Knopf bleibt, bis die Folge
zu Ende ist. Web und App.

**„deu" stand da, weil es in der Datei steht.** Der Server reichte einen
vorhandenen Spurnamen unbesehen durch — und viele Dateien tragen als
Titel schlicht das Sprachkürzel. Wiederholt er bloss die Sprache, gilt er
nicht, und die Tabelle darunter macht „Deutsch" daraus.

**Und zweimal „Deutsch" ist keine Wahl.** Zwei deutsche Untertitelspuren
sind der Normalfall — Vollfassung und Nur-Fremdsprachiges. Gleichnamige
bekommen jetzt ihren Codec dazu, und wenn der auch gleich ist, die
Nummer. Das kann keine Spur für sich beantworten: ob ein Name eindeutig
ist, hängt an den anderen. Deshalb steht es in `Benennung` und hat fünf
Prüfungen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-13 17:34:11 +02:00
ScarriffleandClaude Opus 5 fbd865e93b Heruntergeladen heisst nicht: ohne Angaben
Bei einer lokalen Datei kehrte der Spieler zurück, sobald sie lief — und
liess `item` leer. Daran hing mehr als der Titel: keine Marken, also kein
„Intro überspringen"; keine Nachbarfolgen, also keine Knöpfe zum Blättern.
Nur bei Heruntergeladenem, und darum sah es so lange nach einem Fehler in
der Erkennung aus. Jetzt werden die Angaben nachgeholt, während das Bild
schon läuft.

Dazu, was derselbe Weg betrifft: der Spieler sagt „Staffel 1 · Folge 6"
statt „S1 E6" — der Folgenname wird an einer Stelle gebaut, nicht an
dreien. Im Abspann einer Serie stehen zwei Knöpfe statt einem, weil der
Abspann zwei Fragen stellt.

Und die Abdrücke, mit denen der Tonabgleich geprüft wird, sind jetzt
echte: zwei Aufnahmen desselben dreissigsekündigen Stücks, verschiedene
Bitraten, durch fpcalc gedreht. Vorher war jede Prüfung mit erfundenen
Zahlen bestanden — und genau deshalb war nie belegt, dass der Abgleich an
echten Daten etwas findet. Er findet: 17,8–51,0 s und 72,7–105,9 s, bei
20–50 und 75–105.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-13 16:03:57 +02:00
ScarriffleandClaude Opus 5 afa78f9ee0 Ein Knopf, von dem niemand weiss, dass es ihn gibt, ist keiner
„Intro überspringen" lag im Web in der Bedienleiste und verschwand mit
ihr. Am Fernseher sieht man die Leiste gar nicht — der Knopf war also
da und trotzdem unsichtbar. Jetzt liegt er als eigene Schicht über dem
Bild und bleibt stehen, solange die Marke läuft.

**Im Abspann ist „überspringen" ohnehin die falsche Frage.** Was man
dort will, ist die nächste Folge; ans Ende dieser zu springen bringt
niemanden weiter. Gibt es eine, heisst der Knopf jetzt so — im Web wie
in der App, und in der App nicht mehr erst, wenn alles durchgelaufen
ist. Bei einem Film gibt es nichts danach: dort heisst „Abspann
überspringen" jetzt wirklich Schluss, statt auf ein stehendes Bild zu
spulen und den Spieler offen zu lassen.

Dazu der Titel über dem Spieler. Dort stand bei einer Folge „S1 E6" und
bei einer aus der Detailseite gestarteten sogar nur „Wiedergabe". Auf
einer Kachel ist die Kurzform richtig, dort zählt jeder Buchstabe; über
dem Spieler steht eine Zeile in einer leeren Fläche. Jetzt steht da
„Küstenwache · Staffel 1 · Folge 6 · Der Nebel kommt". In der App hiess
es „Episode" statt „Folge" — das eine Wort, das sonst nirgends steht.

Und drei Prüfungen für die Marken auf dem Weg in die App: aus einer
Serverantwort mit Vorspann und Abspann werden zwei Marken an der
richtigen Stelle. Die Übersetzung war nicht der Grund, warum der Knopf
dort fehlte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-13 15:35:59 +02:00
ScarriffleandClaude Opus 5 7673c73757 Vier Sekunden, die ffprobe zu früh aufhörte zu lesen
Die Untertitel kamen vier Sekunden zu spät. Nicht an ihnen lag es: der
Server meldete dem Spieler einen Anfang, der vor dem lag, an dem der
Strom wirklich begann, und genau diese Differenz landet eins zu eins im
Versatz.

Die Schlüsselbildsuche las mit `-read_intervals` bis eine halbe Sekunde
hinter den Wunsch. ffprobe bricht am Ende eines Fensters auf Paketebene
ab — das letzte Schlüsselbild darin kam regelmässig gar nicht mehr
heraus, und die Suche gab das davor zurück. Bei Bildgruppen von vier
Sekunden sind das vier Sekunden.

Nachgemessen gegen die Stelle, an der ffmpeg tatsächlich anfängt, an
einer Datei mit Schlüsselbildern alle vier Sekunden:

    Wunsch   Suche (0,5 s)   ffmpeg    Abweichung
      52,0            48      52,0         −4,0
      73,3            68      72,0         −4,0
     100,2            96     100,0         −4,0

Mit zehn Sekunden Nachlauf lag dieselbe Messung bei allen sieben Werten
auf 0,000. Was über den Wunsch hinausgelesen wird, verwirft die
Filterung ohnehin.

Die Prüfung vergleicht nicht gegen eine erwartete Zahl, sondern gegen
ffmpeg selbst — mit dem alten Wert fällt sie um.

Dazu der Filmteil der Abspannerkennung: `Abspannkante` als reine
Rechnung mit elf Prüfungen, `Bildabtaster` über ffmpeg, Marken auch an
Filmen, Knöpfe zum Suchen und Verwerfen auf der Filmseite. An einer
erzeugten Datei trifft die Kante auf vier Sekunden genau.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-13 06:42:16 +02:00
ScarriffleandClaude Opus 5 8112c15d4d Jeder Scan hätte jede Tonspur noch einmal gelesen
Gemerkt wurde nur, was gefunden wurde. Eine Staffel ohne Abspann — es
gibt genug davon — sah damit bei jedem Scan aus wie eine, in der noch
niemand nachgesehen hat, und wurde wieder abgetastet: jede Tonspur jeder
Folge noch einmal von der Platte, für immer, ohne Ertrag. Bei
sechstausend Folgen ist das kein Schönheitsfehler.

Jetzt steht auch „gesucht und nichts gefunden" in der Datenbank, je
Staffel und Art. Ausgelöst wird ein zweiter Lauf von der Folgenzahl:
kommt eine Folge dazu, gibt es etwas Neues zu vergleichen, sonst nicht.
Ein Zeitstempel allein täte das nicht — eine Staffel, die sich nie
ändert, hat nie einen Grund für einen zweiten Lauf.

Dazu der Knopf, der ausdrücklich doch noch einmal rechnet: die Uhr auf
der Serienseite sucht ab jetzt immer neu. Von selbst läuft die Suche
nach jedem Scan und überspringt dort das Abgesuchte; wer hier drückt,
will genau das Gegenteil.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-13 05:51:23 +02:00
ScarriffleandClaude Opus 5 2c535e6f47 Drei Wege, die über ein Neuladen führten
**In „Fortsetzen" startet ein Tipp.** Dort steht ein Titel, *weil* man ihn
angefangen hat, und die Stelle steht daneben — der Umweg über die
Detailseite stellte eine Frage, die schon beantwortet war. Überall sonst
bleibt es beim Weg auf die Seite: wer nachsehen will, wie viele Staffeln
eine Serie hat, soll nicht den Film bekommen.

**Ein Haken nimmt die Kachel mit.** In „Fortsetzen" und „Als Nächstes"
steht, was offen ist. Eine abgehakte Folge ist nicht mehr offen — sie mit
einem Haken stehen zu lassen sah aus, als hätte das Abhaken nicht
gewirkt. Dasselbe für „Aus Fortsetzen entfernen": in der Reihe selbst
heisst entfernen genau das.

**Und ein getauschtes Bild erreicht den Aufmacher.** Wer auf der
Startseite ein Plakat wechselt, sieht denselben Titel gleich darüber in
voller Breite — dort stand bis zum nächsten Neuladen das alte. Die
Kachel frischt sich selbst auf; der Aufmacher steht ganz woanders und
erfuhr nichts davon. Jetzt meldet der Bilderdialog es der ganzen Seite,
und wer es angeht, hört zu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-12 21:54:50 +02:00
ScarriffleandClaude Opus 5 8cf2118723 Vorspann und Abspann — erkannt, abgelegt, überspringbar
Beides mit derselben Rechnung, nur in einem anderen Fenster: vorn die
ersten fünfzehn Minuten, hinten die letzten zehn. Was `Tonabgleich`
findet, hängt allein daran, welchen Ausschnitt man ihm gibt — eine
zweite Erkennung für den Abspann wäre dieselbe Suche ein zweites Mal.

Je Staffel verglichen, nicht je Serie: Serien wechseln ihren Vorspann
zwischen Staffeln, und über alle hinweg fände man nichts oder das
Falsche. Gefundenes über fünf Minuten wird verworfen — zwei Folgen, die
dieselbe Datei tragen, teilen vierzig, und darüber stünde sonst ein
Überspringen-Knopf.

Der Lauf geht auf Zuruf, nicht bei jedem Scan: er liest von jeder Folge
ein Stück Ton und dauert Minuten. Der Knopf dafür steht auf der
Serienseite, bei den Verwalterknöpfen.

Die Marken gehen im Folgenvertrag mit — als „intro" und „credits", die
Wörter, die die Apps von Jellyfin her ohnehin kennen. In der App zeichnet
sie der vorhandene Überspringen-Knopf, der bisher nie etwas zu tun
hatte; im Web ist er neu, rechtsbündig über der Zeitleiste.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-12 21:28:36 +02:00
ScarriffleandClaude Opus 5 bfe263d495 Vierundzwanzig Bilder, und der Weg dorthin fehlte sowieso
Zwei Dinge, die zusammengehören.

**Den Bilderdialog gab es nur an der Kachel.** Wer auf der Seite eines
Films stand und sah, dass das Plakat falsch ist, stand genau dort, wo er
nichts dagegen tun konnte — der Weg führte zurück in die Liste und über
das Dreipunktmenü. Jetzt steht „Bearbeiten" in der Knopfreihe der
Detailseite, bei Filmen wie bei Serien, und nur im Kopf: dieselbe Reihe
steht auch über jeder Fassung und jeder Folge.

**Und es waren vierundzwanzig, weil dort vierundzwanzig stand.** Bei
„365 Tage" hat TMDB neunundsechzig Plakate. Dazu ein zweiter, leiserer
Filter: gefragt wurden nur drei Sprachen. Fürs automatische Holen ist
das richtig — dort wird eines genommen, und es soll passen. Wer von Hand
wählt, will sehen, was es gibt; sortiert wird ohnehin nach Sprache, also
steht das Passende weiterhin oben.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-12 20:49:37 +02:00
ScarriffleandClaude Opus 5 fb8ad1c831 Der Stand lag daneben und wurde trotzdem weggeworfen
Der Fortschrittsbalken ist an **einer** Stelle gebaut und wird in jeder
Kachel verwendet — Web wie App. Fehlte er, dann nicht an der Kachel,
sondern weil der Server `State: null` schickte. Drei Listen taten das,
obwohl die Stände in derselben Abfrage danebenlagen:

  /home/suggestions  — „Weil du Ähnliches gesehen hast"
  /home/seasonal     — die saisonale Reihe
  /movies/{id}/similar — „Ähnliche Titel"

Ausgerechnet die erste entsteht aus dem Sehverhalten: ein halb gesehener
Film sah dort aus wie ein unangetasteter, während dieselbe Kachel in der
Mediathek einen Balken trug. `ZuständeZu` gab es längst, es war nur
privat.

**Und „Als Nächstes" lässt sich jetzt räumen.** Das vorhandene Weglegen
reichte nicht dorthin: die Reihe liest `Watched` und `InProgress`, nie
`Dismissed` — und bei einer nie gestarteten Folge ist `InProgress` ohnehin
`false`. Weggelegt wird deshalb die **Serie**, nicht die Folge: beim
nächsten Laden rückte sonst die übernächste nach, und man legte
zwanzigmal weg. Den Zustand dafür gibt es schon, er wurde nur nie
gelesen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-12 19:13:09 +02:00
ScarriffleandClaude Opus 5 fa8d1a97e2 Vom Aufmacher war vor allem Grau zu sehen
Zwei Beschwerden, zwei Ursachen.

**„Niedrig" war nicht niedrig.** Mit 62 vh war es mittel mit anderem
Namen; die Spanne reichte nur nach oben, weil die fünfte Stufe damals
oben gebraucht wurde. Darunter steht jetzt „Flach" mit 46 vh — für den,
der den Aufmacher als Kopfzeile will und nicht als halbe Seite.

**Der Verlauf fing auf halber Höhe schon mit 55 % Deckung an** und wurde
erst bei 85 % durchsichtig. Von einem starken Bild blieb dadurch vor
allem Grau übrig. Jetzt kurz und steil: unten dunkel genug, dass die
Schrift trägt, und die obere Hälfte frei. Der Text sitzt unten links —
genau dort muss es tragen, und darüber nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-12 19:03:45 +02:00
ScarriffleandClaude Opus 5 0a394b9b3b „Wartet" für immer, obwohl der Server längst fertig war
Der Eintrag ging nach einer 202 zurück auf „wartet" und rief danach
`resume`. Das nimmt aber nur auf, was **angehalten oder gescheitert**
ist — ein wartender lief in die Schutzklausel und kam nie wieder heraus.
Im Protokoll packte ffmpeg um, in der App stand „wartet", und dazwischen
lag nichts.

Jetzt wird die Warteschlange abgearbeitet statt ein einzelner Eintrag
aufgenommen; „wartet" steht darin.

Dazu zwei Dinge, um die du gebeten hast:

**Das Protokoll liest sich wie eine Kommandozeile.** Älteste Zeile oben,
neueste unten, die Ansicht steht am Ende. Mitgeschoben wird nur, wenn man
unten steht — wer hochgescrollt hat, liest etwas, und ihn bei jeder neuen
Zeile ans Ende zu reissen wäre, als nähme man ihm die Seite aus der Hand.

**Ein Tipp auf eine Kachel führt auf die Detailseite**, am Telefon wie am
iPad wie am Mac. Nur in „Weiterschauen" spielt er ab: dort steht der
Titel, *weil* man ihn angefangen hat. Vorher war es umgekehrt, mit dem
Argument „wer eine Kachel antippt, weiss schon, was er sehen will". Im
Gebrauch stimmte das nicht — wer nachsehen wollte, wie viele Staffeln
eine Serie hat, bekam den Film. Ein Umweg von einem Schritt ist
ärgerlich; eine Wiedergabe, die man nicht wollte, ist schlimmer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-11 20:56:39 +02:00
ScarriffleandClaude Opus 5 fc36bb7ddb Eine Serie, eine Sprachwahl — nicht zwanzig
Auf der Serienseite im Web stand bei jeder einzelnen Folge ein Knopf für
Ton und einer für Untertitel. Zwanzig Folgen hiessen zwanzigmal dieselbe
Frage, und am Ende wusste niemand, welche Antwort gilt. „Dieser Anime
läuft auf Japanisch mit deutschen Untertiteln" ist eine Aussage über die
Serie, nicht über Folge 7.

Die Wahl steht jetzt einmal oben bei den Angaben zur Serie und an den
Folgen gar nicht mehr. Beim Film bleibt sie, wo sie war — dort ist die
Datei der Titel.

Angeboten werden nur Sprachen, die in **jeder** Folge vorkommen; was
dadurch wegfällt, steht als Satz darunter. Gemerkt wird die Sprache, nicht
die Spurnummer: die unterscheidet sich von Folge zu Folge, und beim Start
wird sie für diese Datei nachgeschlagen.

Dazu die Staffeln. Sie standen alle untereinander — nach Folge 8 kam
wieder eine Folge 1, und wer zur dritten Staffel wollte, scrollte an
zwanzig Folgen vorbei. Die Überschrift ist jetzt das Menü. Bei einer
einzigen Staffel bleibt es bei der Überschrift: ein Menü, das nur sich
selbst anbietet, ist keine Wahl.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-10 21:43:17 +02:00
ScarriffleandClaude Opus 5 2c51f639be Untertitel vorher wählen, wie den Ton auch
Auf der Detailseite stand „Ton: Deutsch" und liess sich vor dem Start
umstellen — aus gutem Grund: im Spieler umzuschalten heisst, den Strom
neu aufzubauen. Für Untertitel gab es das nicht, obwohl dort dieselbe
Überlegung gilt und die Spuren ohnehin schon dastehen.

Jetzt steht „Untertitel: Keine" daneben. Auch bei nur einer Spur: anders
als beim Ton gibt es hier immer mindestens zwei Möglichkeiten — diese
eine, oder gar keine.

Der Wunsch wird gemerkt wie beim Ton, mit einem dritten Zustand. „Keine"
ist eine Antwort und kein Fehlen einer: wer sie abgewählt hat, will sie
beim nächsten Film auch nicht, während „nie etwas gesagt" offen lässt,
ob eine erzwungene Spur erscheinen darf.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-10 21:33:35 +02:00
ScarriffleandClaude Opus 5 a6b3217d6e Das Protokoll steht jetzt da, statt sich holen zu lassen
Vorher: eine Liste von Tagen, je Tag drei Knöpfe, und erst nach „Ansehen"
stand irgendwo Text. Wer wissen wollte, was gerade schiefgeht, brauchte
drei Handgriffe für eine Antwort, die auf der ersten Seite hätte stehen
können.

Jetzt ist „Protokolle" eine Liste von Ereignissen, wie man sie aus Home
Assistant kennt: der heutige Tag sofort und offen, neueste Zeile oben —
damit man zum Mitlesen nicht scrollen muss —, und alle vier Sekunden
kommt dazu, was dazugekommen ist. Fehler und Warnungen tragen die Farbe
am Rand statt im Text; eine ganze Zeile in Rot liest sich schlechter als
eine in Grau mit rotem Strich.

Die früheren Tage stehen darunter als Kacheln zum Herunterladen. Der
heutige nicht: er steht schon oben, und eine zweite Tür zum selben Raum
ist keine Hilfe.

Mehrzeiliges — ffmpeg schreibt gern vier Zeilen — hat keinen eigenen
Zeitstempel und gehört zur Zeile darüber. Es wird eingerückt gezeigt
statt verworfen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-10 20:15:50 +02:00
ScarriffleandClaude Opus 5 8397e042b8 Der Publikumswert steht auf der Seite, also wird er von dort gelesen
OMDb führt im Feld `Ratings` nur eine Zahl je Dienst, und bei Rotten
Tomatoes ist das die der Kritik. Die erweiterten Felder gibt es, sie
stehen aber seit Jahren auf `N/A`; Jellyfin fragt sie an und liest sie
nicht einmal aus — deren Antwortklasse kennt `tomatoUserMeter` gar nicht.
Dort hat den Publikumswert also niemand.

Auf der Seite selbst steht er. Gemessen an `/m/the_matrix`: im Quelltext
liegt `"audienceScore":{… "score":"85" …}` neben `"criticsScore"`, dazu
ein `application/ld+json` mit Titel und Erscheinungsdatum; bei Serien
unter `/tv/…` dasselbe, und ein unbekannter Weg antwortet mit 404. Eine
Prüfung mit `[Explicit]` geht einmal wirklich hinaus und bestätigt es:
`rottenTomatoes 83%, rottenTomatoesAudience 85%`.

Das ist Auslesen einer fremden Webseite, und es hat seinen Preis. Eine
offene Suche gibt es nicht — `/napi/search` antwortet mit 401 —, also
wird der Weg aus dem Titel geraten und hinterher am Jahr geprüft: auf der
Seite steht keine IMDb-Kennung, und `/m/the_lion_king` ist der von 1994.
Weicht das Jahr um mehr als eines ab, wird verworfen; lieber keine Zahl
als die eines fremden Films. Der Originaltitel kommt zuerst dran, sonst
fände ein deutscher Bestand dort fast nichts. Ohne Jahr zuerst, weil der
Normalfall den blanken Namen trägt — mit Jahr zuerst kostete jeder Titel
eine Anfrage zu viel.

Deshalb ein Schalter, und der steht aus, bis jemand ihn umlegt. Dazu eine
Bremse: höchstens eine Anfrage je Sekunde, prozessweit. Achthundert Titel
in einem Schwall von einer Adresse wären eine Zumutung und würden
gesperrt. Der Scan dauert dadurch länger; das ist der Preis fürs
Mitbenutzen.

Die Probe unter Einstellungen → Metadaten fragt die Quelle mit, und dort
ist sie mehr als eine Höflichkeit: wird die Seite umgebaut, merkt man es
genau da und sonst nirgends.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-09 16:51:22 +02:00
ScarriffleandClaude Opus 5 e05bbfc2cd Einen einzelnen Titel neu holen, statt achthundert
Eine neue Quelle wirkt erst beim nächsten Holen der Metadaten. Das ging
bisher nur je Mediathek: achthundert Titel, eine Viertelstunde — nur um
an einem Film zu sehen, ob ein Schlüssel etwas bringt. Wer auf einer
Detailseite bemerkt, dass IMDb und Rotten Tomatoes fehlen, hatte von dort
keinen Weg dorthin.

Der Server kann eine Auswahl längst; es fehlte bloss die Kennung der
Mediathek in der Antwort, damit die Seite weiss, wohin ihr Titel gehört.
Der runde Knopf holt diesen einen Titel, wartet den Lauf ab und zeichnet
die Seite neu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-09 16:02:39 +02:00
ScarriffleandClaude Opus 5 18db89399d Ein leeres Jahrfeld ist eine Angabe, kein Versehen
Wer bei der Zuordnung kein Jahr einträgt, sagt damit, dass er keines
weiss. Der Server reichte trotzdem eines nach — das aus dem Dateinamen —,
und das leere Feld hatte überhaupt keine Wirkung. Gerade bei einem falsch
benannten Film ist der Dateiname aber die unzuverlässigste Quelle, die es
gibt: „Plan B (2010)" heisst bei TMDB „DivertiMento – Plan B" und ist von
2011. Mit dem nachgereichten 2010 kam nie ein Treffer, und es gab keinen
Weg daran vorbei.

Ohne Angabe wird jetzt ohne Jahr gesucht. Der Platzhalter sagt es auch.

Auf der Detailseite stand im Feld bisher das Jahr der bestehenden
Zuordnung — also genau der, die gerade korrigiert werden soll. „Doctor
Strange" war auf ein Making-of von 2022 gelaufen; mit dessen Jahr konnte
der richtige Film von 2016 gar nicht erscheinen. Das Feld bleibt jetzt
leer, und leer heisst überall dasselbe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-09 16:02:29 +02:00
ScarriffleandClaude Opus 5 ac64b20a5b Jede Zahl sagt jetzt, was sie ist — und woher sie kommt
Nebeneinander standen „7,2" und „12", beide ohne Beschriftung. Die 12
konnte alles heissen: zwölf Folgen, zwölf von hundert Punkten, ab zwölf
Jahren. Die Auskunft steckte im Tooltip, und den sieht nur, wer schon
vermutet, dass dort etwas steht. Jetzt trägt jeder Wert seine Quelle:
FSK 12, TMDB 7,2, IMDb 7,4, MC 62.

Bei Rotten Tomatoes ist „RT 87%" ebenfalls keine Auskunft, denn dort
stehen zwei Zahlen — die der Kritik und die des Publikums, oft weit
auseinander. Also „RT Kritik" und „RT Publikum", auch wenn nur eine
der beiden da ist.

Und das Publikum wird mitverlangt: `tomatoes=true` legt die Felder
derselben Antwort bei, kostet keine zweite Anfrage und nichts vom
Tageskontingent. Ob etwas darin steht, ist eine andere Frage — seit 2018
wird berichtet, dass dort `N/A` steht, und die Frage, ob die Felder je
wieder Daten führen, ist bei OMDb seit 2017 unbeantwortet offen. Darum
wird nichts erwartet und nichts erzwungen: steht eine Zahl da, erscheint
sie; steht `N/A`, entsteht keine Wertung. Die Probe unter Einstellungen →
Metadaten zeigt, was wirklich kam.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-08 22:41:41 +02:00
ScarriffleandClaude Opus 5 a609b2d087 Ein Haken, der stehen blieb, als die Rechnung sich änderte
Ein Film stand bei 1:32 und tauchte in „Fortsetzen" trotzdem nicht auf.
Die Reihe fragt nicht die Regel, sondern deren festgehaltenes Ergebnis:
die Spalte `InProgress`. Die Bruchrechnung „Stelle kleiner als Anteil der
Laufzeit" lässt sich nicht nach SQL übersetzen, also steht sie als
Wahrheitswert in der Zeile — und berechnet wird sie nur, wenn eine
Fortschrittsmeldung eintrifft. Die kaputte Meldung von vorgestern hatte
dort `false` hinterlassen; die Korrektur am Server verhinderte neuen
Schaden, räumte den alten aber nicht weg.

`Sehstandpflege` rechnet nach jedem Update einmal durch: erst die
Laufzeit aus der Datei nachtragen, dann neu bewerten — in dieser
Reihenfolge, denn eine Neubewertung auf Basis eines Stummels käme wieder
zu `false`. `UpdatedAt` bleibt, wo es war; danach ist die Reihe sortiert.

Und der Knopf heisst jetzt so wie die Reihe, über der er steht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-08 22:41:22 +02:00
ScarriffleandClaude Opus 5 5dfc22bdce „Hinterlegt" war keine Auskunft, und die Übersicht keine Ablage
**Man konnte nicht sehen, ob ein Schlüssel wirkt.** Nach dem Eintragen
stand „Hinterlegt" da, und das war alles. Ob er stimmt, ob der Dienst
antwortet, ob zu einem Film überhaupt etwas zu holen ist — herausfinden
liess sich das nur, indem man die Metadaten über achthundert Titel
auffrischte und danach nachsah, ob sich etwas geändert hatte.

Jetzt gibt es „Verbindung prüfen". Es wird mit „The Matrix" gefragt, nicht
mit einem Film aus der Mediathek: der könnte schlicht unbekannt sein, und
dann wüsste man wieder nicht, ob es am Schlüssel liegt oder am Film. Die
Antwort nennt, was zurückkam — bei fanart.tv die Zahl der Plakate und
davon die in der eingestellten Sprache, denn genau dafür ist die Quelle da.

Gemessen am laufenden Server:

    tmdb    eingerichtet  ok   Erreichbar — Probeabruf ergab The Matrix (1999).
    fanart  —             —    Kein Schlüssel hinterlegt — die Quelle ist aus.
    omdb    —             —    Kein Schlüssel hinterlegt — die Quelle ist aus.

**Und die Übersicht war eine Ablage für alles geworden.** Zu Recht
angemerkt: es gibt eine Seite „Metadaten", und die Zugänge standen trotzdem
unter „Übersicht" — zwischen Servername, doppelten Einträgen, Fassung und
Speicherplatz. Die drei Quellen stehen jetzt dort, wo man sie sucht, jede
mit einem Satz dazu, was sie liefert und was sie dafür braucht.

Aufmacherhöhe und saisonale Reihen bekommen einen eigenen Bereich
„Darstellung". Eine Seite, die „Übersicht" heisst, ist nicht der Ort für
alles, was sonst nirgends passt.

**Am Telefon tat die Aufmacherhöhe gar nichts.** Gemeldet als „auf 100 %
ist es immer noch zu niedrig" — und das stimmte buchstäblich: unter 860
Pixeln Breite stand `height: min(52vh, 420px)` fest und überschrieb die
Einstellung vollständig. Ob „niedrig" oder „sehr hoch", es kamen immer
dieselben 52 vh heraus.

Jetzt hat jede Stufe zwei Höhen, eine fürs breite und eine fürs schmale
Bild; am Telefon fällt sie eine Spur flacher aus, weil der Bildschirm
hochkant ist und derselbe Anteil der ersten Kachelreihe dort den Platz
nähme. Dazu eine fünfte Stufe „Bildschirmhoch" — mehr ginge nicht
sinnvoll, darüber ist es kein Aufmacher mehr, sondern die ganze Seite.

Eine Prüfung hält ausserdem fest, dass ein Film ohne passendes Stichwort
und ohne passendes Genre nicht in der saisonalen Reihe steht. Anlass war
die Meldung, dort stünden harmlose Zeichentrickfilme — die Reihe arbeitet
richtig, sie macht nur sichtbar, wenn ein Titel auf den falschen Eintrag
zugeordnet ist.

765 Tests grün.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-08 22:11:55 +02:00
ScarriffleandClaude Opus 5 e066f5fe87 Eine Reihe, die nur zu ihrer Zeit dasteht
Zu Halloween, zur Weihnachtszeit, zum Jahreswechsel, im Sommer — und zu
allem, was sonst jemand feiert.

**Nach Stichwörtern, nicht nach Genres.** „Stirb langsam" ist kein
Familienfilm und trägt trotzdem „christmas". Eine Weihnachtsreihe nach
Genres enthielte jeden Zeichentrickfilm und diesen Film nicht. TMDB führt
die Stichwörter ohnehin; sie kommen jetzt über `append_to_response` mit
und landen in einer eigenen Tabelle, nach demselben Muster wie Genres.
Kleingeschrieben abgelegt — TMDB liefert „Christmas" und „christmas" je
nach Eintrag, und zwei Schreibweisen wären zwei Stichwörter.

**Einstellbar und nicht eingebaut.** Halloween und Weihnachten kennt
jeder; der 1. August ist Schweizer Nationalfeiertag, der 4. Juli
amerikanischer, und der Geburtstag des Betreibers steht in keiner
Bibliothek. Eine feste Liste im Quelltext hiesse: für jeden Anlass eine
neue Fassung. Vier sind vorangelegt — als Beispiel, nicht als Meinung
darüber, was jemand feiert.

**Über den Jahreswechsel hinweg.** „28.12. bis 02.01." ist kein Fehler,
sondern der Normalfall für Silvester; ein Vergleich, der nur „von ≤ heute
≤ bis" kennt, fände diesen Zeitraum nie — und die Reihe stünde genau in
den Tagen nicht da, für die sie gedacht ist. Geprüft, Tag für Tag, samt
der Zusicherung, dass sich die vorangelegten Anlässe an keinem Tag im Jahr
überschneiden.

**Leer heisst leer.** Gilt heute kein Anlass oder findet er nichts, kommt
eine Reihe ohne Namen zurück und der Client zeigt gar keine — statt einer
mit Überschrift und nichts darunter. Scheitert der Abruf ganz, fehlt eine
Reihe und nicht die Startseite.

Bedient wird sie als Text, eine Zeile je Anlass: Name, von, bis,
Stichwörter, Genres. Ein Listeneditor mit Zeilen zum Hinzufügen,
Verschieben und Löschen wäre viel Oberfläche für etwas, das man dreimal im
Jahr anfasst — und es ist dieselbe Form, in der es gespeichert wird.

Ein Anlass ohne Stichwort und ohne Genre wird abgewiesen statt
stillschweigend geschluckt: er fände nie etwas, und wer ihn eingetragen
hat, suchte den Fehler woanders.

**Die Stichwörter kommen erst beim nächsten Auffrischen der Metadaten.**
Vorhandene Titel tragen noch keine — bis dahin bleibt die Reihe leer.

764 Tests grün, davon 22 neue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-08 21:45:09 +02:00
ScarriffleandClaude Opus 5 c13d1e78d2 Eine Mediathek für alles, was in keinem Katalog steht
Urlaubsaufnahmen, Mitschnitte, Vorträge. Jedes Verfahren, das bei Filmen
richtig ist, wäre hier falsch: „Sommer 2019 Teil 2" ist kein Film von 2019,
zwei Aufnahmen desselben Tages sind nicht zwei Fassungen derselben Sache,
und in keinem Katalog steht, was da liegt.

Die neue Art `Videos` nimmt den Dateinamen als Titel, zerlegt nichts, legt
nichts zusammen und fragt niemanden. Der Pfad ist dabei der
Vergleichsschlüssel, nicht der Name — zwei Dateien „Ausflug.mp4" in zwei
Ordnern sind zwei Ausflüge.

**Der Unterordner wird zur Kategorie.** Statt eine eigene Gruppierung zu
bauen, bekommt jedes Video den Namen seines Ordners als Genre. Damit
greifen Filter, Kategorienansicht und Suche, ohne dass es in der Oberfläche
etwas Neues gibt. Eine zweite Gruppierung daneben hiesse: zwei Wege für
dasselbe, und einer davon wäre überall sonst ungepflegt.

Die Anreicherung übergeht jetzt alles, was `MatchLocked` trägt. Das galt
bisher nur für von Hand korrigierte Zuordnungen und gilt damit auch hier —
eine Suche nach „Abend am Feuer" fände irgendeinen fremden Film, und der
stünde danach mit Plakat und Beschreibung in der Urlaubsmediathek.

Geprüft: vier Dateien in zwei Ordnern ergeben vier Titel mit ihren
Dateinamen, keine Jahre, keinen fremden Treffer — und genau zwei
Kategorien, denn was direkt in der Wurzel liegt, bekommt keine.

742 Tests grün, davon zwei neue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-08 21:36:06 +02:00
ScarriffleandClaude Opus 5 af2b844d65 IMDb, Rotten Tomatoes und Metacritic neben der TMDB-Wertung
IMDbs eigene Schnittstelle kostet Geld, Rotten Tomatoes vergibt Zugänge nur
an Partner, Letterboxd hat gar keine offene. OMDb liefert alle drei in
einer Antwort, über die IMDb-Kennung, die ohnehin schon an jedem Film steht.

**Eine Tabelle und kein Feld je Quelle.** `Movie.Rating` ist ein Skalar
ohne Quellenangabe, und das war richtig, solange es eine Quelle gab. Für
drei weitere wären es drei Spalten — und bei der vierten wieder eine
Migration. Jetzt ist jede Quelle eine Zeile, je Titel und Quelle eine, mit
eindeutigem Index darauf: ein zweiter Lauf schreibt um statt anzuhäufen.

**Zwei Werte je Bewertung, und beide gebraucht.** Der normierte Wert zum
Vergleichen und Sortieren, die Anzeige zum Hinschreiben. Rotten Tomatoes in
„8,7 von 10" umzurechnen wäre eine Lüge über die Quelle — dort steht 87 %,
und genau so kennt man es.

**Wieder keine zweite Metadatenquelle.** `IBewertungsquelle` liefert
Bewertungen, sonst nichts. Bei Titel und Beschreibung wären zwei Anbieter
zwei Wahrheiten; bei einer Bewertung ist jede Quelle eine eigene Zahl, und
da sind mehrere kein Widerspruch, sondern der Sinn der Sache.

**Ohne Kennung wird nicht gefragt.** OMDb kennt nur den Weg über die
IMDb-Kennung; nach einem Titel zu suchen hiesse, denselben Zuordnungsfehler
ein zweites Mal zu riskieren. Und auf Unbekanntes antwortet OMDb mit 200
und `Response: "False"` — das als Treffer durchzulassen legte eine leere
Bewertung ab, die danach als „keine Wertung" dastünde.

Angezeigt wird mit Kürzel statt Stern: vier gleich aussehende Zahlen
nebeneinander sagen nicht, woher sie kommen. Kein Logo — die Marken von
IMDb und Rotten Tomatoes mitzuliefern hiesse, fremde Zeichen auszuliefern.

Kein mitgelieferter Schlüssel, aus demselben Grund wie bei fanart.tv: OMDb
begrenzt auf tausend Abrufe am Tag je Schlüssel. Einzutragen unter
Einstellungen → Übersicht → Metadaten.

740 Tests grün, davon acht neue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-08 21:26:58 +02:00
ScarriffleandClaude Opus 5 97edb49564 Eine zweite Bildquelle, weil TMDB nicht alles hat
„365 Tage" stand mit polnischem Plakat da. Nachgesehen: TMDB hat zu diesem
Film 26 Plakate und kein einziges deutsches. Die Auswahl von gestern nimmt
seither das sprachlose statt des polnischen — erfinden kann sie keines.

fanart.tv ist die Quelle, bei der jedes Plakat seine Sprache mitführt, und
die Gemeinschaft dort pflegt landessprachliche Fassungen. OMDb wäre keine
Hilfe gewesen: es liefert das Plakat von IMDb, und das ist in aller Regel
das amerikanische.

**Ausdrücklich keine zweite Metadatenquelle.** `IBildquelle` liefert
Bilder, sonst nichts. Titel, Beschreibung und Besetzung kommen weiterhin
von einer Stelle — zwei Anbieter für dieselbe Angabe wären zwei Wahrheiten.

**Gefragt wird nur, wenn es lohnt.** `MovieMetadata` trägt jetzt die
Sprache des gewählten Plakats mit. Hat TMDB schon eines in der
eingestellten Sprache, geht keine Anfrage hinaus — bei achthundert Titeln
ist das der Unterschied zwischen „läuft nebenher" und „hängt am fremden
Dienst". Und nur ein landessprachliches sticht: ein sprachloses von
fanart.tv ist nicht besser als ein sprachloses von TMDB.

**Die Rangfolge liegt jetzt im Kern**, nicht im TMDB-Client. Sie gilt für
alle Quellen, sonst kämen die Bilder zweier Anbieter in zwei Reihenfolgen
zusammen. Im Bilderdialog stehen beide Quellen gemeinsam geordnet: ein
deutsches Plakat von fanart.tv vor einem sprachlosen von TMDB.

**Nur Filme.** Der Serienweg von fanart.tv verlangt eine TVDB-Kennung, und
die führt Flaro nicht. Eine halbe Lösung, die bei Serien stillschweigend
nichts tut, wäre schlechter als eine, die sagt, worauf sie sich beschränkt.

**Kein mitgelieferter Schlüssel.** Bei TMDB gibt es einen als Rückfall;
fanart.tv verlangt einen persönlichen, und einen fremden mitzuliefern
hiesse, ihn fremd zu benutzen. Ohne eigenen Schlüssel geht keine Anfrage
hinaus — geprüft. Einzutragen unter Einstellungen → Übersicht → Metadaten.

Dass „00" dort „ohne Sprache" heisst, wird beim Lesen übersetzt: sonst
führte die gemeinsame Rangfolge ein sprachloses Plakat als Sprache „00"
und setzte es hinter Englisch statt davor.

732 Tests grün, davon sieben neue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-08 21:18:27 +02:00
ScarriffleandClaude Opus 5 144470a413 Im Browser gibt es keine Datei mehr, nur den Strom
Auf der Detailseite stand ein Knopf „Herunterladen", der die Datei als MP4
herausgab. Das ist etwas anderes, als einen Strom zu zeigen: wer eine Datei
bekommt, hat sie und kann sie weitergeben — und das soll dieser Server
nicht anbieten.

Weg sind der Knopf, das Bereitstellen davor und die beiden Stellen in der
Schnittstelle, die nur dafür da waren.

**Der Endpunkt bleibt.** Die Apps holen sich eine Mitnahme über
`/api/v1/files/{id}/download`, und dort ist sie an ein Gerät gebunden statt
an einen Ordner. Das heisst aber auch: wer angemeldet ist und die Adresse
kennt, kommt weiterhin an die Datei. Soll das zu — etwa als Recht je
Benutzer oder als Schalter für den ganzen Server —, ist das ein eigener
Schritt und keine Zeile in dieser Änderung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-08 21:07:20 +02:00
ScarriffleandClaude Opus 5 532473b1f9 Ein Plan für das, was an keinem Aufruf hängt
Sichern, Datenbank aufräumen, verwaiste Bilder wegwerfen — alle drei Tage,
alle sieben Tage, von selbst.

**Der erste Hintergrunddienst in diesem Server, und das mit Bedacht.** An
drei Stellen steht sinngemäss, ein eigener Dienst wäre Aufwand ohne
Gegenwert, und für das Wegräumen abgelaufener Gerätecodes stimmt das:
solche Arbeit hängt an einem Aufruf, der ohnehin kommt. Eine Sicherung
hängt an nichts. Sie soll alle drei Tage geschehen, auch wenn niemand etwas
anklickt, und dafür gibt es eine Uhr. Alle fünfzehn Minuten eine Frage an
eine Tabelle mit einer Handvoll Zeilen; ist nichts fällig — der Normalfall
—, kostet es nichts.

Der letzte Lauf steht in der Datenbank, nicht im Arbeitsspeicher. Ein
Server, der jede Nacht neu startet, sicherte sonst jeden Morgen — oder,
bei einem Zähler, der bei null anfängt, nie. Auch ein Fehlschlag wird
vermerkt, sonst versuchte der Plan es alle fünfzehn Minuten wieder und
eine volle Platte erzeugte ein volles Protokoll.

**Die Sicherung ist `VACUUM INTO`, nicht Datei kopieren.** Die Datenbank
läuft im WAL-Modus: neben `flaro.db` stehen `-wal` und `-shm`, und wer nur
die erste Datei kopiert, bekommt einen Stand von vor Stunden oder einen
halben. `VACUUM INTO` schreibt eine vollständige, aufgeräumte Kopie im
laufenden Betrieb. Der Zielordner ist einstellbar und geht als gebundener
Wert in die Anweisung — eine Einstellung soll keine SQL-Anweisung werden.

Die Prüfung verlässt sich nicht darauf, dass eine Datei entstanden ist: sie
öffnet die Kopie als Datenbank und zählt die Zeilen. Eine Sicherung, die
sich nicht öffnen lässt, ist schlimmer als keine — man verlässt sich
darauf und merkt es erst, wenn es zu spät ist.

**Bilder nur, wenn verwaist.** Den ganzen Bildspeicher zu leeren gibt es
als Knopf und ist gefahrlos, kostet danach aber tausende Abrufe bei TMDB.
Hier fliegt nur, worauf kein Titel mehr zeigt — mit einer Stunde
Schonfrist, weil ein Bild abgelegt wird, bevor der Verweis darauf
gespeichert ist. Ohne diese Frist räumte ein Lauf mitten im Scan genau das
weg, was gerade geholt wurde.

**Eine eigene Seite „Wartung".** Die drei Kratzplatzzahlen standen unter
„Wiedergabe" — dort ist ihr Anlass, aber nicht ihr Thema. Sie ziehen mit
um: alles auf dieser Seite ist etwas, das der Server ohne Zutun erledigt,
und man sieht es an einem Ort nach. Je Aufgabe steht da, wann sie zuletzt
lief und was herauskam, dazu ein Knopf „Jetzt ausführen" — wer gleich etwas
Grosses vorhat, will die Kopie jetzt und nicht in drei Tagen.

725 Tests grün, davon elf neue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-08 21:02:42 +02:00
ScarriffleandClaude Opus 5 c4af182d31 Der Kratzplatz räumt sich auf
39,1 GB in FLARO_TRANSCODE, und das war kein Normalzustand, sondern ein
Leck: für jede Mitnahme baut der Server eine MP4 in Quellgrösse und löschte
sie nie. Die einzige Löschung, die es gab, räumte ältere Fassungen
derselben Datei weg. Stromordner verschwanden nur beim geordneten
Herunterfahren, Untertitel gar nicht.

**Zuerst: fertig heisst fertig.** ffmpeg schrieb direkt auf den Endnamen.
Nach einem harten Abbruch lag dort eine abgeschnittene Datei, `IsReady`
meldete „fertig", und sie ging so hinaus — und ein Aufräumer konnte
vollständig und abgeschnitten nicht unterscheiden. Gebaut wird jetzt unter
`.teil`, umbenannt erst nach Erfolg. Dabei muss das Format ausdrücklich
gesetzt werden: ffmpeg wählt den Muxer an der Endung und antwortet auf
`.teil` mit „Unable to choose an output format". Das hätte jedes Umpacken
zerlegt; die Prüfung hat es gefunden, bevor es jemand zu spüren bekam.

**Zwei Stufen für die Pakete.** Verwaiste gehen bedingungslos: unleserlicher
Name, fremde Bauart, kein Eintrag in der Mediathek, oder der Zeitstempel im
Namen passt nicht mehr. Der Rest fällt unter Obergrenze (20 GB) und Alter
(7 Tage), Ältestes zuerst.

Beides, und nicht eines: ein Alter allein löst den Fall nicht, denn die 39
GB waren gültige, aktuelle Dateien, jede für sich berechtigt. Eine
Obergrenze allein ist zu grob — ein Topf knapp darunter, in dem seit Wochen
nichts gebraucht wurde, besetzt ein Volume, das anderes braucht.

„Zuletzt gebraucht" ist die Änderungszeit der Paketdatei selbst, bei jeder
Auslieferung neu gestempelt. Die Zugriffszeit wäre das Naheliegende, nur
führt sie nicht jedes Dateisystem — mit `noatime` steht sie still, und der
Aufräumer hielte alles für uralt.

Ein laufender Download wird nie gelöscht: ein Benutzungszähler hält die
Datei fest, solange die Antwort läuft, dazu eine Schonfrist von 30 Minuten.
Der Zähler ist auch unter Linux nötig — der laufende Strom überlebt ein
Entfernen, die Fortsetzung einer Bereichsanfrage nicht, und der Client finge
von vorn an.

**Stromordner** werden beim Start bedingungslos geleert — nach einem Start
gibt es keine einzige Sitzung, also ist jeder Ordner verwaist. Im Betrieb
nur die ohne passende Sitzung, deren Änderungszeit älter ist als die
Geduld; das fängt auch den Fall, dass `Abraeumen` an einem IOException
scheitert und der Ordner für immer liegenbleibt.

**Untertitel** nur, wenn sie verwaist sind. Keine Obergrenze: eine .vtt ist
Kilobytes, und eine gültige wird wieder gebraucht — sie nach Platz zu
löschen hiesse, Minuten Lesearbeit gegen Megabytes zu tauschen. Eine leere
bleibt ausdrücklich liegen: sie ist das Ergebnis „diese Spur hat keinen
Text", und wer sie wegräumt, lässt bei jedem Start eine vierzig Gigabyte
grosse Datei neu durchlesen.

**Vier Anlässe, kein Dienst.** Start, vor jedem Umpacken, nach einem Scan,
auf Knopfdruck — wie alles Wiederkehrende in diesem Server. Einer zur Zeit;
wer nicht hineinkommt, geht weiter.

Gemessen am laufenden Server mit Attrappen:

    vorher    packages 17408 KB (4), untertitel 5 KB (3), 1 Stromordner
    nachher   14 MB freigegeben, 4 Dateien
              gültiges Paket blieb, verwaistes/veraltetes/Teilstück weg,
              verwaiste .vtt weg, gültige blieben, Stromordner weg

    Obergrenze 1 MB, Datei in der Schonfrist   -> bleibt
    Obergrenze 1 MB, Schonfrist vorbei         -> 3072 KB freigegeben

In der Übersicht steht die Belegung je Unterordner mit Dateizahl und
daneben „Jetzt aufräumen"; die drei Zahlen stehen unter Wiedergabe, wo
Transcoder-Stufe und Schwellen schon stehen — der Kratzplatz ist, was die
Wiedergabe hinterlässt.

714 Tests grün, davon 36 neue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-08 19:07:52 +02:00
ScarriffleandClaude Opus 5 1b4784f1db Zwei Fassungen dürfen gewollt sein, und die Startseite darf nicht warten
**Mehrfachfassungen lassen sich abhaken.** Zwei Dateien an einem Film sind
meist zwei Fassungen und völlig in Ordnung. In der Liste standen sie
trotzdem für immer: sie rechnet jedes Mal frisch, und es gab keinen Zustand.
Wer absichtlich zwei Fassungen hält, konnte die Gruppe nicht loswerden — und
unter den gewollten ging das Ungewollte unter.

Abgehakt wird eine Dateizahl, kein Zeitpunkt. Ein Zeitstempel müsste gegen
`MediaFile.ModifiedAt` verglichen werden, und eine alte Datei, frisch
hineinkopiert, behält ihre alte Zeit und käme nie wieder hoch. Die Anzahl
ist genau die Frage: kommt eine dritte Fassung dazu, meldet sich die Gruppe
von selbst zurück. Gerechnet wird sie auf dem Server — ein Client mit
veralteter Liste hakte sonst eine Gruppe mit zwei Dateien ab, die inzwischen
drei hat.

„Ignorierte zeigen" führt zurück, wie bei den erledigten Meldungen; ohne das
wäre das Abhaken unumkehrbar und niemand wüsste, was er weggeklickt hat.

**Die Startseite wartete dreimal nacheinander.** Erst die Serverauskunft,
dann Konto und Mediatheken, dann erst die Startseite — drei Rundreisen,
bevor das erste Bild in Auftrag ging. Liegt eine Sitzung im Speicher, laufen
die ersten beiden jetzt zugleich los. Nur dann: ohne Sitzung liefen
`/auth/me` und `/libraries` vor der Antwort auf `needsSetup` in ein 401, und
die Sitzungsprüfung kann daraufhin abmelden.

Gemessen am laufenden Server: `users/me`, `system/info` und `libraries`
starten alle bei 37 ms, die Startseitenabfragen folgen bei 73 ms. Vorher
lagen drei Runden dazwischen.

**Sieben Hintergrundbilder auf einmal waren sechs zu viel.** Jede Folie des
Aufmachers bekam sofort ihr `w1280`-Bild; sichtbar ist immer nur eine. Jetzt
lädt die sichtbare sofort und der Rest in der Leerlaufzeit — und wer
weiterschaltet, bevor das lief, bekommt sein Bild dann.

**Die Schrift kam von Google.** `display=swap` rettete den Text, nicht den
ersten Aufbau: ein Stylesheet blockiert das Zeichnen, und ein Heimserver
ohne Internet oder mit träger Namensauflösung wartete davor. Inter liegt
jetzt als zwei Dateien von zusammen sechzig Kilobyte im Projekt, variabel
für alle Schnitte, mit `unicode-range` getrennt nach latin und latin-ext.
Gemessen: null Anfragen an fonts.googleapis.com. Lizenztext liegt dabei.

**Und mein Untertitelvorrat bremste mit.** Er startete sofort beim
Hochfahren und las die ganze Mediathek — von derselben Platte, von der die
Startseite ihre Bilder holt. Jetzt beginnt er eine Minute später und stellt
zurück, solange eine Wiedergabe läuft. Die Datei bleibt dabei vorn in der
Reihe; verworfen wird nichts.

678 Tests grün, davon zwei neue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-08 17:56:41 +02:00
ScarriffleandClaude Opus 5 2809821c9b Vier Fehler, und bei zweien log der Kommentar daneben
**Der Einstellungsknopf lag hinter der Abspielleiste.** Gemessen: `.pl`
steht auf Stufe 150, `#chrome` auf gar keiner, und die kleine Leiste spannte
über die ganze Breite — genau über die unteren 72 Bildpunkte der
Seitenleiste, wo „Einstellungen" klebt. Weil der Spieler bei jedem Wechsel
der Adresse minimiert, stand sie zuverlässig im Weg, sobald man dorthin
wollte.

Die Leiste beginnt jetzt hinter der Seitenleiste. Nicht über die Stufen
gelöst, und das ist der Punkt: `#chrome` höher zu setzen hiesse, die
Seitenleiste läge auch über dem grossen Spieler — es ist dieselbe Hülle.
Dass diese Leiste Platz wegnimmt statt sich darüberzulegen, stand für
Inhalt, Hinweise und Auswahlleiste ohnehin schon da; die Seitenleiste war
die vergessene vierte. Gemessen, 1400 Bildpunkte breit: Leiste ab 240,
Knopf bei 0, keine Überschneidung, und ein Treffertest in der Knopfmitte
trifft den Knopf.

**Ein Klick auf eine Kategorie kam nie an.** Dort sprang der Code in die
Mediathek und suchte danach `.filterzeile select`, um den Wert zu setzen.
Die Filterzeile hat kein `<select>` — `auswahl()` baut einen Knopf, mit
Absicht und begründet. Der Zweig lief also nie, und man landete in der
ungefilterten Mediathek. Der Kommentar daneben behauptete das Gegenteil.

Das Genre steht jetzt in der Adresse: `#/m/{id}/mediathek/Horror`. Das
löst zugleich das zweite Problem — die Mediathek wird unter ihrem Weg
gemerkt, und stünde das Genre nur im Kopf, zeigte ein zweiter Besuch die
Liste des ersten. Geprüft: Klick setzt den Weg und die Pille, Neuladen
behält beides, Zurück führt auf die Kategorien, Vorwärts wieder hinein.

**Zurückgezogene Einladungen blieben für immer stehen.** Der Knopfblock
steckte ganz in `if (!e.revokedAt)`, eine erledigte Zeile hatte also gar
keinen Knopf. Die Serverbegründung — eine Zeile wegzuwerfen hiesse,
hinterher nicht mehr zu wissen, dass es den Link je gab — bleibt richtig,
sie gilt nur nicht ewig: eine Liste, aus der nichts verschwindet, wird
unlesbar, und dann sieht man die eine Zeile nicht mehr, um die es ging.

Deshalb kein umgedeutetes DELETE, sondern `?purge=true`, und das greift nur
bei einem Link, der ohnehin keine Tür mehr öffnet. Ein gültiger wird mit
einem deutschen Satz abgewiesen.

**Poster in der falschen Sprache.** „365 Tage" stand mit polnischem Plakat
da. Kein fehlender Anbieter: für den Schriftzug gab es die sprachgewichtete
Wahl längst, fürs Plakat wurde das blanke `poster_path` der Hauptantwort
genommen — bei TMDB das Bild der Originalsprache, wenn in der gewünschten
keines eingetragen ist. Die sortierte Liste lag im selben Abruf schon vor
und wurde ausschliesslich für den Schriftzug benutzt.

Plakat und Hintergrund nehmen jetzt dieselbe Rangfolge: eingestellte
Sprache, dann sprachlos, dann Englisch. Sprachlos vor Englisch ist keine
Verlegenheit — ein Bild ohne Sprachkennung trägt keinen Text, und ein
Plakat ohne Titel ist für einen deutschen Bestand besser als dasselbe mit
englischem. Im Bilderdialog stehen die Kandidaten jetzt ebenso sortiert.
Bestehende Titel ändern sich beim nächsten Auffrischen; von Hand gesetzte
Plakate bleiben unangetastet.

676 Tests grün, davon zehn neue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-08 17:46:46 +02:00
ScarriffleandClaude Opus 5 6ad4deb634 Fünf Sekunden Bild ohne Ton — jetzt weiss ich, woher
Deine Angabe war der Schlüssel: du hast **mitten im Film die Tonspur
umgeschaltet**. Dabei baut der Spieler den Strom an der aktuellen Stelle
neu auf, und damit greift der Sprung — den ich gestern nur mit
Spielzeugdateien gemessen hatte.

Also eine Datei gebaut, die einem Film gleicht: 23,976 Bilder je Sekunde,
Schlüsselbild alle fünf Sekunden, zwei Tonspuren, Deutsch als Stereo-AAC
und Englisch als 5.1 in EAC3. Gemessen, erster Zeitstempel je Spur:

| | Bild ab | Ton ab |
|---|---|---|
| Spur 2, ab Sekunde 0 | 0,021 | 0,000 |
| Spur 2, ab 17 (mitten in der Bildgruppe) | 0,000 | **1,964** |
| Spur 2, ab 15 (knapp vor dem Schlüsselbild) | 0,000 | **4,969** |

Fast fünf Sekunden Bild ohne Ton. Zueinander sind beide dabei richtig
getaktet — aber eine solche Lücke am Anfang darf jeder Spieler deuten, wie
er will, und hls.js schiebt den Ton dann nach vorn. Genau das hast du
gehört.

Die Rundung auf das Schlüsselbild, die seit E8GSRE drin ist, nimmt das
weg: dieselbe Datei, Sprung auf 17, gerundet auf 15,015 — **Bild ab 0,000,
Ton ab 0,004**. Du läufst noch auf 5YZ63F; deshalb steht im Protokoll auch
keine ffmpeg-Warnung, die gibt es erst ab E8GSRE.

**Die Tonspur lässt sich jetzt vor dem Start wählen.** Auf der
Detailseite steht neben „Abspielen" ein Knopf „Ton: Deutsch"; das Menü
zeigt alle Spuren der Datei. Gemerkt wird dabei die **Sprache**, nicht die
Spurnummer — welche Nummer Englisch trägt, ist von Film zu Film
verschieden, dass du Englisch willst, ist es nicht. Beim nächsten Film
steht die passende Spur damit schon da, und das Umschalten mitten im Film
entfällt. Wer doch im Spieler wechselt, ändert dieselbe Merkstelle.

**Und ein Fehler aus deinem Protokoll**, der nichts damit zu tun hat:
„UNIQUE constraint failed: Sehtage.UserId, Sehtage.Tag, Sehtage.MovieId".
Das ist ein Wettlauf im Sehprotokoll von vorgestern — der Spieler meldet
alle zehn Sekunden, ein Sprung meldet sofort, und zwei Meldungen können
sich überholen. Dann fanden beide keine Zeile, beide legten eine an. Jetzt
wird in der Datenbank hochgezählt statt im Speicher, und wer dabei zu spät
kommt, zählt beim zweiten Versuch mit. Mit Test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-07 20:09:46 +02:00
ScarriffleandClaude Opus 5 3fe0013be1 Die Auflösung wechselt den Text, statt einen Tooltip zu öffnen
Gestern wanderte der genaue Wert in den Tooltip. Ein Tooltip kommt
verzögert, legt sich über die Nachbarzeile und existiert am Finger gar
nicht. Jetzt steht in Ruhe „Full HD" da, und beim Überfahren tritt
„1080p · 1920 × 800" an dieselbe Stelle.

**Beide liegen übereinander, nicht nacheinander.** Das Feld ist so breit
wie der breitere der beiden Texte — sonst rückte beim Überfahren die halbe
Tabelle. Gerastert statt absolut gesetzt, damit die Zeilenhöhe von selbst
stimmt.

Ohne Zeiger gibt es kein Überfahren: dort steht das Genaue dauerhaft
daneben, statt unerreichbar zu sein.

Gemessen: in Ruhe „Full HD" bei Deckung 1 und „1080p · 1920 × 800" bei 0,
unter dem Zeiger umgekehrt — und kein `title` mehr am Element.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-07 18:32:21 +02:00
ScarriffleandClaude Opus 5 cdea8e3b0a Die Höhe des Aufmachers ist jetzt einstellbar
Vier Stufen unter Einstellungen → Verwaltung → Übersicht: niedrig, mittel,
hoch, sehr hoch. Mittel ist, was gestern fest verdrahtet war.

**Keine Pixelzahl.** Eine einzustellen hiesse, sie an jedem Bildschirm neu
einzustellen — der Aufmacher misst sich an der Fensterhöhe, nicht an einer
festen Grösse. Gemessen bei 800 Bildpunkten Fensterhöhe: 496, 576, 656,
736. Oben ist Schluss, bevor von der ersten Plakatreihe nichts mehr übrig
bleibt; sie soll zeigen, dass unten noch etwas kommt. Am Telefon bleibt es
flacher, dort wäre auch das weg.

**Sie reist mit der Systemauskunft mit**, nicht in einer eigenen Abfrage.
Die holt der Client ohnehin als Erstes, noch vor der Anmeldung; käme die
Höhe später, stünde der Aufmacher einen Augenblick in der Vorgabe und
spränge dann — genau das, was eine einstellbare Höhe vermeiden soll.
Gesetzt wird sie als Marke am `<html>`, das Regelwerk hängt vier Werte
daran.

Serverweit und nur für Admins, dieselbe Linie wie bei den
Wiedergaberegeln: eine Entscheidung des Gastgebers, nicht des Gastes.
Unbekanntes in der Spalte wird zur Vorgabe statt zu einem Fehler — eine
Startseite, die an einem alten Eintrag scheitert, wäre die schlechtere
Antwort.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-07 18:32:10 +02:00
ScarriffleandClaude Opus 5 a7a4419626 Adminrecht geben und nehmen — und einen, dem es niemand nimmt
Ein Konto liess sich anlegen und danach nie wieder ändern: kein Weg zum
Administrator, keiner zurück, keiner zum Löschen. Mit Einladungslinks
füllte sich der Server also in genau eine Richtung.

**Warum es einen Besitzer braucht.** Sobald Administratoren einander das
Recht entziehen können, gibt es einen Zustand ohne jeden Administrator —
und aus dem führt kein Weg zurück ausser dem an der Datenbank. Ein Konto,
das ausgenommen ist, schliesst ihn aus. Es ist das erste, also das, mit
dem eingerichtet wurde; die Migration trägt das auf bestehenden Servern
nach, und weil die Kennungen zeitlich geordnet vergeben werden, ist der
Älteste schlicht der mit der kleinsten.

Weitergeben lässt er sich: vom Besitzer, an einen Administrator, mit
Rückfrage. Nur an einen Administrator, sonst wäre der Server einen Klick
von einem Besitzer entfernt, der die Verwaltung gar nicht sieht.

**Drei Türen sind zugemauert**, und jede hat ihren Test: dem Besitzer das
Recht nehmen, den Besitzer löschen, sich selbst das eigene Recht nehmen.
Das letzte ist die unauffälligste — wer sich im Eifer entmachtet, steht
vor einer Verwaltung, die er nicht mehr öffnen kann, und das Zurücknehmen
braucht genau die.

Gemessen und als Test festgehalten: ein frisch vergebenes Adminrecht gilt
**sofort**, ohne neue Anmeldung. Die Rolle wird je Anfrage aus der
Datenbank gelesen und nicht aus dem Token — ich hatte das Gegenteil
befürchtet.

Löschen nimmt mit, was am Konto hing: Geräte, Sehstände, Sehprotokoll,
Meldungen, offene Einladungen. Alles hängt mit `Cascade` daran. Zahlen
über jemanden zu führen, den es nicht mehr gibt, wäre die schlechtere
Hälfte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-07 18:31:05 +02:00
ScarriffleandClaude Opus 5 d5e21d663f Einladen, statt sich für jemanden ein Passwort auszudenken
Ein Konto von Hand anzulegen heisst: sich für einen anderen ein Passwort
ausdenken und es ihm durchsagen — über denselben Kanal, über den auch ein
Link gegangen wäre. Jetzt gibt es den Link. Wer ihn öffnet, wählt Namen
und Passwort selbst und ist danach angemeldet.

Gültigkeit und Anzahl wählst du beim Erstellen: einen Tag bis einen Monat,
einmal bis unbegrenzt. **Eine Rolle wählst du nicht** — wer eingeladen
wird, ist gewöhnlicher Benutzer. Ein Feld, über das ein Link Adminrechte
verschenken könnte, gibt es gar nicht, und damit auch keinen Weg, es
versehentlich zu setzen.

**Der Link steht genau einmal da.** Gespeichert ist nur sein
Fingerabdruck, wie beim Gerätetoken; aus der Liste lässt sich keiner mehr
bauen. Eine verlorene Einladung wird deshalb nicht wiedergefunden, sondern
neu gemacht. Und gebaut wird die Adresse im Browser: der Server weiss
nicht, unter welchem Namen er von aussen erreichbar ist, und hinter einem
Reverse Proxy rät er falsch.

**Das Rennen beim Einlösen.** Zwei Leute, die gleichzeitig denselben
einmaligen Link öffnen, läsen beide „null benutzt" und schrieben beide
„eins" — und hätten beide ein Konto. Der Zähler geht deshalb mit einer
Bedingung hoch, die die Gültigkeit noch einmal prüft; wer dabei keine
Zeile trifft, war der Zweite. Das Ganze in einer Transaktion, damit ein
Tippfehler im Namen den Link nicht verbrennt. Beides steht als Test da —
zwei gleichzeitige Einlösungen ergeben genau ein Konto.

**Angelegt wird, angemeldet wird danach gewöhnlich.** Derselbe Zweischritt
wie beim Einrichten, und der Grund ist nicht Bequemlichkeit: die Anmeldung
setzt den Sitzungskeks, und ohne den lädt kein Plakat — Bilder weisen sich
über ihn aus, nicht über das Token. Gemessen beim Durchspielen: nach dem
Einlösen kommt ein Bild mit 200 zurück.

**Die Weiche liegt im Hochfahren, nicht im Router.** Der Router läuft nie,
wenn niemand angemeldet ist — ein Ausgeloggter mit Einladungslink sähe
sonst die Anmeldekarte und landete nach dem Anmelden auf der Startseite,
ohne je erfahren zu haben, wozu er eingeladen war. Nach dem Einrichten,
damit ein nagelneuer Server zuerst seinen Administrator bekommt.

Wer schon angemeldet ist, bekommt kein Formular, sondern den Hinweis und
zwei Wege. Und die Gründe einer Ablehnung sind verschieden benannt:
abgelaufen, zurückgezogen, schon benutzt. Verschwiegener wäre ein
einheitliches „gilt nicht" — und dann fragt der Eingeladene nach, und der
Gastgeber rät mit.

Nebenbei korrigiert: die Erkundung meinte, dem Benutzernamen fehle ein
eindeutiger Index. Er hat einen, seit der ersten Migration, sogar mit
`NOCASE`. Das Namensrennen war also nie offen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-07 17:23:25 +02:00
ScarriffleandClaude Opus 5 c65356c16f 4K, Full HD, HD, SD — die Zahl steht beim Überfahren
„1080p" ist eine Angabe für den, der eine Stufe einstellt. Wer sich fragt,
ob es sich lohnt, dafür den Fernseher anzumachen, liest „Full HD". Die
Zeile sagt jetzt das Wort, der Tooltip den genauen Wert und die gemessene
Grösse: `1080p · 1920 × 800`.

**Es gab zwei Leitern, und sie waren sich uneinig.** `Benennung.AusHoehe`
machte aus 2160 ein „2160p", `FileNames.FassungAusHoehe` ein „4K" — auf
derselben Detailseite stand beides übereinander, ein paar Zeilen
auseinander. Die zweite ist weg; sie hatte ausserdem nur die Höhe und
vergab sich damit beim Kinoformat.

Gemessen an zwei echten Dateien: 1920×800 heisst „Full HD" (nur an der
Höhe gemessen hiesse es „HD", und daneben stünde ein 1280×720 mit
demselben Wort), 720×576 heisst „SD".

**1440p fällt unter Full HD.** „QHD" kennt kaum jemand, und ein fünftes
Wort für etwas zwischen zwei bekannten hilft beim Entscheiden nicht.
„8K" steht nur da, damit eine 8K-Datei nicht als 4K gemeldet wird.

**Der Client zerlegt nichts mehr.** Er las die Stufe bisher mit
`display.split(' · ')[0]` heraus — richtig, solange vor der Auflösung nie
etwas anderes steht. Jetzt kommen Wort und genauer Wert als eigene Felder.

**Die Fassung wird nicht mehr gespeichert, sondern gerechnet.** Sie stand
in der Spalte und war damit das, was beim letzten Scan galt: ein neues
Wort hätte keine bestehende Zeile erreicht. Jetzt hält die Spalte nur
noch, was im Dateinamen stand („Mobil"), und die Messung kommt frisch
dazu. Eine Migration räumt die alten gerechneten Werte weg.

**Nicht angefasst:** was eine *gewählte* Stufe ist statt einer gemessenen
— die Umkodierleiter, der Qualitätswähler im Spieler, die Stufen in den
Apps. Wer eine Stufe wählt, wählt eine Zahl.

Die Apps rechnen sich das Wort ohnehin selbst aus und sagen seit jeher
„4K" und „Full HD"; der Server ist ihnen jetzt angeglichen, nicht
umgekehrt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-07 17:13:23 +02:00
ScarriffleandClaude Opus 5 8e9da1355c Der Server schrieb deutsche Sätze an eine Stelle, die niemand liest
„Die Anfrage war so nicht zu gebrauchen" — das ist der Ersatzsatz des
Browsers für eine Ablehnung ohne Begründung. Dabei stand die Begründung
da: „Benutzername darf nicht leer sein, das Passwort braucht mindestens 8
Zeichen." Nur eben in `errors`, und beide Clients lesen `detail`.

Zwei Formen waren betroffen. `Results.ValidationProblem` legt den Satz
unter `errors` ab, `Results.BadRequest(new { fehler = … })` unter
`fehler` — in beiden Fällen kommt er nirgends an. Zusammen 36 Stellen,
darunter jede Zeile, die ich gestern für die Meldungen geschrieben habe.
Dass die Clients `title` und `errors` auslassen, ist dabei richtig: dort
stehen sonst die englischen Prüftexte des Rahmenwerks, und „Not Found" ist
keine Auskunft.

Jetzt eine Form, hinter `Einwand.Bitte` / `.Fehlt` / `.Belegt`. Dass es
drei benannte Türen sind statt eines Aufrufs mit Zahl, hat einen Grund:
man sieht am Wort, ob der Server um eine bessere Eingabe bittet, etwas
nicht findet oder auf etwas Bestehendes stösst.

**Auffallen konnte es nicht**, und das ist der eigentliche Fund. Die
vorhandenen Tests prüften den Rumpf als Zeichenkette — der Satz *stand* ja
drin, nur im falschen Feld. Der neue Test prüft deshalb, in welchem Feld,
und ein Wächter am Quelltext schlägt an, wenn eine der beiden alten Formen
zurückkommt. Er hat beim ersten Lauf gleich eine Stelle gefunden, die mein
Suchmuster übersehen hatte.

Dazu drei Kleinigkeiten, die beim Lesen auffielen:

**Passwörter wurden getrimmt.** Der Dialog schnitt jedem Feld die Ränder
ab, auch dem Passwort — `login.ts` sendet es ungeschoren. Ein Leerzeichen
am Ende, und das angelegte Konto war für immer unbetretbar.

**Beim Einrichten stapelten sich die Fehlerzeilen**, weil `.error`
weggeräumt wurde und `.fehler` entsteht. Drei Fehlversuche, drei rote
Kästen.

**Der Benutzerdialog versprach acht Zeichen und prüfte nichts.** Jetzt
sagt er es selbst, ohne den Umweg über die Leitung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-07 17:12:57 +02:00
ScarriffleandClaude Opus 5 7cd48f5528 Wer etwas sieht, kann es jetzt auch sagen
Wer einen Server für andere betreibt, erfährt von Fehlern zuletzt: dass
die deutsche Tonspur nach einer halben Stunde aussetzt, merkt der, der den
Film sieht, und nicht der, der ihn eingeräumt hat. Bisher gab es dafür
keinen Weg ausser dem Zuruf im Wohnzimmer.

Gemeldet wird an einem Film, einer Serie, einer einzelnen Staffel und
einer einzelnen Folge: Art (Bild, Ton, Untertitel, Angaben, Sonstiges),
eine freiwillige Stelle wie 0:34:12 und der Kommentar. Pflicht ist nur der
Kommentar — die beiden anderen machen aus einer Liste von Sätzen etwas,
das man sortieren und nachstellen kann.

**Eine Staffel gibt es als Zeile nicht**, und das prägt den Entwurf. Sie
ist Serie plus Nummer, so wie überall sonst in diesem Server; die Meldung
trägt deshalb drei Fremdschlüssel und daneben eine Staffelnummer. Dass die
Nummer auf eine Staffel zeigt, die es gibt, prüft der Endpunkt beim
Schreiben — die Datenbank kann es nicht, es gibt nichts, worauf sie zeigen
könnte.

**Die Rechteprüfung steht nirgends.** Wer einen Titel nicht sehen darf,
findet ihn beim Melden nicht — das erledigt der Freigabefilter, ohne ein
einziges `Where`. Elegant und genau deshalb leicht zu zerstören, darum
steht dafür ein Test da.

**Die eigene Liste überlebt fremde Entscheidungen.** Titel werden
nachgeschlagen, nicht verbunden: zieht ein Administrator einen Titel
zurück, nachdem jemand ihn gemeldet hat, bleibt die Meldung beim Melder
stehen — nur ohne Namen. Ein Join hätte sie verschwinden lassen, und das
wäre jemandes eigene Eingabe, weggenommen wegen einer fremden Entscheidung.
`IgnoreQueryFilters` wäre die bequeme Abkürzung und gäbe den Namen eines
unveröffentlichten Titels über einen Weg heraus, an den beim nächsten Mal
niemand denkt.

**Erledigt heisst abgehakt, nicht gelöscht**, als Zeitpunkt und nicht als
Haken — wie `PublishAt` und `ChangedSince`. Daneben steht „Wieder öffnen";
ein Fehlgriff wäre sonst endgültig. Das Archiv wird erst auf Zuruf geholt:
es wächst nur, und für den seltenen Blick dauernd zu zahlen lohnt nicht.

**Der Abschnitt steht neben der Prüfliste, nicht darin.** Die versteckt
sich, sobald nichts auf Freigabe wartet — das ist der Normalfall, und die
Meldungen verschwänden mit ihr. Umgekehrt bleibt der Meldungsabschnitt
stehen, auch wenn nichts drinsteht: ein Kanal, der sich versteckt, solange
ihn niemand benutzt hat, bringt niemandem bei, dass es ihn gibt.

Die Zahl an der Leiste holt sich nur, wer sie nicht ohnehin hat: steht „Zu
prüfen" offen, meldet der Abschnitt sie selbst und nach jedem Abhaken.

Nebenbei zwei Dinge am Dialog, die hier auffielen. Es gab **kein
mehrzeiliges Feld** — und das Einsammeln der Werte hätte ein `<textarea>`
still verschluckt: es ist kein `HTMLInputElement` und wäre ins Auffangnetz
für Auswahlfelder gelaufen, also als `undefined` hinausgegangen. Der
Server hätte „ohne Beschreibung" geantwortet, auf einem Dialog, in dem
sichtbar etwas steht. Und `dialog()` meldete sich als einziger nicht beim
Seitenwechsel an: ein Dialog von der Detailseite überlebte den
Zurück-Knopf und stand danach über der Mediathek.

Neun Testfälle auf dem Server, zwölf Läufe. Für den Web-Client gibt es in
diesem Projekt keine Tests; dort ist von Hand geprüft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-06 22:18:14 +02:00
ScarriffleandClaude Opus 5 02978e482c Die Knöpfe bleiben, die Inhaltsangabe klappt auf
Ich hatte „die Beschreibung nur beim Hovern" gelesen und daraufhin
Beschreibung *und* Knöpfe ausgeblendet. Die Knöpfe gehören immer dahin: in
Ruhe steht oben, was läuft und was man damit tun kann.

Die Inhaltsangabe dagegen steht erst da, wenn man es will. Zwei Sekunden
auf dem Titel stehenbleiben, dann fährt er hoch und darunter klappt sie
auf; wer nur vorbeifährt, sieht nichts. Gibt es keine, passiert gar
nichts — der Absatz fällt dann ganz aus dem Fluss.

**Angefasst wird am Titel, losgelassen am ganzen Aufmacher.** Das ist die
ganze Vorsicht an dieser Stelle. Beim Aufklappen wächst der Block nach
oben, der Titel rückt um 77 Bildpunkte weg und steht nicht mehr unter dem
Zeiger. Hinge das Zuklappen an seinem `:hover`, wäre das die erste Hälfte
einer Schaukel. Der Aufmacher selbst kann das nicht: gemessen, offen wie
zu, 476 px hoch ab 48 — auf den Bildpunkt derselbe Kasten.

**Die Höhe wird gemessen, nicht geraten.** Nach `auto` lässt sich nicht
überblenden, und eine feste Obergrenze wäre bei einer einzeiligen Angabe
zu drei Vierteln Leerlauf. Gemessen wird bei jedem Folienwechsel und bei
jeder Fensteränderung; `scrollHeight` ginge nicht, der meldet bei einem
`-webkit-box` die ungeklammerte Höhe.

**Der Rasterabstand wandert mit.** Gemessen: zugeklappt stehen zwischen
Eckdaten und Knopfzeile 16 px — mit Inhaltsangabe wie ohne, und genau so
viele wie vorher. Aufgeklappt sind es 12 über und 16 unter dem Text, und
die Knopfzeile steht still (Unterkante 492 in beiden Zuständen).

Nebenbei kommt das Abbruchsignal endlich an: `hero()` nahm eines
entgegen, aber `main.ts` baute die Startseite ohne. Sie wird gemerkt — ihr
Neun-Sekunden-Takt lief also weiter, während man längst woanders war.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-06 22:05:44 +02:00
ScarriffleandClaude Opus 5 3c7c0d8799 Der Hintergrund wird erst weich, wenn etwas darüberläuft
Er war es immer: 28 Bildpunkte Weichzeichnung über die ganze Detailseite,
damit der Text darüber lesbar bleibt. Oben steht aber gar nichts darüber —
dort ist das Bild das Beste, was die Seite zu bieten hat, und es lag als
Farbschlieren da. Unscharf gehört es erst, wenn wirklich etwas darüber
hinwegläuft: die Folgen, die Besetzung, die Medienangaben.

Jetzt folgt die Weichzeichnung dem Bildlauf, über etwa siebzig Prozent
einer Bildschirmhöhe und quadratisch statt geradlinig — die ersten
Bildpunkte sollen nichts tun, sonst wäre „scharf, solange nichts
darüberliegt" nach einem Fingerbreit schon dahin. Gerundet auf ganze
Bildpunkte, weil jeder neue Wert eine bildschirmfüllende Fläche neu
zeichnen lässt; über die ganze Strecke sind das 28 Male. Gemessen über 58
Bilder beim Hinunterrollen: 8,3 ms im Mittel, kein Bild über 9,2 ms.

**Und die Deckung geht mit, das ist der unscheinbare Teil.** Eine
Weichzeichnung verrührt die hellen Stellen mit den dunklen; ein scharfes
Bild hat die weisse Stelle genau dort, wo die Zeile steht. Gemessen an der
dunklen Vorlage von „Dark": vorher 4,07∶1, scharf bei derselben Deckung
nur noch 2,44∶1. An einer hellen — Hubschrauber vor blauem Himmel —
vorher 2,75∶1. Mit 0,28 scharf und 0,45 weich stehen beide wieder bei rund
4,0∶1, die helle sogar besser als zuvor.

Der Zuhörer räumt sich selbst ab: die Detailseite wird nicht gemerkt, und
für ungemerkte Ansichten ruft `einhaengen` kein Abbruchsignal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-06 19:53:25 +02:00
ScarriffleandClaude Opus 5 6dc7be9822 Ein eigenes Bild bringt auch seinen Ausschnitt mit
Hochladen konnte man Plakat, Hintergrund und Schriftzug schon lange — der
Knopf stand da, der Endpunkt nahm an. Nur ankommen tat nichts: die Ablage
baute einen Schlüssel, den sie selbst nicht wiederfand (heute früh
repariert). Was blieb, waren drei Lücken, die man erst sieht, wenn der Weg
überhaupt funktioniert.

**Der Ausschnitt.** Ein Plakat steht hochkant im Verhältnis 2∶3, ein
Hintergrund liegt quer. Was man aussucht, passt selten von selbst — und
den Rest beschnitt bisher der Browser beim Anzeigen: mittig. Jetzt wählt
man selbst, zieht und vergrössert, und hochgeladen wird genau dieser
Ausschnitt: 600×900 beim Plakat, 1920×1080 beim Hintergrund. Gerechnet
wird im Browser; das spart die Leitung und dem Server eine Bildbibliothek.

**Der Schriftzug nicht.** Er ist ein PNG mit durchsichtigem Grund. Durch
dieselbe Mühle geschickt würde aus der Durchsicht ein weisses Rechteck —
ein Aufkleber über dem Bild. Er geht unverändert hinaus, Byte für Byte.

**Die Kachel merkte nichts.** Nach dem Hochladen fehlte der Anstoss nach
aussen; die Oberfläche zeigte weiter das alte Bild, bis man sie neu lud.

**Und zurück ging es gar nicht.** „Von Hand gesetzt" heisst auch: beim
Auffrischen bleibt es stehen. Ohne Rückweg wäre ein Fehlgriff ein
Dauerzustand — jetzt steht „Wieder automatisch" daneben, sobald etwas
festgesetzt ist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-06 19:41:04 +02:00
ScarriffleandClaude Opus 5 327e2e9195 Einstellungen hat jeder, Verwaltung nicht
Die Seite hiess „Verwaltung" und war für alle anderen gar nicht
erreichbar — „Meine Sprache" lag dadurch hinter einer Tür, die den meisten
verschlossen ist. Jetzt heisst sie **Einstellungen**, steht jedem offen und
hat zwei beschriftete Gruppen: oben, was einem selbst gehört (Mein Konto,
Geschaut), darunter — nur für Administratoren — **Verwaltung**. Die
Überschrift ist hier die halbe Aussage: sie sagt ohne weiteren Satz, wem
der untere Teil gehört.

In der Hauptleiste steht der Eintrag jetzt unten, ohne Gruppenüberschrift.
Eine Überschrift über einem einzigen Eintrag ist eine Überschrift über
nichts, und am Fuss sucht man Einstellungen ohnehin. `#/profil` und
`#/verwaltung/…` leiten weiter; ein Lesezeichen merkt davon nichts.

**Ein kurzes Menü am Bild.** Erst meldete der Klick ab — ohne Rückfrage.
Dann führte er auf die eigene Seite, und zum Abmelden musste man erst
dorthin. Beides sind zwei Punkte; ein Menü mit zwei Punkten ist ehrlicher
als eine Tür, hinter der eine zweite liegt.

**Und das Profilbild lässt sich zuschneiden.** Ein Profilbild ist rund,
was hochgeladen wird selten quadratisch — den Ausschnitt dem Browser zu
überlassen hiesse: mittig, und das trifft bei einem Porträt den Hals. Der
Dialog zeigt den runden Ausschnitt, man zieht und vergrössert, und
hochgeladen wird genau das: ein Quadrat von 512 Pixeln. Gemessen, es kommt
auch so an.

**Dazu die Spielerleiste.** Beide Knopfgruppen durften schrumpfen, ihre
Knöpfe aber nicht — wird es eng, steht der äusserste halb hinter dem
Fensterrand. Rechts sind es nur Knöpfe, da gibt es nichts nachzugeben;
links schon. Dazu seitlich `env(safe-area-inset-*)`, damit auf einem Gerät
mit runden Ecken nichts darunter liegt. Gemessen: vorher riss es ab 420
Pixeln, jetzt bis 320 nicht mehr.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-06 18:24:44 +02:00
ScarriffleandClaude Opus 5 e30158b84c Eine Sekunde heisst nicht „Weiterschauen"
Die Schwelle aus den Einstellungen wirkt serverseitig, also sofort überall:
`/home/continue` liest die gespeicherte Spalte. Eine Stelle blieb trotzdem
widersprüchlich — die **Beschriftung**.

Web und Apps entschieden „Weiterschauen" gegen „Abspielen" selbst, allein
daran, ob eine Stelle über null steht. Nach einer Sekunde stand der Titel
damit nicht mehr in der Reihe, hiess aber weiter „Weiterschauen", trug
einen Fortschrittsbalken unter der Kachel und bot „Aus Weiterschauen
entfernen" an.

Der Server hatte diese Frage längst beantwortet. `ItemStateResponse` bringt
sie jetzt mit; `MediaItem.isResumable` und `.resumeProgress` sind die
einzigen Stellen, die sie noch stellen. Im Simulator nachgeprüft: nach
einer Sekunde heisst der Knopf „Abspielen", „Von vorn" fehlt, und der
Balken unter der Kachel ist weg.

Kennt ein Server das Feld nicht — Jellyfin, oder ein älterer Flaro —, gilt
wie früher die blosse Stelle.

**Und das Profilbild steht in den Apps.** `FlaroAccount` führt es mit,
`/auth/me` bringt es bei jedem Start frisch, und der Buchstabenkreis tritt
zurück, sobald eines da ist. Jellyfin bleibt beim Buchstaben — dort gibt es
kein Profilbild, und das ist keine Lücke, sondern der Stand der Dinge.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-06 17:30:38 +02:00
ScarriffleandClaude Opus 5 579a49b73b Der Server wusste, was du zuletzt gesehen hast — und sonst nichts
Für „wie viel habe ich letzte Woche geschaut" gab es keine Daten.
`UserItemState` ist eine Zeile je Titel: der letzte Stand. Wer einen Film
zweimal sieht, überschreibt den ersten Durchgang; wann etwas lief, wusste
der Server nur fürs jeweils letzte Mal. Nachträglich erfinden lässt sich
das nicht.

Jetzt gibt es ein Sehprotokoll: **eine Zeile je Nutzer, Tag und Titel.**
Keine Sitzungen — die brauchen ein Ende, und das kommt oft nie an, wenn
der Browser zugemacht oder das Telefon zugeklappt wird. Tagesbündel haben
diesen Lebenslauf nicht, es wird nur addiert.

**Gezählt wird, was wirklich lief.** Der Zuwachs zwischen zwei Meldungen,
gedeckelt auf die Zeit, die dazwischen verstrichen ist (mal zwei als
Toleranz für doppelte Geschwindigkeit und ausgefallene Meldungen). Sonst
ergäbe ein Sprung von Minute 5 auf Minute 90 anderthalb Stunden Sehzeit in
zehn Sekunden. Gemessen an fünf Meldungen im Abstand von elf Sekunden:
88 Sekunden statt 190.

Dabei fiel ein zweiter Fall auf: war **gar keine** Zeit verstrichen, griff
kein Deckel statt eines engen — eine frisch angelegte Zeile hätte ihre
Anfangsstelle voll mitgezählt. Wer einen Film öffnet und sofort auf Minute
fünf springt, hat keine fünf Minuten gesehen.

Im Profil stehen drei Zahlen, und jede sagt, woher sie kommt: die
aufgezeichnete Zeit fängt heute an, die Zahl gesehener Titel steht seit
jeher fest. Dazu eine Wochenkurve, die häufigsten Genres und was zuletzt
lief. **Jeder sieht nur sich selbst, auch ein Administrator** — es gibt
keinen Weg, ein fremdes Konto zu meinen.

Zwei Dinge auf dem Weg dorthin:

**Eine stellbare Uhr für die Tests.** Zwei Minuten Film lassen sich nicht
in fünf Millisekunden sehen, und das ist richtig so — prüfen liess es sich
nur, indem die Zeit vergeht, ohne sie zu verbringen.

**Ein Namenskonflikt im CSS.** Die leeren Wochenbalken trugen die Klasse
`leer`, und die gehört längst der Fläche „hier ist nichts" — mitsamt
24 Pixeln Polster. Jeder leere Balken war dadurch 48 Pixel hoch, egal
welche Höhe dastand.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-06 17:20:01 +02:00
ScarriffleandClaude Opus 5 d8a1633cf4 Das eigene Bild führte aus dem Server heraus
Ein Klick auf den Buchstabenkreis meldete ab. Keine Rückfrage, kein Menü,
kein Weg zurück — hinter einer Geste, die überall sonst „mein Konto"
heisst. Jetzt führt er auf `#/profil`; Abmelden steht dort als Knopf, mit
Nachfrage.

Auf der Seite: Bild wählen, tauschen, entfernen. Dazu „Meine Sprache" —
**umgezogen, nicht kopiert.** Sie stand mitten in der Verwaltung, und die
zeigt der Client nur Administratoren; der Endpunkt erlaubte sie längst
jedem. Wer kein Admin war, konnte seine eigene Sprache nirgends ändern.
Der Warnhinweis „weicht ab" bleibt in der Verwaltung, denn dort entsteht
die Verwirrung — er verweist jetzt aufs Profil.

**Vorher musste ein Fehler weg, der seit Monaten dasteht.**
`ImageCache.StoreStreamAsync` baute den Schlüssel aus 32 Hexzeichen plus
Dateiendung; `PfadFür` verlangt genau 64 Hexzeichen und nichts sonst. Es
gab keinen Wert, den beide gelten liessen: **jeder Bildupload gab `null`
zurück und endete in einem 502.** Kein Test fragte je danach — jetzt vier.
Damit geht nebenbei auch „eigenes Bild hochladen" für Filme und Serien
wieder.

Weil der Schlüssel keine Endung mehr trägt, kommt der Medientyp beim
Ausliefern aus den ersten Bytes der Datei. Vorher ging alles als
`image/jpeg` hinaus — bei TMDB stimmte das, bei einem hochgeladenen PNG
nicht.

**Und die gemerkte Sitzung war eine Kopie, die nie nachzog.** Sie wurde
bei der Anmeldung geschrieben und danach nie wieder. Wer sein Bild am
Telefon setzt und den Browser am Schreibtisch öffnet, fand dort den alten
Buchstaben — bis zum nächsten Anmelden. Gemessen und behoben: beim
Hochfahren wird das Konto abgeglichen, und das Profil meldet Änderungen
an die Kopfleiste, damit sie ohne Neuladen nachzieht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-06 17:07:40 +02:00
ScarriffleandClaude Opus 5 9622da0284 Eine Sekunde ist kein Anfang
Drei Zahlen standen als Konstante im Quelltext und bestimmten, wie sich
der Server anfühlt. Jetzt stehen sie in der Verwaltung, unter
„Wiedergabe".

**Weiterschauen ab.** Gemessen: `BelongsInContinueWatching` verlangte nur
`Position.Ticks > 0` — ein Tick genügte. Wer im Aufmacher eine Sekunde
hineinschaute, fand den Titel danach in „Fortsetzen". Jetzt gibt es eine
Untergrenze, voreingestellt auf 1½ Minuten.

Was sich dabei **nicht** ändert: die Stelle wird weiter gemerkt. Das ist
der Unterschied zu Jellyfin, um dessentwillen es diesen Server gibt — die
Schwelle entscheidet, ob der Titel in der Reihe steht, nicht ob man ihn
wiederfindet. Nachgemessen: nach dem Umstellen ist „Heat" aus der Reihe
verschwunden und steht weiterhin bei Sekunde 1.

**Gesehen ab.** War 90 % als `const`, ist jetzt 85/90/95.

**Umkodieren.** `-preset veryfast -crf 21` und VAAPI `-qp 23` waren fest
verdrahtet, ohne Einstellung und ohne Umgebungsvariable. Drei Stufen:
Qualität (medium/19, qp 21), Ausgewogen (wie bisher), Tempo
(ultrafast/23, qp 26). Mit dem Warnsatz daneben, und der ist ernst
gemeint: was in Echtzeit laufen muss, darf nicht langsamer rechnen als es
abspielt.

**Und das Vorhandene wird neu bewertet.** `InProgress` ist eine
gespeicherte Spalte — die Bruchrechnung lässt sich nicht nach SQL
übersetzen. Eine neue Schwelle wirkte sonst nur auf künftige Meldungen.
Der Endpunkt läuft deshalb einmal in Stapeln durch und meldet zurück, wie
viele Zeilen das umgeworfen hat: „Übernommen — 2 Einträge wurden neu
bewertet." Ohne diesen Satz änderte sich die Startseite scheinbar von
selbst.

`ProgressRule` bleibt ein reiner Typ: die Regeln kommen als Wert herein.
Nebenbei zieht der doppelte `zeile()`-Bauer nach `teile.ts` — er stand
zweimal wortgleich da.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-06 16:52:53 +02:00
ScarriffleandClaude Opus 5 1e4a231d1b Elf Abschnitte in einer Spalte waren zehn zu viel
Die Verwaltung war eine Seite mit 1786 Zeilen. Wer das Protokoll sehen
wollte, scrollte an Mediatheken, Prüfliste, Benutzern und Speicher
vorbei — und jede neue Einstellung hätte sie länger gemacht.

Jetzt hat sie eine eigene Leiste mit sieben Bereichen, jeder mit seiner
Adresse: `#/verwaltung/protokolle` lässt sich ablegen, und ein Neuladen
bleibt dort stehen. Die Leiste sieht aus wie die Hauptleiste daneben,
damit sie als Navigation gelesen wird und nicht als Knopfreihe; am
Telefon wird aus der Spalte ein Streifen zum Schieben.

**Gebaut wird nur, was offen ist.** Das ist nicht nur sparsamer: das
Abspielfenster fragt im Fünf-Sekunden-Takt nach, die Mediathekenliste
beobachtet laufende Scans. Gemessen: nach dem Wechsel in einen anderen
Bereich kommt zwölf Sekunden lang keine Anfrage mehr.

`admin.ts` ist in acht Dateien zerlegt — eine je Bereich, dazu `teile.ts`
für die gemeinsame Überschrift und `index.ts` für Leiste und Weiche.

Zwei Dinge mussten dabei nachziehen:

**Die Markierung in der Hauptleiste.** Sie verglich stur zwei Segmente;
bei `#/verwaltung/metadaten` traf das auf keinen Eintrag, und
„Verwaltung" verlor seinen Balken. Jetzt gilt auch ein Segment.

**„5 Titel warten — ansehen".** Der Knopf sprang mit `scrollIntoView` zur
Prüfliste. Die steht nicht mehr im selben Dokument — er wechselt jetzt
den Bereich. Die Hervorhebung danach entfällt damit, und mit ihr ihr CSS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-06 16:39:50 +02:00
ScarriffleandClaude Opus 5 f10fb4c1bc Abspielen spielt ab
Im Aufmacher der Startseite stand „Abspielen", und wer draufdrückte,
landete auf der Detailseite. Gemessen am laufenden Server: beide Knöpfe
riefen dieselbe Funktion — `oeffnen` —, der eine hiess nur anders.

Drei Dinge waren falsch, alle an derselben Stelle:

**Der Knopf log.** Jetzt startet er den Spieler, mit Fortsetzen ab der
Stelle, an der man war. Ohne Datei — eine ganze Serie — heisst er
„Ansehen" und führt dorthin, wo man wählen kann.

**Eine angefangene Folge war kein Film.** Sie lief durch `alsHero` mit
`art: 'filme'` und ihrer eigenen Kennung; der Klick ging auf
`#/filme/<Folgenkennung>` und endete in „Diesen Film gibt es nicht
mehr". Nachgemessen im Browser, dann `angefangenAlsHero` dafür gebaut:
die Detailseite gehört der Serie, der Fortschritt der Folge.

**Ein geplanter Titel sah aus wie jeder andere.** Jetzt steht statt des
Knopfes „Bald ist es soweit" mit dem Termin, wie auf der Detailseite.

Dafür nennt `/home/continue` und `/home/next` nun Datei, Länge und
Termin, und die Vorschläge bringen ihre Dateien mit — ohne die konnte
der Aufmacher gar nicht abspielen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-06 15:42:42 +02:00