A robust, AI-powered system for indexing, enriching, and viewing your local movie collection.
Before running the Movie Library Manager, ensure you have the following installed:
- Python 3.9+ - Download Python
- VLC Media Player - Download VLC (for playback functionality)
- Git (optional) - For version control
Install dependencies using pip:
pip install -r requirements.txtThe requirements.txt includes:
google-genai- Gemini AI clientrequests- HTTP client for OMDb API (and the Groq provider, which uses Groq's OpenAI-compatible REST API)python-dotenv- Environment variable management
The optional Groq AI provider needs no extra packages — it talks to Groq's HTTP API using
requests, which is already installed.
Create a .env file in the project root with your API keys:
# Google Gemini API Key (required for AI enrichment with the default provider)
# Get yours at: https://aistudio.google.com/app/apikey
GEMINI_API_KEY=your_gemini_api_key_here
# OMDb API Key (required for movie metadata)
# Get yours at: https://www.omdbapi.com/apikey.aspx
OMDB_API_KEY=your_omdb_api_key_here
# Groq API Key (OPTIONAL - only needed when using the Groq AI provider)
# Get yours at: https://console.groq.com/keys
GROQ_API_KEY=your_groq_api_key_here
# AI provider to use for identification (OPTIONAL, default: gemini)
# Accepts "gemini" or "groq". Can also be overridden per-run with --provider.
AI_PROVIDER=geminiAPI key summary:
| Key | Required? | Used by |
|---|---|---|
GEMINI_API_KEY |
Required for Gemini AI enrichment (the default provider) | --enrich, --full-enrich |
OMDB_API_KEY |
Required for all metadata fetching | --fetch-omdb, --full-enrich, --retry-failed |
GROQ_API_KEY |
Optional — only when using the Groq provider | --provider groq |
AI_PROVIDER |
Optional — defaults to gemini |
selects the default AI backend |
Edit src/config.py to customize:
# Directory to scan for movies (default: E:/)
MOVIE_DIRECTORY = Path("E:/")
# VLC executable path
VLC_PATH = r"C:\Program Files\VideoLAN\VLC\vlc.exe"
# Web server port
SERVER_PORT = 8010- Double-click
MovieLibrary.bat - Select from the menu:
[1]Full Scan - Index all movies from your drive[A]AI Enrichment - Identify movies with AI[B]OMDb Enrichment - Fetch metadata from OMDb[C]Full Enrichment - AI + OMDb pipeline (line by line)[K]Bulk AI Enrichment - Faster, single-call AI mode[L]Full Bulk Enrichment - Bulk AI + OMDb[F]Retry Failed OMDb Enrichments - Re-run movies that failed (state 4)[S]Server - Start web viewer athttp://localhost:8010[D]Cleanup - Remove deleted movie entries
The AI actions (
[A],[C],[K],[L]) prompt you to choose a provider/model: Gemini 2.5 Flash (default), Gemini 3.5 Flash, Groq Llama 3.3 70B, Groq Compound (web-search grounded), or a custom Groq model id. The Groq options requireGROQ_API_KEYin.env.
# Scan for movies
python src/main.py --scan
# Scan with limit (for testing)
python src/main.py --scan --limit 50
# Run AI enrichment (uses the configured/default provider)
python src/main.py --enrich --limit 10
# Run bulk AI enrichment (faster, uses single API call)
python src/main.py --enrich --bulk --limit 100
# Choose the AI provider and model for a run
python src/main.py --enrich --provider gemini --model 2.5 # Gemini 2.5 Flash (default)
python src/main.py --enrich --provider gemini --model 3.5 # Gemini 3.5 Flash
python src/main.py --enrich --provider groq --model llama-3.3-70b-versatile
python src/main.py --enrich --provider groq --model groq/compound # web-search grounded
# Fetch OMDb metadata
python src/main.py --fetch-omdb --limit 10
# Run full pipeline (AI + OMDb)
python src/main.py --full-enrich
# Retry movies that previously failed OMDb (state 4 -> 2, re-run OMDb)
python src/main.py --retry-failed
# Start web server
python src/main.py --server
# Show database statistics
python src/main.py --stats
# Check for missing files
python src/main.py --check-missing
# Remove missing movie entries
python src/main.py --cleanup| Flag | Description |
|---|---|
--scan |
Scan MOVIE_DIRECTORY for video files and index them |
--limit N |
Limit the number of items processed (works with most operations) |
--enrich |
Run AI identification on pending movies (state 1) |
--bulk |
With --enrich: use single-call bulk mode (chunked by BATCH_SIZE) |
--fetch-omdb |
Fetch OMDb metadata for AI-identified movies (state 2) |
--full-enrich |
Run the full pipeline (AI + OMDb) |
--retry-failed |
Reset failed movies (state 4 → 2) and re-run OMDb |
--provider {gemini,groq} |
Choose the AI provider for this run (default: AI_PROVIDER) |
--model M |
Model to use. Gemini shortcuts: 2.5, 3.5; otherwise a full model id (e.g. llama-3.3-70b-versatile, groq/compound). For Gemini this sets the formatter/bulk model; the Live-API search model is AI_SEARCH_MODEL (configured separately). |
--sync |
Sync the CSV source of truth into SQLite |
--stats |
Show database statistics (including state breakdown) |
--sample N |
Print N sample records |
--check-missing |
Preview database entries whose files no longer exist |
--cleanup |
Remove database entries for missing files |
--server |
Start the web viewer server |
Once the server is running, open your browser to:
http://localhost:8010
| Feature | Description |
|---|---|
| 🔍 Search | Real-time filtering across title, AI title, file name, genre, actors, director, plot & tags |
| 📂 Filters | Filter by Genre, Decade, and Language |
| 🔢 Sort | Recently added (default), Year ↑/↓, Rating (high→low), Title A–Z |
| 🏷️ Filter chips + count | "Showing X of Y" result count with removable active-filter chips (search term / genre / year / language) |
| ⭐ Your ratings & tags | Rate movies 1–10 and add personal tags in the detail modal; saved via POST /api/update-metadata and persisted to both SQLite and movies.csv. Cards show a "your rating" badge + tag pills |
| 🎲 Surprise me | Open a random movie from the library |
| 🔗 Open on IMDb | Jump to the movie's IMDb page (uses imdb_id) |
| ▶ Play | Launch movies directly in VLC |
| 📂 Open Folder | Open containing folder in Explorer |
| 🔍 Manual Search | Manually search/fix movie data via OMDb |
| ℹ Info | View full movie details in modal |
| 👁️ Views | Toggle Grid / List view modes |
| 🖼️ Posters / ⚡ Auto-Images | Toggle poster visibility / auto-loading for performance |
| 🌗 Theme toggle | Switch light/dark (dark default, persisted to localStorage) |
| ⌨️ Keyboard shortcuts | / focuses search, r surprise me, Esc closes modals, arrow keys move a focus ring between cards, Enter opens the focused card |
| ⭐ Min IMDb filter | Quick Any / 7+ / 8+ rating filter (integrated with the chips + count) |
| 📊 Library stats | Collapsible panel: totals, average IMDb rating, your-rated count, and clickable top-genre chips |
| 🔳 Density | Comfortable / Compact grid (persisted) |
| ⬆️ Scroll to top | Floating button after scrolling |
Premium media dashboard (v1.4.0+): the viewer renders incrementally with a Load more button plus infinite scroll (replacing the old fixed 100-card cap), shows polished skeleton loading and empty / error (with Retry) states, and the detail modal parses extra ratings (Metacritic/Rotten Tomatoes) into score chips with genre/actor chips and a blurred poster backdrop. All toggles persist across reloads.
The admin page matches the viewer's design: segmented Pending / Enriched / Failed tabs
with live counts (the Failed tab surfaces movies that failed OMDb enrichment, state 4, so
you can fix them), a quick search + sort, a premium info modal, skeleton/empty states, and the
same light/dark theme toggle. Each row has inline validation (IMDb tt… id, 4-digit year,
0–10 rating; Save enables only on a valid change) and per-row quick actions to ▶ Play and
📂 open the folder. Failed rows offer a Retry action.
- Recursive Scanning: Deep scan of your drive for all video formats
- Smart Parsing: Extracts title and year from messy filenames
- Duplicate Prevention: Skip already-indexed files automatically
- Two AI providers (choose via
AI_PROVIDERconfig or--provider):- Gemini (default) — a 2-step pipeline:
- Gemini search model (
AI_SEARCH_MODEL, a Live-API model with Google Search grounding) finds the exact movie match and IMDb ID - Gemini formatter model (
AI_MODEL, defaultgemini-2.5-flash) structures the result into clean JSON
- Gemini search model (
- Groq — fast open models (default
llama-3.3-70b-versatile) via Groq's OpenAI-compatible API. Standard models identify from the model's own knowledge (OMDb still verifies by title/year); thegroq/compoundmodels add built-in web-search grounding.
- Gemini (default) — a 2-step pipeline:
- OMDb verifies everything: the AI step only needs to produce a clean official title + year (and an IMDb ID when confident); OMDb is the authoritative metadata source.
- Bulk Mode: identify many movies in a single API call (chunk size set by
config.BATCH_SIZE, default 50 — lower it if a bulk run stalls). - Resilience: per-request timeout (
AI_TIMEOUT_SECONDS, 120s) and automatic backoff/retry on HTTP 429 (rate limit).
- Fetches: Poster, Plot, Genre, Director, Actors, Runtime, Language, Country, Awards, Ratings
- IMDb-verified metadata for accuracy
- Cleanup: Automatically detects and removes entries for deleted files
- State Tracking:
is_activeflag tracks enrichment progress (see the state table below) - Retry:
--retry-failedrecovers movies that failed OMDb (state 4) - Dual Storage: CSV for portability + SQLite for speed
- Premium media-dashboard UI: light/dark theming (dark default, persisted), glassmorphism, and smooth animations — all self-contained (inline CSS/JS + inline SVG icons), CSP-compatible, with no new external dependencies
- Browse controls: sort (recently added / year / rating / title), removable filter chips with a "Showing X of Y" count, surprise-me random pick, IMDb deep links, and keyboard shortcuts (
/,r,Esc) - Personal ratings & tags: rate 1–10 and tag movies in-app; persisted to both the SQLite DB and
movies.csv - Performance: incremental rendering (load-more + infinite scroll) with skeleton loading and polished empty / error (Retry) states for large collections (1000+ movies)
- VLC Integration: One-click playback
- Multi-threaded server: handles concurrent requests so the UI stays responsive
- Security-hardened: binds to
localhostby default; side-effecting actions (/play,/api/open-folder) are POST-only to prevent cross-site triggering; serves a Content-Security-Policy plusX-Content-Type-Options,X-Frame-Options, andReferrer-Policyheaders; static serving is confined toweb/(path-traversal safe)
📂 0_Movie_Project/
├── 📄 README.md # This file
├── 📄 LICENSE # GNU GPLv3
├── 📄 requirements.txt # Python dependencies
├── 📄 .env # API keys (create this)
├── 📄 MovieLibrary.bat # Windows batch launcher (menu)
├── 📄 setup_env.bat # Virtual-environment setup
├── 📂 src/ # Application source
│ ├── main.py # CLI entry point
│ ├── server.py # HTTP server for web viewer
│ ├── config.py # Centralized configuration
│ ├── scanner.py # File system scanner
│ ├── parser.py # Filename parser
│ ├── enricher.py # Enrichment pipeline orchestrator
│ ├── ai_provider.py # AI provider dispatcher (Gemini / Groq)
│ ├── gemini_client.py # Gemini AI integration
│ ├── groq_client.py # Groq AI integration (alternative provider)
│ ├── omdb_client.py # OMDb API client
│ ├── storage.py # CSV/SQLite data layer
│ ├── clean_names.py # Title-cleanup utility
│ └── reset_data.py # Data reset utility
├── 📂 docs/ # Documentation
│ ├── CODE_DOCUMENTATION.md
│ ├── DESIGN_PHILOSOPHY.md
│ ├── CONTRIBUTING.md
│ └── Movie_Project_Requirements.md
├── 📂 web/ # Frontend files
│ ├── index.html # Main viewer page
│ ├── enrichment.html # Enrichment manager
│ └── favicon.png # Browser tab icon
└── 📂 data/ # Generated data
├── movies.csv # Source of truth
└── movies.db # SQLite database
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ SCAN │ => │ AI ENRICH │ => │ OMDb FETCH │ => │ COMPLETE │
│ is_active=1│ │ is_active=2│ │ is_active=3│ │ Web Ready │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
│
v (if failed)
┌─────────────┐
│ FAILED │
│ is_active=4│
└─────────────┘
| State | Meaning | Set by |
|---|---|---|
0 |
Ignored — not a movie / skipped, never processed | manual / parser |
1 |
Pending AI identification | scan |
2 |
AI done, pending OMDb metadata | AI enrichment |
3 |
Success — fully enriched, shown in web viewer | OMDb enrichment |
4 |
Failed — OMDb could not match it (needs manual fix or retry) | OMDb enrichment |
--retry-failed (menu [F]) resets state 4 → 2 and re-runs the OMDb pass.
This recovers transient failures and matches that now succeed via a verified AI
IMDb ID. Movies that still can't be matched return to state 4 and are best
fixed with the web viewer's Manual Search.
| Issue | Solution |
|---|---|
| "VLC not found" | Update VLC_PATH in src/config.py |
| "API key not set" | Add keys to .env file |
| "Permission denied" | Run as Administrator or check folder permissions |
| Movies not showing | Run --sync to refresh database |
| Slow browsing | Disable auto-images in viewer (⚡ button) |
This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.
In brief:
- ✅ You can freely use, modify, and distribute this software
- ✅ You can use it for commercial purposes
⚠️ Any modifications must also be open-sourced under GPL v3⚠️ No warranty is provided
For the full license text, see: https://www.gnu.org/licenses/gpl-3.0.html
Contributions are welcome! Please see the documentation in:
- docs/DESIGN_PHILOSOPHY.md - Project philosophy and design goals
- docs/CODE_DOCUMENTATION.md - Technical implementation details
- docs/CONTRIBUTING.md - Guidelines for contributors