# omniMux
A self-hosted music server that lets you search YouTube, cache tracks to your library, and stream everything through a Spotify-like PWA. Built on top of Navidrome with a FastAPI middleware layer and a SvelteKit frontend.
Your music. Your server. No middlemen.
Live demo β omnimux.wwel.sh (guest access, read-only library)

# Table of contents
# Why omniMux?
Streaming services rent you access to music youβll never own, lock your library behind monthly fees, and vanish the moment licensing deals fall through. omniMux flips that: search YouTube, keep the files on your own hardware, and stream them from anywhere over a PWA you install once. No cloud. No subscription. No gatekeepers. Just your music, on your server.
# Features
# π§ AutoDJBeat-locked crossfades, tempo matching, and realistic pitch/speed slop β plus 10+ music visualizers driven by high-res iTunes album art. |
# π YouTube SearchFind any track and cache it locally. Topic channel results rank first for clean, official-quality audio. |
# πΏ Album DetectionOpen any album and see missing tracks found on YouTube β one-click import fills the gaps. |
# π€ Artist PagesBrowse an artistβs local albums alongside their full YouTube discography in one unified view. |
# π Playlist ImportPaste a YouTube playlist URL β omniMux queues all tracks and builds a matching Navidrome playlist automatically. |
# π§ Mood AnalysisEvery download is analysed for mood, BPM, energy, and key via mood-detector. |
# π± PWAInstallable on desktop and mobile with a responsive mobile mini-player. Works offline once tracks are cached. |
# β‘ Instant SearchServer-side cache (1 h for tracks, 2 h for albums) makes repeated YouTube searches feel instant. |
# π Shuffle & LoopShuffle the queue, loop all, or loop one β the basics, done right. |
# Stack
| Layer | Tech |
|---|---|
| Music server | Navidrome (Subsonic API) |
| API | Python Β· FastAPI Β· yt-dlp Β· ytmusicapi Β· mutagen |
| Frontend | SvelteKit 5 Β· TypeScript |
| Audio analysis | mood-detector |
| Infrastructure | Docker Compose |
# Quick start
Prerequisites: Docker and Docker Compose.
git clone https://github.com/usr-wwelsh/omnimux.git
cd omniMux
Copy .env.example to .env and set a real value for JWT_SECRET:
cp .env.example .env
openssl rand -hex 32 # copy the output into JWT_SECRET below
nano .env
docker compose up -d --build
| Service | URL |
|---|---|
| Web app | http://localhost:8801 |
| API | http://localhost:8800 |
| Navidrome | http://localhost:4533 |
On first run, open Navidrome at :4533, create an admin account, then log into the omniMux web app with those same credentials.
Optional β auto-update: the web UI can show a changelog banner with a one-click update button once you opt in:
sudo ./deploy/install.sh
docker compose up -d
See deploy/README.md for what that installs and why.
Configuration
Most configuration is fixed in docker-compose.yml. Secrets are the
exception β theyβre read from .env (copy from .env.example, gitignored)
so a git pull never conflicts with values youβve set locally:
| Variable | Where | Default | Description |
|---|---|---|---|
NAVIDROME_URL |
docker-compose.yml |
http://navidrome:4533 |
Internal URL of the Navidrome service |
MUSIC_DIR |
docker-compose.yml |
/music |
Where downloaded audio files are stored |
DATA_DIR |
docker-compose.yml |
/data |
Where the SQLite database is stored |
JWT_SECRET |
.env |
change-me-in-production |
Secret used to sign auth tokens β change this |
UPDATER_TOKEN |
.env |
(blank) | Auth for the opt-in auto-update helper (see Quick start above) β set for you by deploy/install.sh |
# FAQ
Why the heck an AutoDJ? Real DJs are great β but who doesnβt want a personal robot DJ running on their own hardware? AutoDJ analyses every track for BPM, key, mood, and energy using deterministic DSP (no AI, no cloud), then crossfades between them with beat-locked transitions. Itβs just math, and it slaps.
Why YouTube? Itβs the largest music catalogue on the planet and the only one without a paywall. Topic channels are officially uploaded by labels and provide near-CD-quality audio for most releases.
Can I use my existing music library?
Yes β drop your files into the MUSIC_DIR volume and Navidrome will scan them. omniMux treats YouTube as an augmentation to your library, not a replacement.
Does it work on iOS? Yes, via the PWA. Safari β Share β Add to Home Screen. Requires HTTPS, so expose it through a reverse proxy or a Cloudflare Tunnel.
Why not just use Spotify? Because you donβt own anything on Spotify. The day they drop a track, raise prices, or go under, your library is gone. omniMux tracks live as files on your disk.
Project structure
music-server/
βββ api/ # FastAPI backend
β βββ routers/ # auth, search, download endpoints
β βββ services/ # youtube, navidrome, download worker, cache
β βββ db/ # SQLAlchemy models + async SQLite
βββ web/ # SvelteKit PWA
β βββ src/
β βββ routes/ # pages (search, library, artist, album, playlists, browse)
β βββ components/ # Player, MiniPlayer, AlbumCard, TrackList, β¦
β βββ lib/ # subsonic.ts, api.ts, player store
βββ docker-compose.yml
# License
MIT Β© usr-wwelsh