libsync

Docker app from JPDVM2014's Repository

Overview

A self-hosted web UI for managing and downloading your Qobuz and Tidal music libraries. Runs as a small FastAPI + SvelteKit server in Docker (or locally) and is accessed through any browser. It syncs your streaming-service favorites into a local database, lets you search and trigger downloads with live progress, and organizes the files on disk with your preferred folder/track templates. Both Qobuz and Tidal go through standalone async Python SDKs (consumed as a git submodule) — no CLI, no TOML config, no hidden state.

Libsync

A self-hosted web UI for managing and downloading your Qobuz and Tidal music libraries.

Runs as a small FastAPI + SvelteKit server in Docker (or locally) and is accessed through any browser. It syncs your streaming-service favorites into a local database, lets you search and trigger downloads with live progress, and organizes the files on disk with your preferred folder/track templates. Both Qobuz and Tidal go through standalone async Python SDKs (consumed as a git submodule) — no CLI, no TOML config, no hidden state.

Libsync started life as a fork of nathom/streamrip and was rebuilt around a web UI. The original rip CLI, the TUI, and the Deezer/SoundCloud source clients are no longer part of this project. See Acknowledgements for credit to the upstream. Some internals (env var names, the on-disk SQLite filename, the .streamrip.json sentinel) still carry the old name to preserve compatibility with existing deployments — those will rename in a future major release.

Features

  • Library browsing — every album you've favorited in Qobuz or Tidal, with cover art, sortable table, and search
  • Album detail — full track list, bit-depth / sample-rate / codec info, per-track download status
  • Search — queries the streaming services directly; results show whether each album is already in your library
  • Downloads — queue albums from the library or search, with real-time per-track progress pushed over WebSocket
  • Playlists — browse Qobuz playlists and queue all referenced albums from a playlist detail panel
  • Sync — manual refresh or scheduled auto-sync to keep local library in step with the streaming service
  • Custom paths — folder/track format templates with live preview in Settings ({albumartist}, {title}, {container}, {bit_depth}, {sampling_rate}, etc.)
  • Filesystem dedup — a .streamrip.json sentinel file per album folder so re-scans and reset-database operations don't re-download work you already have
  • Library scan — fuzzy-matches pre-existing local collections against your synced library (bit-depth-aware, read-only-mount friendly) with a review UI for ambiguous cases and a manual Mark as downloaded button on album pages
  • Artwork embedding — cover art baked into tags at configurable resolution
  • OAuth login for Qobuz and Tidal (browser/device flows, including a headless URL-paste flow for Qobuz)
  • Per-source dedup database so Qobuz and Tidal track IDs never collide

Requirements

  • Docker (recommended) — everything runs inside the image, you just need a folder to mount for music and a volume for the SQLite data
  • or Python 3.10+, Node 20+, poetry, ffmpeg, and access to arthursoares/qobuz_tidal_api_client for the SDK submodule

A premium Qobuz or Tidal subscription is required for downloads. This project doesn't bypass DRM or account restrictions — it uses your own credentials against the streaming services' own APIs.

Quick start — Docker

# clone with submodules so the Qobuz + Tidal SDKs come along
git clone --recursive git@github.com:arthursoares/libsync.git
cd libsync

# build
docker build -f docker/Dockerfile -t libsync .

# run — mount your music folder and a data volume for the SQLite DB
# (env var and volume names retain the legacy `streamrip` prefix for
# now to keep existing installations working — see top-of-README note)
docker run -p 8080:8080 \
  -v ~/Music:/music \
  -v streamrip-data:/data \
  -e STREAMRIP_DB_PATH=/data/streamrip.db \
  libsync

Open http://localhost:8080 and follow the first-time setup below.

If you forgot --recursive, you can initialize the submodule after the fact:

git submodule update --init --recursive

Using Docker Compose

Prefer compose? A ready-to-use file is at docker-compose.example.yml. It pulls the published image from GHCR — no clone, no local build:

curl -O https://raw.githubusercontent.com/arthursoares/libsync/main/docker-compose.example.yml
docker compose -f docker-compose.example.yml up -d

Config, credentials, and the library database land in ./data next to the compose file — back that directory up to preserve your setup. Downloaded music goes to ./music; edit the volume mapping if you want it elsewhere.

The :latest tag tracks stable releases. Swap to :main or :dev if you want rolling branch builds.

Quick start — local dev

git clone --recursive git@github.com:arthursoares/libsync.git
cd libsync

# install backend deps + both SDKs from the submodule
make deps
poetry install

# install frontend deps
cd frontend && npm install && cd ..

# build frontend + run backend with hot-reload on :8080
make dev

