A self-hostable TV/movie tracker — built to replicate what TV Time used to be before it shut down (July 2026). Deploy your own instance for you and your friends: track shows/movies, mark episodes watched, see stats, follow friends' libraries. Import your old TV Time data straight from your GDPR export.
backend/ Cloudflare Worker API + D1 database
├── src/
│ ├── index.js main router
│ └── routes/
│ ├── auth.js signup / login / sessions
│ ├── import.js importing a cleaned TV Time export
│ ├── library.js shows, movies, marking episodes watched
│ ├── follow.js follow/unfollow, private profiles
│ ├── stats.js stats screen data
│ └── admin.js invite keys, user management
├── schema.sql D1 database schema
├── wrangler.toml Cloudflare config (D1/KV bindings, env vars)
└── package.json
frontend/ React + TypeScript + Vite app (Cloudflare Pages)
import-cleaner-service/ Standalone Render web service
├── app.py upload your raw TV Time zip, get a cleaned zip back
├── rerun_importer.py the actual cleaning + TVDB ID-resolving pipeline
└── requirements.txt
- Export your data from TV Time (while it's still available, or from a saved
gdpr-data.zip) - Upload it to the import-cleaner-service (deployed separately on Render) — it cleans the messy export and resolves real TMDB/IMDb IDs for every show and movie via TheTVDB's public pages
- Download the resulting
clean-output.zip - Sign up on your deployed Rerun instance (needs an admin-generated invite key), then upload that clean zip on the import screen — it lands in your personal library, ready to go
New users who never used TV Time can just skip straight to using the app.
cd backend
npm install
wrangler login
wrangler d1 create rerun-db # copy the id into wrangler.toml
wrangler kv namespace create TMDB_CACHE # copy the id into wrangler.toml
wrangler d1 execute rerun-db --file=./schema.sql
wrangler secret put TMDB_API_KEY
wrangler deploy
cd frontend
npm install
npm run dev # local dev
npm run build # then deploy the dist/ folder to Cloudflare Pages
Deploy import-cleaner-service/ to Render (or run locally). It's fully
independent of the main site — no login, no shared database, just a
zip-in/zip-out utility.
The very first user needs to be made an admin manually, since invite keys can only be generated by an existing admin:
wrangler d1 execute rerun-db --command="UPDATE users SET is_admin = 1 WHERE username = 'YOUR_USERNAME'"
(run this after you've signed up as that user through the normal signup flow)
- Passwords are hashed (PBKDF2 via Web Crypto), never stored in plaintext — even the admin panel only ever sees hashes.
tvtime/and any*.zipfiles are gitignored — never commit your personal export data.- Change
FRONTEND_URLinwrangler.tomlfrom*to your actual deployed frontend domain before going live, to lock down CORS properly.
Backend API routes: done (auth, import, library, follow, stats, admin). Frontend: in progress, currently wired to mock data — real API integration is the next step.