The Problem
I have a problem that a lot of people who've been collecting digital media for years will recognize — I had nearly 1,000 movie files spread across multiple drives and absolutely no idea what I actually owned. Was I about to buy a movie I already had? Did I have three copies of the same file hiding in different folders? No idea.
I looked at the existing options. Plex and Jellyfin are great but they're full media servers — I didn't need transcoding or streaming, I just needed a catalog. Spreadsheets work but they're manual. MediaElch was close but not quite what I wanted.
So I built Film Forge.
What It Does
Film Forge is a desktop application for Windows built in Python and Tkinter. Here's the core workflow:
- Add folders — point it at any directory containing video files
- Start Scan — it recursively finds every video file (.mp4, .mkv, .avi, .mov, and more)
- Fetch Details — pulls metadata from the OMDb API for every movie found
- Browse your library — search, filter, rate, and track everything from the Database tab
Everything is stored in a local SQLite database. No cloud. No accounts. No subscriptions.
The Tech Stack
Desktop app: Python 3.13, Tkinter, SQLite, Pillow, pandas, openpyxl
Web server: Flask, Flask-CORS, Gunicorn
Metadata: OMDb API
Deployment: Railway, GitHub
Packaging: PyInstaller, Inno Setup
I chose Tkinter because it's built into Python and requires no additional UI framework. It's not the flashiest toolkit but it gets the job done and keeps the dependency list short.
The Web Interface
One of the features I'm most proud of is the built-in Flask web server. From the Settings tab you can start a local web server and browse your entire movie library from any browser on your network.
Each movie card shows:
- Poster art from OMDb
- Title, year, runtime, MPAA rating, genre, cast
- Full plot summary
- 5-star personal rating (click to set)
- Watched / Unwatch button
The web interface also exposes a REST JSON API:
GET /api/movies # Paginated, filterable movie list
GET /api/movies/<imdb_id> # Single movie detail
POST /api/set_rating # Set 1-5 star rating
POST /api/set_watched # Mark watched/unwatched
GET /api/docs # API documentation
Railway Deployment
For public access, Film Forge supports one-click sync to GitHub and auto-redeploy to Railway. The web server component is a standalone Flask app that reads from a SQLite database file. Point a custom domain at your Railway deployment and your collection is accessible from anywhere.
Packaging for Windows
Building the Windows installer was an interesting challenge. The process:
-
PyInstaller — bundles the Python app and all dependencies into a single
.exe - Inno Setup — wraps the EXE into a polished one-click installer with Start Menu shortcuts, desktop icon, and a bundled PDF user manual
python -m PyInstaller --onefile --windowed --name="FilmForge" \
--icon="Film_Forge.ico" \
--hidden-import=film_forge_db \
Film_Forge_3_7_7.py
The final installer is about 26MB and includes the full application and user manual.
What I Learned
- Tkinter is underrated — it gets a bad reputation but for a desktop utility app it's perfectly capable
- SQLite is incredibly powerful for this use case — a single file database that handles 1,000+ movies without breaking a sweat
- PyInstaller hidden imports will catch you off guard — always test in a clean environment before distributing
- Inno Setup is still the gold standard for Windows installers — free, powerful, and well documented
What's Next
- Android app (WebView wrapper to start, native later)
- Automatic metadata refresh on a schedule
- TV show support
- Better duplicate resolution UI
Links
- Download: github.com/oddbitstudios/Film-Forge/releases
- GitHub: github.com/oddbitstudios/Film-Forge
- Support my effort: buymeacoffee.com/oddbitstudios
Built by Oddbit Studios — independent software, crafted with odd precision.
Top comments (0)