Self-hosted TV and film tracker: what to watch next and when the next episode airs.
116
A personal TV and film tracker: what to watch next, how far behind you are, and when the next episode airs. Self-hosted, single user, no accounts to make and nothing phoning home.
Data comes from TMDB. Tracked shows refresh automatically every 12 hours; finished shows are checked far less often. Film availability is re-checked every few days, and streaming service listings come from JustWatch by way of TMDB.
Artwork is fetched from TMDB once, cached in the data directory and then served by this app. No page ever points a browser at a third-party host, and the font is served locally too.
Nextup needs a free TMDB API key. It is not an environment variable — you
paste it into the Settings page, where it is checked against TMDB and then
stored encrypted in the database. The encryption key lives beside the database
as secret.key with 0600 permissions.
To get one: make a free account, then go straight to https://www.themoviedb.org/settings/api and copy the API Key (v3 auth).
sudo mkdir -p /opt/nextup
sudo chown -R 1000:1000 /opt/nextup
docker compose up -d
The compose file in this repository pulls
lightmorphic/nextup from Docker
Hub. Every release is tagged with its version number as well as latest.
The container runs as UID 1000, so the bind-mounted directory has to be owned by that same UID or writes fail silently.
Then open the app, sign in with admin / nextup, and change both on the Settings page straight away.
Updating:
docker compose pull
docker compose down
docker compose up -d
docker compose up -d on its own does not re-pull a :latest tag.
Something like Tailscale Serve listening on the same port number the container
publishes will fight it for that port, and whichever starts first wins. The
symptom is address already in use on a restart that worked yesterday. Bind the
container to the loopback address instead, and let the proxy be the only thing
listening publicly:
ports:
- "127.0.0.1:4090:8080"
Nextup never needs to become root and only ever writes to /data, so the
compose file in this repo runs it with no extra privileges, no Linux
capabilities and a read-only filesystem:
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
read_only: true
tmpfs:
- /tmp
If you wrote your own compose file before, adding those four blocks is worth doing. Nothing else has to change.
| Variable | Default | What it does |
|---|---|---|
NEXTUP_DATA_DIR | /data | Where the database, encryption key and poster cache live |
NEXTUP_PORT | 8080 | Port inside the container |
NEXTUP_SYNC_HOURS | 12 | Hours between automatic refreshes |
NEXTUP_HTTPS_ONLY | 0 | Set to 1 only when every way in really is HTTPS. It marks the sign-in cookie Secure, so a browser will not send it over plain HTTP at all. Leave it off if you ever reach the container directly on 127.0.0.1:4090 |
TZ | unset | Only needed if you want a different timezone from the machine itself. The compose file mounts /etc/localtime read-only instead, so the container follows the server. The morning email and the meaning of "today" both read the clock |
Everything else — the TMDB key, your password, the accent colour — is set in the app itself.
The Settings page has a Download a backup button. One JSON file holds every show and film you added, everything you marked watched, what you dismissed, and your settings, alongside enough show detail for a fresh copy to be usable immediately. Restore it on another machine and you carry on where you left off.
Your TMDB key and mail password are left out by default, because they are encrypted with a key that stays on that server. A second button includes them, written into the file as plain text, so keep that one somewhere safe.
nextup.db — shows, episodes, what you have watchedsecret.key — encrypts the TMDB key (0600)session.key — signs the login cookie (0600)images/ — cached posters and stillsBacking up that one directory backs up everything.
pip install -r requirements.txt
NEXTUP_DATA_DIR=./data python run.py
pip install -r requirements-dev.txt
pytest -q
Comments are stripped from the published code to keep it lean.
GPL-3.0. See LICENSE.
This product uses the TMDB API but is not endorsed or certified by TMDB.
Content type
Image
Digest
sha256:e17ee09fa…
Size
55.7 MB
Last updated
about 5 hours ago
docker pull lightmorphic/nextup