Tracker TV

active · since 2026

A movie and TV series tracker. Watchlist, progress season by season and episode by episode, and a catalogue that keeps itself current from TMDB.

stack
  • ▸Elixir / Phoenix (REST JSON API)
  • ▸Next.js (App Router, SSR), TypeScript
  • ▸PostgreSQL 18
  • ▸Meilisearch
  • ▸Oban (cron jobs)
  • ▸Prometheus, Grafana, GlitchTip
Tracker TV, home page
The home page.
Tracker TV, the discover page
Discover: the catalogue, narrowed by type and genre.
Tracker TV, a series page
A series page, with its progress and where to watch it.
Tracker TV, a movie page
A movie page, with the cast and the platforms carrying it.

What it does

Put a film or a series on your watchlist, tick a season or a single episode, and read your progress from your library. Series are followed episode by episode, rewatches included. Search answers films, series, sagas and people from a single field in the header. Follow a person and their new films land on your watchlist on their own.

Two things make it fit in a homelab rather than stay a website: imports and webhooks. A BetaSeries or Simkl account connects over OAuth2 and hands over its whole library: films, series, episodes. Plex, Jellyfin and Tautulli post what you finish watching to an address of your own, and it gets marked as watched here, with a "leave what I don't track alone" switch for the rest.

Everything is bilingual down to the API responses: French at /, English at /en.

How it's built

The repo is a monorepo with one Docker image per app. The backend is a Phoenix REST API (no LiveView, no server-rendered HTML), and the Next.js frontend is its only consumer, fetching server-side so pages render on the server.

The part I find the most interesting is the catalogue pipeline. TMDB publishes daily ID exports; a nightly Oban pipeline ingests them, enriches every entity through the TMDB API, and pushes what changed into the Meilisearch indexes. Nobody triggers anything: the catalogue is current the next morning, and the notifications fall out of the same pass: a film that got a release date, a new episode, a series that ended.

PromEx feeds Prometheus and Grafana, GlitchTip catches errors over the Sentry protocol. Both are optional; the app runs without them.

Why

I've gone through a fair share of trackers, and none of their interfaces ever stuck. Too many clicks to tick one episode, progress buried two pages deep, a watchlist that tells you everything except the one thing you want to know: what do I watch tonight. Building my own was the only way to get the screens I actually wanted, starting with the next episode of each series, in front of me, on the first screen.

Elixir and Phoenix gave me a second reason to start: a catalogue that refreshes itself every night is exactly the kind of workload OTP and Oban are good at, and it made a real project out of a language I had only ever read about.

An Android client is in progress, on the same API.

← back to projects