New download mode alongside Soulseek, YouTube, Tidal, and Qobuz. Uses
community-run REST API instances (no auth required) that serve Tidal CDN
FLAC streams. Features quality fallback chain (hires→lossless→high→low),
automatic instance rotation on failure, and full hybrid mode support.
Also fixes 6 missing streaming source checks for HiFi and Qobuz in the
frontend that were blocking playback with "format not supported" errors.
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.
Add Hydrabase support as an optional/dev metadata source and comparison tool.
- Add core/hydrabase_client.py: synchronous Hydrabase WebSocket client that normalizes results to Track/Artist/Album types and exposes raw access.
- Update config/settings.py: add hydrabase settings (url, api_key, auto_connect) and getter.
- Update web_server.py: integrate HydrabaseClient, initialize client alongside the existing HydrabaseWorker, add auto-reconnect using saved config, persist credentials on connect/disconnect, add endpoints for status and stored comparisons, background comparison runner (Hydrabase vs Spotify vs iTunes), and adapt multiple search endpoints to optionally use Hydrabase as the primary metadata source with fallbacks.
- Update web UI (webui/index.html, webui/static/script.js, webui/static/style.css): add network stats and source comparison UI, pre-fill saved credentials, show peer count, load/display comparisons, update disconnect behavior to disable dev mode, and add Hydrabase badge styling.
Behavioral notes: when dev mode + Hydrabase are active, searches can be served from Hydrabase and comparisons to Spotify/iTunes are run in background; when Hydrabase fails the code falls back to Spotify/iTunes. Saved Hydrabase credentials are persisted for auto-reconnect; disconnect disables dev mode and auto_connect.
Files touched: config/settings.py, core/hydrabase_client.py, web_server.py, webui/index.html, webui/static/script.js, webui/static/style.css.
Set m3u_export.enabled default to false and update the UI so the M3U auto-save checkbox is unchecked unless explicitly enabled. Changes: config/settings.py flips the default to false, webui/index.html removes the checked attribute from the checkbox, and webui/static/script.js adjusts the logic to only check the box when settings.m3u_export.enabled === true. This prevents automatic M3U exports for users who don't explicitly opt in.
Introduce M3U export feature with UI control and server-side saving. Adds a new m3u_export config option (enabled flag) and a checkbox in the settings UI. The web endpoint /api/save-playlist-m3u now checks the m3u_export setting (unless force=true), builds the target folder using a new _compute_m3u_folder() helper (leveraging existing template logic with sensible fallbacks), sanitizes filenames, and writes .m3u files into the computed folder. Frontend JS loads/saves the new setting, supplies album/artist metadata when auto-saving, and both autoSave and manual export now POST M3U data to the server (manual export uses force=true). Also changed browser download filename extension to .m3u and added minor logging/response behavior.
Introduce an optional "Blasphemy Mode" that deletes the original FLAC after a verified MP3 copy is created.
- config: add lossy_copy.delete_original (default: false).
- webui/index.html & static script: add checkbox and warning in settings UI and persist the setting.
- web_server.py: make _create_lossy_copy return the MP3 path when it deletes the FLAC (otherwise None); validate the MP3 using mutagen before removing the FLAC; rename associated .lrc files if present; update post-processing to use the final processed path in logs and wishlist checks and to consider .mp3 variants when FLAC may have been removed.
Behavior is off by default and includes safety checks and logging to avoid accidental deletion of originals.
Introduce $artistletter and $disc template variables across config, UI, and backend to support artist-first-letter tokens and multi-disc albums. Update web_server.py to include disc_number in template context, prefer user-controlled $disc in templates, and create configurable disc subfolders using a new file_organization.disc_label setting. Update example and active config, web UI to expose the new variable and disc label selector, and script.js to validate, load, and save the new settings and substitutions.
Introduce a configurable "lossy_copy" feature that creates an MP3 copy alongside downloaded FLAC files. Adds default config (example and runtime) and UI controls for enabling the feature and selecting an MP3 bitrate. Implements _create_lossy_copy in web_server.py which checks the FLAC extension, respects the configured bitrate (default 320 kbps), locates ffmpeg (including a local tools/ffmpeg fallback), performs conversion, and attempts to update the QUALITY tag via mutagen. The feature is invoked after post-processing/moving downloads. Logs and graceful failures (missing ffmpeg, timeouts, tag errors) are included.
Introduce a new $quality template variable that is only substituted into filenames to avoid splitting album folders when tracks of mixed qualities are present. Updates include:
- web_server.py: populate template contexts with 'quality' (from context['_audio_quality']), strip $quality from folder components, substitute it only in the filename, and clean up empty brackets/parentheses/dashes when the variable is empty.
- config/config.example.json and config/config.json: document the new variable in the file_organization template variables string.
- webui/index.html and webui/static/script.js: update UI help text and client-side template validation to include $quality.
This prevents folder fragmentation for albums with mixed-quality files while still allowing quality information in filenames.
Added an Import feature that lets users process local audio files through the existing post-processing pipeline (metadata enrichment, cover art, lyrics, library organization). Files are placed in a configurable Staging folder and imported via two modes: Album mode (search/match files to a Spotify tracklist) and Singles mode (select individual files for processing). Includes auto-suggested albums based on staging folder contents and real-time per-track progress tracking.
Enrich downloaded audio files with external identifiers and improved genre metadata in a single post-processing write. During metadata enhancement, the app now looks up the MusicBrainz recording and artist MBIDs, retrieves the ISRC and MusicBrainz genres from a follow-up detail lookup, merges them with Spotify's artist-level genres (deduplicated, capped at 5), and embeds everything alongside the Spotify/iTunes track, artist, and album IDs. All MusicBrainz API calls are serialized through the existing global rate limiter, making concurrent download workers safe without needing to pause the background worker. Includes a database migration adding Spotify/iTunes ID columns to the library tables.
Add optional post-download audio fingerprint verification using AcoustID.
Downloads are verified against expected track/artist using fuzzy string
matching on AcoustID results. Mismatched files are quarantined and
automatically added to the wishlist for retry.
- AcoustID verification with title/artist fuzzy matching (not MBID comparison)
- Quarantine system with JSON metadata sidecars for failed verifications
- fpcalc binary auto-download for Windows, macOS (universal), and Linux
- MusicBrainz enrichment worker with live status UI and track badges
- Settings page AcoustID section with real-fingerprint connection test
- Source reuse for album downloads to keep tracks from same Soulseek user
- Enhanced search queries for better track matching
- Bug fixes: wishlist tracking, album splitting, regex & handling, log rotation
Introduces a reload_config method to SpotifyClient and refactors ConfigManager to support reloading configuration from a file. Updates web_server.py to use the new config loading mechanism, ensuring configuration is loaded into the existing singleton instance and SpotifyClient is properly re-initialized after settings changes.
Introduces a DownloadOrchestrator class to route downloads between Soulseek and YouTube based on user-configurable modes (Soulseek only, YouTube only, Hybrid with fallback). Updates web server and UI to support new download source settings, including hybrid mode options and YouTube confidence threshold. Refactors YouTube client for thread-safe download management and bot detection bypass. Ensures quality filtering is skipped for YouTube results and improves file matching and post-processing logic for YouTube downloads.
Introduces the $year variable for album, single, and playlist path templates, allowing users to include the release year in file organization. Updates the backend to extract and provide the year, adjusts the web UI to document the new variable, and updates validation logic to recognize $year as valid in templates.
Updated Dockerfile, entrypoint.sh, and Python code to store database files in /app/data instead of /app/database, avoiding conflicts with the Python package. The database path is now configurable via the DATABASE_PATH environment variable, improving flexibility for container deployments.
Introduces 'search_timeout' and 'search_timeout_buffer' options to Soulseek settings in the config, backend, and web UI. The backend now uses these values to control search duration and polling, allowing users to fine-tune how long searches run and how long to wait for late results.
Introduces a template-based file organization system for downloads, allowing users to define custom folder and filename structures for albums, singles, and playlists. Updates the backend, config example, web UI, and client-side validation to support template editing, resetting, and error checking. Improves consistency in file placement and metadata handling across all download modes.
ConfigManager now stores configuration in a SQLite database instead of a JSON file. The class supports migration from existing config.json files and falls back to defaults if no configuration is found. This change improves reliability and centralizes configuration management.
Improves Docker integration by copying config.example.json as the default config.json and updating ownership in the Dockerfile. Adjusts config paths in config.example.json for container compatibility and updates docker-compose.yml to build the image and comment out the config volume for baked-in config testing. Also updates .dockerignore to allow config.example.json.