Commit graph

207 commits

Author SHA1 Message Date
Broque Thomas
d9efcbdf99 feat: AcoustID audio verification, MusicBrainz enrichment UI, v1.5
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
2026-02-05 16:33:07 -08:00
Broque Thomas
8cdf548561 fix - cleared status too early before it could be read for live status updated. Musicbrainz 2026-02-03 21:26:15 -08:00
Broque Thomas
2a4cab3f96 fix polling for musicbrainz worker 2026-02-03 19:47:31 -08:00
Broque Thomas
cee5590718 feat(ui): add MusicBrainz enrichment status UI with real-time monitoring
MusicBrainz library enrichment with real-time
status monitoring and manual control.
Features:
- Status icon button in dashboard header with glassmorphic design
- Animated loading spinner during active enrichment
- Hover tooltip showing:
  - Worker status (Running/Paused/Idle)
  - Currently processing item
  - Artist matching progress with percentage
- Click-to-toggle pause/resume functionality
- Auto-polling every 2 seconds for live updates
Backend Changes:
- Added GET /api/musicbrainz/status endpoint
- Added POST /api/musicbrainz/pause endpoint
- Added POST /api/musicbrainz/resume endpoint
- Worker tracks current_item for UI display
- get_stats() returns enhanced status data
Frontend Changes:
- New MusicBrainz button component with tooltip
- Premium CSS styling with animations
- JavaScript polling and state management
- Positioned tooltip below button with centered arrow
Files Modified:
- web_server.py: API endpoints and worker initialization
- core/musicbrainz_worker.py: current_item tracking
- webui/index.html: Button and tooltip structure
- webui/static/style.css: Complete styling (240 lines)
- webui/static/script.js: Polling and interaction logic (115 lines)
2026-02-03 15:20:04 -08:00
Broque Thomas
35e65b2106 When downloading albums/EPs from Soulseek, after the first track downloads successfully, browse the source's folder and reuse it for subsequent tracks. This keeps entire albums coming from one source instead of scattering across many users.
- Single-worker mode for album batches (sequential downloads enable clean source reuse)
  - Browse API integration to list files in a source's directory
  - Failed source tracking per-batch to avoid retrying broken sources
  - Graduated quality scoring for upload speed, queue length, and free slots
  - Track number fallback fix (uses Spotify track number instead of hardcoded 1)
  - Duplicate completion guard to prevent double-decrement of active worker count
  - Dedicated logging for source reuse and post-processing diagnostics
2026-02-01 00:42:39 -08:00
Broque Thomas
da44278f12 add fourth search query for enhanced matching with both a cleaned and artist removed search. 2026-01-31 20:53:56 -08:00
Broque Thomas
7d8bb2b88a Revert "Add album-level Soulseek search and fix unbounded log growth"
This reverts commit 258fd7a8ae.
2026-01-31 18:42:37 -08:00
Broque Thomas
bbac51412d Revert "album level search for wishlist albums/eps"
This reverts commit 28ca3f5ce5.
2026-01-31 18:42:17 -08:00
Broque Thomas
28ca3f5ce5 album level search for wishlist albums/eps 2026-01-31 11:21:35 -08:00
Broque Thomas
258fd7a8ae Add album-level Soulseek search and fix unbounded log growth
When downloading an album/EP, perform a single album-level search on Soulseek to find a user with the complete album folder before falling back to per-track  search. This improves album completion rates and ensures consistent quality across tracks.
2026-01-30 12:46:52 -08:00
Broque Thomas
622e95e4df fix tidal auth issue on restart 2026-01-29 11:33:29 -08:00
Broque Thomas
56222b799a Fix ListenBrainz playlists not showing when tables don't exist yet
ListenBrainzManager opens its own raw sqlite3 connection, bypassing MusicDatabase initialization. If it runs   before MusicDatabase creates the tables, all queries fail with "no such table: listenbrainz_playlists". Added _ensure_tables() to ListenBrainzManager init that runs CREATE TABLE IF NOT EXISTS for both ListenBrainz tables — a  no-op when they already exist, but creates them if MusicDatabase hasn't run yet.
2026-01-29 10:16:19 -08:00
Broque Thomas
a74596cdd6 Fix Quality Scanner for Navidrome & expand ListenBrainz playlist limit
- Expose suffix, bitRate, and path fields on NavidromeTrack from the Subsonic API response
  - Add fallback in insert_or_update_media_track() to populate file_path and bitrate for Navidrome tracks, fixing the Quality Scanner
   returning 0 results
  - Increase ListenBrainz playlist cache limit from 4 to 25 per type
  - Add sub-tab grouping in the Recommendations tab (Weekly Jams, Weekly Exploration, Top Discoveries, etc.)
