Commit graph

419 commits

Author SHA1 Message Date
Broque Thomas
afa495756f Version 1.7 update 2026-02-28 21:58:13 -08:00
Broque Thomas
acfc26a4bd Add Tidal as a download source with full pipeline integration
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.
2026-02-28 21:47:19 -08:00
Broque Thomas
49c769ff5c Fix Hydrabase endpoint gaps, M3U default, and soul_id mapping
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.
2026-02-28 18:25:55 -08:00
Broque Thomas
0193f53d28 Improve Spotify artist search for short names using field filter 2026-02-28 11:04:50 -08:00
Broque Thomas
97502ec600 Boost exact artist name matches to top of search results
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.
2026-02-28 08:41:19 -08:00
Broque Thomas
694f190b6d Update web_server.py 2026-02-28 08:00:11 -08:00
Broque Thomas
1fbb1ec2c5 debug post processing flow 2026-02-27 11:34:27 -08:00
Broque Thomas
698b1fa4f3 clear current downloads 2026-02-27 11:18:13 -08:00
Broque Thomas
2dc72a39b7 Add music library selection for Navidrome
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.
2026-02-27 09:37:58 -08:00
Broque Thomas
7dfc10eb0b Store sync status in database instead of JSON file
Sync status was being saved to storage/sync_status.json on disk, which fails in Docker with permission denied         errors. Moved to the existing database preference system so it works in all environments.
2026-02-27 08:50:50 -08:00
Broque Thomas
c4bf6ff0f3 jellyfin server connection fix 2026-02-27 08:47:50 -08:00
Broque Thomas
e14a317a56 Add wishlist batch remove API and UI
Introduce batch removal support for wishlist tracks. Adds a new POST endpoint /api/wishlist/remove-batch that validates input, removes multiple tracks via the wishlist service, logs the result and returns a removed count. Updates the frontend (webui/static/script.js) to provide per-track and per-album checkboxes, a Select All button, a batch action bar with selection count and a Remove Selected action (with confirmation), and logic to refresh the view and wishlist count after removal. Styles (webui/static/style.css) are extended to support unified watchlist/wishlist batch bars, checkbox styling, and a Select All button. Preserves existing single-item removal behavior.
2026-02-26 17:19:34 -08:00
Broque Thomas
8c145c29cd Raise min_confidence thresholds to 0.9
Increase the minimum confidence cutoff to 0.9 in multiple discovery/search routines to reduce false positives. Affected functions: _search_spotify_for_tidal_track, _run_youtube_discovery_worker, _run_listenbrainz_discovery_worker, and _run_beatport_discovery_worker. This tightens matching criteria (previously 0.6/0.7/0.75) to favor higher-confidence matches, potentially reducing incorrect matches at the cost of fewer total matches.
2026-02-26 14:17:43 -08:00
Broque Thomas
e3a5608c95 Add manual candidate download API and UI
Add server endpoint to trigger a manual download for a user-selected candidate from the candidates modal (/api/downloads/task/<id>/download-candidate). The endpoint validates input, resets task and batch state (status, error, used_sources, active_count, permanently_failed_tracks), reconstructs Track/TrackResult objects and dispatches a background download attempt via missing_download_executor. Update the frontend candidates modal to show a download button per candidate, wire it to POST the candidate to the new API, and add CSS for table layout and download button styling. Enables restarting failed/not_found tasks by choosing a specific source without blocking the UI.
2026-02-26 13:45:38 -08:00
Broque Thomas
2852e2b39f Add candidates review modal & API
Expose cached search results for failed downloads and add a UI to review them. Implements a new GET /api/downloads/task/<task_id>/candidates endpoint that serializes any cached_candidates and track_info for a task and returns an error message and candidate count. The download worker now collects top raw search results (all_raw_results) and stores them in download_tasks[task_id]['cached_candidates'] when no match is found so users can inspect what Soulseek returned. The batch status payload includes has_candidates to mark "not_found" tasks as reviewable. On the frontend, new script functions (_ensureCandidatesClickListener, showCandidatesModal, _renderCandidatesModal, closeCandidatesModal) fetch and render a modal table of candidates; existing status rendering is updated to attach click handlers and error tooltips. Styles for the modal and a clickable .has-candidates state are added to style.css.
2026-02-26 13:09:51 -08:00
Broque Thomas
b814ae17ce Add quarantine clear API and folder sweeper
Add a POST /api/quarantine/clear endpoint to delete all files and folders inside the ss_quarantine directory (uses docker_resolve_path and reports removed item count). Implement _sweep_empty_download_directories() to walk the downloads folder bottom-up and remove empty directories (preserves root download dir, skips hidden entries, robust against locked/non-empty dirs). Wire the sweeper into existing cleanup flows: clear_finished_downloads(), the periodic _simple_monitor_task(), and the failed-tracks post-cleanup path so leftover empty folders are removed. Also add a Clear Quarantine button in the web UI and a clearQuarantine() client function to call the new API and show feedback.
2026-02-26 11:40:13 -08:00
Broque Thomas
fff8e62070 Set Spotify artist albums limit to 50
Add limit=50 to spotify_client.get_artist_albums so up to 50 albums/singles/compilations are returned per request, reducing the need for extra pagination and ensuring more complete discography results from a single call.
2026-02-26 10:03:02 -08:00
Broque Thomas
3c0d1fc187 Add album artists and watchlist artist fallback
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.
2026-02-26 08:58:44 -08:00
Broque Thomas
3893d75ad0 Raise artist threshold; add title similarity floor
In web_server.py, increase the minimum artist similarity from 0.4 to 0.5 in both cache validation and candidate scoring. Add a title similarity floor (min_title_similarity = 0.5) to _discovery_score_candidates: compute cleaned/core titles, allow a core-title exact match to bypass the floor, otherwise require title similarity >= 0.5. Only candidates that pass both artist and title floors proceed to full weighted scoring. This reduces false positives where a strong artist match could previously mask a poor title match.
2026-02-26 07:54:21 -08:00
Broque Thomas
e77dbf3f1e Refactor matching + use improved discovery scoring
Introduce a generic score_track_match(...) in core/matching_engine.py and make calculate_match_confidence(...) delegate to it. The new scorer is source-agnostic, consolidates artist/title/duration logic (core-title fast path, cleaned similarity, weighted 60/30/10 scoring) and improves artist matching.

