Spotify-quality music discovery for self-hosted libraries. Automates downloads, curates playlists, monitors artists, and organizes your collection with zero manual effort.
IMPORTANT: Configure file sharing in slskd to avoid Soulseek bans. Set up shared folders at
http://localhost:5030/shares.
Community: Discord | Website: ssync.net | Support: GitHub Issues | Donate: Ko-fi
SoulSync bridges streaming services to your music library with automated discovery:
- Monitors artists → Automatically detects new releases from your watchlist
- Generates playlists → Release Radar, Discovery Weekly, Seasonal, Decade/Genre mixes, Cache-powered discovery
- Downloads missing tracks → From Soulseek, Deezer, Tidal, Qobuz, HiFi, Amazon Music, YouTube, or any combination via Hybrid mode
- Verifies downloads → AcoustID fingerprinting for all download sources
- Enriches metadata → 14 enrichment workers (Spotify, MusicBrainz, iTunes, Deezer, Discogs, AudioDB, Last.fm, Genius, Tidal, Qobuz, JioSaavn, Amazon, Bandcamp, Similar Artists)
- Tags consistently → Picard-style MusicBrainz release preflight ensures all album tracks get the same release ID
- Organizes files → Custom templates for clean folder structures
- Manages library → Plex, Jellyfin, Navidrome, or SoulSync Standalone (no media server required)
- Scrobbles plays → Automatic scrobbling to Last.fm and ListenBrainz from your media server
Plus a full video side. SoulSync also manages Movies, TV Shows, and YouTube — the same discovery, automation, and enrichment approach applied to video, with its own isolated database, dashboard, and pipeline. Works with Plex and Jellyfin. See Video Library below.
Release Radar — New tracks from watchlist artists, personalized by listening history
Discovery Weekly — 50 tracks from similar artists with serendipity weighting
Seasonal Playlists — Halloween, Christmas, Valentine's, Summer, Spring, Autumn (hemisphere-aware)
Personalized Playlists (12+ types)
- Recently Added, Top Tracks, Forgotten Favorites
- Decade Playlists (1960s-2020s), Genre Playlists (15+ categories)
- Because You Listen To, Daily Mixes, Hidden Gems, Popular Picks, Discovery Shuffle, Familiar Favorites
- Custom Playlist Builder (1-5 seed artists → similar artists → random albums → shuffled tracks)
Cache-Powered Discovery (zero API calls)
- Undiscovered Albums — albums by your most-played artists that aren't in your library
- New In Your Genres — recently released albums matching your top genres
- From Your Labels — popular albums on labels already in your library
- Deep Cuts — low-popularity tracks from artists you listen to
- Genre Explorer — genre landscape pills with artist counts, tap for Genre Deep Dive modal
ListenBrainz — Import recommendation and community playlists
Beatport — Full electronic music integration with genre browser (39+ genres)
Artist Map & Artist Web — Interactive full-screen graph explorers of your library's taste landscape: every artist as a node, clustered by genre, wired by similarity; plus a Playlist Explorer that renders any playlist as an explorable tree
7 Download Sources: Soulseek, Deezer, Tidal, Qobuz, HiFi, Amazon Music, YouTube — use any single source or Hybrid mode with drag-to-reorder priority
Deezer Downloads — ARL token authentication, FLAC lossless / MP3 320 / MP3 128 with automatic quality fallback and Blowfish decryption
Tidal Downloads — Device-flow OAuth, quality tiers from AAC 96kbps to FLAC 24-bit/96kHz Hi-Res
Qobuz Downloads — Email/password auth, quality up to Hi-Res Max (FLAC 24-bit/192kHz)
HiFi Downloads — Free lossless via public API instances, no account required
Soulseek — FLAC priority with quality profiles, peer quality scoring, source reuse for album consistency
YouTube — Audio extraction with cookie-based bot detection bypass
Hybrid Mode — Enable any combination of sources, drag to set priority order, automatic fallback chain
Playlist Sources: Spotify, Tidal, YouTube, Deezer, Qobuz, Beatport charts, ListenBrainz, Spotify/Deezer link paste (no API needed), CSV/TSV/M3U file import
Post-Download
- Lossy copy creation: MP3, Opus, AAC with configurable bitrate (Opus capped at 256kbps)
- Hi-Res FLAC downsampling to 16-bit/44.1kHz CD quality
- Blasphemy Mode — delete original FLAC after conversion
- Synchronized lyrics (LRC) via LRClib
- ReplayGain analysis — optional track-level loudness tagging via ffmpeg, runs before lossy copy so both files get tagged
- Picard-style album consistency — pre-flight MusicBrainz release lookup ensures all tracks get the same release ID
Listening Stats Page — Full dashboard with Chart.js visualizations
- Overview cards: total plays, listening time, unique artists/albums/tracks
- Timeline bar chart, genre breakdown donut with legend
- Top artists visual bubbles, top albums and tracks with play buttons and cover art
- Library health: format breakdown bar, enrichment coverage rings, database storage chart
- Time range filters: 7 days, 30 days, 12 months, all time
Scrobbling — Automatic Last.fm and ListenBrainz scrobbling from Plex, Jellyfin, or Navidrome
AcoustID Fingerprinting (optional) — Verifies downloaded files match expected tracks
- Runs for all download sources (Soulseek, Tidal, Qobuz, HiFi, Deezer, Amazon Music, YouTube)
- Catches wrong versions (live, remix, cover) even from streaming API sources
- Fail-open design: verification errors never block downloads
AcoustID verification is opt-in. To enable it, request a free API key at https://acoustid.org/new-application and paste it into Settings → AcoustID. Without a key, downloads still complete but the verification step is skipped silently.
If a track was previously tagged by AcoustID but the retag action in
the AcoustID Scanner no longer changes anything, see issue #704 — the
most common cause is that the file already carries a
MUSICBRAINZ_TRACKID tag, which the retag step uses as a short-circuit
and therefore never overwrites. Removing the cached
MUSICBRAINZ_TRACKID (and the ACOUSTID_ID if present) from the file
restores the retag.
14 Background Enrichment Workers: Spotify, MusicBrainz, iTunes, Deezer, Discogs, AudioDB, Last.fm, Genius, Tidal, Qobuz, JioSaavn, Amazon, Bandcamp, Similar Artists — plus SoulID generation
- Each worker independently processes artists, albums, and tracks
- Pause/resume controls on dashboard (animated worker orbs show live status), auto-pause during database scans
- Error items don't auto-retry in infinite loops (fixed in v2.1)
Multi-Source Metadata
- Primary source selectable: Spotify, iTunes/Apple Music, Deezer, or Discogs
- Spotify no longer auto-overrides — user chooses their preferred source in Settings
- Spotify auth still enables playlists, followed artists, and enrichment
- MusicBrainz enrichment with Picard-style album consistency
Hydrabase (optional P2P metadata network) — replaces iTunes as the metadata source when connected. Federated lookup with community-matched results, falls back automatically if disconnected. Dev-mode feature, enable in Settings → Connections.
Genre Whitelist — filter junk genre tags (artist names, radio show names, playlist names) from all enrichment sources. 272 curated default genres, fully customizable. Off by default for backward compatibility.
Post-Processing Tag Embedding
- Granular per-service tag toggles (18+ MusicBrainz tags, Spotify/iTunes/Deezer IDs, AudioDB mood/style, Tidal/Qobuz ISRCs, Last.fm tags, Genius URLs)
- Multi-artist tagging options: configurable separator (comma/semicolon/slash), multi-value ARTISTS tag for Navidrome/Jellyfin multi-artist linking, optional "move featured artists to title" mode
- Album art embedding, cover.jpg download
- Spotify rate limit protection across all API calls
- Version-aware matching: strictly rejects remixes when you want the original (and vice versa)
- Unicode and accent handling (KoЯn, Bjork, A$AP Rocky)
- Fuzzy matching with weighted confidence scoring (title, artist, duration)
- Album variation detection (Deluxe, Remastered, Taylor's Version, etc.)
- Streaming source match validation: same confidence scoring applied to Tidal/Qobuz/HiFi/Deezer results as Soulseek
- Short title protection: prevents "Love" from matching "Loveless"
Automation Engine — Visual drag-and-drop builder for custom workflows
- Triggers: Schedule, Daily/Weekly Time, Track Downloaded, Batch Complete, Playlist Changed, Discovery Complete, Signal Received, Library Scan Complete, Watchlist Match, Wishlist Item Added, and more
- Actions: Process Wishlist, Scan Watchlist, Refresh Mirrored, Discover Playlist, Sync Playlist, Scan Library, Database Update, Quality Scan, Full Cleanup, and 10+ more
- Then Actions (up to 3 per automation): Fire Signal (chain to other automations), Discord/Telegram/Pushbullet notifications, audible chimes
- Signal Chains — One automation fires
signal:foo, another listens for it. Cycle detection + chain depth limit + cooldown prevent runaway chains. - Playlist Pipeline — Single automation for full playlist lifecycle: refresh → discover → sync → download missing. No manual signal wiring.
- Pipelines — Pre-built one-click deployments (New Music, Nightly Operations, Full Library Maintenance, etc.) that install a linked group of automations at once
- Automation Groups — Drag-and-drop organization, bulk enable/disable, rename, right-click context menus
Watchlist — Monitor unlimited artists with per-artist configuration
- Release type filters: Albums, EPs, Singles
- Content filters: Live, Remixes, Acoustic, Compilations
- Auto-discover similar artists, periodic scanning
Wishlist — Failed downloads automatically queued for retry with auto-processing
Mirrored Playlists — Mirror from Spotify, Tidal, YouTube, Deezer and keep synced
- Auto-refresh detects source changes via URL/ID tracking in playlist metadata
- Discovery pipeline matches source tracks to user's primary metadata source (Spotify/iTunes/Deezer/Discogs)
- Auto Wing It fallback — tracks that fail all metadata APIs get stub metadata from the raw source title and flow through the normal download pipeline anyway
- Followed Spotify playlists that hit 403 errors fall back to public embed scraper
- Unmatch button on found tracks with DB persistence for mirrored playlists
Local Profiles — Multiple profiles with isolated settings, watchlists, and playlists
- Per-profile side access — each profile can be music-only, video-only, or both; single-side profiles never see the side switcher
- Per-profile page access, login passwords / quick-switch PINs, per-profile Spotify + Tidal accounts (My Accounts)
Dashboard — Service status, system stats, activity feed, enrichment worker controls
- Unified glass UI design across all tool cards, service cards, and stat cards
Library Page — Artist grid with staggered card animations, per-artist enrichment coverage rings
- Artist Radio button — play random track with auto-queue radio mode
- Play buttons on Last.fm top tracks sidebar
Enhanced Library Manager — Toggle between Standard and Enhanced views
- Inline metadata editing, per-service manual matching
- Write Tags to File (MP3/FLAC/OGG/M4A), tag preview with diff
- Server sync after tag writes (Plex, Jellyfin, Navidrome)
- Bulk operations, sortable columns, multi-disc support
- Re-identify — re-file an imported track under a different release (staged back through the import pipeline; the original is never deleted until the re-import succeeds)
- Artist photo picker — hover the artist image, pick from every connected source; updates SoulSync, your media server, and artist.jpg on disk (what Navidrome reads) in one click
- Enhance Quality (upgrade tracks to FLAC/higher bitrate) and Reorganize Album modals
Library Maintenance — 10+ automated repair jobs
- Track Number, Dead Files, Duplicates, Metadata Gaps, Album Completeness, Missing Cover Art, AcoustID Scanner, Orphan Files, Fake Lossless, Library Reorganize, Lossy Converter, MBID Mismatch, Album Tag Consistency, Live/Commentary Cleaner
- Enrichment workers auto-pause during database scans
- One-click Fix All with findings dashboard
Database Storage Visualization — Donut chart showing per-table storage breakdown
Live Log Viewer — Real-time terminal-style log viewer on Settings → Logs. Color-coded levels (DEBUG/INFO/WARNING/ERROR), live filter + search, switch between log files (app, post-processing, AcoustID, source reuse). Auto-scroll, copy, clear. Updates via WebSocket every 0.5s.
Import System — Tag-first matching, auto-grouped album cards, staging folder workflow
- Exact-ID identification first — a Spotify link in the comment tag resolves 1:1; ISRC tags resolve the album by folder consensus (fixes text-search failures on Japanese releases)
- Auto-Import worker: recursive scan, single file support, AcoustID fingerprinting fallback
- Confidence-gated: 90%+ auto-imports, 70-90% queued for review
.lrclyrics sidecars travel with their tracks (imports and downloads), renamed to match
SoulSync Standalone Mode — Use SoulSync without Plex, Jellyfin, or Navidrome
- Downloads and imports write directly to the library database
- Filesystem scanner for incremental and deep scan of Transfer folder
- Pre-populated enrichment IDs from download context (Spotify, Deezer, MusicBrainz)
- Select in Settings → Connections → Standalone
Template Organization — $albumartist/$album/$track - $title and 10+ variables
- Stream tracks from your library with queue system
- Now Playing modal with album art ambient glow and Web Audio visualizer
- Smart Radio mode — auto-queue similar tracks by genre, mood, and style
- Repeat modes, shuffle, keyboard shortcuts, Media Session API
- Comprehensive mobile layouts across both sides — every music page plus the full video side (dashboard through both Studios)
- Artist hero section, enhanced library track table with bottom sheet action popover
- Enrichment rings, filter bars, and discover cards all adapt to narrow screens
A fully isolated video side that brings SoulSync's discovery/automation/enrichment philosophy to movies, TV, and YouTube. Its own database, dashboard, search, calendar, and download pipeline — sharing the automation engine but never touching the music side. Works with Plex and Jellyfin (per-server isolation).
- Plex + Jellyfin, source-agnostic — Movies and TV are tracked as independent libraries
- Three scan modes: incremental (a modified-since delta — only re-reads what the server touched), deep (full re-read + prune removed), full (clean reset)
- Smart post-download scan — probes the server with a cheap search and skips the full crawl when it already has the newest grab
- Weekly deep scans (TV Mondays, Movies Tuesdays) + an hourly incremental safety net for manual additions
Matchers — TMDB (movies + shows), TVDB (shows + an episode-metadata fallback for titles/overviews TMDB lacks), OMDb (IMDb / Rotten Tomatoes / Metacritic ratings)
12 background enrichment workers — fanart.tv (logos/art), OpenSubtitles (subtitles), Return YouTube Dislike, SponsorBlock, DeArrow (better titles/thumbnails), YouTube upload dates, Trakt (ratings/votes), TVmaze, AniList (anime), Wikidata (official sites), TMDB watch providers (streaming availability), MediaStinger (after-credits scenes) — live status orbs on the dashboard, click to pause/resume, Manage Workers modal with per-service queues and manual matching
- Gap-fill by design — enrichment only fills what the media server left blank, never clobbers server data; per-field user locking (a locked field belongs to the user, enrichment skips it forever)
- Rolling re-enrichment automation — keeps ratings, overviews, art, and episode air-dates from going stale: re-pulls the stalest matched items by stored id (never re-search, so no mis-match risk), oldest first, ~monthly per item, self-healing OMDb daily-quota latch
- Lazy on-view refresh + a daily airing-schedule refresh keep what you're actively watching current
- Netflix-style billboard hero with real title-logo art and a wishlist CTA, auto-rotating over trending titles
- A deep, endlessly lazy-loading rail stack: For You, Top 10 Today, personalized "Because you like…" rails, "On your streaming services", mood/studio/genre/decade/foreign rails
- Every rail opens as a paged See All grid; a browse filter bar (kind / genre / decade / provider / language / sort) builds arbitrary grids; Hide owned toggle
- Wishlist / In Library state on every card, everywhere
- Source-agnostic movie / show / person / studio pages — cinematic full-bleed billboard with trailer autoplay, cast & crew, where-to-watch, similar titles, seasons & episodes
- Get modal + download view — see your quality target, judge any owned copy against it, then per-source Manual (pick the release yourself) or Auto (grab the best) search — or one header Auto that searches every source and grabs the single best
- Play on Plex/Jellyfin deep-link, four switchable season views, "Missing only" episode filter, Wishlist Missing (every missing aired episode across all seasons in one click)
- Manage panel — inline metadata edits with per-field locks (a locked field is yours forever), plus a per-service match editor (TMDB / TVDB / IMDb re-match)
- Poster Manager — full-screen artwork picker; writes poster.jpg, repoints the DB, pushes to the server
- Progressive "Netflix-feel" search — results stream in per group (movies, TV, YouTube channels, people, studios) as they arrive instead of one blocking load
- A real 7-column week grid (today first) with time-band rows (Prime Time etc.) and a "Now" cue lighting the current band
- A "Next up" billboard hero — the soonest episodes with Tonight/Today labels
- Scope toggle: your watchlist (followed ∪ airing) vs the whole library; compact/comfortable views
- Wishlist an aired-but-missing episode straight from the calendar modal
Follow anything — shows, actors/directors (their whole filmography), studios, YouTube channels, YouTube playlists
- Studio watchlist — follow Pixar, A24, Disney… with family presets (Disney = Pixar + Marvel + Lucasfilm) and per-member selection (follow just Pixar if you want); a settled-films vote floor keeps obscure shorts out
- People watchlist — every un-owned movie a followed actor/director made, back catalog + upcoming
- Look-ahead horizon — upcoming titles are wishlisted only within ~1 year of theatrical/digital release, so the wishlist never fills with distant announcements but is never out of date
- Sonarr-style airing — wishlist every episode airing today for the shows you follow
- Sources: Soulseek (slskd), Prowlarr indexers (torrent + usenet), YouTube (yt-dlp) — reorderable hybrid chain with per-source toggles
- Radarr/Sonarr-class quality profiles — quality ladder, cutoff, upgrade-until-cutoff, reject rules, preferred-words scoring
- Fulfillment engine, download monitor, organization + sidecars + subtitle fetch, disk guard
- Downloads page: live rows with an expandable detail drawer (format facts, dest path, open item), batch grouping for season packs, cancel/retry per row
- Permanent download-history archive + a History modal (All / Movies / Shows / YouTube tabs)
- Release blocklist (auto-added only on proven-bad-file rejects, one-click block from failed rows, blocklist manager modal) + a recycle bin for reversible deletes
- Visual overlay-template editor, applied via Pillow directly onto Plex/Jellyfin posters
- Per-scope assignments (movie / show / season / episode), a logo-badge system (provider/resolution/rating badges)
- Nightly re-apply automation that skips items whose template + art + data are unchanged
- Clean Up Plex Images job reclaims the space poster re-uploads accumulate
- Build Plex Collections / Jellyfin BoxSets from smart filters and ranked lists
- Ranked list sources: IMDb charts & lists, TMDB charts & lists, Trakt lists, MDBList — rendered in true rank order (e.g. IMDb Top 250 by rank, not year)
- Franchise auto-backfill, a paginated gallery, and a nightly Sync Collections automation that pushes add/remove to the server
- Follow channels as shows and playlists as shows (yt-dlp, no API key) — long-form only, Shorts excluded
- Import your subscriptions — upload or paste a ytdl-sub / Kometa
subscriptions.ymland follow everything in one background pass - Paste any channel URL or
@handleinto video search to resolve + follow it - Per-channel keep windows / retention with an old-episode cleanup job
- True downloaded-state tracking (ownership derived from download history) + ghost cleanup
- Headless-friendly: the Settings "Paste cookies.txt" mode applies to video-side YouTube too
- Broken files, duplicate movies, metadata gaps, missing episodes, naming conformance, quality upgrade, watched-cleanup, wishlist audit, movie collections, YouTube ghosts
- Rich findings dashboard with lazy detail, mirrored from the music-side Maintenance standard
- Manage panel — inline metadata edits with per-field locking, plus re-identify (re-file an imported title to a different release through the staging pipeline)
- Bulk select bar for mass metadata operations
- Issues system — report a problem from the Manage sidebar; an Issues page + nav badge (full music-side parity)
- Live Plex/Jellyfin now-playing + watch history in an app-wide slide-out drawer, plus statistics & graphs
- Gated to Plex/Jellyfin servers (hidden when the active server can't provide it)
- A dedicated video Automations page — the same drag-and-drop builder, showing only video-owned rows (the music page is untouched)
- A video event bus (batch-complete, scan-complete, …) drives the full watchlist → wishlist → download pipeline plus airing refresh, re-enrichment, overlays, collection sync, deep scans, cleanup, and backups
- Dashboard — recently-added hero, library/upcoming/stats cards, enrichment-coverage rings, and a combined Studios (Overlay + Collection) admin card
curl -O https://raw.githubusercontent.com/Nezreka/SoulSync/main/docker-compose.yml
docker-compose up -d
# Access at http://localhost:8008SoulSync publishes two Docker image tracks so you can choose your level of stability.
Stable — :latest (recommended for most users). Hand-promoted from the dev branch to main when a batch of changes is ready for release. Published to Docker Hub. Your docker-compose.yml pulls this by default — no changes needed.
docker pull boulderbadgedad/soulsync:latestNightly — :dev. Rebuilt every night from the dev branch (and on every push to dev). Published to GitHub Container Registry. Gets new features and bug fixes before they reach :latest, at the cost of occasional instability as changes settle. Good for early adopters, contributors validating their own merges, and anyone helping shake out bugs on Discord before a stable release.
To switch, edit docker-compose.yml:
image: ghcr.io/nezreka/soulsync:devThen run docker-compose pull && docker-compose up -d.
Pinned dev builds are also published as ghcr.io/nezreka/soulsync:dev-YYYYMMDD-<sha> if you want to stick with an exact known-good snapshot.
Version-tagged releases (e.g. :2.3, :2.4) are permanent tags published on both registries when a stable release is promoted:
docker pull boulderbadgedad/soulsync:2.4
# or
docker pull ghcr.io/nezreka/soulsync:2.4| You are... | Use |
|---|---|
| A typical user who wants things to work | :latest |
| Pinning to a specific version for stability | :2.3, :2.4, etc. |
| An early adopter who wants new features early and is OK reporting bugs | :dev |
| A contributor testing post-merge behavior | :dev or a pinned dev build |
SoulSync is available as an Unraid template. Install from Community Applications or manually add the template from:
https://raw.githubusercontent.com/Nezreka/SoulSync/main/templates/soulsync.xml
PUID/PGID are exposed in the template — set them to match your Unraid permissions (default: 99/100 for nobody/users).
The template points at boulderbadgedad/soulsync:latest (stable) by default. To use the nightly :dev channel on Unraid, edit the container's Repository field to ghcr.io/nezreka/soulsync:dev after installing from the template.
git clone https://github.com/Nezreka/SoulSync
cd SoulSync
python -m pip install -r requirements.txt
# Build the React WebUI bundle used by the Python server.
# Docker does this automatically; Python installs must do it manually.
cd webui
npm ci
npm run build
cd ..
gunicorn -c gunicorn.conf.py wsgi:application
# Open http://localhost:8008When updating a Python/no-Docker install with git pull, rebuild the WebUI before restarting SoulSync:
cd webui
npm ci
npm run build
cd ..If webui/static/dist/.vite/manifest.json is missing or stale, React-owned routes and route handoffs may not load correctly.
YouTube streaming / music videos need two extra things on bare-metal installs (Docker bundles both):
- Deno — yt-dlp now requires a JavaScript runtime to unlock YouTube formats. Without it, streams and music-video downloads fail with
Requested format is not available. Install:winget install DenoLand.Deno(Windows) or see deno.com, then restart SoulSync. - yt-dlp nightly — the stable release can lag months behind YouTube changes. If YouTube breaks, update with:
python -m pip install -U --pre "yt-dlp[default]"
This is only for contributors working on the WebUI with hot reload. Normal Python/no-Docker installs should build once with npm run build as shown above, then run only Gunicorn.
For active frontend development, use two terminals so the backend and Vite stay independent:
- Backend
The dev Gunicorn config watches backend files and restarts the Python server when they change.
python -m pip install -r requirements-dev.txt gunicorn -c gunicorn.dev.conf.py wsgi:application
- Frontend
Vite hot reloads the React side when you change webui files.
cd webui npm ci npm run dev
Run tests separately when needed:
python -m pytestIf you want a convenience launcher, python dev.py starts both halves together
on any OS. ./dev.sh remains available as a Unix shell wrapper.
- slskd running and accessible (Download) — required for Soulseek downloads
- Spotify API credentials (Dashboard) — optional but recommended for discovery
- Media Server (optional): Plex, Jellyfin, or Navidrome
- Deno (Python/no-Docker installs only): JavaScript runtime required by yt-dlp for YouTube streaming/music videos —
winget install DenoLand.Denoor deno.com. Docker images bundle it. - Deezer ARL token (optional): For Deezer downloads — get from browser cookies after logging into deezer.com
- Tidal account (optional): For Tidal downloads — authenticate via device flow in Settings
- Qobuz account (optional): For Qobuz downloads — email/password login in Settings
SoulSync talks to slskd through its API. See the slskd setup guide for API key configuration.
- Add an API key in slskd's
settings.ymlunderweb > authentication > api_keys - Restart slskd
- Paste the key into SoulSync's Settings → Downloads → Soulseek section
Configure file sharing in slskd to avoid Soulseek bans. Set up shared folders at http://localhost:5030/shares.
Spotify gives you the best discovery features. Without it, SoulSync falls back to iTunes/Deezer for metadata.
- Create an app at developer.spotify.com/dashboard
- Add Redirect URI:
http://127.0.0.1:8888/callback - Copy Client ID and Client Secret into SoulSync Settings
More detail in Support/DOCKER-OAUTH-FIX.md.
Open SoulSync at http://localhost:8008 and go to Settings.
Download Source: Choose your preferred source (Soulseek, Deezer, Tidal, Qobuz, HiFi, Amazon Music, YouTube, or Hybrid)
Paths:
- Input Folder: Container path to slskd's download folder (e.g.,
/app/downloads) - Output Folder: Where organized music goes (e.g.,
/app/Transfer) - Import Folder: Optional folder for importing existing music (e.g.,
/app/Staging)
Media Server (optional): Use your machine's actual IP (not localhost — that means inside the container)
| What | Container Path | Host Path |
|---|---|---|
| Config | /app/config |
Your config folder |
| Logs | /app/logs |
Your logs folder |
| Database | /app/data |
Named volume (recommended) |
| Input | /app/downloads |
Same folder slskd downloads to |
| Output | /app/Transfer |
Where organized music goes |
| Import | /app/Staging |
Optional folder for importing music |
Important: Use a named volume for the database (soulsync_database:/app/data). Direct host path mounts to /app/data can overwrite Python module files.
| Feature | SoulSync | Lidarr | Headphones | Beets |
|---|---|---|---|---|
| Custom Discovery Playlists (15+) | ✓ | ✗ | ✗ | ✗ |
| Cache-Powered Discovery (zero API) | ✓ | ✗ | ✗ | ✗ |
| Listening Stats Dashboard | ✓ | ✗ | ✗ | ✗ |
| Last.fm/ListenBrainz Scrobbling | ✓ | ✗ | ✗ | ✗ |
| 7 Download Sources | ✓ | ✗ | ✗ | ✗ |
| Deezer Downloads (FLAC) | ✓ | ✗ | ✗ | ✗ |
| Tidal Downloads (Hi-Res) | ✓ | ✗ | ✗ | ✗ |
| Qobuz Downloads (Hi-Res Max) | ✓ | ✗ | ✗ | ✗ |
| Soulseek Downloads | ✓ | ✗ | ✗ | ✗ |
| Beatport Integration | ✓ | ✗ | ✗ | ✗ |
| Audio Fingerprint Verification | ✓ | ✗ | ✗ | ✓ |
| 9 Enrichment Workers | ✓ | ✗ | ✗ | Plugin |
| Picard-Style Album Tagging | ✓ | ✗ | ✗ | ✗ |
| Visual Automation Builder | ✓ | ✗ | ✗ | ✗ |
| Enhanced Library Manager | ✓ | ✗ | ✗ | ✗ |
| Library Maintenance Suite (10+ jobs) | ✓ | ✗ | ✗ | ✓ |
| Multi-Profile Support | ✓ | ✗ | ✗ | ✗ |
| Mobile Responsive | ✓ | ✓ | ✗ | ✗ |
| Built-in Media Player + Radio | ✓ | ✗ | ✗ | ✗ |
Scale: ~400,000 lines across Python backend and JavaScript/TypeScript frontend, 1,000+ API endpoints, handles 10,000+ album libraries
Integrations: Spotify, iTunes/Apple Music, Deezer, Tidal, Qobuz, YouTube, Soulseek (slskd), HiFi, Beatport, ListenBrainz, MusicBrainz, AcoustID, AudioDB, Last.fm, Genius, LRClib, music-map.com, Plex, Jellyfin, Navidrome
Stack: Python 3.11, Flask, SQLite (WAL mode), vanilla JavaScript SPA, Chart.js
Core Components:
- Matching Engine — version-aware fuzzy matching with streaming source bypass
- Download Orchestrator — routes between 7 sources with hybrid fallback and batch processing
- Discovery System — personalized playlists, cache-powered sections, seasonal content
- Metadata Pipeline — 14 enrichment workers, Picard-style album consistency, dual-source fallback
- Album Consistency — pre-flight MusicBrainz release lookup before album downloads
- Automation Engine — event-driven workflows with signal chains and pipeline deployment
- SoulID System — deterministic cross-instance artist/album/track identifiers via track-verified API lookup
SoulSync uses a dev → main flow:
main— release branch.:latestimages auto-build from this. Only receives merges fromdev.dev— integration branch. Nightly:devimages build from here. PRs land here first for validation before being promoted tomain.- Feature branches — branched from
dev. PRs targetdev.
- Fork and clone the repo
- Branch off
dev:git checkout -b fix/your-change dev - Make your changes and commit
- Push and open a PR against
dev(notmain) - CI (
build-and-test.yml) runs ruff lint + compile +python -m pyteston your branch — wait for green - A maintainer reviews and merges
Use the Local Development section above for the full repo-wide setup and the portable dev launcher.
For web UI work, see webui/README.md. It keeps the React-side notes close to the app while this file stays the single place for repo-wide dev instructions.
Ruff config lives in pyproject.toml. The ruleset is intentionally lenient — it catches real bugs (undefined names, import shadowing, closure-in-loop) without style nits.
Open an issue on GitHub. For user-side support, the Discord community is the fastest place to ask.