Files
flimmer/docs/API.md
T
Florian Wilde 9ee8664233
CI / pruefen (push) Canceled after 0s
Release / veroeffentlichen (push) Canceled after 0s
feat: eigene Sammlung — „hab ich" mit Quelle
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.
2026-09-01 21:15:53 +02:00

5.8 KiB
Raw Blame History

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:

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:

{ "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

GET /api/v1/me

Bibliothek

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:

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
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

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:

# 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

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

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

GET /api/v1/statistik?jahr=2026

Liefert totals, monthly, providers, genres und yearReview auf einmal.

Universen

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

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

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

#!/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:

curl -X POST -H "Authorization: Bearer $CRON_SECRET" \
  https://flimmer.example.com/api/cron/sync