Allow multiple users to share a single SoulSync instance with isolated personal data. Each profile gets its own watchlist, wishlist, discovery pool, similar artists, and bubble snapshots — while sharing the same music library, database, and service credentials.
- Netflix-style profile picker on startup when multiple profiles exist
- Optional PIN protection per profile; admin PIN required when >1 profiles
- Admin-only profile management (create, edit, rename, delete)
- Profile avatar images via URL with colored-initial fallback
- Zero-downtime SQLite migration — all existing data maps to auto-created
admin profile
- Single-user installs see no changes — profile system is invisible until
a second profile is created
- WebSocket count emitters scoped to profile rooms (watchlist/wishlist)
- Background scanners (watchlist, wishlist, discovery) iterate all profiles
Incremental database updates now detect when artists or albums have been removed from your media server (Plex, Jellyfin, or Navidrome) and automatically clean them up from SoulSync's database. Previously, deleted content would persist as ghost entries until you ran a full refresh. Removal counts are reported in the scan results. Includes safety checks to prevent accidental mass deletion if the server is unreachable or returns incomplete data.
Adds Tidal as a third download source alongside Soulseek and YouTube. Uses the tidalapi library with device-flow authentication to search and download tracks in configurable quality (Low/High/Lossless/HiRes) with automatic fallback. Integrates into the download orchestrator for all modes (Tidal Only, Hybrid with fallback chain), the transfer monitor, post-processing pipeline, and file finder. Frontend includes download settings with quality selector, device auth flow, and dynamic sidebar/dashboard labels that reflect the active download source. No breaking changes for existing users.
Filled all missing Hydrabase fallthrough gates across 6 endpoints (artist album tracks, iTunes album, discover album, Spotify track, both similar artists), added track_number/disc_number to Track dataclass, fixed get_album_tracks to send soul_id instead of text query, mapped soul_id field from Hydrabase responses across all search methods, updated 7 frontend call sites to pass album name/artist params, and fixed M3U export defaulting to enabled when users never turned it on.
Fix short artist names (e.g. "ano") getting buried by wildcard matches. Re-ranks Spotify and iTunes results so exact name matches appear first, without changing what's returned.
SoulSync was importing from all Navidrome libraries regardless of user access restrictions. Added a "Music Library" dropdown in Navidrome settings that lets users scope imports to a specific music folder. Uses the Subsonic musicFolderId parameter on artist, album, and search API calls. Selecting "All Libraries" reverts to the previous behavior.
AcoustID sometimes returns featuring info in square brackets like [W/ Barnes Blvd.] instead of parentheses. The normalizer only stripped parenthetical featuring tags, so these tracks failed verification and got quarantined despite being correct. Now strips [W/ ...], [with ...], [feat. ...], and [ft. ...] bracket patterns too.
Store album artists in the Spotify track data structure (handles both dict and object album forms) so downstream processing has access to album-level artist metadata. Also update missing-track processing to fall back to source_info['watchlist_artist_name'] when artist_name is absent, ensuring artist context is preserved for legacy/watchlist-sourced entries.
Raise the default Jellyfin API timeout for bulk operations from 30s to 120s to better handle slow servers and large database syncs. Updated core/jellyfin_client.py to set bulk_timeout to 120, webui/index.html to show 120s in the settings input, and webui/static/script.js to use 120 as the fallback when loading settings. Aligns UI and client behavior to reduce timeout errors during heavy syncs.
Add a configurable API timeout for Jellyfin bulk requests and improve fetch retry behavior. UI: adds an "API Timeout (seconds)" field (15–300s, default 30) in webui/index.html and persists it via webui/static/script.js (load/save). Client: jellyfin_client.py now reads api_timeout from config_manager, uses it as the bulk timeout and computes a sensible non-bulk timeout (max(5, bulk_timeout//6)). Fetch loops for tracks and albums were hardened: reducing batch size now resets consecutive failure counters, log messages were clarified, and the stopping/retry thresholds were adjusted to avoid premature aborts at minimum batch sizes.