Separate targets if you want more control:

  • make dev-backend — backend only, assumes backend/static/ already has a built frontend
  • make dev-frontend — frontend only with Vite hot-reload, proxied to a running backend
  • make test — unit tests (no credentials needed; ~1s)
  • make lint — ruff check on backend/
  • cd frontend && npm run check — Svelte typecheck / diagnostics
  • node --test frontend/tests/*.test.js — lightweight frontend logic tests
  • make docker — build and run the Docker image

First-time setup

  1. Open http://localhost:8080Settings.
  2. Qobuz — click Login with Browser to run the OAuth flow. On a remote/headless host, use Headless Login instead: run the flow on a machine with a browser, copy the redirect URL, paste it into the box.
  3. Tidal — click Connect Tidal to start the device-code OAuth flow. The Settings page opens the approval URL and polls automatically until authorization completes.
  4. Set Download Path to /music (Docker) or your preferred local path.
  5. Choose your Qobuz Quality tier and adjust folder / track format templates if needed. The Settings page has a live preview.
  6. Optional: use Scan Downloads to reconcile any existing music collection on disk with the library. Fuzzy-matches Artist/Album/ folders by tags + bit-depth, auto-marks exact matches, and surfaces ambiguous cases for manual confirmation. For read-only mounts (NFS/SMB), turn Write sentinel file off before running.
  7. Click Save.
  8. Go to LibraryRefresh Library to pull in your favorites.

Architecture (one-paragraph version)

backend/ is a FastAPI app serving both a REST API and a WebSocket channel. frontend/ is a SvelteKit app compiled to static HTML/CSS/JS and served by the backend. State lives in a single SQLite database (backend/models/database.py) — albums, tracks, config, sync history. Streaming-service access goes through arthursoares/qobuz_tidal_api_client, consumed as a git submodule at sdks/qobuz_api_client/, which provides two separate Python packages: qobuz and tidal. Each exposes an AlbumDownloader with progress callbacks that the backend wires to WebSocket events. There is no CLI, no TOML config file, no hidden process — everything the app does is controlled from the Settings page and persisted in the SQLite DB.

For more detail see docs/WEB_UI.md, frontend/README.md, and CLAUDE.md.

Repo layout

libsync/
├── backend/           FastAPI app (REST + WebSocket)
│   ├── api/           Route modules (library, downloads, sync, auth, config, websocket)
│   ├── services/      Library, download, sync services wiring the SDKs to the DB
│   ├── models/        SQLite schema + Pydantic request/response models
│   └── main.py        create_app factory + lifespan
├── frontend/          SvelteKit app
│   └── src/lib/       Components, stores, API client, design system
├── sdks/
│   └── qobuz_api_client/     Git submodule: qobuz + tidal Python SDKs
├── tests/             Pytest suite covering backend services, API routes, database
├── docker/Dockerfile  Multi-stage build (Node → Python)
├── docs/WEB_UI.md     Full architecture + API reference
├── CLAUDE.md          Architecture notes for AI assistants working in the repo
├── Makefile           Dev/test/build/run targets
└── pyproject.toml     Poetry, 3.0.0, backend-only

Contributing

Bug reports and PRs are welcome. Please run make test and make lint before opening a PR. For non-trivial changes, open an issue first so we can agree on the approach.

Acknowledgements

The original nathom/streamrip — this fork started from there and inherited the Qobuz/Tidal client logic, the tagging helpers, and the MQA decryption primitives. Most of that code now lives in the standalone qobuz_tidal_api_client SDK, but the design and much of the hard-won protocol knowledge came from upstream. Thanks to nathom, Vitiko98, Sorrow446, DashLt, and the projects that inspired streamrip in the first place:

Disclaimer

This software is for personal use with your own legitimately-purchased streaming subscriptions. You are responsible for complying with the terms of service of Qobuz and Tidal. The authors take no responsibility for how you use it.

License

GPL-3.0-only, same as the upstream nathom/streamrip project.

Install Libsync on Unraid in a few clicks.

Find Libsync in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.

Open the Apps tab on your Unraid server Search Community Apps for Libsync Review the template variables and paths Click Install

Related apps

Explore more like this

Explore all

Details

Repository
ghcr.io/arthursoares/libsync:latest
Last Updated2026-07-15
First Seen2026-05-22

Runtime arguments

Web UI
http://[IP]:[PORT:8080]/
Network
bridge
Shell
sh
Privileged
false
Extra Params
--user 99:100

Template configuration

WebUIPorttcp
Target
8080
Default
8080
Value
8080
MusicPathrw

Where downloaded music is stored.

Target
/music
AppdataPathrw
Target
/data
Default
/mnt/user/appdata/libsync
Value
/mnt/user/appdata/libsync
STREAMRIP_DB_PATHVariable
Default
/data/streamrip.db
Value
/data/streamrip.db