🎞️ I Built a Free Windows App to Catalog My Movie Hoard — Sharing It

:hammer_and_wrench: Built for Myself, Free for You — CineLibrary, Open Source

Long-time movie hoarder. Built a tiny Windows app so my external drives finally stop feeling like a graveyard. Free, MIT, no server nonsense.

Four Seagate externals. A few thousand movies. No idea what’s on which drive.
Plex wants to be a server. Kodi wants my living room. Everything else wanted to re-scrape my whole collection with its own scheme.
So I wrote my own. CineLibrary.

Think of it as a bookshelf, not a cinema. It just shows you what you own — plugged in or not.


🎬 What It Is?

A Windows app that reads your existing Movie folders and TV Shows folders turns them into one searchable, poster-filled library. It doesn’t play movies. It doesn’t run in the background. It doesn’t want an account. You open it, see every movie you own across every drive, double-click to play in whatever your default player is. That’s it.

Works with Windows 10 (19041+) / Windows 11, 64-bit
Costs $0 — MIT licence, source on GitHub
RAM ~60 MB with ~1,500 movies loaded
Startup Under 1 second
Installer 42 MB, portable — move the folder, keeps working
🧰 The One Thing You Need First — MediaElch

CineLibrary doesn’t fetch data from the internet. It reads what’s already next to your movies. That data has to come from somewhere, and that somewhere is MediaElch — a free scraper that drops three files next to each movie:

File What It Holds
movie.nfo Plot, year, genre, cast, rating (plain text)
poster.jpg The cover art you’d see on Netflix
fanart.jpg The wide backdrop for the detail view

Run MediaElch once, let it scrape. Point CineLibrary at the same folders. Done. If you already set up Kodi or Plex before, those .nfo files are probably already there — skip the scrape step.

:link: MediaElch — free, Windows/Mac/Linux

💡 Stuff I Built Because It Annoyed Me Personally
Problem How CineLibrary Handles It
Drive letters change when I swap USB hubs Drives tracked by hardware ID, not letter
All my externals named “Seagate Backup Plus Drive” Rename inside the app — “Seagate 5TB Bollywood” etc.
Drive unplugged = movies vanish from catalog Still shown, marked OFFLINE with poster intact
Deleted movies leave ghost entries Orphan detector flags them, one click cleanup
Don’t want random folders scanned Per-folder opt-in per drive, not whole-drive scan
Plex eats 500+ MB RAM just to sit idle Native WinUI 3, no hidden browser, ~60 MB

:light_bulb: The giveaway this was built by a hoarder: the orphan cleanup screen exists. That’s the kind of feature you only add after it bites you.

🧭 Where This Fits vs Plex / Kodi / Jellyfin
Tool What It Is What It Wants
Plex Netflix clone, self-hosted A PC running 24/7, an account
Jellyfin Free open-source Plex A home server + setup time
Kodi Living-room media centre A TV-connected PC, full-screen takeover
CineLibrary Offline catalog Nothing — open it, close it, done

You can run CineLibrary alongside any of them — they all read the same MediaElch files. Use Plex to watch on the TV. Use this to remember what you own on the laptop.

🛠️ Setup in 5 Steps

1. Install MediaElch, point it at your movie folders, let it scrape.
2. Download CineLibrary portable .exe from releases — 42 MB.
3. Drop the folder anywhere (Desktop, Documents, even an external drive).
4. First launch: add a drive → pick which folders to scan per drive.
5. Rename your drives to something useful. Done.

First scan takes a few minutes per ~1,000 movies. After that it just opens.

🚧 What It Doesn't Do Yet
  • Windows only (WinUI 3 is Windows-native — no Mac/Linux)
  • No built-in scraper (that’s MediaElch’s job)
  • No streaming or casting — plays via your default player locally
  • Single user, desktop only

file an issue. Feature requests welcome — this is very much a “built for myself” project, so I’m sure I missed obvious stuff.


:high_voltage: Quick Hits

Want Do
:bullseye: Download Latest release
:scroll: Source GitHub repo
:film_frames: Scraper first MediaElch
:bug: Bug / feature GitHub Issues
:prohibited: Skip this if You have one drive with 20 movies — just use Explorer

Built for myself. Sharing it because someone out there has the same mess.

CineLibrary-v1.3.0-Portable-Setup.exe

What about for linux?
:face_with_medical_mask:

I have tried to make it multi-platform but honestly Electon overload makes it too slow that was too frustrating.
If you are interested can look it here, and fork it if you wish to. That is totally separate release.
CineLibrary (Electorn)

Thanks @Aung_Ko_Ko

v2.0.0 Major Release is live now!

