Turn your TV Time GDPR export into a beautiful, offline archive of everything you watched — shows, episode check-ins, movies, stats — and portable files to migrate anywhere. Built because TV Time is shutting down on July 15, 2026 and deleting all user data.
No account, no API key, no server. You point it at your export, it builds a self‑contained folder you can open in any browser and keep forever.
When TV Time goes dark, your watch history goes with it. Trakt and Simkl can import the raw export for shows + episodes, but nothing gives you a viewer you own or a clean path for your movies. This does both.
git clone <this-repo>
cd tvtime-time-machine
python build.py path/to/your-tvtime-export.zip
# then open output/index.htmlYou need Python 3.8+ (standard library only — no pip install).
Get your export at gdpr.tvtime.com (or email support@tvtime.com, subject "GDPR Data Request"). You'll receive a .zip and a password in a separate email.
python build.py export.zip # a .zip (unencrypted or ZipCrypto)
python build.py export.zip --password PW # a password-protected .zip
python build.py ./my-export-folder # an already-extracted folder
python build.py # auto-detect ./export, ./gdpr-data, or a lone *.zip
python build.py export.zip --link-only # don't download images (posters need internet to view)
python build.py export.zip --no-posters # skip artwork entirely (instant)
python build.py export.zip -o ~/my-archive # choose the output folderThe first run downloads ~1 poster per title, so it takes a few minutes and prints progress (shows 200/295 …). It's resumable — already-downloaded posters and matched URLs are cached, so if you cancel (Ctrl-C) and re-run, it picks up where it left off.
Encrypted zips: TV Time zips are password-protected. Python's standard library can't open AES‑encrypted zips — if
--passwordfails, just unzip it yourself and pass the folder.
index.html |
The viewer — Overview, Shows, Movies, Watchlist, Export. Dark/light, responsive, keyboard-accessible. |
data.js |
Your parsed data. |
posters/ |
Cover art (see below). |
exports/ |
full.json, letterboxd-movies.csv, shows.csv, episodes.csv, watchlist.csv. |
The whole output/ folder is self-contained — copy it to a USB stick, it still works.
Artwork is matched against the public TMDB website (shows by title, movies by title + year) and pulled from TMDB's public image CDN. No API key or account. Images are downloaded into output/posters/ at build time and referenced by relative path, so the archive shows cover art offline, by double-click — no server, no browser storage. Matched URLs and downloaded files are cached (.poster-cache.json + posters/), so re-runs are fast and resumable. Anything that can't be matched falls back to a clean typographic tile. Use --link-only if you'd rather keep the folder tiny and load posters from the CDN on demand (needs internet).
- Trakt / Simkl — upload your original GDPR
.zipon their import pages (they match against TheTVDB). Brings over shows, episode progress, and watchlist. - Letterboxd — import
exports/letterboxd-movies.csvat letterboxd.com/import. - Anywhere else — the CSVs carry TheTVDB ids for shows/episodes and title+year for movies.
Reactions, comments, and social activity don't transfer to any service (no tracker accepts them) but are preserved in full.json.
Everything runs locally. The build reads only your show/movie/watch files and never touches personal files (user*.csv, login, IP, tokens, Facebook/social, devices, friends, sessions, ad ids). Your generated archive and export are git-ignored — you won't accidentally commit them.
build.py reads the CSVs → data model → scrapes posters → writes output/
app/index.html the viewer template (copied into output/ at build time)
Single-file viewer, hand-rolled SVG charts, zero runtime dependencies.
MIT — do whatever you like.