smithflix/server/ai-playlists
2026-10-11 13:28:58 -04:00
..
.env.example Back up the server pieces: Smithflix Hub and AI playlists script [skip ci] 2026-10-11 13:28:58 -04:00
docker-compose.yml Back up the server pieces: Smithflix Hub and AI playlists script [skip ci] 2026-10-11 13:28:58 -04:00
Dockerfile Back up the server pieces: Smithflix Hub and AI playlists script [skip ci] 2026-10-11 13:28:58 -04:00
jellyfin_ai_playlists.py Back up the server pieces: Smithflix Hub and AI playlists script [skip ci] 2026-10-11 13:28:58 -04:00
README.md Back up the server pieces: Smithflix Hub and AI playlists script [skip ci] 2026-10-11 13:28:58 -04:00

Jellyfin AI Playlists

Each night every user gets up to four AI-picked playlists from your own library: Because you watched …, a seasonal row (Halloween / Holiday / Date Night Picks), Hidden Gems (movies nobody has watched yet) and a shared Family Movie Night list. Turn the extra rows on or off in .env (ENABLE_SEASONAL, ENABLE_HIDDEN_GEMS, ENABLE_FAMILY, FAMILY_USERS).

Builds a private "Because you watched …" playlist for every Jellyfin user each night. A local Ollama model picks movies from your own library that the user hasn't watched yet, so every suggestion is playable, and the playlist shows up in every Jellyfin app (TV, phone, web).

How it works

  1. Reads each user's recently watched movies and favorites from the Jellyfin API.
  2. Pre-filters unwatched movies by genre match and rating, down to about 150 candidates, so the prompt stays small.
  3. Asks Ollama to pick the best 12 and name the "anchor" movie that explains them.
  4. Replaces that user's previous AI playlist with the new one, for example Because you watched Heat.

If Ollama is down or returns nonsense, the user's existing playlist is left alone.

Setup

cd jellyfin-ai-playlists
cp .env.example .env
nano .env                      # set JELLYFIN_API_KEY (Dashboard -> API Keys)
ollama pull llama3.1:8b        # or: docker exec -it ollama ollama pull llama3.1:8b
docker compose up -d --build
docker compose logs -f

DRY_RUN=true is set in the example, so the first run only logs the picks. Check that they look sensible, then set DRY_RUN=false and run docker compose up -d.

Networking notes

  • If Jellyfin and Ollama run on the same machine, host.docker.internal works as shown. If they're on different machines, use their LAN IPs, for example http://192.168.1.50:11434.
  • If Ollama runs in Docker on the same host, it must publish port 11434, or you can join this container to Ollama's Docker network and use http://ollama:11434.
  • Don't expose Ollama publicly; it has no authentication.

Useful settings

Variable Default What it does
PICKS 12 Movies per playlist
CANDIDATE_POOL 150 Unwatched titles sent to the model. Lower it for small models or less RAM.
USERS / EXCLUDE_USERS all Limit which accounts get playlists
RUN_AT 03:30 Daily run time, in the container's TZ
RUN_ONCE false Run once and exit, if you'd rather use host cron

Run on demand: docker compose run --rm -e RUN_ONCE=true jellyfin-ai-playlists

Limitations

  • Movies only for now. TV series would need episode-level history.
  • Playlists can't show the model's reasons on screen; they're printed in the logs instead.
  • The script tracks the playlists it created in ./data/state.json. If you delete that file, the next run removes any of a user's playlists whose name starts with PLAYLIST_PREFIX.