- Python 63.8%
- JavaScript 20.7%
- CSS 9%
- Kotlin 4.7%
- HTML 1.2%
- Other 0.6%
Self-hosted Qobuz downloader & Navidrome library manager: download albums and discographies as hi-res FLAC, with a review/tag/de-dupe/file workflow, Last.fm recs, in-library badges, auth, persistent queue, and Docker deploy. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| android | ||
| backend | ||
| deploy | ||
| frontend | ||
| tests | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yml | ||
| Dockerfile | ||
| LICENSE | ||
| pytest.ini | ||
| README.md | ||
| run.sh | ||
Quaver 🎵
A self-hosted web app for downloading albums and full artist discographies from your own Qobuz account into a Navidrome-friendly FLAC library — then reviewing, tagging, de-duplicating, and filing them.
Requires an active Qobuz subscription. This uses your own credentials to download your own music for offline/local listening, which Qobuz permits.
How it works
-
On startup it scrapes the Qobuz web-player bundle for the current
app_idand signing secrets (so it survives Qobuz rotating them), then logs in with your credentials to obtain auser_auth_token. -
Search albums or artists, queue a single album or a whole discography.
-
Tracks are requested at the highest quality your tier allows (up to 24-bit/192kHz FLAC), streamed to disk, tagged with mutagen, and filed as:
MUSIC_DIR/<Album Artist>/<Album Title> (Year)/NN - Title.flacMulti-disc albums prefix the filename with the disc number, and a
cover.jpgis saved alongside plus embedded in each file.
Setup
cp .env.example .env # then fill in QOBUZ_AUTH_TOKEN (or email/password) + MUSIC_DIR
./run.sh # creates a venv, installs deps, starts the server
Open http://127.0.0.1:8000.
Docker (recommended for deployment)
cp .env.example .env # fill it in; set MUSIC_DIR to your library path
docker compose up -d --build
.env, the SQLite queue (./data), and your music library are mounted as
volumes, so rebuilds/redeploys never touch them. Published on 127.0.0.1:8000
for nginx to proxy. To deploy an update: git pull && docker compose up -d --build.
Tests
pip install -r backend/requirements-dev.txt
pytest # unit tests for signing, the bundle regexes, validation,
# library matching, auth, import parsing, and persistence
To reach it from your phone on the LAN, set HOST=0.0.0.0 in .env. It has no
auth of its own — keep it behind your VPN / reverse proxy / Tailscale, not on
the open internet, since it holds your Qobuz session.
Layout
backend/app/
main.py FastAPI routes + serves the UI
config.py settings from .env
qobuz/
spoofer.py scrapes app_id + secrets from the web bundle
client.py login, search, metadata, signed file URLs
downloader.py async job queue: fetch → tag → file
tagger.py FLAC tagging + path layout
frontend/ vanilla HTML/CSS/JS UI
Optional integrations
Both are off unless their .env vars are set; the app runs fine without them.
Last.fm — "For You" recommendations. Set LASTFM_API_KEY (free, from
last.fm/api) and LASTFM_USERNAME. A ★ For You button appears in the header.
Since Last.fm's own recommendation endpoint is retired, it derives picks from
your top artists/tracks → their similar artists/tracks, then resolves each to
Qobuz so you can download it. Cached for an hour; ↻ Refresh forces a rebuild.
Navidrome — in-library badges. Set NAVIDROME_URL, NAVIDROME_USERNAME,
NAVIDROME_PASSWORD. The app indexes your library over the Subsonic API and
marks albums already present with a green "✓ In library" badge (refreshed every
15 min; POST /api/library/refresh forces it). Matching is album-level by
normalized artist + album name (edition/remaster suffixes stripped).
Format ids
MAX_FORMAT_ID in .env: 27 = 24/192 (default), 7 = 24/96, 6 = 16/44
CD FLAC, 5 = MP3 320. Qobuz returns the best available up to your request.