I pay for streaming services and they still show me ads. I pay for music and they paywall basic features. I buy ebooks and they track every page I read. So I said fuck it, I'll build my own.
Cinemate is a self-hosted media server with native clients for macOS, Windows, Linux, and iOS. You point it at your media folders, it scans everything, and you get a clean UI to browse and play it all. No subscriptions, no cloud, no tracking. Your files stay on your machine.
Is this vibecoded? Yes. Does it work? Try it out ;)
Server -- Python FastAPI backend that does the heavy lifting. Scans your directories, extracts metadata, generates thumbnails, streams video and audio with HTTP Range support, handles multiple user accounts, and syncs state over WebSocket. Enriches your music library with artist bios, images, and genres scraped from Spotify (no API key needed). Auto-discoverable on your LAN via Zeroconf.
Mac app -- Native SwiftUI. Has a full music player with album art, queue management, shuffle, keyboard shortcuts, and media key support. Also connects to the server for movies, TV, and books. Scans local directories for audio files and watches for new ones automatically.
Windows/Linux app -- Electron + React + TypeScript + Tailwind. Connects to your Cinemate server and gives you movie/TV browsing with genre rows, quality filters, a video player with progress tracking, multi-account support, and an admin panel. Works offline with a local SQLite fallback.
iOS app -- SwiftUI. Movies, music, books, TV shows. Connects to the server just like the desktop apps.
cd server
pip install -r requirements.txt
python3 -m uvicorn main:app --host 0.0.0.0 --port 9876That's it. API docs are at http://localhost:9876/docs. The server broadcasts itself on your LAN -- client apps will find it automatically.
macOS (requires macOS 14+):
cd mac
bash build.sh
open ~/Desktop/Cinemate.appWindows/Linux:
cd windows
npm install
npm run dev # dev mode
npm run build # production buildiOS: Open ios/CinemateApp in Xcode and run on your device.
Either hit the scan endpoint through the API docs, or use the "Scan Folder" button in any client app. Point it at your movie/music/book directories and Cinemate handles the rest -- metadata extraction, thumbnail generation, album art, the whole thing.
- Full player with play/pause, skip, shuffle, repeat, volume
- Artist and album detail views -- click an artist name anywhere and it takes you to their page
- Artist profiles enriched with bios, images, and genres pulled from Spotify and Wikipedia (no API credentials needed -- uses anonymous tokens)
- Smart genre classification that backfills missing genres from Spotify data across your whole library
- Playlists with custom cover photos and descriptions
- Favorites and play counts that persist across sessions
- Sort by title, artist, album, duration, or recently added
- Keyboard shortcuts (space for play/pause, arrows for skip, Cmd+F for search)
- System media key integration (play/pause/next/prev from your keyboard)
- Right-click context menus on any track
- Queue panel with drag-to-reorder
- Auto-detects new audio files dropped into your library folder
- Waveform visualization (server-generated)
- Audio streaming with HTTP Range support
- Directory scanning with automatic metadata extraction
- Thumbnail generation
- Genre browsing, quality filters (4K/1080p/720p), search
- Video player with progress tracking and resume
- Continue watching, recently played, favorites
- Multi-account with optional PIN protection
- Library scanning for ePub and PDF
- Reading progress tracking (auto-detects when you finish a book)
- Bookmarks with optional notes on any page
- Favorites
- Currently reading and finished book lists per account
- Multi-account support -- everyone in the house gets their own profile
- LAN auto-discovery via Zeroconf
- WebSocket real-time sync between clients
- Optional WAN access with security middleware
- Works offline -- Windows app falls back to local SQLite
server/ Python FastAPI -- the brain
mac/ macOS app -- SwiftUI + SwiftPM
windows/ Windows/Linux app -- Electron + React + TS + Tailwind
ios/ iOS app -- SwiftUI
The server exposes a full REST API. Key endpoints:
| Endpoint | What it does |
|---|---|
GET /api/music/tracks |
List tracks (filterable by artist, album, genre) |
GET /api/music/artists |
List artists with track/album counts |
GET /api/music/artists/{name} |
Artist detail with albums and tracks |
GET /api/music/artists/{name}/profile |
Enriched artist profile (bio, image, genres from Spotify) |
GET /api/music/artists/{name}/image |
Serve cached artist image |
POST /api/music/artists/enrich-all |
Batch-enrich all artists in your library |
POST /api/music/genres/classify |
Backfill missing genres from Spotify data |
GET /api/music/albums |
List albums (sortable by name, artist, year) |
GET /api/music/stream/{id} |
Stream audio with Range support |
GET /api/music/art/{album_id} |
Serve album artwork |
GET /api/music/waveform/{id} |
Generate waveform data |
GET /api/movies |
List all movies |
GET /api/tv-shows |
List TV shows with seasons/episodes |
POST /api/scan |
Scan a directory for movies |
POST /api/music/scan |
Scan a directory for music |
GET /api/accounts/{id}/playlists |
User's playlists |
POST /api/accounts/{id}/music/history |
Log a play event |
POST /api/accounts/{id}/music/favorites/{track_id} |
Toggle favorite |
Full interactive docs at http://localhost:9876/docs when the server is running.
| Component | Stack |
|---|---|
| Server | Python 3.9+, FastAPI, aiosqlite, Zeroconf, Mutagen, ffmpeg |
| Mac | Swift 5.9, SwiftUI, SwiftPM, SQLite.swift, AVFoundation |
| Windows | Electron, React 18, TypeScript, Tailwind CSS, Vite, better-sqlite3 |
| iOS | Swift, SwiftUI, AVFoundation |
- Server: Python 3.9+, ffmpeg (for thumbnails and waveforms)
- Mac: macOS 14+ (Sonoma), Xcode command line tools
- Windows: Node.js 18+
- iOS: Xcode 15+, iOS 17+
MIT