In web_server.py add cache-validation (_validate_discovery_cache_artist) and a reusable _discovery_score_candidates(...) helper that calls the new scorer. Propagate per-match confidence through discovery flows (Tidal, YouTube, ListenBrainz, Beatport), increase Spotify/iTunes search limits, add an extended high-limit search strategy, tighten per-source thresholds, and save match confidence to the discovery cache. Overall this centralizes and standardizes matching logic and improves accuracy/validation for cached discovery results.
2026-02-25 22:43:33 -08:00
Broque Thomas
a2cff3f16f Use album artists for wishlist track grouping
Add album.artists to the album data when adding wishlist tracks and change the missing-tracks processing to prefer album-level artists for constructing artist context. The code now uses spotify_data.get('album') or {} and picks artist_ctx from album.artists first, falls back to source_info.artist_name (with safe JSON parsing if source_info is a string), then to track-level artists, and finally to a generic Unknown Artist. This ensures tracks from compilations or albums where the album artist differs from track artists are grouped consistently.
2026-02-25 20:06:19 -08:00
Broque Thomas
a0828c7aad Improve album grouping and normalize suffixes
Expand track title normalization and refine album grouping logic.

- core/acoustid_verification.py: Broadened the parenthetical-suffix regex to strip year-based remasters and additional variants (e.g. "2025 Remaster", "single edit", "album edit") while still removing common extras like (Live), (Deluxe), (Radio Edit), and featuring tags.
- web_server.py: Restrict the smart album grouping to only run for singles/auto-detected albums; explicit album downloads now preserve the original Spotify album name to avoid mangling names (e.g. reworked/remastered vs deluxe). Added explicit logging for both smart grouping and skipped grouping paths. The verification post-processing worker now checks an is_album_download flag in context and skips re-grouping when true, with fallback logging on errors.

These changes prevent unintended renaming of explicit album downloads and improve normalization of common title suffixes.
2026-02-25 15:39:01 -08:00
Broque Thomas
4bff57cb70 Handle edit versions, improve cleanup & thresholds
- matching_engine.py: Add 'single edit' and 'album edit' tokens and clarify radio edit comment so edit/cut variants are recognized as different cuts rather than being silently normalized away.
- database/music_database.py: Fix SQL param ordering by appending server_source to params; add a pre-step to strip "(with ...)" / "[with ...]" only when used inside brackets (so titles like "Stay With Me" are preserved); stop removing edit/version tokens in the generic cleanup and document that radio/single/album edits are treated as distinct by the similarity scorer to avoid incorrect matches.
- web_server.py: Increase DB match confidence threshold from 0.70 to 0.80 and update the runtime check accordingly.

