v0.3.0 — Self-hosted first, artwork-forward redesign
Note
Superseded on the cloud-hosting question. The finding below — that YouTube
refuses datacenter IPs and cookies don't lift it — still holds. The conclusion
drawn from it does not: the refusal isn't uniform, and
v0.5.0 makes cloud
hosting work by falling back through a pool of proxies. Home hosting is still
the simplest path.
Syncwave is now self-hosted first — it runs on a machine you own, and it looks the part.
🏠 Runs at home, by design
Cloud one-click deploys were removed. Testing on a cloud host with a valid logged-in cookies.txt, a working JS runtime, and all five yt-dlp player clients, every request was refused with "Sign in to confirm you're not a bot" — YouTube blocks datacenter IP ranges, and cookies don't lift it. The same build on a home connection works with no cookies at all. Shipping those buttons would have sent people to an app that can't play music.
Three ways to run it now:
- 🖱️ Double-click a file —
start.bat(Windows) or./start.sh(macOS/Linux). Installs, builds, starts, opens your browser, and prints the LAN address to share. Rebuilds itself when you update. - 🐳 Docker —
docker compose up -d --build - 🐧 One command —
curl -fsSL .../scripts/install.sh | sudo bash
ffmpeg now ships with it, so a desktop user needs nothing but Node.
🎨 Redesigned around the artwork
- Now Playing panel — large cover art with a colour halo, live equalizer, and who's listening. Its own tab on mobile, a dedicated column on wide screens.
- Rebuilt player — identity left, transport centred, volume and reactions right. The old 4px hairline is a real scrubber with elapsed/remaining, keyboard support, and buffer fill while a track caches.
- Fixed the ambient backdrop — a saturated album cover used to flood the whole app and wreck text contrast. It's now mood lighting under a two-layer scrim.
- Volume control, per listener, remembered across visits. Position stays shared; loudness is yours.
- Real empty states, queue numbering and run time, and
prefers-reduced-motionsupport.
🔐 Setup and security
- First-run wizard at
/setup— set an admin password, optionally upload YouTube cookies, optionally enable the AI DJ. /adminis now behind that password. It previously wasn't: anyone who could reach the instance could read your LLM configuration and change it./api/settingsis gated too.- Upload
cookies.txtfrom the browser — validated on upload, stored0600, applied to the very next track without a restart. Clear messages for the usual mistakes (JSON export, wrong site, exported while signed out).
🛠️ Fixes
- yt-dlp failures say what went wrong. Its stderr was read for progress then discarded, so any failure produced an empty trace. Bot-checks, unavailable tracks, and everything else now report a real reason.
- Deno is installed in the image — yt-dlp needs a JS runtime for YouTube's player challenge and was silently falling back to limited clients.
YTDLP_PROXYfor anyone who must run on a datacenter IP.- Join with a room code from the home page. Guests told a code aloud previously had no way in.
Upgrading
git pull && docker compose up -d --buildYour rooms, settings, and cache are preserved. On first load you'll be sent to /setup to claim the instance with an admin password — do this before sharing the address.