Semantische Filmsuche für deine Jellyfin-Sammlung. Durchsuche deine Filme mit natürlicher Sprache – „ein netter Familienfilm mit Pferden" – und erhalte passende Ergebnisse mit direktem Jellyfin-Link.
Find a file
2026-04-15 23:19:32 +02:00
.bg-shell node 24 2026-04-14 15:49:12 +02:00
app Ollama url gefixed, Proxy Konfig 2026-04-15 15:48:19 +02:00
data Ollama url gefixed, Proxy Konfig 2026-04-15 15:48:19 +02:00
plans chore: init gsd 2026-04-13 21:30:32 +02:00
* Jellyfin Server mit Benutzer-Rechten verwenden 2026-04-15 08:27:59 +02:00
.codex feat: Hybrid-Suche, Jellyfin-Integration & Admin-UI 2026-04-12 13:34:04 +02:00
.env.example Ollama url gefixed, Proxy Konfig 2026-04-15 15:48:19 +02:00
.gitignore chore: init gsd 2026-04-13 21:30:32 +02:00
.node-version node 24 2026-04-14 15:49:12 +02:00
appctl.sh Jellyfin Server mit Benutzer-Rechten verwenden 2026-04-15 08:27:59 +02:00
CHANGES.md indizierung läuft wieder 2026-04-12 19:21:43 +02:00
copy_random.sh Erster Versuch 2026-02-21 22:47:54 +01:00
docker-compose.yml feat: Hybrid-Suche, Jellyfin-Integration & Admin-UI 2026-04-12 13:34:04 +02:00
Dockerfile Authentifizierung mit OIDC 2026-02-22 13:41:51 +01:00
jellyfin-vector-search-v1.1.tar.gz feat: Hybrid-Suche, Jellyfin-Integration & Admin-UI 2026-04-12 13:34:04 +02:00
jellyfin-vector-search-v1.2.tar.gz feat: Hybrid-Suche, Jellyfin-Integration & Admin-UI 2026-04-12 13:34:04 +02:00
Modelfile Ollama url gefixed, Proxy Konfig 2026-04-15 15:48:19 +02:00
openapi.yaml chore: init gsd 2026-04-13 21:30:32 +02:00
README.md chore: init gsd 2026-04-13 21:30:32 +02:00
requirements.txt Authentifizierung mit OIDC 2026-02-22 13:41:51 +01:00

🎬 Jellyfin Vector Search

Semantische Filmsuche für deine Jellyfin-Sammlung. Durchsuche deine Filme mit natürlicher Sprache „ein netter Familienfilm mit Pferden" und erhalte passende Ergebnisse mit direktem Jellyfin-Link.

Features

  • Natürlichsprachliche Suche beschreibe was du sehen willst
  • Stimmungs-Filter optional die gewünschte Stimmung angeben
  • Benutzerprofile mit FSK Kinder sehen nur altersgerechte Filme
  • PIN-Schutz für Profile mit höherer Altersfreigabe
  • Ähnliche Filme klicke einen Film an für Empfehlungen
  • Jellyfin-Integration direkter "In Jellyfin öffnen"-Link
  • Dark Mode schickes dunkles Design
  • Responsive funktioniert auf Handy, Tablet & Desktop

Architektur