These changes prevent edit/cut variants from being conflated with original recordings, improve title normalization for "with" featuring syntax in brackets, and fix a params ordering bug and a too-low match threshold.
2026-02-25 12:09:53 -08:00
Broque Thomas
35a03d6839 Add global watchlist override and UI
Introduce a global watchlist override feature and UI to control release/content filters across all watchlist artists. Backend: add /api/watchlist/global-config (GET/POST) for reading/updating global settings, validation to require at least one release type when override is enabled, and _apply_watchlist_global_overrides() to apply settings to WatchlistArtist objects. Scanners (manual and automatic) now call _apply_watchlist_global_overrides() and perform additional checks (_should_include_release, _should_include_track) to skip releases/tracks according to config. Frontend: add a Global Watchlist Settings modal, controls (release types, content filters, include-all shortcut), save/validation logic, banners/notices when global override is active, and integration into the watchlist modal and per-artist config. Styles: add supporting CSS for the modal and banners. Small cleanup/whitespace adjustments included.
2026-02-24 22:09:08 -08:00
Broque Thomas
7261b04950 Add hero cycling for similar artists
Add support for cycling hero/featured similar artists by introducing a last_featured timestamp and using it to prefer least-recently-featured artists. Changes include:

- DB migration: add _add_similar_artists_last_featured_column and call it during migrations to add a last_featured TIMESTAMP column (non-fatal on error).
- Query changes: get_top_similar_artists now excludes watchlist artists via a LEFT JOIN and wa.id IS NULL and orders results by last_featured (nulls first), then by last_featured asc, occurrence_count desc, and similarity_rank asc. The query aliasing was also added for clarity.
- New helper: mark_artists_featured updates similar_artists.last_featured = CURRENT_TIMESTAMP for shown artists.
- Web server: increase fetch limit to 50, remove random shuffle and instead take the top 10 (already ordered by cycling logic), and call mark_artists_featured to rotate featured artists.

These changes aim to provide deterministic, least-recently-shown cycling of hero artists while keeping watchlist artists out of recommendations.
2026-02-24 18:54:21 -08:00
Broque Thomas
f90d6567f7 Hydrabase: improve parsing add discography/tracks
Improve Hydrabase response handling and add discography/album track helpers. core/hydrabase_client.py: extract peer counts from stats.connectedPeers, handle new "response" key and stats-only or unexpected response shapes (return empty instead of wrapping), and add search_discography() and get_album_tracks() to map Hydrabase results into Album/Track objects. web_server.py: avoid redundant Hydrabase round-trips by passing precomputed hydrabase_counts into the background comparison worker; prefer Hydrabase for artist discography and album track import when active (with Spotify fallback); and route album-context searches to Hydrabase when configured. These changes reduce duplicate network calls and improve robustness against varied Hydrabase payloads.
2026-02-24 18:42:48 -08:00
Broque Thomas
44297a210b Add thread-safe MusicBrainz release cache
Introduce an in-memory, locked cache (_mb_release_cache and _mb_release_cache_lock) for MusicBrainz release lookups to ensure concurrent post-processing threads use a consistent release MBID and avoid splitting albums in players. Use the track artist (first artist in multi-artist fields) for artist MBID matching. Remove usage of AudioDB's per-track strMusicBrainzAlbumID as a fallback for MUSICBRAINZ_RELEASE_ID and add a comment explaining why (AudioDB links tracks to original albums which can differ per track and split albums). Includes safeguards around match_release calls and stores empty results in the cache to avoid repeated failed lookups.
2026-02-24 16:43:36 -08:00
Broque Thomas
fb7b373d71 Improve edition detection and completion logic
Prefer an album's stored track count when owned_tracks meets or exceeds it (avoids marking a complete standard edition as incomplete when an external source reports a larger deluxe count). Add more robust edition-detection regexes and generic catch-alls (parenthesized/bracketed text containing "edition") in music_database.py and web_server.py, and include silver/gold/platinum edition variants. Also tidy related regex handling and comments to improve matching for varied edition naming (e.g. "MMXI Special Edition").
2026-02-24 12:05:12 -08:00
Broque Thomas
a8e84fa20f Verify bytes before marking downloads complete
Add robust checks and stabilization before treating transfers as finished. The patch verifies bytesTransferred vs expected size in multiple places (monitor, API polling, YouTube handling, and batch status building) to avoid acting on premature "Completed/Succeeded" states. It adds per-poll file-claiming to prevent two contexts from grabbing the same file, introduces file-stability loops and retries when locating/moving files, replaces a blind 1s wait with repeated size checks, and fsyncs destination files after copy. Also introduces an _incomplete_warned flag to reduce log spam and ensures post-processing is triggered reliably once files are truly stable.
2026-02-24 08:52:47 -08:00
Broque Thomas
1283041836 Integrate Hydrabase P2P metadata client
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.
2026-02-24 08:11:48 -08:00
Broque Thomas
1c34967fd3 Raise Spotify API interval; pause enrichments
Increase Spotify client rate limit and reduce API contention during watchlist scans. Changes:

