roon-extension-bandcamp
v0.2.1
Published
Roon extension to browse and play your Bandcamp collection on any Roon zone
Readme
Roon Extension: Bandcamp
Browse and play your Bandcamp collection directly from Roon. This extension lets you stream albums, tracks, and wishlists from Bandcamp to any Roon zone.
Features
- 🎵 Browse your Bandcamp collection — all purchased and wishlisted albums
- ▶️ Play through Roon — stream to any zone with full Roon playback controls
- 🔍 Search Bandcamp — find albums and add them to your queue
- 💾 Queue persistence — resume playback after restarts
- 🔐 Private & secure — identity cookie stays local, never shared
- 🌐 LAN-based — auto-discovers Roon Core via SOOD, no cloud required
Requirements
- Roon Server (2.70+) on your LAN
- Node.js 20+ on a Linux/macOS/Windows host
- Bandcamp account with a collection
- Network access between the extension host and Roon Core
Quick Start
1. Install & Run
git clone https://github.com/hhinnekint/roon-extension-bandcamp.git
cd roon-extension-bandcamp
npm install
npm run build
npm startThe extension starts on http://localhost:3000 and auto-discovers your Roon Core.
2. Configure Bandcamp (in web UI)
- Go to Settings
- Enter your Bandcamp username
- Extract identity cookie:
- Open bandcamp.com → DevTools (F12)
- Application → Storage → Cookies → bandcamp.com →
identity - Copy and paste in Settings
- Click Save
3. Add Live Radio Station in Roon
- Roon → Settings → Audio → My Live Radio → ⊕ Add station
- URL:
http://<extension-host>:3000/stream - Name: "Bandcamp"
- Save
4. Approve Extension in Roon
When you first play something, Roon will ask you to approve the extension. Click Approve in Roon's extension settings.
Done! Your collection is now in Roon.
Architecture
The extension:
- Discovers Roon Core via SOOD multicast on your LAN
- Integrates with Roon's browse API to expose your Bandcamp collection
- Relays signed Bandcamp stream URLs to Roon (Roon does the actual playback)
- Persists your queue and settings in
config/(gitignored)
See docs/protocol-notes.md for reverse-engineering details.
Configuration
Environment Variables
| Variable | Default | Purpose |
|----------|---------|---------|
| ROON_CORE_HOST | (auto-discover) | Roon Core IP (if SOOD fails) |
| ROON_CORE_PORT | 9330 | Roon API port |
| WEB_PORT | 3000 | Web UI port |
| STATION_NAME | Bandcamp | Display name in Roon |
Example: Skip discovery and connect directly:
ROON_CORE_HOST=192.168.1.100 npm startPersistent Storage
config/roonstate.json— Roon pairing token (gitignored, never commit)config/state.json— Credentials, queue, zone selection (gitignored, never commit)
Troubleshooting
Extension not appearing in Roon
- Ensure the extension host can reach Roon Core on port 9330
- Check firewall rules
- Try setting
ROON_CORE_HOSTto force direct connection - Restart Roon if the extension was running before
"no Bandcamp username configured yet"
- Go to web UI Settings and fill in username + identity cookie
- Double-check that the identity cookie is pasted correctly (no extra spaces)
- Try re-extracting the cookie from your browser
Audio doesn't play
- Verify the Live Radio URL is correct in Roon settings
- Check that the extension host can reach bandcamp.com
- Bandcamp stream URLs expire after ~1 hour; skip to next track to refresh
Collection loads slowly
First load can take 30+ seconds with 1000+ items. Subsequent loads are instant. Restart the extension to refresh.
Development
Running Locally
npm install
npm run dev # TypeScript watch + hot reload
npm test # Unit tests
npm run test:integration # Requires Roon Core (ROON_CORE_PRESENT=1)
npm run test:contract # Requires live Bandcamp (BANDCAMP_LIVE=1)
npm run lint # ESLint
npm run build # Compile TypeScript
npm start # Run compiled versionProject Structure
src/
bandcamp/ # Bandcamp scraper & reverse-engineered API client
core/ # Config, logging, types, queue management
roon/ # Roon SDK integration & pairing
web/ # Web UI backend (API + HTTP server)
index.ts # Composition root
test/
unit/ # Unit tests (Vitest)
integration/ # Live Roon Core integration
contract/ # Live Bandcamp scraping tests
fixtures/ # HTML/JSON test data
docs/
protocol-notes.md # Roon API & Bandcamp findings
deploy/
deploy.sh # Production deployment script
roon-bandcamp.service # systemd service (Linux)Key Design Decisions
- No official Bandcamp API — This extension reverse-engineers and scrapes Bandcamp's site
- Schema validation — All Bandcamp responses are validated with Zod; breaking changes fail loudly and are caught by tests
- Roon integration — Uses the undocumented Roon SDK (see
docs/protocol-notes.md) - Security — Identity cookie stays local, logs never expose secrets
- ESM + strict TypeScript — Modern, type-safe codebase with zero implicit any
Known Limitations
- MP3 preview quality only — Full FLAC/WAV only available for purchased tracks
- Unowned tracks — Preview streams are 30–90 seconds; disable in Settings
- Queue doesn't survive restarts — Roon API limitation; the extension persists its queue but Roon doesn't replay it
- No sorting/filtering — Collection order is as returned by Bandcamp
- Single account only — One Bandcamp username per extension instance
Contributing
Contributions welcome! Please:
- Fork and create a feature branch
- Run
npm testto verify - Submit a PR with a clear description
Areas for contribution:
- UI improvements (responsive design, dark mode, album art)
- Performance (caching, pagination)
- Endpoint discovery when Bandcamp changes
- Better error messages
License
MIT — see LICENSE
Disclaimer
This extension is not affiliated with Bandcamp. It uses reverse-engineered endpoints and scraping to provide read-only access to your own collection. Use at your own risk and respect Bandcamp's terms of service.
