All apps · 0 apps
SoulSync
Docker app from snuffomega's Repository
Overview
Readme
View on GitHub
SoulSync - Intelligent Music & Video Automation Platform
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
What It Does
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.
Key Features
Discovery Engine
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
Multi-Source Downloads
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 & Scrobbling
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
Audio Verification
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 API key
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.
Metadata & Enrichment
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
Advanced Matching Engine
- 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
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)
Library Management
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
Built-in Media Player
- 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
Mobile Responsive
- 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
Video Library — Movies, TV Shows & YouTube
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).
Libraries & Scanning
- 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
Metadata & Enrichment
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
Discover
- 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
Detail Pages & Search
- 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
TV Calendar
- 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
Watchlist → Wishlist → Download Pipeline
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
Downloads
- 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
Overlay Studio (Kometa-style overlays)
- 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
Collection Manager (Kometa-style collections)
- 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
YouTube
- 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
Library Maintenance (repair jobs)
- 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
Bulk Editing, Locking & Issues
- 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)
Server Activity (Tautulli-style monitoring)
- 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)
Automations & Dashboard
- 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
Installation
Docker (Recommended)
curl -O https://raw.githubusercontent.com/Nezreka/SoulSync/main/docker-compose.yml
docker-compose up -d
# Access at http://localhost:8008
Release Channels
SoulSync 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:latest
Nightly — :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:dev
Then 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 |
Unraid
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.
Python (No Docker)
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:8008
When 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]"
Local Development
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 pytest
If you want a convenience launcher, python dev.py starts both halves together
on any OS. ./dev.sh remains available as a Unix shell wrapper.
Setup Guide
Prerequisites
- 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
Step 1: Set Up slskd
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.
Step 2: Set Up Spotify API (Optional)
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.
Step 3: Configure SoulSync
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)
Step 4: Docker Path Mapping
| 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.
Comparison
| 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 | ✓ | ✗ | ✗ | ✗ |
Architecture
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
Contributing
Branch workflow
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.
Opening a PR
- 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
Running locally
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.
Reporting bugs / requesting features
Open an issue on GitHub. For user-side support, the Discord community is the fastest place to ask.
Install SoulSync on Unraid in a few clicks.
Find SoulSync in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.
Requirements
Categories
Download Statistics
Total Downloads Over Time
Related apps
Explore more like this
Explore allLinks
Details
boulderbadgedad/soulsync:latestRuntime arguments
- Web UI
http://[IP]:[PORT:8008]- Network
bridge- Shell
bash- Privileged
- false
Template configuration
Web interface port
- Target
- 8008
- Default
- 8008
- Value
- 8008
Spotify OAuth callback port
- Target
- 8888
- Default
- 8888
- Value
- 8888
Tidal OAuth callback port
- Target
- 8889
- Default
- 8889
- Value
- 8889
Configuration files
- Target
- /app/config
- Default
- /mnt/user/appdata/soulsync/config
- Value
- /mnt/user/appdata/soulsync/config
Log files
- Target
- /app/logs
- Default
- /mnt/user/appdata/soulsync/logs
- Value
- /mnt/user/appdata/soulsync/logs
Database storage (SQLite)
- Target
- /app/data
- Default
- /mnt/user/appdata/soulsync/data
- Value
- /mnt/user/appdata/soulsync/data
Path to Soulseek (slskd) downloads folder — should match your slskd download path
- Target
- /app/downloads
- Default
- /mnt/user/downloads/
- Value
- /mnt/user/downloads/
Your music library folder for organized/transferred files
- Target
- /app/Transfer
- Default
- /mnt/user/library/
- Value
- /mnt/user/library/
User ID for file permissions (default 99 = nobody on Unraid)
- Default
- 99
- Value
- 99
Group ID for file permissions (default 100 = users on Unraid)
- Default
- 100
- Value
- 100
Timezone for log timestamps and scheduling (e.g., America/New_York)
- Target
- TZ
- Default
- America/New_York
- Value
- America/New_York