Files
horror/README.md
2026-08-12 19:30:41 +02:00

6.0 KiB
Raw Blame History

Horrorfilme

Privater Katalog-Browser mit zwei Reitern:

  • Netflix — alle Horrorfilme im Netflix-DE-Abo, aktuell 325.
  • Kanon — 194 Einträge aus anerkannten Bestenlisten, davon 28 Filmreihen. Zusammen 320 Filme, unabhängig davon, wo sie laufen.

Daten kommen von TMDB (Provider-Info stammt dort aus der JustWatch-Partnerschaft). Die deutschen Teaser schreibt MiniMax M3 beim Sync und landen in der SQLite-Datei.

Einrichten

cp .env.example .env      # TMDB_TOKEN und MINIMAX_KEY eintragen
make install

Sync

Holt den Katalog und erzeugt fehlende Teaser. Der erste Lauf dauert einige Minuten, weil für jeden Film ein Teaser generiert wird.

make sync

Teaser werden nur einmal erzeugt. Spätere Syncs schreiben nur für neue Filme. Im Betrieb läuft der Sync täglich um 4:30 von selbst.

Entwickeln

make dev     # Backend :8000, Frontend :5173
make stop

Der Vite-Dev-Server leitet /api an den Backend-Port weiter.

Produktiv

Auf dem Server im Projektverzeichnis. Läuft hinter Traefik im externen Docker-Netz web, wie die anderen Projekte.

make prod    # docker compose up -d --build
make logs
make down

Die SQLite-Datei liegt im Bind-Mount ./data, überlebt also jeden Rebuild.

Ohne Docker geht es auch:

make build   # Vue nach backend/static
cd backend && .venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000

Wie es läuft

APScheduler (täglich 4:30)
        │
        ▼
TMDB /discover/movie  ──►  pro Film /movie/{id} (Bilder, Videos, Übersetzungen)
        │                                    │
        │                                    ▼
        │                          MiniMax M3 schreibt den Teaser
        ▼                                    │
SQLite (backend/horror.db)  ◄────────────────┘
        │
        ▼
FastAPI /api/movies  ──►  Vue-Grid, Detail-Overlay

API

Endpoint Zweck
GET /api/movies ganzer Katalog, das Frontend filtert clientseitig
GET /api/movies/{id} einzelner Film
GET /api/status Anzahl Filme, letzter Sync, läuft gerade einer
GET /api/health für den Docker-Healthcheck
POST /api/sync Sync von Hand anstoßen

Filmreihen

Gehört ein Film zu einer Reihe, zeigt die Detailansicht die anderen Teile — aber nur die, die selbst auf Netflix liegen. Grundlage ist TMDBs belongs_to_collection. Ein Klick springt direkt zum nächsten Teil.

Aktuell haben 86 Filme eine Reihe, 24 Reihen sind mit mehr als einem Teil vertreten. Die größte ist Resident Evil mit fünf Filmen.

Der Kanon-Reiter

Die Liste steht in app/canon_list.py. Ein Eintrag ist ein Film oder eine Reihe. Reihen bekommen eine breitere Karte, die durch ihre Teile blättert — immer ein Teil vollständig sichtbar.

app/canon.py löst die deutschen Verleihtitel gegen TMDB auf. Das klappt bei 309 von 320 Titeln allein über die Suche. Der Rest steht in OVERRIDES mit fester TMDB-ID, weil die Suche danebengriff:

  • Ohne Jahresangabe liefert TMDB den jüngsten Titel zuerst. "Final Destination" traf deshalb "Bloodlines", "A Quiet Place" den zweiten Teil.
  • "Das Böse" ist auf Deutsch sowohl Phantasm als auch Amityville Horror.
  • "Us" traf "Forgive Us All" von 2025.

Die Vorlage führte "Black Christmas" und "Jessy Die Treppe in den Tod" getrennt. Das ist derselbe Film, hier nur einmal.

Innerhalb einer Reihe wird nach Erscheinungsjahr sortiert, nicht nach der Reihenfolge der Vorlage. Die gruppiert das Conjuring-Universum nach Sub-Reihen — erst alle Conjuring, dann Nun, dann Annabelle.

Die TMDB-API nennt nur den Anbieternamen, nicht die Titel-ID. Die steht ausschließlich im HTML der Watch-Seite, URL-kodiert im JustWatch-Link. app/netflix.py liest sie dort aus und merkt sie sich in der Spalte netflix_id, damit spätere Syncs die Seite nicht erneut laden.

Der Abruf läuft seriell mit 1,5 Sekunden Pause. Bei dichteren Abrufen antwortet TMDB mit Status 200, aber ohne Anbieterblock — die ID fehlt dann stillschweigend. Filme ohne ID versucht der nächste Sync erneut.

Hat ein Film mehrere IDs, gewinnt die erste. Godzilla Minus One liegt bei Netflix in Farbe und in Schwarzweiß.

Warum der Katalog bei drei Stimmen abschneidet

JustWatch ordnet unbekannte Titel gelegentlich der Netflix-ID eines gleichnamigen bekannten Films zu. TMDB übernimmt das ungeprüft. Der Film steht dann im Katalog, obwohl Netflix ihn nicht hat.

Nachgewiesen an fünf Fällen, alle nach demselben Muster:

Eintrag Stimmen bekam die ID von
CREEP (2014, 8 Min) 2 Creep (2014, 1678 Stimmen)
Muerte, muerte, muerte 2 Bodies Bodies Bodies
LIENZO 1 Die Leinwand / Canvas
NOISE! 1 Noise
The Roommate (2022) 1 The Roommate (2011)

Nachweis über TMDBs Watch-Seiten: Dort steht die Netflix-ID im Weiterleitungslink. Zwei Filme mit derselben ID können nicht beide stimmen. Oberhalb von zwei Stimmen trat kein einziger Fall auf, deshalb die Grenze bei drei. Das kostet 11 Einträge von 336.

Grenzen

  • Verfügbarkeit hinkt Netflix 2448 h hinterher. So oft liefert JustWatch an TMDB.
  • Es gibt keine Info, ob ein Film deutsche Synchronisation hat. TMDB kennt nur die Originalsprache, nicht die Tonspuren bei Netflix.
  • Der Netflix-Knopf führt bei 310 von 325 Filmen direkt auf die Titelseite. Die restlichen 15 landen auf TMDBs Watch-Seite, weil dort kein Netflix-Link hinterlegt ist. Der nächste Sync versucht sie erneut.
  • Die Szenenbilder sind TMDB-Backdrops. Der Sync wirft Duplikate raus, indem er die Bilder selbst vergleicht (dHash plus Farbhistogramm, siehe app/imagehash.py). Motive mit Titeltext fliegen ganz raus. Werbemotive ohne Text bleiben drin — die lassen sich nicht von Szenenfotos trennen.
  • 15 Filme haben gar keine Bilder, 46 keinen Trailer. Dann zeigt die Detailansicht entsprechend weniger.

Attribution

This product uses the TMDB API but is not endorsed or certified by TMDB. Verfügbarkeitsdaten stammen von JustWatch.