- core/spotify_client.py: Bumped MIN_API_INTERVAL from 0.2s to 0.35s (~171 calls/min) to stay safely under Spotify's ~180/min limit.
- web_server.py: In start_watchlist_scan and automatic scan flow, pause spotify_enrichment_worker and itunes_enrichment_worker before scanning (tracking with _enrichment_was_running/_itunes_enrichment_was_running) and resume them in finally blocks; added console prints for pause/resume. This prevents enrichment workers from contending for API quota during long scans.
- webui/static/script.js: Improved enrichment status tooltip logic to prioritize explicit currentType and then fall back to completion-based inference with explicit branches for artists, albums, and tracks for clearer progress text.

These changes aim to avoid API rate violations and make scan progress display more predictable.
2026-02-23 21:22:27 -08:00
Broque Thomas
317d5c1770 Add Retag tool (DB, backend, frontend)
Introduce a new Retag tool to track and re-tag previously downloaded albums/singles. Changes include:

- Database: add migration hook and create retag_groups and retag_tracks tables, indexes, and many helper methods (add/find/update/delete groups & tracks, stats, trimming).
- Backend (web_server): capture completed album/single downloads into the retag tables, implement retag execution logic (_execute_retag) to fetch album metadata, match tracks, update tags, move files, download cover art, and update DB. Add thread-safe globals, executor, and REST endpoints for stats, listing groups, group tracks, album search, execute, status, and delete.
- Frontend (webui): add Retag Tool card, modals, search UI, JS to list groups/tracks, search albums, start retag operations, poll status, and update UI; include help content. Add CSS for modals and components.

The migration is invoked during DB init to ensure existing installations create the new tables. The tool caps stored groups (default 100) and avoids duplicate track entries.
2026-02-23 20:39:04 -08:00
Broque Thomas
81617b06aa Reset watchlist scan timestamps on clear/period change
When clearing the wishlist or changing the discovery lookback period, reset watchlist_artists.last_scan_timestamp to NULL so subsequent scans can re-discover older releases that were previously filtered by an earlier scan timestamp. clear_wishlist now deletes wishlist_tracks, updates last_scan_timestamp for all watchlist artists, and logs the number of tracks cleared and artists reset. set_discovery_lookback_period also resets last_scan_timestamp and reports how many artists were reset. Minor whitespace cleanups in watchlist_scanner and web_server included.
2026-02-23 16:47:04 -08:00
Broque Thomas
7eee2be38c Add release_date to Track and UI
Add a release_date field to the Track dataclass for both iTunes and Spotify clients (iTunes: parsed from releaseDate, Spotify: from album.release_date). Propagate release_date into enhanced search results in web_server and into the client-side script so album objects include release_date when available. Also broaden playlistId matching in the missing-tracks process to include 'enhanced_search_track_'. Removed SQLite SHM/WAL files from the repo (cleanup of DB temporary files). These changes enable showing and using track release dates across the app.
2026-02-23 16:25:23 -08:00
Broque Thomas
f1fe72ceb2 Add track selection UI and backend mapping
Add per-track selection checkboxes, select-all control and a selection count to download modals (missing/YouTube/Tidal/artist-album). Implement JS helpers (toggleAllTrackSelections, updateTrackSelectionCount) to manage checkbox state, row dimming, button disabling, and to filter/stamp selected tracks with _original_index before sending to the backend. Update start/add-to-wishlist flows to use only selectedTracks and disable controls once analysis starts. Backend _run_full_missing_tracks_process now reads _original_index to preserve original table indices in analysis results. CSS updates (mobile.css and style.css) add styling for checkbox columns, responsive hiding logic for headers/columns, selection visuals (.track-deselected), and small layout/width tweaks.
2026-02-23 15:54:58 -08:00
Broque Thomas
2ba48f917d Add server-side M3U export and UI setting
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.
2026-02-23 11:59:16 -08:00
Broque Thomas
666e65ed3b Add repair scanning, tracklist fallbacks, UI polling
Introduce deferred album repair scanning and robust tracklist resolution plus UI/presentation tweaks.

