SoulSync Documentation
repository·main·Indexed 22 days ago
https://github.com/nezreka/soulsyncAn intelligent automation platform for music and video libraries that automates discovery, downloading, metadata enrichment, and organization. It supports hybrid download sources including Soulseek, Deezer, Tidal, and YouTube, and integrates with media servers like Plex, Jellyfin, and Navidrome. Features include a visual Automation Engine for custom workflows, AcoustID audio verification, and comprehensive metadata workers for both audio and video content.
What's inside SoulSync
- SoulSync is an intelligent music and video automation platform designed to bridge streaming services with self-hosted libraries. It automates the entire lifecycle of media management: from discovering new releases and generating playlists (similar to Spotify's Release Radar or Discovery Weekly) to downloading tracks from multiple sources (Soulseek, Deezer, Tidal, etc.), verifying audio quality via AcoustID, enriching metadata using 14 different workers, and organizing files into clean folder structures. It supports integration with media servers like Plex, Jellyfin, and Navidrome, or can be used as a standalone library manager.
Understand Spotify and iTunes fallback logic
mainThe
SpotifyClientprovides fallback capabilities to theiTunesClientto ensure high availability of metadata. The behavior depends on the method type:Search Methods
search_tracks,search_albums, andsearch_artistsalways try Spotify first. If any exception occurs, they fall through to iTunes.ID-based Methods
get_track_details,get_album,get_album_tracks,get_artist, andget_artist_albumstry Spotify first. They only fall through to iTunes if the provided ID is numeric (id_str.isdigit()). If the ID is alphanumeric (Spotify format) but Spotify fails, the method returnsNoneor[]and does not attempt an iTunes lookup.User-specific Methods
Methods like
get_user_playlistsandget_saved_tracksare Spotify-only and have no fallback to iTunes.Add delays to automation actions
mainAction blocks include an optional Delay field (measured in minutes). The action will wait for the specified duration after the trigger fires before executing. This is useful for ensuring preceding processes (like file moves or database writes) have completed.Understand UnifiedTrack, UnifiedArtist, and UnifiedAlbum data structures
mainTo ensure consistency across different metadata providers (Spotify vs. iTunes), SoulSync uses unified dataclasses. These objects normalize fields like
id,name,artists, andalbumregardless of the source.Key Fields in
UnifiedTrack:id: A unique identifier (prefixed withitunes:if from iTunes).source: TheMetadataSourceused (e.g.,SPOTIFY_OAUTH,ITUNES).spotify_id/itunes_id: Original source IDs for cross-referencing.popularity: Available for Spotify sources; defaults to0for iTunes.isrc: International Standard Recording Code (Spotify only).
Key Fields in
UnifiedArtist:followers: Available for Spotify sources.
Key Fields in
UnifiedAlbum:total_tracks: Number of tracks in the album.explicit: Boolean indicating explicit content.
Authenticate with the SoulSync API
mainAll
/api/v1/endpoints (except the bootstrap endpoint) require authentication. Keys are prefixed withsk_.Method Details Header Authorization: Bearer sk_...Query ?api_key=sk_...Authentication Error Codes
Status Code Meaning 401 AUTH_REQUIREDNo API key provided 403 INVALID_KEYAPI key is wrong or revoked Rate Limiting
Requests are limited to 60 per minute per IP address. Exceeding this limit returns
429 RATE_LIMITED.Understand the Import route data and invalidation model
mainThe Import route uses TanStack Query to manage data fetching and synchronization. Understanding the invalidation rules is critical for ensuring the UI reflects the current state of the staging folder.
Query Options
- Critical Loader Data:
importStagingFilesQueryOptions() - Prefetch Data:
importStagingGroupsQueryOptions(),importStagingSuggestionsQueryOptions() - Nested Route Data:
autoImportStatusQueryOptions(),autoImportSettingsQueryOptions(),autoImportResultsQueryOptions(autoFilter) - Lazy Search Data:
importAlbumSearchQueryOptions(query),importTrackSearchQueryOptions(query)
Invalidation Rules
To keep the UI in sync with backend changes, the following invalidation patterns are used:
- Processing files (Album or Singles): Invalidates
staging files,staging groups,staging suggestions,auto-import results, and any route-local queue completion summaries. - Auto-import actions: Invalidates
auto-import statusandresults. - Auto-import settings writes: Invalidates
settingsandstatus. - Manual Refresh: Invalidates
staging files,groups, andsuggestions.
- Critical Loader Data:
Understand the SoulSync Metadata Fallback Strategy
mainSoulSync uses a tiered priority system for metadata and search operations. This allows the platform to provide immediate functionality to users without requiring them to set up Spotify Developer credentials or complete OAuth flows.
Priority Order of Access Methods:
- Spotify OAuth: Full feature set including playlists, library, search, and metadata. Requires user credentials and OAuth flow.
- Spotify Client Credentials: Provides search and metadata functionality but requires application
client_idandclient_secret. - Anonymous Spotify Access: Provides search and metadata functionality with no credentials required.
- iTunes Search API: Provides search and metadata functionality with no credentials required, using a different data source.
Use Multi-Profile Support with X-Profile-Id
mainSoulSync supports multiple user profiles. To perform actions (like adding to a watchlist) or retrieve discovery data for a specific profile, include the
X-Profile-Idheader in your request. If omitted, the request typically defaults to the primary profile.Example: Adding an artist to the watchlist for profile ID
2using Python:requests.post( f"{API_URL}/watchlist", headers={**headers, "X-Profile-Id": "2"}, json={"artist_id": "4tZwfgrHOc3mvqYlEYSvnL", "artist_name": "Daft Punk"} )How the DownloadEngine and Plugins interact
mainSoulSync uses a centralized
DownloadEngineto manage the complexities of downloading media from multiple sources. This architecture separates high-level orchestration from source-specific logic.The DownloadEngine Responsibilities
- Concurrency & Threading: Spawns and manages
BackgroundDownloadWorkerinstances. - State Management: Tracks
active_downloadsand manages globalstate_lock. - Rate Limiting: Uses a
rate_limiterpool to ensure plugins respect source-specific limits (e.g.,engine.rate_limit.acquire(source)). - Reliability: Manages fallback chains (
engine.fallback_chain) and result deduplication.
The Plugin Responsibilities
Plugins are lightweight adapters that only handle:
- Authentication: Managing OAuth tokens, session cookies, or API keys.
- Protocols: Handling specific transport layers (e.g., HTTP REST, HLS demux, or
yt-dlpsubprocesses). - Atomic Operations: Executing the actual
search_rawordownload_rawcalls.
Implementation Nuances
- Event-Driven Sources (e.g., Soulseek/slskd): For sources that are not thread-based,
download_rawreturns immediately, and the engine subscribes to source events for state updates. - Subprocess Sources (e.g., YouTube/yt-dlp): The plugin wraps the subprocess call; the engine treats the subprocess execution as the managed thread.
- Concurrency & Threading: Spawns and manages
Use the Automation Engine to build workflows
mainThe Automation Engine is a visual drag-and-drop builder for creating custom workflows using Triggers, Actions, and Signal Chains.
Triggers
Common triggers include:
Schedule/Daily/Weekly TimeTrack Downloaded/Batch CompletePlaylist Changed/Discovery CompleteWatchlist Match/Wishlist Item AddedLibrary Scan Complete
Actions
Common actions include:
Process Wishlist/Scan WatchlistSync Playlist/Discover PlaylistScan Library/Database UpdateQuality Scan/Full CleanupDiscord/Telegram/Pushbulletnotifications
Signal Chains
Automations can communicate via signals. One automation can fire a signal (e.g.,
signal:foo), which another automation listens for. SoulSync includes cycle detection, chain depth limits, and cooldowns to prevent runaway loops.Understand the Mirrored Playlist Sync Pipeline
mainTo prevent raw metadata (like YouTube video titles) from polluting your library, use a three-step automation chain for mirrored playlists.
The Pipeline Workflow
- Refresh: Re-fetch the playlist from the source (e.g., every 6 hours). This emits a
Playlist Changedevent if changes are detected. - Discover: Triggered by
Playlist Changed. Matches raw tracks to official Spotify/iTunes metadata via the matching engine and caches the result. This emits aDiscovery Completeevent. - Sync: Triggered by
Discovery Complete. Pushes only the verified, discovered tracks to your media server.
Note for Spotify users: Spotify-sourced playlists skip the Discover step because their metadata is already official. You can chain
Playlist Changeddirectly toSync Playlist.### Step 1: RefreshWHEN: Schedule (every 6 hours) DO: Refresh Mirrored Playlist (all)
### Step 2: DiscoverWHEN: Playlist Changed DO: Discover Playlist (all)
### Step 3: SyncWHEN: Discovery Complete DO: Sync Playlist (select playlist)
- Refresh: Re-fetch the playlist from the source (e.g., every 6 hours). This emits a
Handle API response type inconsistencies
mainSoulSync returns different data structures depending on the method called. Consumers must be prepared to handle both Dataclass instances and raw Dictionaries.
Return Type Mapping
Method Returns search_tracks/albums/artistsDataclass instances ( Track,Album,Artist)get_track_detailsDict (enhanced, same shape both sources) get_albumDict (Spotify raw / iTunes normalized) get_album_tracksDict with itemslistget_artistDict (Spotify raw / iTunes normalized) get_artist_albumsDataclass instances ( List[Album])Access Patterns
- For Dataclasses: Use attribute access:
track.name,track.artists. - For Dicts: Use key access:
track_details['name'],track_details['album']['name'].
- For Dataclasses: Use attribute access: