MediaPassport

Records what you finished, and who was there.

A self-hosted tracker for TV, film, books, podcasts and music. Check off episodes as you watch, and record whether you watched them alone or with someone. Built to replace TV Time's core loop, on a server you control, with an invite list instead of a signup page.

Self-hosted Invite-only Deployed
Get in touch
Overview

A watch history is also a record of company.

Every tracker knows you finished the season. None of them knows who was on the sofa. That second fact turns out to be the one worth having years later, so MediaPassport treats it as a first-class column rather than a note you might have left.

A watch event with no companion rows is a solo watch. Recording absence rather than writing a sentinel keeps "alone" and "with three people" the same shape of query, and it makes tagging a past watch an INSERT instead of a migration.

The interface leans on it: red means solo, purple means co-watched, so scanning down a season tells you at a glance who you watched each episode with. Companions are named people, not accounts. No invites, no permissions, no second login for somebody who just sat there.

Metadata

Two sources, because neither one is enough.

TheTVDB and TMDB are not equivalent, and the app uses both. Each supplies something the other omits entirely.

TheTVDB: absolute numbering
TMDB omits absolute episode numbers entirely. That matters for anime and for long-running shows, where season-and-episode is not how anyone actually refers to a given episode.
TMDB: streaming availability
Licensed from JustWatch, and TheTVDB has no equivalent. Availability always comes from TMDB regardless of which provider imported the show, because it is the only source that has it.
One interface, either source
Both implement MetadataProvider, and nothing outside src/lib/providers/ imports either one directly. Adding a third source is one new file.
Cross-referenced, never guessed
A show imported from TheTVDB still gets the availability panel, because TheTVDB's remoteIds carry the TMDB id and it is stored at ingest. A show with no cross-reference simply gets no panel, never a lookup with the wrong provider's id.
Where to watch

Licensed data, obtained the boring way.

JustWatch has no public API. It is enterprise data-partnership only, and the unofficial scrapers that exist violate their terms. But TMDB licenses this exact data from JustWatch and exposes it on an endpoint the app already has a key for, so it arrives legitimately with no scraping and no second integration.

Two conditions come attached, and both are enforced in the component rather than left to good intentions: JustWatch is credited as the source, and the panel links out to TMDB's page rather than inventing per-service deep links, which the API deliberately withholds. TMDB revokes access for non-compliance, so this is a correctness requirement, not a courtesy.

Results cache for twelve hours, and the panel is omitted entirely when the provider has nothing for your region. A provider outage degrades to a missing section rather than a broken page.

Access

There is no signup page.

Invite-gated everywhere
The gate runs on every account-creation path, not just the join form, so there is no side door left open by a route somebody forgot about.
Single-use codes
Each invite prints one link and burns on use. Codes can be locked to a single email address or given an expiry.
Your server, your disk
Deployed to your own machine under its own service user. No hosted tier, no account with anybody, no viewing history on somebody else's infrastructure.
Room for the rest
The schema was built for media generally rather than television specifically, so film, books, podcasts and music slot in without a rewrite.
Explorable without a key
A demo seed inserts a fake three-season show with specials and two companions, so the tracking interface can be exercised offline before you hold any API token.
Defaults that fit a household
A show can default to "we watch this one together", so the companion is not re-picked for every episode of a series you only ever watch with the same person.
Status

Running.

MediaPassport is the furthest along of the Locke Werks house apps: it is deployed and in daily use on our own infrastructure. Next.js 16, React 19, TypeScript, Drizzle and PostgreSQL, running as its own service user behind our own reverse proxy.

The source is private. For access or a conversation about running your own, write to archon@lockewerks.com.

This product uses the TMDB API but is not endorsed or certified by TMDB. Streaming availability data by JustWatch, via TMDB. Metadata provided by TheTVDB.