- core/repair_worker.py: Add lazy MusicBrainz and AudioDB client accessors, per-batch folder queues, and register_folder/process_batch to defer folder scans until a batch completes. Implement cascading tracklist resolution (_resolve_album_tracklist) using Spotify/iTunes IDs, Spotify track→album lookup, album search, MusicBrainz release lookup, and AudioDB→MusicBrainz fallback. Add helpers to read Spotify track IDs, MusicBrainz album IDs, album/artist tags from files, MB/AudioDB fetchers, placeholder-ID filtering, and rename associated .lrc files when renaming audio files. Cache/locking and background-threaded scanning included. Improves resilience to missing/placeholder IDs and avoids circular imports.

- web_server.py: Register album folders for repair in post-processing and trigger repair_worker.process_batch when batches complete (multiple completion paths) so scans run after downloads finish.

- webui/static/script.js: Reduce unnecessary background work by skipping many fetches when the tab is hidden, and refresh dashboard-specific data on visibility change to ensure UI updates after OAuth or tab switch.

- webui/static/style.css: Replace glassmorphic backdrop-filters with opaque dark gradients for sidebar and main content to improve GPU rendering and visual consistency.

Overall: Adds reliable post-download album repair scanning using multiple metadata sources and reduces unnecessary client polling and heavy CSS effects for better performance and robustness.
2026-02-23 10:18:31 -08:00
Broque Thomas
129f69fce9 Add Blasphemy Mode to delete FLAC after MP3
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.
2026-02-22 23:23:52 -08:00
Broque Thomas
24bfc2462d Add Spotify & iTunes workers; update repair worker
Add full-featured SpotifyWorker and iTunesWorker background workers to enrich artists, albums, and tracks with external metadata using batch cascading searches, fuzzy name matching, ID validation, and DB backfills. Update RepairWorker to re-read the transfer path from the database each scan, resolve host paths when running in Docker, and trigger immediate rescans when the transfer path changes; remove the static config_manager dependency. Also include supporting changes to the database layer and web UI/server (stats, controls, and styles) to integrate the new workers and reflect updated worker status.
2026-02-22 22:29:10 -08:00
Broque Thomas
2aa529f8e4 Use new Spotify /items endpoint with fallback
Add _get_playlist_items_page to call the new playlists/{id}/items endpoint (Feb 2026 API migration) and fall back to spotipy.playlist_items (old /tracks) on 403/404. Update _get_playlist_tracks and web_server.get_playlist_tracks to use the new helper to avoid 403 errors for Development Mode apps while preserving compatibility with Extended Quota Mode.
2026-02-22 19:15:11 -08:00
Broque Thomas
58df2ba33c Scope fuzzy key match to username and add lock
Tighten fuzzy matching in post-processing when no exact context is found: acquire matched_context_lock for thread-safe access and limit candidate keys to those starting with the current username prefix ("{task_username}::") while still matching the file basename. This prevents cross-album/username metadata contamination during mass downloads (e.g., multiple albums with identical track basenames) and reduces erroneous fuzzy matches.
2026-02-22 16:21:28 -08:00
Broque Thomas
eedd21f9aa Fallback MusicBrainz IDs from AudioDB
Use MusicBrainz IDs returned by AudioDB as fallbacks when MB lookup is missing. The patch maps strMusicBrainzID/strMusicBrainzAlbumID/strMusicBrainzArtistID to MUSICBRAINZ_RECORDING_ID, MUSICBRAINZ_RELEASE_ID, and MUSICBRAINZ_ARTIST_ID respectively (only if those tags are not already present), sets recording_mbid and artist_mbid where applicable, and adds informational prints for debugging.
2026-02-21 18:02:09 -08:00
Broque Thomas
8ac00f124a Update web_server.py 2026-02-21 17:50:18 -08:00
Broque Thomas
b0fdf6b220 Embed MusicBrainz release MBID in audio tags
Request recording 'releases' from MusicBrainz and, when available, capture the first release MBID into id_tags['MUSICBRAINZ_RELEASE_ID']. Persist this release (album) MBID across tag formats by adding TXXX ('MusicBrainz Album Id'), a generic tag 'MUSICBRAINZ_ALBUMID', and an iTunes MP4 freeform key. This allows tracks to be associated with their MusicBrainz release/album.
2026-02-21 17:19:59 -08:00
Broque Thomas
aa59ab7cd0 Verify using actual processed path and handle stream moves
Stop recomputing expected file paths during verification and instead use the exact path computed/moved during post-processing (context['_final_processed_path']). If that context value is missing, assume success to avoid false failures and mark the task completed.

