Streaming-Verfügbarkeit beantwortet nur die halbe Frage: manche Filme laufen nirgends mehr, die hat man gekauft und liegen zu Hause — in Jellyfin, Plex, Emby, auf dem NAS oder als Scheibe. Bewusst getrennt vom Feld „wo schaue ich das": das eine sagt, wo ein Titel gerade läuft, und das ändert sich ständig; das andere sagt, was einem gehört, und das bleibt. Auf der Detailseite steht die Sammlung deshalb vor der Verfügbarkeit — was man hat, ist die verlässlichere Antwort. Durchgezogen bis in Filter, Export, CSV-Import und REST-API.
202 lines
5.8 KiB
Markdown
202 lines
5.8 KiB
Markdown
# Flimmer — REST-API
|
||
|
||
Alles, was die Oberfläche kann, geht auch über die Schnittstelle: Bibliothek
|
||
lesen und pflegen, Episoden abhaken, suchen, Kalender und Statistik abrufen,
|
||
Universen verwalten, Daten exportieren.
|
||
|
||
Die maschinenlesbare Beschreibung liegt unter
|
||
`GET /api/v1/openapi.json` (OpenAPI 3.1) — damit lassen sich Clients erzeugen
|
||
oder die Endpunkte in Insomnia, Bruno oder Postman importieren.
|
||
|
||
## Anmeldung
|
||
|
||
Jede Anfrage trägt einen persönlichen API-Schlüssel im `Authorization`-Kopf:
|
||
|
||
```bash
|
||
curl -H "Authorization: Bearer flm_a1b2c3d4.xxxxxxxxxxxx" \
|
||
https://flimmer.example.com/api/v1/me
|
||
```
|
||
|
||
Schlüssel legst du unter **Einstellungen → API-Schlüssel** an. Der Klartext ist
|
||
**einmalig** sichtbar; danach liegt in der Datenbank nur ein Hash. Ein Schlüssel
|
||
hat dieselben Rechte wie dein Konto — behandle ihn wie ein Passwort und zieh ihn
|
||
zurück, sobald du ihn nicht mehr brauchst.
|
||
|
||
Aus dem Browser heraus funktioniert stattdessen das Sitzungscookie; dieselben
|
||
Endpunkte bedienen also Skripte und das eigene Frontend.
|
||
|
||
## Antwortformat
|
||
|
||
Alle Antworten sind JSON. Zeitangaben in ISO 8601, Laufzeiten in Minuten.
|
||
Fehler tragen immer ein Feld `error`:
|
||
|
||
```json
|
||
{ "error": "Diesen Eintrag gibt es nicht." }
|
||
```
|
||
|
||
| Status | Bedeutung |
|
||
|---|---|
|
||
| 200 | In Ordnung |
|
||
| 401 | Kein oder ungültiger Schlüssel |
|
||
| 404 | Nicht vorhanden (oder nicht deins) |
|
||
| 422 | Anfrage unvollständig — `details` nennt die Felder |
|
||
| 502 / 503 | TMDB nicht erreichbar bzw. kein Schlüssel hinterlegt |
|
||
|
||
## Endpunkte
|
||
|
||
### Konto
|
||
|
||
```http
|
||
GET /api/v1/me
|
||
```
|
||
|
||
### Bibliothek
|
||
|
||
```http
|
||
GET /api/v1/bibliothek?status=WATCHING&typ=SERIES&genre=Drama&q=nord&limit=50&offset=0
|
||
POST /api/v1/bibliothek
|
||
```
|
||
|
||
Filter: `q`, `status`, `typ`, `genre`, `tag`, `dienst`, `sammlung`, `limit`,
|
||
`offset`. Status: `WATCHING`, `PAUSED`, `COMPLETED`, `DROPPED`, `WATCHLIST`.
|
||
`sammlung=1` liefert nur Titel, die in der eigenen Sammlung liegen.
|
||
|
||
Aufnehmen — entweder mit interner Kennung oder direkt mit der TMDB-Kennung:
|
||
|
||
```bash
|
||
curl -X POST -H "Authorization: Bearer $KEY" -H "content-type: application/json" \
|
||
-d '{"tmdbId": 1396, "type": "SERIES", "status": "WATCHING"}' \
|
||
https://flimmer.example.com/api/v1/bibliothek
|
||
```
|
||
|
||
```http
|
||
GET /api/v1/bibliothek/{entryId}
|
||
PATCH /api/v1/bibliothek/{entryId}
|
||
DELETE /api/v1/bibliothek/{entryId}
|
||
```
|
||
|
||
`GET` liefert den Eintrag samt `progress` und `nextEpisode`.
|
||
`PATCH` ändert `status`, `rating` (1–10), `notes`, `whereToWatch`, `favorite`
|
||
sowie `owned` (liegt der Titel in der eigenen Sammlung?) und `ownedSource`
|
||
(wo genau — Jellyfin, Plex, Blu-ray …).
|
||
`DELETE` legt den Eintrag in den Papierkorb — dort bleibt er 30 Tage.
|
||
|
||
### Sichtungen
|
||
|
||
```http
|
||
GET /api/v1/bibliothek/{entryId}/sichtungen
|
||
POST /api/v1/bibliothek/{entryId}/sichtungen
|
||
DELETE /api/v1/bibliothek/{entryId}/sichtungen
|
||
```
|
||
|
||
`POST` kennt fünf Formen:
|
||
|
||
| Rumpf | Wirkung |
|
||
|---|---|
|
||
| `{"action":"next"}` | Die nächste offene Episode abhaken |
|
||
| `{"action":"movie"}` | Einen Film als gesehen markieren |
|
||
| `{"action":"episodes","episodeIds":["…"]}` | Eine Auswahl abhaken |
|
||
| `{"action":"season","seasonId":"…"}` | Eine ganze Staffel |
|
||
| `{"action":"upTo","episodeId":"…"}` | Alles bis einschließlich dieser Episode |
|
||
|
||
Die Antwort trägt `watchIds` — damit lässt sich genau diese Aktion zurücknehmen:
|
||
|
||
```bash
|
||
# Nächste Episode abhaken
|
||
IDS=$(curl -s -X POST -H "Authorization: Bearer $KEY" -H "content-type: application/json" \
|
||
-d '{"action":"next"}' \
|
||
https://flimmer.example.com/api/v1/bibliothek/$ENTRY/sichtungen | jq -c .watchIds)
|
||
|
||
# … und wieder zurücknehmen
|
||
curl -X DELETE -H "Authorization: Bearer $KEY" -H "content-type: application/json" \
|
||
-d "{\"watchIds\": $IDS}" \
|
||
https://flimmer.example.com/api/v1/bibliothek/$ENTRY/sichtungen
|
||
```
|
||
|
||
Alternativ nimmt `DELETE` auch `{"episodeIds":["…"]}` — dann verschwindet die
|
||
Markierung dieser Episoden im aktuellen Durchlauf.
|
||
|
||
### Suche
|
||
|
||
```http
|
||
GET /api/v1/suche?q=nordlicht&typ=serie
|
||
```
|
||
|
||
Durchsucht TMDB. Die Treffer tragen `tmdbId` und `type` — direkt verwendbar für
|
||
`POST /api/v1/bibliothek`. Ohne hinterlegten TMDB-Schlüssel antwortet der
|
||
Endpunkt mit 503.
|
||
|
||
### Kalender
|
||
|
||
```http
|
||
GET /api/v1/kalender?von=2026-09-01&bis=2026-09-30
|
||
```
|
||
|
||
Kommende Episoden der getrackten Serien. Ohne Zeitraum: die nächsten 30 Tage.
|
||
|
||
### Statistik
|
||
|
||
```http
|
||
GET /api/v1/statistik?jahr=2026
|
||
```
|
||
|
||
Liefert `totals`, `monthly`, `providers`, `genres` und `yearReview` auf einmal.
|
||
|
||
### Universen
|
||
|
||
```http
|
||
GET /api/v1/universen
|
||
POST /api/v1/universen
|
||
GET /api/v1/universen/{id}?reihenfolge={orderId}
|
||
POST /api/v1/universen/{id}
|
||
```
|
||
|
||
`GET /api/v1/universen/{id}` gibt die Einträge in der gewählten Reihenfolge
|
||
zurück, dazu `progress` und `nextUp`. Ohne `reihenfolge` gilt die
|
||
Erscheinungsreihenfolge.
|
||
|
||
### Export
|
||
|
||
```http
|
||
GET /api/v1/export?format=json
|
||
GET /api/v1/export?format=csv
|
||
```
|
||
|
||
JSON enthält zusätzlich alle Sichtungen und Universen.
|
||
|
||
## Beispiel: was ich habe, aber noch nicht gesehen habe
|
||
|
||
```bash
|
||
curl -s -H "Authorization: Bearer $KEY" \
|
||
"$HOST/api/v1/bibliothek?sammlung=1&status=WATCHLIST" \
|
||
| jq -r '.items[] | "\(.title) — liegt bei: \(.ownedSource // "ohne Angabe")"'
|
||
```
|
||
|
||
## Beispiel: Serien mit offener Episode auflisten
|
||
|
||
```bash
|
||
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
KEY="flm_…"
|
||
HOST="https://flimmer.example.com"
|
||
|
||
curl -s -H "Authorization: Bearer $KEY" \
|
||
"$HOST/api/v1/bibliothek?status=WATCHING&typ=SERIES" \
|
||
| jq -r '.items[] | "\(.title): \(.watched)/\(.total)"'
|
||
```
|
||
|
||
## Grenzen
|
||
|
||
Es gibt bewusst keine Ratenbegrenzung: Flimmer läuft auf deinem eigenen Server,
|
||
und ein Limit gegen dich selbst hilft niemandem. Wer die Instanz öffentlich
|
||
erreichbar macht, setzt so etwas besser im Reverse Proxy.
|
||
|
||
Der Abgleich mit TMDB lässt sich über einen eigenen Endpunkt anstoßen — der
|
||
nimmt allerdings das Cron-Geheimnis, nicht einen API-Schlüssel:
|
||
|
||
```bash
|
||
curl -X POST -H "Authorization: Bearer $CRON_SECRET" \
|
||
https://flimmer.example.com/api/cron/sync
|
||
```
|