tidal-collaborative
overview
A self-hosted server that lets multiple Tidal users collaboratively sync playlists in real time. Sign in with your Tidal account in any browser, link a playlist, and every change — adds and removes — propagates to all collaborators automatically within 30 seconds.
Designed to run on a home server or NAS (CasaOS, Debian, etc.) via Docker. Users must be on the same home LAN or connected via VPN.
Additional features include: an activity log (full audit trail of every change with who, what, and when), an invite-code system for private shared playlists, an admin panel for managing playlists and users, track deletion (removes a track from the shared playlist and all linked Tidal playlists at once), per-user sync status indicators (surfaces rate limits and expired sessions), and a browser-guided first-run setup wizard that generates secrets and walks through Tidal app registration.
tech stack
Server: Node.js 20 LTS, Express 4, ws (WebSocket), better-sqlite3 (SQLite), express-session.
Auth & encryption: Tidal OAuth 2.1 PKCE — handled entirely server-side, no tokens ever touch the browser. Tidal access and refresh tokens are encrypted at rest with AES-256-GCM using a key stored in the database (or overridden via env var).
Container: Docker on node:20-alpine, multi-platform (amd64 + arm64). Image published to Docker Hub.
Web UI: Vanilla HTML/CSS/JavaScript — no frameworks or build step.
Observability: prom-client — exposes a /metrics endpoint compatible with Prometheus and Grafana.
architecture
The server polls each linked Tidal playlist every 30 seconds, detects added/removed tracks via set-difference against the SQLite state, writes changes to the shared playlist table, calls the Tidal API to propagate those changes to every other linked user's playlist, and pushes real-time notifications to all open browser tabs over WebSocket.
Secrets (encryption key, session secret) are auto-generated on first run and stored in SQLite. Setting the corresponding env vars overrides the database values, which is useful for existing deployments or deterministic local dev.
A first-run setup wizard in the browser handles Tidal OAuth app registration, admin PIN creation, and the redirect URI calculation.
development
The entire persistent state is one SQLite file (docker/data/db.sqlite), making backups trivial.
Roadmap: granular view-only collaborator permissions, configurable poll interval per playlist, pagination for large playlists (>500 tracks).