Integrations Guide
soundspan works standalone, but these integrations unlock additional discovery and playback workflows.
For environment and secret setup, see CONFIGURATION_AND_SECURITY.md.
Lidarr
Connect soundspan to Lidarr to request/download new music and trigger imports.
What you get
- Browse artists/albums you do not own
- Request downloads from soundspan
- Discover Weekly playlist import flows
- Automatic library sync via webhook
Setup
- Open Admin → Download Services
- Enable Lidarr
- Set Lidarr URL (for example
http://localhost:8686) - Set Lidarr API key (Lidarr → Settings → General)
- Test and save
Networking note
Lidarr must reach the soundspan callback URL.
- AIO: default callback uses
host.docker.internal:3030 - Split stack: usually
http://backend:3006on compose network - Custom Docker networking: set
SOUNDSPAN_CALLBACK_URLto a reachable soundspan address
environment:
- SOUNDSPAN_CALLBACK_URL=http://YOUR_SOUNDSPAN_IP:3030
Audiobookshelf
Connect your Audiobookshelf instance for audiobook playback in soundspan.
Audiobook detail metadata and section navigation are served from soundspan's local cache. A scheduled sync keeps that cache in step with Audiobookshelf: it adds new books within a few minutes and removes books that were deleted in Audiobookshelf, together with their cached covers and listening progress. Removals are deliberately cautious: a book is only removed after it has been absent from two complete, verified library listings taken several minutes apart, and an unreachable server or an incomplete listing never triggers removals. Books without a recorded source library are never removed automatically. Scheduled or manual sync also validates chapter coverage and backfills section data for rows that do not have it yet. Multi-file part boundaries are playable because the stream proxy exposes all files as one byte-addressable audiobook resource.
Setup
- Open Admin → Media Servers
- Turn on Enable Audiobookshelf
- Set Server URL (for example
http://localhost:13378) - Set API Key from the Audiobookshelf user settings
- Test and save
Soulseek
soundspan can connect directly to Soulseek for discovery/download flows.
Disclaimer: You are responsible for legal use in your jurisdiction.
Setup
- Open Admin → Download Services
- Enter Soulseek username/password
- Save
Notes
- Discovery results include filename, size, bitrate, and parsed metadata
- Download progress appears in Activity Panel
- Quality/availability depends on peer uptime and speed
- Album downloads prefer one uploader's complete album folder: a folder is only chosen when it covers at least 90% of the requested tracks and its contents clearly belong to the same album. When no folder qualifies, tracks are assembled one by one from the best individual matches.
YouTube Music
Stream unowned tracks via per-user YouTube Music OAuth.
Disclaimer: Uses unofficial libraries (
ytmusicapi,yt-dlp) and requires YouTube Music Premium.
Requirements
- Running
ytmusic-streamersidecar - Google OAuth client configured as "TVs and Limited Input devices"
Admin setup
- Create OAuth client in Google Cloud Console
- Open Admin → YouTube Music
- Enable and set client ID/secret
- Save
Per-user setup
- Open Settings → Integrations → YouTube Music
- Select Open Google Sign-In Page
- Complete the provider authorization flow
- Choose quality and save
Quality settings
| Setting | Approximate bitrate |
|---|---|
| Low | ~64 kbps |
| Medium | ~128 kbps |
| High | ~256 kbps |
| Lossless | Best available |
API access modes
All routes below still require soundspan authentication and
ytMusicEnabled=true. Browse, search, and public stream routes normally work
without a linked account, subject to sidecar availability and provider behavior.
| Mode | Endpoints |
|---|---|
| Normally works without a linked account (sidecar-dependent) | GET /api/browse/ytmusic/charts, GET /api/browse/ytmusic/categories, GET /api/browse/ytmusic/playlist/:id, POST /api/ytmusic/search, POST /api/ytmusic/match, POST /api/ytmusic/match-batch, GET /api/ytmusic/stream-info-public/:videoId, GET /api/ytmusic/stream-public/:videoId |
| Per-user OAuth required | GET /api/ytmusic/album/:browseId, GET /api/ytmusic/artist/:channelId, GET /api/ytmusic/song/:videoId, GET /api/ytmusic/stream-info/:videoId, GET /api/ytmusic/stream/:videoId, GET /api/ytmusic/library/songs, GET /api/ytmusic/library/albums |
Track Mapping and Playlist Import APIs
soundspan also exposes provider mapping and playlist import routes for cross-provider workflows:
| Endpoint | Purpose |
|---|---|
POST /api/browse/playlists/parse |
Parse Spotify, Deezer, YouTube Music, and TIDAL playlist URLs before import |
GET /api/track-mappings/album/:albumId |
Read provider mappings for an album's local tracks |
POST /api/track-mappings/batch |
Persist multiple mapping links in one request |
POST /api/import/preview |
Resolve playlist tracks (local/YT/TIDAL) without creating a playlist |
POST /api/import/execute |
Create a playlist from a resolved import |
POST /api/import/jobs |
Start a provider-neutral playlist import job |
GET /api/import/jobs |
List the authenticated user's import jobs |
GET /api/import/jobs/:jobId |
Read one import job and its current progress |
POST /api/import/jobs/reconnect |
Reconnect to an active import for the same source |
POST /api/import/jobs/:jobId/cancel |
Cancel a queued or running import job |
POST /api/import/m3u/preview |
Parse and preview an uploaded M3U playlist before import |
TIDAL Streaming
Stream unowned tracks via per-user TIDAL OAuth.
Disclaimer: Requires TIDAL subscription and uses
tiddllibrary.
Requirements
- Running
tidal-streamersidecar - TIDAL enabled in admin settings
Per-user setup
- Open Settings → Integrations → TIDAL
- Select Open TIDAL Authorization Page
- Complete the provider authorization flow
- Choose quality and save
Streaming auth is separate from admin download auth.
Quality settings
| Setting | Format |
|---|---|
| Low | AAC 96 kbps |
| High | AAC 320 kbps |
| Lossless | FLAC 16-bit / 44.1 kHz |
| Max / Hi-Res | FLAC 24-bit / 192 kHz |
TIDAL Downloads
Use TIDAL as a download source for tracks/albums.
Disclaimer: Intended for personal use with your own subscription.
Setup
- Ensure
tidal-streamerservice is running - Open Admin → Download Services
- Authenticate via device-code flow
- Choose download quality and naming template
- Save
File naming template examples
# Default
{album.artist}/{album.title}/{item.number:02d}. {item.title}
# Disc-track format
{album.artist}/{album.title}/{item.volume}-{item.number:02d} {item.title}
# With year
{album.artist}/{album.title} ({album.date:%Y})/{item.number:02d}. {item.title}
Default template:
{album.artist}/{album.title}/{item.number:02d}. {item.title}
TIDAL sidecar environment values
| Variable | Default | Description |
|---|---|---|
TIDAL_TRACK_DELAY |
3 |
Delay between track downloads |
MUSIC_PATH |
/music |
Path for downloaded music |
TIDDL_PATH |
/data/.tiddl |
Sidecar cache/config path |
DEBUG |
(unset) | Enable debug logging |
Main-channel image:
docker pull ghcr.io/soundspan/soundspan-tidal-streamer:main
ghcr.io/soundspan/soundspan-tidal-downloader is published as an alias of soundspan-tidal-streamer, and the tidal-downloader Compose hostname resolves to tidal-streamer.
YouTube Music Downloads
Use YouTube Music as a download source for albums, the same way TIDAL works.
Disclaimer: Uses unofficial libraries (
ytmusicapi,yt-dlp). Intended for personal use.
Setup
- Ensure the
ytmusic-streamersidecar is running - Open Admin → YouTube Music and enable YouTube Music
- Open Admin → Download Preferences
- Choose YouTube Music (Albums) as the primary source, or pick Try YouTube Music as the fallback for another source
- Save
No account link is needed for downloads — the sidecar uses public album pages.
How it works
When a download job runs, soundspan searches YouTube Music for the album, then the sidecar downloads each track and files it under your music folder as Artist/Album/01. Title.mp3. The library scanner picks the album up automatically when the job finishes.
If the album is not found on YouTube Music, the job follows your When Primary Source Fails setting — it can hand off to Soulseek, Lidarr, or TIDAL, or skip.
Sidecar environment values
| Variable | Default | Description |
|---|---|---|
MUSIC_PATH |
/music |
Path for downloaded music |
YT_ALBUM_DOWNLOAD_CONCURRENCY |
1 |
Album download jobs processed at once |
Last.fm and ListenBrainz Scrobbling
Each user can send their soundspan listening history to Last.fm and/or ListenBrainz. Connections are per user, under Settings -> Scrobbling. Plays from the web app and from connected Subsonic clients both forward.
ListenBrainz setup
No server configuration is needed.
- Copy your user token from
listenbrainz.org/settings - Open Settings -> Scrobbling, paste the token, and click Connect
Last.fm setup
The server operator must first create a free Last.fm API account (https://www.last.fm/api/account/create) and set two environment values:
LASTFM_API_KEY=your_api_key
LASTFM_SHARED_SECRET=your_shared_secret
LASTFM_API_KEY may already be set for metadata enrichment; scrobbling additionally requires the shared secret. Helm users storing keys in an existing Secret must add LASTFM_SHARED_SECRET to it.
These two values identify your soundspan server as an application to Last.fm — like an OAuth app credential. They are not a listener account and never receive scrobbles. Each user still connects their own Last.fm account, and each user's plays go to their own Last.fm profile.
The shared secret is intentionally never displayed in any admin screen. The Scrobbling settings page reports which of the two values is missing when Last.fm is unavailable.
Then each user connects their own account:
- Open Settings -> Scrobbling and click Connect Last.fm
- Approve the connection on the Last.fm page that opens
- Return and click I've approved — finish connecting
Notes
- Each service has its own enable toggle; Disconnect removes the stored credential
- Scrobbles and now-playing updates are delivered in the background and retried on failure; playback is never delayed
- If a service rejects a stored credential, that connection is disabled and the user is asked to reconnect
Podcasts
Podcast discovery and subscriptions require no credentials. Search uses the iTunes discovery catalog. Subscriptions use each podcast's RSS feed for episode metadata and playback.
- Open Podcasts
- Search the iTunes catalog or add an RSS feed
- Subscribe to keep the feed in your library
OpenSubsonic API Compatibility
soundspan exposes a Subsonic/OpenSubsonic-compatible /rest surface.
- Full contract and known-gap policy:
OPENSUBSONIC_COMPATIBILITY.md - Split deployment client URL guidance: use frontend base URL
- Backend-direct deployments can target backend URL directly
Local smoke check:
cd backend
npm run test:smoke:subsonic-proxy
See also
- Configuration and Security — Secret handling and external access settings
- Environment Variables — Complete env var reference by container
- Deployment Guide — Docker and compose deployment options
- Usage Guide — Navigation, playback behavior, and administration