Jellyfin einmal verbinden, danach übernimmt Flimmer Bestand und Sichtungen. Zugeordnet wird über die TMDB-Kennung, die Jellyfin zu jedem Item mitliefert — dieselbe Kennung, auf der Flimmers Katalog ohnehin aufbaut. Kein Raten über Titel und Jahreszahlen: die Zuordnung ist eindeutig oder sie findet nicht statt.
Umfang: Stufe 1 und 2
Die Abnahmeliste des Issues deckt genau diese ab. Stufe 3 (Zurückschreiben) ist nicht dabei — sie kommt in der Abnahme nicht vor, ist laut Beschreibung standardmäßig aus und bräuchte eine Versionsweiche für den umgezogenen Endpunkt, die sich ohne echten Server nicht verlässlich prüfen lässt. Das Feld writeBack ist wie beschrieben angelegt, die Logik dahinter bleibt leer.
Was dazugekommen ist
prisma/schema.prisma
MediaServerConnection, MediaServerItem, Watch.source, zwei Enums
Anmeldung statt API-Schlüssel. Mit einem Schlüssel liefert Jellyfin den Bestand ohne UserData — also ohne Gesehen-Status, ohne Fehlermeldung. Der Verbindungstest prüft ausdrücklich nach und sagt es deutlich. Nachgestellt und geprüft (siehe unten).
Der Endpunkt zum Zurückschreiben betrifft nur Stufe 3, die hier nicht dabei ist.
Entdoppelt wird zweifach
Episoden über den vorhandenen Index (userId, episodeId, run). Filme brauchen eine eigene Prüfung: dort ist episodeId null, und Postgres behandelt NULL in eindeutigen Indizes als jeweils verschieden — der Index greift dort gar nicht.
Einbahnstraße
Der Abgleich ergänzt und löscht nie. Fehlende Titel werden nur mit gesetztem Häkchen aufgenommen — im täglichen Lauf also nie, eine Mediathek mit achthundert Filmen soll nicht nachts ungefragt zur Bibliothek werden.
Geprüft
Elf Tests gegen nachgebildete Antworten, ohne echten Server — inklusive eines Items ohne TMDB-Kennung und eines mit einer Kennung, die nicht im Katalog steht. 78 Tests grün, Typecheck sauber.
Zusätzlich der ganze Klickweg gegen einen echten HTTP-Server im Produktionsbau:
Schritt
Ergebnis
Verbinden
„Heimserver" erkannt, ✓ Gesehen-Status kommt mit
Token in der Datenbank
s6sGpiNTHbTYZGNd.… — verschlüsselt
Abgleich
5 gelesen, 3× „hab ich", 1 nicht zuzuordnen (Item ohne Kennung)
Sichtungen
2 angelegt, Termin 2026-07-14 20:15 aus Jellyfin
Zweiter Lauf
weiterhin 2 Sichtungen — nichts doppelt
Server ohne UserData
„Der Gesehen-Status fehlt. Das passiert, wenn die Anmeldung über einen API-Schlüssel …"
Ein Zwischenergebnis war lehrreich: beim ersten Lauf gegen echte Seed-Daten kamen 0 Sichtungen heraus. Das war kein Fehler, sondern korrektes Entdoppeln — die betroffenen Episoden waren im Seed längst als gesehen markiert. Erst mit Inhalten, die noch offen waren, zeigte sich der Import.
Die Entwicklungsdatenbank ist nach den Proben wieder im Ausgangszustand.
Jellyfin einmal verbinden, danach übernimmt Flimmer Bestand und Sichtungen. Zugeordnet wird über die **TMDB-Kennung**, die Jellyfin zu jedem Item mitliefert — dieselbe Kennung, auf der Flimmers Katalog ohnehin aufbaut. Kein Raten über Titel und Jahreszahlen: die Zuordnung ist eindeutig oder sie findet nicht statt.
## Umfang: Stufe 1 und 2
Die Abnahmeliste des Issues deckt genau diese ab. **Stufe 3 (Zurückschreiben) ist nicht dabei** — sie kommt in der Abnahme nicht vor, ist laut Beschreibung standardmäßig aus und bräuchte eine Versionsweiche für den umgezogenen Endpunkt, die sich ohne echten Server nicht verlässlich prüfen lässt. Das Feld `writeBack` ist wie beschrieben angelegt, die Logik dahinter bleibt leer.
## Was dazugekommen ist
| | |
|---|---|
| `prisma/schema.prisma` | `MediaServerConnection`, `MediaServerItem`, `Watch.source`, zwei Enums |
| `src/lib/jellyfin.ts` | Client: Anmeldung, Bestand, Serien-Kopfdaten, Verbindungsprüfung |
| `src/lib/mediaserver.ts` | Zuordnung, Bestand, Sichtungen, Bericht |
| `src/lib/secrets.ts` | AES-256-GCM, Schlüssel aus `AUTH_SECRET` |
| Einstellungen → Medienserver | verbinden, prüfen, abgleichen, Bericht, Schalter |
| `src/lib/sync.ts` | läuft im täglichen Abgleich mit |
| `docs/ANLEITUNG.md` | eigener Abschnitt samt der Rewatch-Grenze |
## Die beiden Haken aus dem Issue
**Anmeldung statt API-Schlüssel.** Mit einem Schlüssel liefert Jellyfin den Bestand ohne `UserData` — also ohne Gesehen-Status, ohne Fehlermeldung. Der Verbindungstest prüft ausdrücklich nach und sagt es deutlich. Nachgestellt und geprüft (siehe unten).
**Der Endpunkt zum Zurückschreiben** betrifft nur Stufe 3, die hier nicht dabei ist.
## Entdoppelt wird zweifach
Episoden über den vorhandenen Index `(userId, episodeId, run)`. **Filme brauchen eine eigene Prüfung:** dort ist `episodeId` null, und Postgres behandelt NULL in eindeutigen Indizes als jeweils verschieden — der Index greift dort gar nicht.
## Einbahnstraße
Der Abgleich ergänzt und löscht nie. Fehlende Titel werden nur mit gesetztem Häkchen aufgenommen — im täglichen Lauf also nie, eine Mediathek mit achthundert Filmen soll nicht nachts ungefragt zur Bibliothek werden.
## Geprüft
**Elf Tests** gegen nachgebildete Antworten, ohne echten Server — inklusive eines Items ohne TMDB-Kennung und eines mit einer Kennung, die nicht im Katalog steht. **78 Tests grün**, Typecheck sauber.
Zusätzlich der ganze Klickweg gegen einen **echten HTTP-Server** im Produktionsbau:
| Schritt | Ergebnis |
|---|---|
| Verbinden | „Heimserver" erkannt, ✓ Gesehen-Status kommt mit |
| Token in der Datenbank | `s6sGpiNTHbTYZGNd.…` — verschlüsselt |
| Abgleich | 5 gelesen, 3× „hab ich", 1 nicht zuzuordnen (Item ohne Kennung) |
| Sichtungen | 2 angelegt, Termin `2026-07-14 20:15` aus Jellyfin |
| Zweiter Lauf | weiterhin 2 Sichtungen — nichts doppelt |
| Server ohne `UserData` | „Der Gesehen-Status fehlt. Das passiert, wenn die Anmeldung über einen API-Schlüssel …" |
Ein Zwischenergebnis war lehrreich: beim ersten Lauf gegen echte Seed-Daten kamen **0 Sichtungen** heraus. Das war kein Fehler, sondern korrektes Entdoppeln — die betroffenen Episoden waren im Seed längst als gesehen markiert. Erst mit Inhalten, die noch offen waren, zeigte sich der Import.
Die Entwicklungsdatenbank ist nach den Proben wieder im Ausgangszustand.
Closes #1
Zugeordnet wird ueber die TMDB-Kennung, die Jellyfin zu jedem Item
mitliefert — dieselbe Kennung, auf der Flimmers Katalog ohnehin aufbaut. Eine
unscharfe Suche ueber Titel und Jahr ist damit nicht noetig: die Zuordnung ist
eindeutig oder sie findet nicht statt. Was Jellyfin ohne Kennung fuehrt,
landet im Bericht statt falsch zugeordnet zu werden.
Angemeldet wird mit Benutzername und Passwort, nicht mit einem API-Schluessel.
Mit einem Schluessel liefert Jellyfin den Bestand ohne UserData, also ohne
Gesehen-Status — und zwar ohne Fehlermeldung. Der Verbindungstest prueft
deshalb ausdruecklich nach und sagt es, statt den Abgleich stumm ins Leere
laufen zu lassen. Das Zugangstoken liegt mit AES-256-GCM verschluesselt in der
Datenbank; abgeleitet aus AUTH_SECRET.
Der Abgleich ist eine Einbahnstrasse: er ergaenzt, was auf dem Server liegt
oder dort gelaufen ist, und loescht nie etwas, das in Flimmer steht. Fehlende
Titel werden nur aufgenommen, wenn das Haekchen gesetzt ist — im taeglichen
Lauf also nie.
Entdoppelt wird zweifach: Episoden ueber (userId, episodeId, run), Filme
ausdruecklich per Nachschlagen. Bei Filmen ist episodeId null, und Postgres
behandelt NULL im eindeutigen Index als jeweils verschieden — der Index greift
dort nicht.
Watch.source haelt fest, was von wo kam. Ohne diese Angabe liesse sich spaeter
nicht mehr sagen, welche Sichtung aus Jellyfin stammt.
Umgesetzt sind Stufe 1 und 2. Stufe 3 (Zurueckschreiben) kommt in der
Abnahmeliste nicht vor und braeuchte eine Versionsweiche, die sich ohne echten
Server nicht verlaesslich pruefen laesst; das Feld writeBack ist angelegt, die
Logik dahinter bleibt leer.
Elf Tests gegen nachgebildete Antworten. Zusaetzlich der ganze Klickweg gegen
einen echten HTTP-Server im Produktionsbau: verbinden, pruefen, abgleichen,
zweiter Lauf ohne Dubletten, und der Warnfall ohne UserData.
Refs #1
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Jellyfin einmal verbinden, danach übernimmt Flimmer Bestand und Sichtungen. Zugeordnet wird über die TMDB-Kennung, die Jellyfin zu jedem Item mitliefert — dieselbe Kennung, auf der Flimmers Katalog ohnehin aufbaut. Kein Raten über Titel und Jahreszahlen: die Zuordnung ist eindeutig oder sie findet nicht statt.
Umfang: Stufe 1 und 2
Die Abnahmeliste des Issues deckt genau diese ab. Stufe 3 (Zurückschreiben) ist nicht dabei — sie kommt in der Abnahme nicht vor, ist laut Beschreibung standardmäßig aus und bräuchte eine Versionsweiche für den umgezogenen Endpunkt, die sich ohne echten Server nicht verlässlich prüfen lässt. Das Feld
writeBackist wie beschrieben angelegt, die Logik dahinter bleibt leer.Was dazugekommen ist
prisma/schema.prismaMediaServerConnection,MediaServerItem,Watch.source, zwei Enumssrc/lib/jellyfin.tssrc/lib/mediaserver.tssrc/lib/secrets.tsAUTH_SECRETsrc/lib/sync.tsdocs/ANLEITUNG.mdDie beiden Haken aus dem Issue
Anmeldung statt API-Schlüssel. Mit einem Schlüssel liefert Jellyfin den Bestand ohne
UserData— also ohne Gesehen-Status, ohne Fehlermeldung. Der Verbindungstest prüft ausdrücklich nach und sagt es deutlich. Nachgestellt und geprüft (siehe unten).Der Endpunkt zum Zurückschreiben betrifft nur Stufe 3, die hier nicht dabei ist.
Entdoppelt wird zweifach
Episoden über den vorhandenen Index
(userId, episodeId, run). Filme brauchen eine eigene Prüfung: dort istepisodeIdnull, und Postgres behandelt NULL in eindeutigen Indizes als jeweils verschieden — der Index greift dort gar nicht.Einbahnstraße
Der Abgleich ergänzt und löscht nie. Fehlende Titel werden nur mit gesetztem Häkchen aufgenommen — im täglichen Lauf also nie, eine Mediathek mit achthundert Filmen soll nicht nachts ungefragt zur Bibliothek werden.
Geprüft
Elf Tests gegen nachgebildete Antworten, ohne echten Server — inklusive eines Items ohne TMDB-Kennung und eines mit einer Kennung, die nicht im Katalog steht. 78 Tests grün, Typecheck sauber.
Zusätzlich der ganze Klickweg gegen einen echten HTTP-Server im Produktionsbau:
s6sGpiNTHbTYZGNd.…— verschlüsselt2026-07-14 20:15aus JellyfinUserDataEin Zwischenergebnis war lehrreich: beim ersten Lauf gegen echte Seed-Daten kamen 0 Sichtungen heraus. Das war kein Fehler, sondern korrektes Entdoppeln — die betroffenen Episoden waren im Seed längst als gesehen markiert. Erst mit Inhalten, die noch offen waren, zeigte sich der Import.
Die Entwicklungsdatenbank ist nach den Proben wieder im Ausgangszustand.
Closes #1