A theater-themed media library manager and launcher for Windows. Scans your local media folders, enriches titles with IMDb data via the OMDb API, and opens your selection directly in VLC β all wrapped in a dark velvet-and-gold Qt GUI.
- Recursively scans categorized media folders (Movies, TV, Anime, etc.)
- Ignores blacklisted directories and hidden/system files via configurable rules in
settings.py - Filters titles live as you type in the search bar
- Downloads and caches movie/series posters from IMDb
- Falls back to a default poster when an image is unavailable
- Cards display: poster, IMDb rating, year, runtime, watch-time estimate, genre, and truncated plot synopsis
- Pulls the full episode list per season from IMDb
- Compares against video files detected on disk
- Shows a completeness badge per title:
- β Complete β all episodes accounted for
- β¬ Upgrades available β episodes missing from local collection
- β No data β not yet fetched
- Movies: runtime from IMDb
- TV series: per-episode runtime Γ number of local video files
- Displayed in human-friendly format (
2h 15m)
- Detects whether VLC is running before attempting playback
- Enqueues the title's folder into the existing VLC instance (playlist-enqueue)
- Paths are configurable for both VLC and your media root
- Edit
settings.pythrough a built-in Qt modal β comments and blank lines are preserved - Atomically rewrites only the values you change
- A companion HTML/JS web app (
_collection_tool/) for tracking manual collection progress - Persists input to
localStorage - Status-coded entries with copy support
- Redirects
stdout/stderrto/dev/nullunderpythonw.exeso silent failures don't crash the app - Debug prints for VLC launch paths
Osyra/media_mimic/
βββ main.py # Entry point, Qt GUI, card grid, detail panels
βββ requirements.txt # Python deps (pinned)
βββ settings.py.example # Example config β copy to settings.py
βββ zzz_launcher.bat # Windows launcher: venv check, pythonw.exe, detach
βββ core/
β βββ paths.py # Project-root-relative Path helper
β βββ library.py # Scan titles, posters, ratings, watch time, episode audit
β βββ omdb_client.py # Cached OMDb API client + clean_title()
β βββ settings_io.py # Read/write settings.py preserving comments
β βββ enrich.py # CLI enrichment runner (writes _cache/report.json)
β βββ title_overrides.py # Folder-name β OMDb title fixes for illegal chars
βββ _collection_tool/
β βββ index.html # Standalone web UI
β βββ script.js # Status-flag logic, localStorage sync
β βββ style.css # Layout + colors
β βββ theme.css # Dark theme variables
β βββ version.js # Version constant (2026.06.08@09.00)
βββ assets/
β βββ icon.png # App icon (PNG fallback)
β βββ icon.ico # Windows taskbar icon
βββ posters/ # Downloaded posters live here (gitignored except placeholder)
βββ _cache/ # OMDb response cache (gitignored)
βββ venv/ # Python virtual environment (gitignored)
| Layer | Technology |
|---|---|
| GUI | PySide6 (Qt 6 for Python) |
| Threading | QThread + QObject worker pattern for non-blocking OMDb fetches |
| HTTP | urllib (stdlib) β zero external HTTP deps |
| Cache | Local JSON file (_cache/omdb_cache.json) |
| Video | subprocess β VLC with shell-escaped paths |
| Web tool | Vanilla HTML/CSS/JS, no build step |
| Launcher | Batch file with venv sanity checks |
- Python 3.9+
- VLC Media Player installed at the path set in
settings.py - VLC running in the background before clicking Play (the app enqueues to the existing instance)
git clone https://github.com/osyra42/media_mimic.git
cd media_mimicpython -m venv venv
venv\Scripts\pip install -r requirements.txtWindows (PowerShell):
python -m venv venv
.\venv\Scripts\pip install -r requirements.txtCopy the example settings file and edit it:
cp settings.py.example settings.pyEdit settings.py:
window_title = "Media Mimic"
app_icon = "icon.png"
media_path = "Z:/" # <-- your media root
poster_path = "posters"
default_poster = "default.jpg"
blacklisted_directories = ["$RECYCLE.BIN", "System Volume Information", "#media_mimic"]
blacklisted_starting_characters = ["_"]
omdb_api_key = "YOUR_OMDB_KEY_HERE" # <-- free tier at omdbapi.comNote:
vlc_pathis hardcoded inmain.py(C:/Program Files/VideoLAN/VLC/vlc.exe). Update it there if your VLC lives elsewhere, or patch the launcher to read it fromsettings.py.
Option A β launcher (recommended):
zzz_launcher.batOption B β manual:
venv\Scripts\pythonw.exe main.pyOn first launch, the app will show a splash overlay while scanning your library. Cards build in the background.
Click β Settings β Fetch Online Data to pull ratings, posters, watch times, and episode data from IMDb.
- Free OMDb tier: 1,000 requests/day, resets at midnight UTC.
- A live countdown is shown in the fetch modal.
- Check Force re-fetch to bypass the local cache.
| Setting | Type | Default | Description |
|---|---|---|---|
window_title |
str |
"Media Mimic" |
Title bar text |
app_icon |
str |
"icon.png" |
Relative path to app icon |
media_path |
str |
"Z:/" |
Root folder containing category subfolders |
vlc_path |
str |
"C:/Program Files/VideoLAN/VLC/vlc.exe" |
VLC executable |
poster_path |
str |
"posters" |
Folder for downloaded posters |
default_poster |
str |
"default.jpg" |
Fallback poster image |
blacklisted_directories |
list |
see above | Folder names to skip entirely |
blacklisted_starting_characters |
list |
["_"] |
Prefixes that hide folders |
omdb_api_key |
str |
"" |
OMDb API key (required for all online data) |
- Cache first: Every
lookup_titleand season/episode call is cached to_cache/omdb_cache.json. Offline browsing works for previously-fetched titles. - Rate limits: The free tier is 1,000 req/day. The GUI surfaces a UTC countdown so you know exactly when you can fetch again.
- Cache busting: Use the Force re-fetch checkbox or the β³ button on an individual card's detail panel.
Run the full enrichment pipeline without the GUI:
python core/enrich.pyProcess a single title (substring match):
python core/enrich.py "American Dad"Outputs a JSON report to _cache/report.json.
library.scan_titles()walksmedia_path/and yields(category, title, title_path).omdb_client.cached_info(title)pulls the cached (or freshly-fetched) OMDb dict without hitting the network.library.get_rating(),library.total_watch_minutes(), andlibrary.episode_audit()enrich that dict.- Cards are
QPushButtonsubclasses arranged in aQGridLayoutper category. - Search filters reflow the grid live by hiding/showing individual cards and empty category headers.
"VLC Not Found"
- Make sure VLC is running before you click Play.
- Verify
vlc_pathinmain.pymatches your VLC install location.
"OMDb rejected the request"
- You hit the 1,000 req/day ceiling. Wait for midnight UTC, or upgrade to a paid OMDb tier.
- Double-check your
omdb_api_keyinsettings.py.
No posters loading
- Confirm the
posters/folder is writable. - Ensure
omdb_api_keyis set and you have remaining API quota. - Check that your folder names match IMDb titles (see
title_overrides.pyfor known fixes).
Cards show "β No data"
- The title hasn't been fetched yet. Open Settings β Fetch Online Data.
- If a title still shows "No data" after fetching, add an entry to
core/title_overrides.pywith the correct OMDb name.
Branches are short-lived. PRs should be scoped and self-contained.
git checkout -b feat/your-thing
# work, test, then:
git commit -am "feat: describe your change"
git push -u origin feat/your-thingOpen a PR against main.
MIT β use it, break it, fix it however you want.