2026-01-29 09:24:55 -08:00
Broque Thomas
6750c20dc4 display all listenbrainz playlsts in unique categories. 2026-01-29 08:55:19 -08:00
Broque Thomas
681d4b3cd2 Fixed an issue where the wishlist wouldn't open if null value is detected 2026-01-27 17:04:31 -08:00
Broque Thomas
8248fab16e Fix iTunes wishlist and remove Single suffix
iTunes tracks now include album field for proper wishlist support.
  Strip " - Single" and " - EP" suffixes from iTunes album names.
2026-01-26 17:00:51 -08:00
Broque Thomas
ceafcdc49f Revert "Fix iTunes wishlist and remove ' - Single' suffix"
This reverts commit d9685364c1.
2026-01-26 16:51:12 -08:00
Broque Thomas
d9685364c1 Fix iTunes wishlist and remove ' - Single' suffix
Two fixes for iTunes integration:

1. iTunes failed tracks now properly added to wishlist
   - Root cause: iTunes tracks had no 'album' field (unlike Spotify)
   - Fix: Added album information to each track in get_album_tracks()
   - Tracks now include: album id, name, images, release_date

2. Remove ' - Single' suffix from iTunes album names
   - Root cause: iTunes API includes ' - Single' in collectionName
   - Fix: Added _clean_album_name() helper method
   - Strips ' - Single' and ' - EP' suffixes from all album names
   - Applied to all 6 locations where collectionName is used

Both Spotify and iTunes sources now work identically for wishlist
auto-processing when tracks fail or are cancelled.
2026-01-26 16:44:42 -08:00
Broque Thomas
9af0be1300 fixed issue where legacy cold was called. 2026-01-26 13:37:42 -08:00
Broque Thomas
db2400b42a fix navidrome sync issue where duplicate playlists are created 2026-01-26 10:25:55 -08:00
Broque Thomas
b9f2344f0f lookup artist name on track/album pull to ensure clean data.
Great for multi artist scenarios
2026-01-25 15:08:08 -08:00
Broque Thomas
48b914a4be Update spotify_client.py 2026-01-25 13:51:29 -08:00
Broque Thomas
4f1dc2c15f force refetch similar artists when Spotify IDs missing
When Spotify is enabled after populating similar artists with only iTunes IDs, the freshness check now detects missing Spotify IDs and triggers a refetch. This fixes the Discover page not showing data when switching from iTunes-only mode.
2026-01-24 23:46:01 -08:00
Broque Thomas
3cb88669e3 Fix iTunes-only Discover page not loading data
- Add similar artists fetching to web UI scan loop
  - Add database migration for UNIQUE constraint on similar_artists table                                          - Add source-agnostic /api/discover/album endpoint for iTunes support
  - Fix NOT NULL constraint on discovery_recent_albums blocking iTunes albums
  - Add fallback to watchlist artists when no similar artists exist
  - Add /api/discover/refresh and /api/discover/diagnose endpoints
  - Add retry logic with exponential backoff for iTunes API calls
  - Ensure cache_discovery_recent_albums runs even when pool population skips
