230beb96648eecf2817cffeef891f06a5d65d762
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
230beb9664 |
Mehrere Mediatheken, jede für sich
Bisher gab es in der Seitenleiste „Filme" und „Serien" — zwei feste Zeilen, hinter denen alles zusammenfiel, was der Server kannte. Wer „Filme" und „Dokumentationen" getrennt angelegt hatte, sah sie wieder in einem Topf. Das nahm die Entscheidung zurück, sie zu trennen. Jetzt führt die Seitenleiste **jede Mediathek einzeln**, mit Namen und Zahl, wie bei Plex und Jellyfin. Die Startseite bekommt je Mediathek eine Reihe mit dem zuletzt Hinzugefügten; steht mehr drin, als die Reihe zeigt, führt „Alle zeigen" dorthin. Die Mediathekenseite trägt den Namen im Titel, sucht innerhalb der Mediathek und lässt sich sortieren. **Am Server dafür:** `?sort=` auf `/movies` und `/series` — `title`, `added`, `year`. Der Titel immer als letzter Vergleich, sonst hätten zwei Filme aus demselben Jahr keine feste Reihenfolge und Seite 2 zeigte denselben Film noch einmal oder gar nicht. Die Liste der Bibliotheken nennt je Zeile einen Zählwert. „Dokumentationen · 0" sagt mehr als ein Eintrag, hinter dem sich nach dem Klick nichts findet — da ist der Unterschied zwischen „noch nicht gescannt" und „falscher Pfad" wenigstens sichtbar. `null` heisst „nicht gezählt", nicht „leer". Umbenennen und Entfernen, beides nur für Administratoren. **Umbenennen, mehr nicht:** die Art zu ändern hiesse, Filme in Serien zu verwandeln; den Pfad zu ändern hiesse, einen Bestand gegen einen anderen zu tauschen, während die Einträge stehenbleiben. Beides ist kein Bearbeiten, sondern eine neue Bibliothek. **Beim Entfernen bleiben die Mediendateien liegen.** Weg sind der Eintrag, die Zuordnungen und der Sehfortschritt aller Benutzer dazu; die Oberfläche sagt das vorher, und eine Prüfung hält fest, dass die Datei danach noch da ist. Ein Server, der beim Aufräumen in der Oberfläche fremde Filme löscht, ist einer, den man nicht noch einmal benutzt. --- **Der Fehler, den der Browser zeigte, und er betrifft jeden Betrieb:** nach einem Server-Update lief weiter die alte Oberfläche. Die Dateien unter `assets/` tragen eine Prüfsumme im Namen — ändert sich der Inhalt, ändert sich der Name. `index.html` trägt keine; sie nennt nur deren Namen. Lag sie im Zwischenspeicher, bekam der Browser weiter die alte App: nicht kaputt, sondern veraltet, und das fällt niemandem auf. Nachgemessen: geladen war `index-C0K3V8eg.js`, ausgeliefert wurde längst `index-DomHN4_b.js`. Jetzt zwei Lebensdauern — `no-cache` für die Seite, ein Jahr und `immutable` für die Bausteine. Mit Prüfung, und am Container nachgemessen. Der Beispielbestand bekommt zwei weitere Mediatheken, „Dokumentationen" und „Konzerte". Mit nur Filme und Serien liesse sich gar nicht prüfen, ob mehrere wirklich getrennt bleiben — zwei Bestände **derselben Art** sind der Fall, in dem es auffällt. 358 Tests grün. Am Container nachgewiesen: vier Mediatheken in der Seitenleiste mit Zählwerten, je eine Reihe auf der Startseite, und „Dokumentationen" zeigt zwei Titel statt sieben. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
67cf0fd1d9 |
HEAD auf den Download, und /api verschluckt nichts mehr
Zwei Fehler, derselbe Grund — und beide zeigte erst der Browser.
**Der Spieler bekam die Webseite statt des Films.** „MEDIA_ELEMENT_ERROR:
Format error", 531 Byte, `Content-Type: text/html`. Das ist genau die Grösse
von `index.html`.
`MapGet` nimmt HEAD nicht an. Die Oberfläche fragt aber mit HEAD nach, ob das
Umpacken fertig ist — einen halbfertigen Film herunterzuladen, nur um das zu
erfahren, wäre absurd. Die Anfrage fiel durch den Methodenabgleich hindurch
bis zum SPA-Rückfall, und der nimmt jeden Pfad ohne Dateiendung. Antwort:
200, mit der Startseite im Rumpf. Der Client hielt das Umpacken für fertig
und reichte HTML an `<video>` weiter.
Jetzt `MapMethods` mit GET und HEAD. Kestrel lässt den Rumpf bei HEAD selbst
weg.
**Und ein vertippter Aufruf sah aus wie ein Erfolg.** `GET /api/v1/gibtsnicht`
gab 200 und die Webseite zurück — derselbe Rückfall. Ein Fehler, der erst
dort auffällt, wo jemand HTML durch einen JSON-Parser schickt.
`app.Map("/api/{*rest}", 404)` davor. Buchstaben schlagen Platzhalter, also
gewinnt jeder echte Endpunkt; was übrig bleibt, ist nicht da und sagt das
auch.
350 Tests grün, die zwei neuen eingerechnet. Am Container nachgemessen: HEAD
auf den Download gibt 200 `video/mp4` mit 71 920 Byte, `/api/v1/gibtsnicht`
gibt 404, und ein Neuladen auf `/verwaltung` bekommt weiterhin die Seite.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
91eb934048 |
Die Weboberfläche — im Zuschnitt von Plex, vom Server selbst ausgeliefert
Einrichtung, Anmeldung, Mediathek, Detailseite mit Abspielen und Herunterladen, Zuordnung korrigieren, Verwaltung. Die Oberfläche aus der Jellyfin-Zeit ist dabei vollständig ersetzt: `types.ts`, `prefs.ts`, `contrast.ts`, `views/cards.ts`, `views/player.ts` und `views/settings.ts` sprachen Jellyfins Schnittstelle und hatten hier nichts mehr zu suchen. Seitenleiste links, waagerechte Reihen auf der Startseite, Plakate im Verhältnis 2:3, unscharfer Hintergrund hinter dem Kopf der Detailseite — das ist der Zuschnitt von Plex, weil er gefällt. **Die Farbe bleibt Flaros Orchidee**, nicht Plex' Orange; der Aufbau ist das Vorbild, nicht das Aussehen. Welche Bibliothek gezeigt wird, entscheidet die Seitenleiste. Eine zweite Umschaltung innerhalb der Seite wäre dieselbe Entscheidung an zwei Orten. --- **Der Zugang liegt jetzt auch in einem Cookie.** Ein `<img>`, ein `<video>` und ein Download-Link senden keine eigenen Kopfzeilen — eine App kann ihr Token in jede Anfrage legen, ein Browser nicht. Das Token stattdessen in die Adresse zu schreiben wäre der naheliegende Ausweg und stünde danach in jedem Zugriffsprotokoll, in jedem Verlauf und in jedem weitergegebenen Link. `HttpOnly`, damit kein eingeschlichenes Skript herankommt. `SameSite=Strict` gegen Anfragen von fremden Seiten. `Secure` nur über https — sonst liesse sich die Oberfläche im Heimnetz über http gar nicht benutzen. Die Apps benutzen weiterhin die Kopfzeile: ein zweiter Weg zum selben Token, kein zweites Verfahren. --- **Der Fehler, den erst der echte Container zeigte:** eine weisse Seite, ohne Hinweis worauf. Die Rückfallregel verlangt für jede Anfrage ohne eigenen Endpunkt einen angemeldeten Benutzer, und `/assets/index.js` hat keinen. Die statischen Dateien standen unter `UseAuthorization` — ein neuer Besucher bekam 401 auf genau das Skript, das ihm die Anmeldemaske zeichnen sollte. `/` kam durch, weil der SPA-Rückfall `AllowAnonymous` trägt; alles mit Dateiendung nicht. Jetzt liegen sie davor. Mit Prüfung. Beim Bau desselben Images der zweite: seit der Kontext die Projektwurzel ist, überschrieb `COPY server/` die `obj/`-Verzeichnisse aus dem Container mit denen vom Arbeitsrechner — die zeigen auf osx-arm64, gebaut wird linux-arm64, `dotnet publish` brach mit NETSDK1047 ab. Dafür gibt es jetzt eine `.dockerignore` in der Wurzel; die unter `server/` sucht Docker seit dem Umzug nicht mehr. --- Vier Prüfungen schlugen danach fehl, und zwar zu Recht: sie hiessen „ohne Anmeldung gibt es nichts", benutzten aber den Client, der nach dem Anmelden ein Cookie hält. Sie prüften also den Angemeldeten. Jetzt sagen sie ausdrücklich, dass sie ohne Zugang fragen. 313 Tests grün. Im Container nachgewiesen: Anmelden, Plakate, Abspielen, Staffeln und Folgen, Verwaltung — und ein Neuladen auf `/verwaltung`, das nicht in einem 404 endet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |