A lightweight, installable (PWA) movie & TV watchlist
Features · Tech Stack · Architecture · Setup · Development
@tailwindcss/postcssvite-plugin-pwasvelte-adapter-deno)./.data/cinelist.kv)Pages are standard SvelteKit routes:
| Route | Description |
|---|---|
/ |
Discover — trending, featured, recommendations, library previews |
/search |
Search results for movies, TV shows, and people |
/library |
Library management, import, and export |
/library/blacklist |
Manage hidden (blacklisted) items |
/movie/[id] |
Movie detail page |
/tv/[id] |
TV show detail page |
/person/[id] |
Person page — biography and credits |
/settings |
Jellyfin integration and custom provider settings |
All TMDB and OMDb calls are server-side only (src/lib/api/). API keys are never exposed to the client.
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/watchlist |
Fetch full watchlist |
POST |
/api/watchlist |
Add an item |
DELETE |
/api/watchlist/[id] |
Remove an item (?type=movie|tv) |
PATCH |
/api/watchlist/[id] |
Toggle state (?toggle=server|watched|rating) |
POST |
/api/watchlist/import |
CSV bulk import |
GET |
/api/featured |
Featured items for the carousel |
GET |
/api/recommendations |
Personalised recommendations |
GET |
/api/people |
Favourite people list |
POST |
/api/people |
Add a favourite person |
DELETE |
/api/people/[id] |
Remove a favourite person |
GET |
/api/blacklist |
Hidden items list |
POST |
/api/blacklist |
Hide an item |
DELETE |
/api/blacklist/[id] |
Un-hide an item |
GET |
/api/graph/keywords |
Keyword edges for the graph view |
POST |
/api/jellyfin/sync |
Sync availability from Jellyfin |
GET |
/api/config/[key] |
Read a config value |
PUT |
/api/config/[key] |
Write a config value |
storage.config.ts via unstorage../.data/cinelist.kv.src/lib/stores/watchlist.ts) and kept in sync via the API.src/lib/stores/people.ts.npm install
Create a .env file at the project root:
# Required — TMDB API key (server-side only, never exposed to the client)
TMDB_API_KEY=your_tmdb_api_key_here
# Optional — OMDb API key for enriched ratings (Rotten Tomatoes, Metacritic)
OMDB_API_KEY=your_omdb_api_key_here
# Optional — comma-separated list of allowed origins for mutating API requests
# Leave unset to bypass CSRF checks (e.g. during local development)
CSRF_ALLOWED_ORIGINS=""
Note:
TMDB_API_KEYandOMDB_API_KEYare private server-side variables accessed via$env/dynamic/private. They are never included in the client bundle.
This project targets Deno as the production runtime (via svelte-adapter-deno).
Start the dev server:
npm run dev
# or
deno task dev
Tip: The default storage backend is Deno KV (
storage.config.ts), which requires the Deno runtime. For a Node-based dev workflow, switch the driver instorage.config.tsto a Node-friendly backend (e.g. filesystem).
Build a production bundle:
npm run build
# or
deno task build
Run the generated Deno server:
deno run -A --unstable-kv build/index.js
To load environment variables from a local .env file:
deno run -A --unstable-kv --env-file=.env build/index.js
Common runtime environment variables:
| Variable | Default | Description |
|---|---|---|
TMDB_API_KEY |
— | Required. TMDB v3 API key |
OMDB_API_KEY |
— | Optional. Enables OMDb rating enrichment |
HOST |
0.0.0.0 |
Bind address |
PORT |
3000 |
Bind port |
CSRF_ALLOWED_ORIGINS |
— | Comma-separated origin allowlist for mutating API requests |
Build the image:
docker build -t cinelist .
Run the container on port 8000:
docker run --rm -p 8000:8000 \
-e TMDB_API_KEY=your_tmdb_api_key_here \
-e OMDB_API_KEY=your_omdb_api_key_here \
cinelist
The watchlist importer accepts a .csv with either:
type, title, originalTitle, year, link, orIf a row contains a TMDB movie link it is used directly; otherwise the importer searches TMDB by title (and year when present).
link to the TMDB movie page or provide title + year.| Command | Description |
|---|---|
npm run dev |
Start the Vite dev server |
npm run build |
Build the production bundle |
npm run preview |
Preview the production build locally |
npm run check |
Type-check with svelte-check |
npm run check:watch |
Type-check in watch mode |
Deno task equivalents (see deno.json):
| Command | Description |
|---|---|
deno task dev |
Type-check then start the dev server |
deno task build |
Build the production bundle |
deno task preview |
Preview the production build |
deno task check |
Type-check with svelte-check |