2026-01-24 21:48:17 -08:00
Broque Thomas
4319d440ee Add iTunes as resilient primary source for discovery features
Implement dual-source architecture where iTunes serves as always-available
  primary source and Spotify as preferred source when authenticated.

  - Make watchlist scans provider-aware (manual and auto paths)
  - Update discovery pool population to process both sources
  - Update recent albums caching for both sources
  - Create source-specific curated playlists (Fresh Tape, Archives)
  - Add on-the-fly iTunes ID resolution for similar artists
  - Add iTunes ID check to similar artists freshness validation
  - Fix sqlite3.Row compatibility in personalized playlists
  - Fix iTunes ISO 8601 date format parsing
  - Update API endpoints to serve source-appropriate data

  This ensures the app remains fully functional if Spotify becomes
  unavailable (rate limits, auth issues, bans) by seamlessly falling
  back to iTunes data that has been building in parallel.
2026-01-24 09:47:41 -08:00
Broque Thomas
1d14a8b987 Discover page itunes integration. Spotify and Itunes will have their own pool 2026-01-23 23:05:58 -08:00
Broque Thomas
1560726bbc rebuild discovery pool flow to allow multiprocessing of itunes and spotfiy. each getting their own pool. 2026-01-23 14:25:26 -08:00
Broque Thomas
fecd371b5e Add lazy loading for artist images across UI
Implements lazy loading of artist images in search results, artist pages, and similar artist bubbles to improve performance and user experience. Updates the iTunes client to prefer explicit album versions and deduplicate albums accordingly. Adds a new API endpoint to fetch artist images, and updates frontend logic to asynchronously fetch and display images where missing.
2026-01-23 07:38:03 -08:00
Broque Thomas
f12478ee70 Add iTunes fallback and improve artist/album handling
Adds iTunes fallback to SpotifyClient for search and metadata when Spotify is not authenticated. Updates album type logic to distinguish EPs, singles, and albums more accurately. Refactors watchlist database methods to support both Spotify and iTunes artist IDs. Improves deduplication and normalization of album names from iTunes. Updates web server and frontend to use new album type logic and support both ID types. Adds artist bubble snapshot example data.
2026-01-22 19:12:14 -08:00
Broque Thomas
b790c34657 Add support for scanning artists with iTunes provider
Refactored artist scanning logic to use the active metadata provider (Spotify or iTunes) for fetching artist data, discography, and album tracks. Introduced helper methods to select the correct client and artist ID based on the provider, and updated image and similar artist handling accordingly. This enables watchlist scanning to work with iTunes when Spotify is not authenticated, improving flexibility and provider support.
2026-01-22 18:14:23 -08:00
Broque Thomas
579124c477 Normalize iTunes API responses to Spotify format
Updated get_album, get_album_tracks, and get_artist methods to return data structures compatible with Spotify's API format. This includes normalizing image arrays, artist and album fields, and adding synthetic URIs and external URLs for better interoperability.
2026-01-22 17:32:23 -08:00
Broque Thomas
f126cf7118 Add cross-provider support for watchlist artists
Introduces iTunes artist ID support to WatchlistArtist and database schema, enabling proactive backfilling of missing provider IDs (Spotify/iTunes) for watchlist artists. Updates WatchlistScanner to use MetadataService for provider-agnostic scanning and ID matching, and modifies web_server to support scans with either provider. Includes new database migration and update methods for iTunes and Spotify artist IDs.
2026-01-22 17:04:23 -08:00
Broque Thomas
e7c1e44cf1 Add iTunes metadata client and fallback guide
Introduces core/itunes_client.py implementing an iTunes Search API client for music metadata, providing search and lookup for tracks, albums, and artists with rate limiting. Adds METADATA-FALLBACK-IMPLEMENTATION.md, a comprehensive guide comparing fallback strategies for music metadata, including anonymous Spotify access and iTunes, and outlines integration approaches for seamless user experience without requiring Spotify credentials.
2026-01-22 15:31:02 -08:00
Broque Thomas
05c2cd7320 Update tidal_client.py 2026-01-16 11:48:50 -08:00
Broque Thomas
fdb9435fbe Fix pagination cursor retrieval in TidalClient
Updates the method for obtaining the next cursor during track pagination to use the approach from PR #113, retrieving it from 'links.meta.nextCursor' instead of 'meta.nextCursor'. This ensures correct pagination behavior.
2026-01-16 10:15:18 -08:00
Broque Thomas
6e02aa03ac Remove redundant playlist ownership filtering
Eliminated unnecessary filtering of playlists by owner or collaboration status, as the Spotify API already returns all accessible playlists. This simplifies the code and ensures all relevant playlists are processed.
2026-01-15 07:16:59 -08:00
Broque Thomas
665281f184 Refactor playlist fetching to use Tidal JSON:API
Rewrites playlist and track fetching to use Tidal's JSON:API endpoints with cursor-based pagination and batch track hydration. Adds robust rate limiting with retry logic, and introduces ISO-8601 duration parsing. This improves reliability, performance, and compatibility with Tidal's latest API structure.
2026-01-15 06:44:35 -08:00
Broque Thomas
007640a37f Reload Soulseek client config on orchestrator init
Added a call to self.soulseek._setup_client() in DownloadOrchestrator to ensure the Soulseek client configuration is reloaded when the orchestrator is initialized. This helps keep the client settings in sync with the latest configuration.
2026-01-11 21:02:23 -08:00
Broque Thomas
a8766828d9 Add content type filters for watchlist artists
Introduces new filters for live versions, remixes, acoustic versions, and compilation albums to the watchlist artist configuration. Updates the database schema, backend API, and web UI to support these options, allowing users to customize which content types are included for each artist in their watchlist.
2026-01-11 01:33:39 -08:00
Broque Thomas
9d275488e2 Add config reload support and improve config loading
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.
2026-01-06 09:29:11 -08:00
Broque Thomas
a23b033d37 Add search_and_download_best method to orchestrator
Introduces an async method to search for a query and automatically download the best result based on quality preferences and source priority. The method handles empty results, filters by quality, and logs the download process.
2026-01-05 22:33:24 -08:00
Broque Thomas
304cc84ad5 Add clearing of completed YouTube downloads
Implemented clear_all_completed_downloads in YouTubeClient to remove completed, cancelled, errored, and aborted downloads from memory. Updated DownloadOrchestrator to call this method, ensuring both Soulseek and YouTube completed downloads are cleared.
2026-01-05 22:00:38 -08:00
Broque Thomas
9bf1948097 Add priority query for Artist + Album + Title in matching
Introduces a new priority 0 query that combines artist, album, and title for improved matching, especially for YouTube and hybrid download modes. This helps better match tracks where the album is significant, such as soundtracks, and only applies when the album is not a generic label like 'single' or 'greatest hits'.
2026-01-05 21:27:54 -08:00
Broque Thomas
ddd2ebdb13 Improve YouTube download handling and shutdown safety
Adjusts matching weights for YouTube sources to rely more on title and duration, adds a shutdown callback to the YouTube client to prevent new downloads during shutdown, and enhances post-processing to reliably resolve actual YouTube file paths. Improves error handling for file removal, ensures no new batch downloads start during shutdown, and refines download monitoring to trigger post-processing on completed YouTube downloads. Also increases YouTube download retries and improves logging for debugging.
2026-01-05 18:08:43 -08:00
Broque Thomas
381e43c76b Update youtube_client.py 2026-01-04 15:02:41 -08:00
Broque Thomas
58f7fdb005 style youtube cards 2026-01-04 14:56:05 -08:00
Broque Thomas
61e822bf6f Add robust YouTube streaming support and improve format checks
Enhances streaming logic to better support YouTube as a download source, including improved filename handling, fuzzy file matching, and search query generation. Updates format checks in the frontend to skip them for YouTube (always MP3). Refactors backend to use a unified download status API for both Soulseek and YouTube, and improves service test messaging based on the active download mode.
2026-01-04 12:30:35 -08:00
Broque Thomas
c94b1d2f5b Add hybrid Soulseek/YouTube download orchestration - TESTING
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.
2026-01-03 22:20:36 -08:00
Broque Thomas
ce67e64ff7 Update youtube_client.py 2026-01-03 14:57:43 -08:00
Broque Thomas
eaf33f6f6d just testing things 2026-01-03 13:10:37 -08:00