ollama-net                         db-net
├── ollama-server:11434    ←→    ├── chromadb:8000
│   (LLM + Embeddings)          │   (Vektordatenbank)
│                                │
└── filmsuche:42000 ─────────────┘
    (Python/FastAPI)
    ├── liest /media/filme/*.nfo
    └── verlinkt auf Jellyfin (HTTPS)

Voraussetzungen

  1. Ollama läuft im Docker-Netzwerk ollama-net
  2. ChromaDB läuft im Docker-Netzwerk db-net
  3. Jellyfin ist via HTTPS erreichbar
  4. Embedding-Modell in Ollama geladen:
    docker exec ollama-server ollama pull nomic-embed-text
    

ChromaDB (falls noch nicht vorhanden)

# chromadb/docker-compose.yml
version: "3.8"
services:
  chromadb:
    image: chromadb/chroma
    container_name: chromadb
    restart: unless-stopped
    ports:
      - "42010:8000"
    volumes:
      - CHANGE_TO_COMPOSE_DATA_PATH/42_chromadb/data:/chroma/chroma
    networks:
      - db-net

networks:
  db-net:
    external: true

Setup

1. docker-compose.yml anpassen

Drei Stellen in docker-compose.yml müssen angepasst werden:

volumes:
  - CHANGE_TO_COMPOSE_DATA_PATH/42_filmsuche/data:/app/data
  - /pfad/zu/jellyfin/filme:/media/filme:ro  # ← Pfad zu deinen NFO-Dateien
environment:
  - JELLYFIN_URL=https://dein-jellyfin.example.com  # ← Deine Jellyfin-URL
  - JELLYFIN_API_KEY=DEIN_API_KEY_HIER               # ← Dein API-Key

2. Jellyfin API-Key erstellen

  1. Jellyfin → Dashboard → API-Schlüssel
  2. Neuen Schlüssel erstellen (Name: "Filmsuche")
  3. Den Key in docker-compose.yml eintragen

3. Netzwerke erstellen (falls noch nicht vorhanden)

docker network create ollama-net
docker network create db-net

4. Starten

cd filmsuche
docker compose up -d --build

5. Filme indexieren

  1. Öffne http://dein-server:42000
  2. Klicke unten auf ⚙️ Verwaltung
  3. Prüfe ob Ollama (🟢) und ChromaDB (🟢) verbunden sind
  4. Klicke 🔄 Filme neu indexieren
  5. Warte bis alle Filme verarbeitet sind (~2-5 Min. für 1500 Filme)

6. Suchen!

Wähle ein Profil, optional eine Stimmung, und beschreibe deinen Wunschfilm.

Umgebungsvariablen

Basis

Variable Standard Beschreibung
OLLAMA_URL http://ollama-server:11434 Ollama API
CHROMA_URL http://chromadb:8000 ChromaDB API
JELLYFIN_URL http://localhost:8096 Jellyfin URL (wie du sie im Browser öffnest)
JELLYFIN_API_KEY Jellyfin API-Schlüssel
COLLECTION_NAME filmsuche ChromaDB Collection-Name
EMBEDDING_MODEL nomic-embed-text Ollama Embedding-Modell
NFO_PATH /media/filme Pfad zu den NFO-Dateien im Container

OIDC / Authentik (optional)

Variable Standard Beschreibung
OIDC_ISSUER Authentik OIDC-Issuer-URL
OIDC_CLIENT_ID OAuth2 Client-ID
OIDC_CLIENT_SECRET OAuth2 Client-Secret
OIDC_REDIRECT_URI Callback-URL (z.B. https://filmsuche.example.com/auth/callback)
OIDC_SCOPES openid profile email groups Angeforderte Scopes
OIDC_LOGOUT_URL Optional: Logout-URL (sonst aus Discovery)
OIDC_DEFAULT_FSK 0 FSK wenn User keiner fsk-Gruppe zugeordnet
OIDC_ADMIN_GROUP filmsuche-admin Authentik-Gruppe für Admin-Zugriff
SECRET_KEY change-me... Unbedingt ändern! Signatur für Session-Cookies
SESSION_MAX_AGE 86400 Session-Dauer in Sekunden (24h)

Wenn OIDC_ISSUER, OIDC_CLIENT_ID und OIDC_CLIENT_SECRET alle gesetzt sind, ist OIDC aktiv. Sonst werden lokale Profile verwendet.

Authentik einrichten

1. Application & Provider in Authentik erstellen

  1. Authentik Admin → Applications → Providers → Create

    • Typ: OAuth2/OpenID Provider
    • Name: Jellyfin Vector Search
    • Authorization flow: default-provider-authorization-implicit-consent (oder mit Consent)
    • Client ID: wird automatisch generiert → kopieren
    • Client Secret: wird automatisch generiert → kopieren
    • Redirect URIs: https://filmsuche.example.com/auth/callback
    • Scopes: openid, profile, email, groups (Signing Key auswählen!)
  2. Authentik Admin → Applications → Create

    • Name: Jellyfin Vector Search
    • Slug: jellyfin-vector-search
    • Provider: den eben erstellten auswählen

2. Gruppen für FSK anlegen

In Authentik unter Directory → Groups folgende Gruppen erstellen und Benutzer zuordnen:

Gruppe Wirkung
fsk-0 Nur FSK 0 Filme
fsk-6 Bis FSK 6
fsk-12 Bis FSK 12
fsk-16 Bis FSK 16
fsk-18 Alle Filme
filmsuche-admin Darf indexieren und Profile verwalten

Ein User bekommt die höchste FSK-Stufe aus allen seinen Gruppen. Ohne fsk-Gruppe → OIDC_DEFAULT_FSK (Standard: 0).

3. OIDC-Issuer-URL

Die Issuer-URL für Authentik hat das Format:

https://auth.example.com/application/o/jellyfin-vector-search/

(wobei jellyfin-vector-search der Slug der Application ist)

4. Umgebungsvariablen setzen

- OIDC_ISSUER=https://auth.example.com/application/o/jellyfin-vector-search/
- OIDC_CLIENT_ID=<deine-client-id>
- OIDC_CLIENT_SECRET=<dein-client-secret>
- OIDC_REDIRECT_URI=https://filmsuche.example.com/auth/callback
- SECRET_KEY=<openssl rand -hex 32>

Profile (lokal)

Lokale Profile sind der Fallback wenn OIDC nicht konfiguriert oder nicht erreichbar ist.

Beim ersten Start werden drei Standard-Profile erstellt:

Profil FSK PIN
👨‍👩‍👧‍👦 Familie 6
🎓 Jugendliche 12
🎬 Erwachsene 18 1234

Profile können über die Verwaltung angepasst werden. Die Standard-PIN für "Erwachsene" sollte geändert werden.

Tipps

  • Suchanfragen funktionieren am besten auf Deutsch (weil die NFO-Plots oft deutsch sind)
  • Ähnliche Filme: Klicke auf eine Filmkarte, um ähnliche Filme zu finden
  • Neu-Indexierung bei neuen Filmen die alten bleiben erhalten (Upsert)
  • Die ChromaDB-Collection filmsuche kann unabhängig von anderen Projekten genutzt werden

API

Die Anwendung bietet eine REST-API für Programme und Skripte.

Endpoints

Endpoint Methode Beschreibung
/ GET Startseite
/login GET Login-Seite
/api/status GET System-Status (Admin)
/auth/login GET/POST Login-Seite / Authentifizieren
/auth/register POST Benutzer registrieren
/auth/logout GET Ausloggen
/auth/oidc/login GET OIDC-Login starten
/auth/callback GET OIDC-Callback
/auth/me GET Aktueller Benutzerstatus
/api/search GET Filme suchen
/api/similar/{movie_id} GET Ähnliche Filme
/api/index/status GET Indexierungsstatus
/api/index POST Vollständige Indexierung
/api/servers GET Server auflisten
/api/servers POST Server hinzufügen
/api/servers/{server_id} PUT Server aktualisieren
/api/servers/{server_id} DELETE Server löschen
/api/servers/sync POST Server-Liste synchronisieren
/api/servers/{server_id}/sync POST Server synchronisieren
/api/servers/{server_id}/index POST Server indexieren
/api/index-all POST Alle Server indexieren
/api/profiles GET Profile auflisten
/api/profiles POST Profil hinzufügen
/api/profiles/verify-pin POST PIN verifizieren
/api/profiles/{profile_id} PUT Profil aktualisieren
/api/profiles/{profile_id} DELETE Profil löschen

Authentifizierung

Geschützte Endpoints erfordern einen Bearer-Token:

Authorization: Bearer <JWT-Token>

OpenAPI-Spezifikation

Eine vollständige OpenAPI-Spezifikation ist verfügbar unter plans/openapi.md.

Beispiel-Anfrage

# Suche nach Filmen
curl "http://localhost:42000/api/search?query=Sci-Fi&limit=10"

# Server auflisten
curl -H "Authorization: Bearer <token>" "http://localhost:42000/api/servers"

# Film suchen mit Stimmung
curl "http://localhost:42000/api/search?query=romantisch&limit=5"