Also store the computed final path into context in _post_process_matched_download so verification uses the exact same path. Add logic to handle cases where the source vanished but a variant (quality-tagged) file exists in the destination — treat that as success, set the final path, download art and generate LRC.

In the post-processing worker: skip verification when the task is already completed or marked as stream_processed, check for stream_processed status while searching, increase file search retries from 3 to 5 with longer sleeps, and re-check stream_processed before marking a task failed. Improve log messages and error text to reduce false negatives caused by independent recomputation or concurrent stream processing.
2026-02-21 17:11:20 -08:00
Broque Thomas
c7e3169b82 Recover uncaptured failed tracks for wishlist
Add a recovery step during wishlist processing that scans in-memory download_tasks (under tasks_lock) for tasks marked 'failed' or 'not_found' but not present in permanently_failed_tracks, and appends normalized track entries (including retry_count, failure_reason, spotify_track, and cached candidates). This prevents tasks that were force-marked failed by stuck-detection logic from being silently skipped in wishlist sync. Also fix post-processing context lookup by rebuilding the context key with _make_context_key(task_username, task_filename) so it matches how context keys are stored.
2026-02-21 15:52:39 -08:00
Broque Thomas
ce474749d5 Add library repair worker and UI
Introduce a RepairWorker to scan the transfer folder and automatically detect/repair broken album track numbers (e.g. the "all tracks = 01" bug). The worker uses mutagen to read/write tags, fuzzy-matches titles against an album tracklist (Spotify/iTunes via a SpotifyClient), updates filenames and the tracks DB file_path when renamed, and caches album tracklists. It also adds DB schema support (repair_status, repair_last_checked, and an index).

Integrates the worker into the web server: initializes and starts the worker, and exposes /api/repair/status, /api/repair/pause and /api/repair/resume endpoints. Adds UI elements (button, tooltip), client-side JS to poll and control the worker, CSS for visuals/animations, and a new image asset (whisoul.png).
2026-02-21 15:00:23 -08:00
Broque Thomas
49a6c58ea8 Add Hydrabase P2P mirror worker
Introduce a Hydrabase P2P mirror worker and integrate it into the web UI and server flows. Adds core/hydrabase_worker.py: a background thread with a capped queue (1000), enqueue API, rate limiting, basic stats (sent/dropped/errors), and logic to send JSON requests over a provided WebSocket (responses received and discarded). Integrates the worker into web_server.py (import, startup init, status/pause/resume endpoints, and enqueues queries from multiple search endpoints when dev mode is enabled). Adds UI elements, JavaScript polling/toggle logic, and CSS styling for a Hydrabase status button in webui (index.html, static/script.js, static/style.css) to display and control worker state.
2026-02-21 02:15:43 -08:00
Broque Thomas
35fd7bb294 Add Hydrabase dev UI and WebSocket support
Introduce a developer-only Hydrabase testing UI and backend WebSocket integration. Adds a simple dev-mode toggle (password 'hydratest') and new API endpoints (/api/dev-mode, /api/hydrabase/connect, /api/hydrabase/disconnect, /api/hydrabase/status, /api/hydrabase/send) that use websocket-client to connect/send raw JSON to a Hydrabase instance. Frontend changes include a Hydrabase nav/page, payload editors, response panel, dev-mode UI in Settings, associated JS handlers, CSS styling, and an icon asset. Also add websocket-client to requirements.
2026-02-21 00:32:04 -08:00
Broque Thomas
cfa4a0c59f Add $artistletter and multi-disc support
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.
2026-02-20 22:53:15 -08:00