Personal watchlist app with TMDB collections, filters, and Meilisearch-backed library search.
- JavaScript 39.9%
- Python 28.4%
- CSS 22.1%
- HTML 8.2%
- Shell 0.9%
- Other 0.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
- Sticky area is only the top app bar; filters live in main inside a toolbar card - Toolbar uses row clusters for tabs, types, rating, tags, search, and tools - Hero stats align to a tighter grid; main column uses consistent max-width and gap - Footer sticks to bottom via flex shell; update collection-focus selectors - VERSION 1.3.0 Co-authored-by: Cursor <cursoragent@cursor.com> |
||
| static | ||
| templates | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| app.py | ||
| compose.yaml | ||
| deploy.sh | ||
| docker-entrypoint.sh | ||
| Dockerfile | ||
| README.md | ||
| requirements.txt | ||
| update_tmdb.py | ||
| VERSION | ||
Watchlist
A self-hosted personal watchlist app for movies, series, anime, animation, and documentaries.
Built for a clean home-library workflow: quick TMDB search, rich filtering, collection tracking, recent additions, continuation suggestions, and fast local search.
Highlights
-
TMDB-powered add flow
- Search and add movies, TV shows, anime, animation, and documentaries
- Pulls posters, backdrops, overviews, runtime, ratings, languages, and collection info
-
Two main library views
watchlistwatched
-
Rich filters
- Type
- Rating
- Genre
- Language
- Collection / series
- Incomplete collections
-
Collection-aware experience
- Open a full collection view
- See owned vs missing parts
- Bulk-add missing entries
- Mark an entire collection as watched or watchlist
- Hide owned entries while browsing a collection
-
Dashboard sections
- Summary stats
- “Continue these collections” suggestions
- Recently added titles
-
Library search
- Fast internal search across your existing library
- Meilisearch support for better search quality and scalability
- Automatic SQL fallback if Meilisearch is unavailable
Stack
- Backend: Flask
- Database: SQLite
- Metadata: TMDB API
- Search: Meilisearch (optional, recommended)
- Frontend: Vanilla HTML / CSS / JavaScript
Project structure
.
├── app.py
├── update_tmdb.py
├── compose.yaml
├── static/
│ ├── css/style.css
│ └── js/app.js
├── templates/
│ └── index.html
└── db/
└── watchlist.db
Requirements
- Python 3
- Flask
- Requests
- TMDB API key
The production service currently runs with:
python3 app.py- systemd service for app runtime
- optional
docker composefor Meilisearch
Environment variables
Required
TMDB_API_KEY
Optional
MEILI_URL— default:http://127.0.0.1:7700MEILI_MASTER_KEY— optional if Meilisearch is protectedMEILI_INDEX— default:watchlist_items
Run locally
python3 app.py
By default the app listens on:
0.0.0.0:8000
Run Meilisearch
docker compose up -d meilisearch
This starts Meilisearch on:
127.0.0.1:7700
Search behavior
The app exposes a library search endpoint:
GET /api/library-search?q=QUERY&status=watchlist
Search uses:
- Meilisearch when available
- SQLite fallback when Meilisearch is unavailable
So the UI still works even if the search service is down.
Notes
- SQLite database files are intentionally not committed
- Cache / compiled Python files are ignored
- Meilisearch data directory is ignored
- This repo is meant for app source, not runtime data
Deployment workflow
Server setup
Production uses:
- repo checkout in
/home/mrn/watchlist - secrets in
/home/mrn/watchlist/.env - systemd service:
watchlist.service - Meilisearch via
docker compose
Deploy update
cd /home/mrn/watchlist
git pull --ff-only
./deploy.sh
What deploy.sh does:
- validates Python syntax
- ensures Meilisearch is up
- restarts
watchlist.service
Future improvements
- Better autocomplete UI
- Auth / multi-user support
- Better backup / restore helpers
Built for a private home setup on majlis.lab ✨