:sparkles: New things you can do

  • Make your own lists. Right-click any movie → Add to list (or use the :bookmark_tabs: Add to list button in the detail dialog) and drop it into a list of your own — Date night, 80s sci-fi, Rewatch list, anything. Each list appears in the sidebar with a count.
  • Copy a list to a folder. Right-click a list in the sidebar → Copy movies to folder… — pick any drive or folder, and CineLibrary copies every movie’s full folder (video + posters + .nfo + extras) there. Asks once before overwriting if anything’s already at the destination. Skips offline movies and tells you which drive(s) to plug in.
  • Continue Watching. Anything you’ve hit Play on but haven’t marked Watched shows up in this sidebar shortcut — most-recently-played first. Disappears once you mark it Watched.
  • Recently Added. A sidebar shortcut sorted by when each movie was added to the catalog.
  • Surprise me. A random unwatched pick — prefers movies whose drive is connected so you can play it right away.
  • Notes per movie. Open any movie → :memo: Notes → write your own thoughts, where you stopped, who you watched with. Saved as a tiny cinelibrary-note.txt next to the .nfo so the note travels with the movie folder. MediaElch leaves it alone.
  • Refresh changes. New button on top of the Drives page. After re-scraping in MediaElch, click it — CineLibrary picks up just what you changed, no full rescan needed.
  • Click chips to filter. In the movie detail dialog, click a genre, director, actor, or studio name to filter your library by that.

CineLibrary v2.7.0 — Personal state travels with your drives

Latest

You can finally remove a drive, plug it back in next month, and find every watched mark, favorite, list membership and note exactly where you left them.

:backpack: The problem this fixes

Your watched marks, ★ favorites, :pushpin: watchlist, :bookmark_tabs: list memberships, and :memo: notes are the one thing CineLibrary couldn’t rebuild for you by re-reading a .nfo. Until now, removing a drive in CineLibrary cascade-deleted all of those movies’ rows — and with them, every personal mark you’d made on them. Re-adding the drive later gave you a fresh, blank slate.

:magic_wand: What v2.7.0 does

Every movie that has any personal state attached now gets a tiny sidecar file written into its own folder, right next to the .nfo:

…/My Movies/Inception (2010)/
   ├── Inception.mkv
   ├── Inception.nfo
   ├── poster.jpg
   └── cinelibrary-state.json   ← new

A sample cinelibrary-state.json:

{ “version”: 1, “watched”: true, “favorite”: true, “lastPlayedUnix”: 1747576800, “lists”: [“All Time Great”] }

Live mirroring

Every Mark Watched, Favorite, Watchlist, Play, Add/Remove to list, and note save writes the sidecar immediately. Best-effort, silent if the drive is offline.

Auto-import on scan

On the next scan or rescan, CineLibrary reads any cinelibrary-state.json it finds and merges those values back in. Remove drive → re-add drive → everything’s back.

“Remove Drive” now has a safety net

The Remove Drive dialog shows how many movies on the drive carry personal data and offers a checkbox (default ON): “Save that state to the drive first.” Leaving it ticked guarantees re-adding the drive later restores everything. If the drive is offline, a red warning recommends cancelling until you reconnect.

Per-drive “Sync state” button

Each drive card has a new Sync state action — manually push everything to disk on demand (useful before handing the drive to a friend, after restoring from a DB backup, etc.).

Background catch-up on startup

A quiet sweep at startup mirrors current DB state to disk so anything you’d already marked (before this feature existed, or while a drive was offline) gets exported automatically.

:scroll: The rules

  • DB wins where it already has a value. If you mark something watched on machine A then plug the drive into machine B that already has its own copy, the data on B isn’t overwritten.
  • Lists are additive. A list named in the sidecar that doesn’t yet exist locally gets created; a list the local install has that the sidecar doesn’t mention is never silently dropped.
  • .nfo files are never touched. The only file CineLibrary writes inside a movie folder is cinelibrary-state.json. Posters, fanart, video files — all untouched. A .nfo rescrape in MediaElch can’t disturb your CineLibrary state.

What’s new in v2.8.0 — TV Shows :television:
TV shows, alongside your movies. Any folder with a tvshow.nfo is detected as a show; episodes are read from the SxxExx in each filename. A single drive can hold both — movies are unaffected.
One show page, no drilling. Poster, plot, year · rating · status, a watched roll-up, genre chips and a cast strip up top; below it, each season is a horizontal row of episode cards (Netflix-style).
:play_button: Play next unwatched — jumps straight to the first unwatched episode; reads “✓ All watched” when you’re done.
Per-episode watched, show-level favorite / watchlist. Toggle watched right on each episode card; the progress roll-up updates instantly. Double-click or :play_button: Play opens it in your default player (and marks it watched).
Travels with the drive, just like movies — a per-show cinelibrary-state.json mirrors favorite / watchlist / note + per-episode watched, so removing and re-adding a drive brings your progress back.
Drives page shows a purple SHOWS count pill beside the gold MOVIES pill.
Browse back button — drilling into By Genre / Decade / Rating / Studio / Collections now gives you a “‹ Back” to that page.
Everything from earlier versions (drive-portable personal state, multi-select, brand polish, motion, active filter chips, light-theme tightening) carries forward unchanged.