A Python CLI application to manage personal movie collections with multi-user profiles, OMDb API lookups, and static website generation. Each user has an isolated library, and posters link to IMDb. Notes added to movies appear as a tooltip when hovering the poster.
- Multiple user profiles with isolated movie lists
- Add/delete/update/search/list movies
- Update notes shown as poster tooltips on the website
- Stats per user: average, median, best/worst rating
- Random movie picker and rating sort
- Website generator per user (e.g.,
John.html) with responsive grid - OMDb integration for title, year, rating, poster, and IMDb ID
- Environment-based API key loading
- Python 3.10+
- SQLite + SQLAlchemy (Core)
- Requests
- python-dotenv
- HTML/CSS for static website output
project_root/
├─ movies.py # CLI entry point
├─ README.md
├─ requirements.txt
├─ .gitignore
├─ .env # contains OMDB_API_KEY
├─ data/
│ └─ movies.db # SQLite database
├─ static/
│ ├─ style.css
│ └─ index_template.html
└─ movie_storage/
├─ init.py
└─ movie_storage_sql.py
- Python 3.10 or newer
- Internet access for OMDb API
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt`requirements.txt` should include:
sqlalchemy
requests
python-dotenvCreate a .env file at the project root:
OMDB_API_KEY=your_omdb_api_key_here
python movies.py
- Select or create a user profile at startup.
- Use the menu to add/list/update/delete movies, get stats, etc.
- Choose “Generate website” to build
<username>.html.
When you run python movies.py, you’ll see:
Menu:
0. Exit
- List movies
- Add movies
- Delete movies
- Update movies
- Stats
- Random movie
- Search movie
- Movies sorted by rating
- Generate website
- Switch user
- Add a movie: fetches data from OMDb (Title/Year/IMDb rating/Poster/IMDb ID)
- Update movie: prompts for a note; saved to DB; shown as tooltip on poster hover
- Generate website: produces
<username>.htmlusingstatic/index_template.html
Tables are created automatically if missing.
-
usersid INTEGER PRIMARY KEY AUTOINCREMENTname TEXT UNIQUE NOT NULL
-
moviesid INTEGER PRIMARY KEY AUTOINCREMENTtitle TEXT NOT NULLyear INTEGER NOT NULLrating REAL NOT NULLposter_url TEXTuser_id INTEGER NOT NULL REFERENCES users(id)note TEXTimdb_id TEXT
If you previously created movies without these columns, either run ALTER TABLEs or drop and recreate the table during development.
- Template:
static/index_template.htmlmust contain the placeholders:__TEMPLATE_TITLE____TEMPLATE_MOVIE_GRID__
- Output:
<username>.html - Each poster is wrapped in an anchor to IMDb:
<a href="https://www.imdb.com/title/{imdb_id}/" target="_blank" rel="noopener noreferrer">
- Poster tooltip uses the movie note via the
titleattribute. - CSS grid is defined in
static/style.css.
Preview locally in a browser or run a simple server: python -m http.server
then open http://localhost:8000/.html
from dotenv import load_dotenv
import os
load_dotenv()
API_KEY = os.getenv("OMDB_API_KEY")
- HTML escaping for safe tooltips:
import html
note = html.escape(info.get("note") or "") - Always pass
user_idinto storage functions (list/add/delete/update/stats/search/sort/random/generate).
- “Not an executable object” with SQLAlchemy:
- Wrap raw SQL strings with
text("...")before executing. - “table movies has no column named user_id”:
- Your table predates multi-user. Migrate (ALTER TABLE) or drop/recreate during dev.
AttributeError: 'NoneType' object has no attribute 'replace'fromhtml.escape:- Ensure
html.escape(info.get("note") or "")soNonebecomes an empty string. - Posters not showing:
- Ensure
poster_urlis stored and your HTML uses it; fallback to a placeholder if missing. - Links not opening in a new tab or security warnings:
- Use
target="_blank" rel="noopener noreferrer"on external links.
- Open issues/PRs with clear descriptions.
- Keep functions user-specific by passing
user_id. - Avoid dropping tables in production code.
MIT (or your preferred license). Add a LICENSE file if distributing publicly.
- OMDb API for movie metadata and posters.