Commit graph

763 commits

Author SHA1 Message Date
Broque Thomas
46f82027cb Allow re-sync from download_complete state and add Rediscover button
All 6 playlist sync endpoints now accept download_complete phase so
users can re-sync after downloading. Added Rediscover button to
discovered and download_complete states (YouTube + Beatport). Added
full button set (Sync, Download Missing, Rediscover) for
download_complete which previously showed no buttons at all.
2026-03-19 22:17:59 -07:00
Broque Thomas
c53583716a Fix batch_complete firing with 0 downloads and album ID int cast error
- Only emit batch_complete automation event when successful_downloads > 0
- Remove int() cast on album_id in _fix_incomplete_album — Plex/Jellyfin
  use hash/text IDs that SQLite stores as-is in INTEGER columns
- Use string comparison for album_id equality check
2026-03-19 19:48:06 -07:00
Broque Thomas
fc4e16337a Redesign hybrid mode with N-source priority ordering
Replace fixed primary/secondary hybrid dropdowns with an ordered list
of all 5 download sources. Users enable/disable each source and reorder
with up/down arrows to set download priority. Sources are tried in
order until one returns results.

- New hybrid_order config field (backward compat with legacy primary/secondary)
- Download orchestrator loops ordered list with per-source error handling
- Sortable source list UI with icons, toggle switches, priority numbers
- Source-specific settings shown for all enabled hybrid sources
- Seamless migration from legacy 2-source to N-source format
2026-03-19 18:51:52 -07:00
Broque Thomas
3293a476fc Check staging folder for existing files before downloading
Before searching Soulseek/YouTube, checks the staging folder for a
matching file using tag-based or filename-based fuzzy matching. On match,
copies the file to the transfer folder and runs normal post-processing
(tagging, AcoustID, path organization). Staging scan is cached per batch
to avoid re-walking for every track.
2026-03-19 16:51:10 -07:00
Broque Thomas
e715ceef3e Add multi-source search tabs for enhanced search (Spotify/iTunes/Deezer)
Search results now show switchable tabs for alternate metadata sources.
Primary source renders immediately, alternate sources load in parallel
and tabs appear progressively as each completes.

- New /api/enhanced-search/source/<name> endpoint for per-source queries
- Source-aware routing via ?source= param on discography, album tracks,
  album detail, and artist image endpoints (prevents numeric ID
  misrouting between iTunes and Deezer)
- Source override stored on artistsPageState for consistent navigation
- Tabs styled with source brand colors, show result counts
- All additive — users who ignore tabs see zero behavioral change
2026-03-19 13:23:43 -07:00
Broque Thomas
b9c83a50fa Add Soulseek peer queue filtering and configurable download timeout
- Add max_peer_queue setting to skip peers with long queues (soft filter
  with fallback to unfiltered if all results removed)
- Add download_timeout setting replacing hardcoded 10-minute limit
- Include quality_score (peer health: upload speed, free slots, queue
  length) in result ranking — was calculated but never used in sort key
- New UI controls in Soulseek settings section
2026-03-19 11:47:37 -07:00
Broque Thomas
11b1222c90 Fix YouTube playlist parsing capped at ~100 tracks
Force full playlist resolution with lazy_playlist=False and materialize
entries list to prevent yt-dlp from stopping at the first page of results.
2026-03-19 09:47:12 -07:00
Broque Thomas
99481a0232 Fix Track Match search ignoring Track/Artist fields and low result limit
- Frontend was concatenating Track and Artist inputs into a single
  query string, causing Spotify to return mixed results matching
  either word in any field. Now sends track and artist as separate
  params; backend builds field-filtered query (track:X artist:Y).
- Result limit was silently capped at 10 in spotify_client.search_tracks
  via min(limit, 10). Raised to respect requested limit up to
  Spotify's API max of 50.
- iTunes fallback endpoint updated with same field-specific params.
- Legacy ?query= param still supported for backward compatibility.

Fixes #194
2026-03-19 08:23:19 -07:00
Broque Thomas
0a3cca4f1f Fix Spotify invalid_client and Tidal redirect URI mismatch on auth
- Duplicate `spotify` key in saveSettings() object literal caused
  second definition (embed_tags/tags) to silently overwrite the first
  (client_id/client_secret/redirect_uri), destroying credentials on
  every save. Merged into single key.
- authenticateSpotify() and authenticateTidal() now await saveSettings()
  before opening auth window, ensuring credentials are persisted.
- Tidal auth now dynamically sets redirect_uri from request host for
  LAN/Docker users and stores it in tidal_oauth_state so the callback
  token exchange uses the same URI.

Fixes #191
2026-03-19 08:02:12 -07:00
Broque Thomas
6b5e37aded Add preflight track-hash comparison and fix duplicate sync history entries
Preflight: hash track IDs before syncing and compare against last sync.
Skip only if exact same tracks were already synced and all matched.
Replaces the old count-based smart-skip which could miss track swaps.

Sync history: update existing entry for same playlist_id instead of
creating duplicates. Re-syncing the same playlist now refreshes the
existing row with new timestamps and stats.
2026-03-18 18:17:50 -07:00
Broque Thomas
0428a4565d Deduplicate variant album releases in artist discography view
Metadata sources (Deezer/iTunes/Spotify) return separate entries for
Explicit/Clean/Remastered variants of the same album. Normalize titles
by stripping variant suffixes and group by name+year, keeping the
version with the most tracks or preferring explicit.
2026-03-18 17:22:39 -07:00
Broque Thomas
e4579b4f2a Fix wishlist items from playlist sync missing album name and cover art
Playlist refresh was storing matched_data.album as a bare string with
no images dict. When unmatched tracks were added to the wishlist, they
showed as 'Unknown Album' with no cover art. Now all three playlist
import paths (authenticated API, public scraper, spotify_public) store
album as a proper dict with name and images array, matching the format
used by the discovery worker.
2026-03-18 17:11:26 -07:00
Broque Thomas
7b3bfd8db4 Fix artist discography miscategorizing albums as singles/EPs
Track count heuristics were overriding the album_type field from
Spotify/iTunes/Deezer, forcing any release with <=3 tracks into
singles and 4-6 tracks into EPs regardless of actual album type.
Now trusts the source's album_type directly.
2026-03-18 16:52:27 -07:00
Broque Thomas
b9732156cd Add per-tag granular toggle settings for all 47 embedded tags
Replace category-based tag settings (10 toggles) with per-tag controls
grouped by source service in an accordion UI. Each of the 11 service
groups (Spotify, iTunes, MusicBrainz, Deezer, AudioDB, Tidal, Qobuz,
Last.fm, Genius, General) has a master toggle that disables all child
tags, with individual toggles for fine-grained control. ISRC and
copyright fallback chains are now per-source toggleable. Genre merge
contributions from each source are independently controllable. All
tags default to enabled for backward compatibility.
2026-03-18 16:17:20 -07:00
Broque Thomas
d3bff90fd6 Add Picard-compatible MusicBrainz tags and per-category tag settings
Post-processing now writes all 18 MusicBrainz tags that Picard writes:
Release Group ID, Album Artist ID, Release Track ID, Release Type,
Status, Country, Original Date, Media, Barcode, Catalog #, ASIN,
Script, Total Discs (plus the 5 already supported). One cached API
call per album via get_release with recordings include.

New "Tags to Embed" settings section with 10 category toggles (all
enabled by default): MusicBrainz IDs, Release Info, Source IDs, ISRC,
BPM, Mood & Style, Copyright & Label, Genre Merging, URLs, Quality.
Each shows inline description of what it includes.
2026-03-18 15:49:36 -07:00
Broque Thomas
5adfdad9a3 Speed up dashboard polling intervals for more responsive UI
Service status 10s→5s, activity feed 5s→2s, watchlist/wishlist/db stats 30s→10s.
2026-03-18 15:02:00 -07:00
Broque Thomas
2c2c006f83 Fix wishlisted tracks showing 'Unknown Album' with no cover art
Multiple code paths built wishlist album data as a bare string instead
of a dict with images/album_type/total_tracks, causing wishlist entries
to lose album name and artwork. Fixed in: Beatport fallback conversion,
sync normalization, _ensure_spotify_track_format, and wishlist service
track reconstruction. Now uses track name as album fallback and always
includes required album dict keys.
2026-03-18 14:23:53 -07:00
Broque Thomas
333b8577ca Fix NoneType crash on Soulseek test when download orchestrator fails to init 2026-03-18 08:56:36 -07:00
Broque Thomas
2656927f79 Beatport enrichment progress, metadata cache fixes, per-source cache clearing
- Fix enrichment progress never updating: remove `continue` that skipped
  progress_callback for successful tracks in enrich_chart_tracks
- Split chart/extract into two-step flow: extract raw tracks, then enrich
  via polling endpoint with live progress overlay updates
- Move Beatport enrichment cache to persistent metadata cache system
- Fix metadata cache detail modal for Beatport (URL entity_ids with slashes)
- Add per-source Clear dropdown (Spotify/iTunes/Deezer/Beatport) to cache browser
- Remove debug logging from enrichment progress tracking
2026-03-18 08:39:02 -07:00
Broque Thomas
cde5754f0f Add Auto-Fill fix handler for incomplete album findings
When the maintenance worker flags an incomplete album, users can now
click "Auto-Fill" to automatically locate missing tracks in the library,
move/copy them into the album folder, and apply full metadata enhancement
(MusicBrainz, Deezer, cover art, etc.). Singles are moved; tracks from
multi-track albums are copied. Quality gate prevents filling FLAC albums
with lossy files. Tracks not found in library are added to wishlist with
album context for auto-download.
2026-03-17 22:56:24 -07:00
Broque Thomas
fbf44123ec Add Beatport download bubbles, enrichment cache, and batch enrichment
- Persistent download bubble cards on Beatport page and dashboard,
  matching the existing artist/search bubble UX with click-to-reopen,
  green checkmark on completion, and snapshot persistence
- In-memory enrichment cache (2h TTL, thread-safe) skips re-scraping
  when the same chart is clicked twice
- Batch enrichment replaces one-by-one HTTP requests with a single
  POST, using WebSocket progress events for overlay updates
- Fix _beatportModalOpening guard blocking modal open after fast
  cached enrichment by resetting the flag in openBeatportChartAsDownloadModal
- Hide Browse/My Playlists tabs — Browse is now the only Beatport view
2026-03-17 21:41:04 -07:00
Broque Thomas
27a0cf8b81 Add Sync History feature with live re-sync progress and source detection
- New sync_history DB table tracks last 100 syncs with full cached context
- Records history for all sync types: Spotify, Tidal, Deezer, YouTube,
  Beatport, ListenBrainz, Mirrored playlists, and Download Missing flows
- Sync History button on sync page with modal showing entries, source
  filter tabs, stats badges, and pagination
- Re-sync button: server syncs expand card inline with live progress bar,
  matched/failed counts, and cancel button; download syncs open download modal
- Re-syncs update the original entry (moves to top) instead of creating duplicates
- Delete button (x) on each entry with smooth remove animation
- Fix mirrored playlist source detection (youtube_mirrored_ matched youtube_)
- Fix broken server import thumbnails with URL validation
2026-03-17 20:39:41 -07:00
Broque Thomas
f8f113d0e7 Beatport direct download — skip discovery, open download modal directly
Clicking any Beatport item now opens the download modal directly instead of
going through the discovery flow (scrape → chart card → discovery modal →
Spotify/iTunes matching → download).

Releases (albums/EPs) open as album downloads with full context.
Charts/playlists (Top 100, Featured Charts, DJ Charts, Top 10) open as
playlist downloads with per-track enrichment — each track's individual
Beatport page is visited to get release name, duration, artwork, BPM, key,
genre, and label.

Key changes:
- Add get_release_metadata() and enrich_chart_tracks() to scraper
- Add /api/beatport/release-metadata and /api/beatport/enrich-tracks endpoints
- Rewrite all Beatport click handlers to open download modal directly
- Per-track enrichment with live progress overlay (one-by-one fetching)
- Split combined artist strings so folder paths use primary artist only
- Prevent Beatport IDs from being written to Spotify tag fields
- Add beatport_release_ prefix detection for album download mode
- Support enrich=false query param for frontend-driven enrichment
2026-03-17 19:28:11 -07:00
Broque Thomas
b186fed05b Fix Beatport new releases scraper broken by hashed CSS class changes
Replace all hardcoded styled-components class selectors (with build hashes
that break on every Beatport deploy) with partial class name matches using
[class*="prefix"] pattern. Applies to new releases endpoint and hero
release scraper.
2026-03-17 15:56:00 -07:00
Broque Thomas
6bf337423d Prefer album versions over singles when matching tracks to metadata sources
Add album_type and total_tracks fields to Track dataclass, populate from
Spotify/iTunes/Deezer API responses, and apply a small tiebreaker bonus
(+0.02 for albums, +0.01 for EPs) in all matching loops so album versions
win when confidence scores are otherwise equal.
2026-03-17 15:18:28 -07:00
Broque Thomas
6759f68b2b Fix $year template variable empty in discovery worker downloads
All discovery workers (playlist, Tidal, Deezer, Spotify Public, YouTube,
ListenBrainz, Beatport) built album_data dicts without release_date when
using fallback metadata sources. The Track dataclass had release_date
available but it was never extracted into album_data, causing $year to
resolve as empty in file path templates.
2026-03-17 12:46:39 -07:00
Broque Thomas
6bccbd9cf2 Fix Hydrabase background comparison to use configured metadata source instead of hardcoded iTunes 2026-03-17 12:09:05 -07:00
Broque Thomas
503e45fd9c Update What's New modal with recent fixes and downsample feature 2026-03-17 11:58:21 -07:00
Broque Thomas
a9d0607d25 Add hi-res FLAC to CD quality downsampling in post-processing
New toggle under Post-Download Conversion: automatically converts 24-bit
or high sample rate FLAC files to 16-bit/44.1kHz after download, replacing
the original. Uses ffmpeg with temp file + verify + atomic swap for safety.
Runs before lossy copy so MP3s are made from the downsampled version.
Also prevents bit depth strict mode from rejecting files that will be
downsampled anyway.
2026-03-17 11:53:56 -07:00
Broque Thomas
a62cc821ee Fix $year template variable empty in playlist/sync downloads
The fallback download path (playlists, discovery, sync) built spotify_album_context
from track_info.album which can be a plain string (no release_date) for discovery
playlists or missing metadata. Now backfills release_date, album_type, total_tracks,
and album name from the existing get_track_details API call — zero extra API calls.
Also adds total_discs passthrough for fallback path parity.
2026-03-17 11:35:19 -07:00
Broque Thomas
cc62541a65 Add Select All, Fix Selected & Fix All to Library Maintenance findings 2026-03-17 09:25:21 -07:00
Broque Thomas
162542a0cf Fix wishlist Unknown Album caused by stale cross-provider discovery data
Mirrored playlist discovery results are cached per-track in extra_data with
the provider that discovered them. When the user switches metadata source
(e.g. Spotify → Deezer), prepare-discovery was serving stale data from the
old provider — wrong IDs, empty albums, no cover art. Now it compares the
cached provider against the current active source and invalidates mismatched
entries, forcing a clean re-discovery with the correct provider.
2026-03-17 09:09:07 -07:00
Broque Thomas
b9d3c4051e Fix Unknown Album in wishlist: album name lost when raw Spotify data missing
Root cause: discovery searches return (Track, raw_data, confidence) but
raw_data can be None (Strategy 4 extended search) or have mismatched index.
When raw_data is None, album_obj becomes {} — an empty dict that passes
normalization unchanged, so album name is never populated.

Fix: after extracting album_obj from raw_data, fall back to track_obj.album
(always populated from the SpotifyTrack dataclass) when album_obj has no
name. Applied to all 3 discovery paths (Deezer, Tidal, Spotify Public).

Also handle both string and dict album formats in wishlist UI rendering.
2026-03-17 08:12:34 -07:00
Broque Thomas
8b403e3947 Fix wishlist normalization mutating tracks_json in-place
The normalization loop was modifying dict objects shared with the
SpotifyTrack construction loop. SpotifyTrack.artists expects List[str]
but normalization converted to [{'name': ...}] dicts. Use dict(t) copy
so original tracks_json is untouched.
2026-03-17 07:57:02 -07:00
Broque Thomas
7fd29c4f77 Fix confirm modals hidden behind other modals and wishlist showing Unknown Album
- Bump confirm dialog z-index to 200000 (both #confirm-modal-overlay and
  .confirmation-modal-overlay) so they always appear above all other modals
- Normalize track data in _run_sync_task before storing in original_tracks_map:
  album as dict {'name': ...} and artists as [{'name': ...}] — fixes all
  source converters (Deezer, YouTube, Tidal, Spotify Public, ListenBrainz,
  Beatport) whose fallback paths stored plain strings, causing the wishlist
  UI to show "Unknown Album" for every synced track
2026-03-17 07:53:59 -07:00
Broque Thomas
4c6e2fe1ec Revamp automation page: 2-col grid, duplicate, search/filter, templates, grouping
- Switch user automations to 2-column grid layout (matches system automations)
- Add duplicate button on non-system cards with POST /api/automations/<id>/duplicate
- Add search/filter bar (text search + trigger/action dropdowns) shown at 6+ automations
- Add Inspiration section with 8 starter templates that pre-fill the builder
- Add folder-style automation grouping with group_name DB column, dropdown
  popover for assignment, collapsible group sections, and builder group input
2026-03-17 07:40:14 -07:00
Broque Thomas
4a308483ab Add smart-skip to sync playlist node for efficient scheduled syncing
Sync now compares current discovered track count against last sync's
matched count. Skips when all discovered tracks are already on the server.
Re-syncs when wishlist may have downloaded missing tracks since last sync.
Saves matched/discovered/total counts to sync status after each run.

Enables putting sync on a schedule without wasting resources — it skips
instantly when nothing changed and only runs when there's something new.
2026-03-16 22:32:08 -07:00
Broque Thomas
a7e60f2aaf Improve mirrored playlist refresh logic and suppress no-op discovery events
- Set album_name from embed entity for album-type Spotify public scrapes
- Log warning and show skip status when Tidal not authenticated during refresh
- Only emit discovery_completed event when new tracks were actually discovered,
  preventing unnecessary sync triggers when retrying the same failed matches
2026-03-16 21:57:54 -07:00
Broque Thomas
7604239b9a Filter refresh playlist dropdown by source and add spotify_public refresh handler
- Exclude file and beatport playlists from refresh (no external API)
- Hide Spotify library playlists from refresh dropdown when not authenticated
- Add spotify_public refresh handler using public embed scraper via stored URL
- Fix YouTube refresh to use stored description URL instead of hash-based source_id
- API returns source and spotify auth status for frontend filtering
2026-03-16 20:37:44 -07:00
Broque Thomas
d58fee17b0 Fix duplicate mirrored playlists from YouTube pill system and add Deezer/Spotify public refresh
YouTube URL hash used Python's hash() which is randomized per process restart,
causing pill re-clicks to create duplicates instead of upserts. Replaced with
deterministic hashlib.md5 of canonical URL. Includes auto-migration to deduplicate
existing entries and update their source_playlist_id.

Also adds mirrored playlist refresh support for Spotify (public embed scraper
fallback when not authenticated) and Deezer playlists.
2026-03-16 20:21:02 -07:00
Broque Thomas
53ef9fa913 Add Deezer support to watchlist config modal and linked provider section
- Query/update watchlist artists by deezer_artist_id in config endpoint
- Return deezer_artist_id in config response and recent albums response
- Add Deezer provider badge (purple) to linked provider section
- Detect Deezer vs iTunes for provider linking using fallback source setting
- Show "X fans" instead of "Pop: 0" for Deezer artist search results
- Include followers count in match/search artist response
- Add deezer_artist_id matching to library enrichment and recent releases queries
2026-03-16 19:49:54 -07:00
Broque Thomas
7d0df2b9ed Fix discover page Deezer source support
- personalized_playlists._get_active_source() now returns 'deezer' when
  configured instead of always falling back to 'itunes'
- Add deezer_track_id to _build_track_dict() for discovery pool tracks
- Include album_deezer_id and artist_deezer_id in get_discovery_recent_albums()
  response — fixes "No deezer album ID available" error when clicking cards
- Skip Spotify library section entirely when Spotify is not authenticated
2026-03-16 19:35:26 -07:00
Broque Thomas
42a4285e09 Add clear findings button to library maintenance modal
Per-job and per-status filtering — respects active toolbar filters so
users can clear e.g. only track number findings or only dismissed items.
Confirmation uses the app's styled modal instead of browser confirm().
2026-03-16 15:37:33 -07:00
Broque Thomas
a8f95592af Bump version to 2.0 with Deezer metadata source and latest changes
Add Deezer Metadata Source section to release notes covering configurable
fallback, source badges, auto-matching, and backward compatibility.
Update HiFi section with improved failover wording and add HiFi 500
failover fix to bug fixes list.
2026-03-16 14:02:46 -07:00
Broque Thomas
f10beeea0a Add source badges (Spotify/iTunes/Deezer) to watchlist artist cards
Shows which metadata sources each artist is matched to with small
colored badges on the card. Also adds deezer_artist_id to the
watchlist API response and fixes the data-artist-id fallback chain
to include Deezer-only artists.
2026-03-16 13:37:53 -07:00
Broque Thomas
46ac46134b Add Deezer as configurable free metadata fallback source alongside iTunes
Users can now choose between iTunes/Apple Music and Deezer as their free
metadata source in Settings. Spotify always takes priority when authenticated;
the fallback handles all lookups when it's not.

Core changes:
- DeezerClient: full metadata interface (search, albums, artists, tracks)
  matching iTunesClient's API surface with identical dataclass return types
- SpotifyClient: configurable _fallback property switches between iTunes/Deezer
  based on live config reads (no restart needed)
- MetadataService, web_server, watchlist_scanner, api/search, repair_worker,
  seasonal_discovery, personalized_playlists: all direct iTunesClient imports
  replaced with fallback-aware helpers

Database:
- deezer_artist_id on watchlist_artists and similar_artists tables
- deezer_track_id/album_id/artist_id on discovery_pool and discovery_cache
- Full CRUD for Deezer IDs: add, read, update, backfill, metadata enrichment
- Watchlist duplicate detection by artist name prevents re-adding across sources
- SimilarArtist dataclass and all query/insert methods handle Deezer columns

Bug fixes found during review:
- Similar artist backfill was writing Deezer IDs into iTunes columns
- Discover hero was storing resolved Deezer IDs in wrong column
- Status cache not invalidating on settings save (source name lag)
- Watchlist add allowing duplicates when switching metadata sources
2026-03-16 13:12:12 -07:00
Broque Thomas
e2ba879197 Update recent updates modal with library history, MBID repair, and latest fixes 2026-03-16 10:14:21 -07:00
Broque Thomas
ce3bbd86c8 Fix $year template variable empty for playlist/sync downloads & empty bracket cleanup
Two issues fixed:
1. Download Missing modal fallback path hardcoded release_date: '' and
   discarded album metadata that discovery had already found on track_info.
   Now extracts release_date, image_url, album_type, and total_tracks from
   the enriched track data, fixing empty $year for all non-album-page
   downloads (playlist syncs, wishlist, Tidal/streaming sources).
2. _sanitize_context_values turned empty strings into '_' via
   _sanitize_filename, so template cleanup regex couldn't match empty
   brackets like (). Now skips sanitization for empty strings so the
   existing () [] {} cleanup works correctly.
2026-03-16 10:10:54 -07:00
Broque Thomas
837c5ff680 Add persistent library history tracking downloads and server imports
New library_history table logs every completed download and every new
track imported from Plex/Jellyfin/Navidrome. A "History" button next
to "Recent Activity" on the dashboard opens a modal with Downloads and
Server Imports tabs, album art thumbnails, quality/source badges, and
pagination.
2026-03-16 09:36:05 -07:00
Broque Thomas
7871f4581c Add cancel button for watchlist scans (manual and automation-triggered) 2026-03-15 23:24:18 -07:00
Broque Thomas
e6fdefec1f Update recent updates with HiFi, Spotify Link, and latest fixes 2026-03-15 22:56:40 -07:00
Broque Thomas
ec389c5ae8 Add HiFi as free lossless download source via public hifi-api instances
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.
2026-03-15 22:53:34 -07:00
Broque Thomas
483e45cbc0 Add Spotify Link tab for public playlist/album scraping without API credentials
Scrapes Spotify's embed endpoint to extract track data from any public
playlist or album URL. Full discovery flow with Deezer parity: parse →
card → discovery modal → live progress → sync → download missing.

- New scraper: core/spotify_public_scraper.py (embed endpoint parsing)
- 12 API endpoints mirroring Deezer's discovery/sync/download flow
- WebSocket live discovery updates via spotify_public_discovery_states
- Green-branded tab, cards, and input styling (#1DB954)
- Album vs playlist detection with distinct card icons (💿/🎵)
- Download persistence: card click reopens download modal after close
- Card phase reset on cancel/completion (closeDownloadMissingModal)
- Backend download linking for spotify_public_ and deezer_ prefixes
- Completion handlers (V2 + no-missing-tracks) for both platforms
- Source URLs stored on mirrored playlists for future auto-refresh
2026-03-15 21:25:05 -07:00
Broque Thomas
0742cc45e6 Add hemisphere setting for seasonal playlists on Discover page
Southern hemisphere users now see correct seasons (e.g. March = Autumn,
December = Summer). Holidays (Halloween, Christmas, Valentine's) stay
calendar-fixed regardless of hemisphere.

- Hemisphere dropdown in Discovery Pool Settings
- GET/POST /api/discovery/hemisphere endpoints
- Season detection offsets months by 6 for southern hemisphere
- Stored in metadata table, defaults to northern
2026-03-15 18:49:51 -07:00
Broque Thomas
219f453b74 update recent updates 2026-03-15 14:41:32 -07:00
Broque Thomas
ab21855af3 Enrich repair findings with album art, artist images & live job progress
- All 9 repair jobs now emit report_progress() for real-time card updates
  (phase, log lines, per-item activity) via WebSocket repair:progress events
- Enrich finding details with album/artist thumb URLs across all repair jobs
  (dead_file, duplicate, metadata_gap, album_completeness, missing_cover_art,
  acoustid_scanner, track_number_repair, fake_lossless, orphan_file)
- Track number repair: return match_score from fuzzy matching, add suffix-based
  DB lookup for album/artist art (handles cross-environment path mismatches)
- Fix Plex/Jellyfin relative thumb URLs in findings endpoint via fix_artist_image_url
- Labeled media cards in finding detail panels (album title + artist name under images)
- Dashboard tooltip shows current job name + per-job progress instead of stale stats
2026-03-15 14:08:26 -07:00
Broque Thomas
7a706e8c11 Add fix actions for maintenance findings (dead files, orphans, duplicates, etc.)
- New fix_finding() dispatcher in repair_worker with per-type handlers:
  dead_file (remove DB entry), orphan_file (delete from disk),
  track_number_mismatch (update DB), missing_cover_art (apply artwork URL),
  metadata_gap (apply found fields), duplicate_tracks (keep best quality)
- New POST /api/repair/findings/<id>/fix endpoint
- Frontend: contextual fix buttons per finding type, bulk "Fix Selected"
- Removed path_mismatch from fixable types (dry-run preview only)
2026-03-15 12:51:18 -07:00
Broque Thomas
dab94ce65d update soulsync repair worker with new jobs 2026-03-15 10:18:50 -07:00
Broque Thomas
6fa3b490ea Fix Windows path mangling for artist names with trailing dots (e.g. Fred again..) 2026-03-14 23:11:18 -07:00
Broque Thomas
cae2bd0c62 Add granular post-processing toggles for metadata services, cover art, and lyrics 2026-03-14 22:45:50 -07:00
Broque Thomas
5f72fe79a6 Embed Tidal, Qobuz, Last.fm, and Genius metadata into file tags during post-processing 2026-03-14 22:28:22 -07:00
Broque Thomas
264e696fe3 Fix per-profile ListenBrainz playlist cache scoping and stale data recovery 2026-03-14 21:11:59 -07:00
Broque Thomas
8f0b9518bc Add per-profile ListenBrainz support with personal settings modal 2026-03-14 20:12:19 -07:00
Broque Thomas
9a22c49a0e Add FLAC bit depth fallback option to quality profile 2026-03-14 19:24:25 -07:00
Broque Thomas
7e19e66ef3 Add quality enhance button to upgrade existing library tracks & Add iTunes fallback to Quality Enhance endpoint for full metadata source parity 2026-03-14 17:09:08 -07:00
Broque Thomas
0b8bfa1e6b Scope automation-triggered watchlist scans to the calling profile & Fix watchlist scan silently skipping all albums due to metadata cache returning incomplete data 2026-03-14 13:23:03 -07:00
Broque Thomas
3bbbfb125e Add $albumtype template variable with smart EP/Single/Album detection 2026-03-14 12:40:25 -07:00
Broque Thomas
a512d6ae70 Fix discover hero/modal to strictly filter similar artists by active source 2026-03-14 10:20:25 -07:00
Broque Thomas
945f86c643 Library Repair Worker: multi-job background maintenance daemon with 10 jobs, findings system, and management modal 2026-03-14 09:09:18 -07:00
Broque Thomas
6de3ab7cef Add universal metadata cache for Spotify & iTunes API responses with browsable dashboard tool 2026-03-14 01:26:45 -07:00
Broque Thomas
c54e52e18d Add Spotify Library discovery section, instrumental filter, custom exclusion terms & album download modal fixes 2026-03-14 00:21:44 -07:00
Broque Thomas
a5e72cff05 Add instrumental filter & custom exclusion terms to watchlist content filters 2026-03-13 23:09:12 -07:00
Broque Thomas
9856ec6772 update recent updates 2026-03-13 22:49:35 -07:00
Broque Thomas
e3fdb12d78 Preserve watchlist scan timestamps for UI display instead of wiping on lookback changes 2026-03-13 22:46:41 -07:00
Broque Thomas
32f1cc946c Improve watchlist cross-provider matching accuracy and add manual artist linking UI 2026-03-13 22:28:13 -07:00
Broque Thomas
e1a5bf678a Add library issue reporting system with actionable detail modal 2026-03-13 21:14:57 -07:00
Broque Thomas
57a8bdd107 Add album file reorganization to Enhanced Library Manager 2026-03-13 18:43:54 -07:00
Broque Thomas
d4d1b8c7a0 Update web_server.py 2026-03-13 16:34:29 -07:00
Broque Thomas
9261d1f182 update latest updates 2026-03-13 16:06:56 -07:00
Broque Thomas
02c1da76ba update recent updates and fix spotify worker rate limit button 2026-03-13 14:08:30 -07:00
Broque Thomas
de2cc6db7a Detect rate limits in methods that swallow 429 exceptions so the modal appears 2026-03-13 14:00:23 -07:00
Broque Thomas
7da7f3b112 Cache similar artist metadata at scan time to eliminate redundant Spotify API calls 2026-03-13 13:35:54 -07:00
Broque Thomas
ae6fb929bf Cache hero slider artist metadata to eliminate Spotify API calls on every page load 2026-03-13 13:13:31 -07:00
Broque Thomas
5ee9390c05 Add album art to discovery pool by extracting image URLs from match data 2026-03-13 12:40:30 -07:00
Broque Thomas
55186c6a51 Add Deezer playlist sync tab with discovery, fix modal, and cache persistence 2026-03-13 12:29:49 -07:00
Broque Thomas
f9d80606e3 Expand debug info with library stats, service status, config, and configurable log output 2026-03-13 08:47:04 -07:00
Broque Thomas
603ed06465 Improve album download analysis with album-scoped track matching 2026-03-12 21:38:02 -07:00
Broque Thomas
7b83959c30 Add Navidrome ReportRealPath guidance when library files can't be found 2026-03-12 19:16:19 -07:00
Broque Thomas
e8df863205 enhanced library write all modal and confirmation dialog 2026-03-12 16:57:38 -07:00
Broque Thomas
ded906bef4 Fix false positive track matching & tag writing visibility for library files 2026-03-12 16:08:44 -07:00
Broque Thomas
a3bf858558 Seamless Spotify rate limit UX — replace intrusive modal with ambient indicators 2026-03-12 12:45:59 -07:00
Broque Thomas
8d059b2e65 Extend race guard verification to all download source monitors 2026-03-12 11:28:56 -07:00
Broque Thomas
dc9a8a3845 Fix wrong track downloads when album name matches a track title in hybrid mode 2026-03-12 10:40:33 -07:00
Broque Thomas
ef43e4b5a6 Add album pre-flight search to find complete album folders before track-by-track downloading 2026-03-12 10:23:29 -07:00
Broque Thomas
4d2487db81 Guard all direct Spotify API calls against rate limit ban 2026-03-12 10:00:06 -07:00
Broque Thomas
9557e6bdd3 Fix sync stuck at 80% — serialize datetime in SyncResult for WebSocket emit 2026-03-12 08:52:08 -07:00
Broque Thomas
691e026208 Fix Tidal API search — correct endpoint casing, JSON:API Accept header, and best-match selection 2026-03-11 22:51:51 -07:00
Broque Thomas
ac2c710a1e Tidal & Qobuz Background Enrichment Workers 2026-03-11 21:26:20 -07:00
Broque Thomas
fb04d0f4bc Full qobuz support 2026-03-11 17:43:27 -07:00
Broque Thomas
f4d8280642 css & error notification fixes 2026-03-11 14:56:45 -07:00
Broque Thomas
d329dd4fe8 Fix Tidal playlist endpoints redundantly re-fetching all playlists — use direct single-playlist fetch 2026-03-11 13:50:53 -07:00
Broque Thomas
e42f373f80 Isolate service client initialization so one failure doesn't break the entire app 2026-03-11 11:25:15 -07:00
Broque Thomas
bde2be1cfa Spotify rate limit re-trigger loop caused by periodic auth probes 2026-03-11 08:28:36 -07:00
Broque Thomas
0aa8950436 fix build a playlist functionality and update the ui 2026-03-11 07:52:58 -07:00
Broque Thomas
e5450d9f89 Help Docs Overhaul & Settings Fixes 2026-03-10 23:50:21 -07:00
Broque Thomas
c06fd044a1 Profile Permissions & Page Access Control 2026-03-10 23:23:43 -07:00
Broque Thomas
a159ac3fd6 Fix activity feed blinking and show live relative timestamps 2026-03-10 20:34:57 -07:00
Broque Thomas
b75f115a85 update latest updates 2026-03-10 15:50:31 -07:00
Broque Thomas
58a2f1ac4a Fix iTunes country setting not persisting on save 2026-03-10 13:27:30 -07:00
Broque Thomas
08cc10c909 update latest updates 2026-03-10 12:59:13 -07:00
Broque Thomas
7138125b9e Fix post-processing race condition logging errors on already-moved files 2026-03-10 11:30:55 -07:00
Broque Thomas
dbe0ce4db4 Fix playlist folder mode race condition where second thread deletes successfully moved file 2026-03-10 10:01:39 -07:00
Broque Thomas
6506c2f163 update latest updates 2026-03-10 09:28:55 -07:00
Broque Thomas
dc7140c459 Add Last.fm and Genius to on-demand enrichment, settings reload, and enrich dropdown parity 2026-03-10 09:12:36 -07:00
Broque Thomas
f8d23ec37c Add Last.fm and Genius API clients with settings integration 2026-03-09 22:35:10 -07:00
Broque Thomas
aa93458ed3 Configurable ListenBrainz API endpoint for self-hosted instances 2026-03-09 20:52:33 -07:00
Broque Thomas
bbccd3524f Explicit content filter with configurable toggle to skip explicit tracks during downloads 2026-03-09 20:39:40 -07:00
Broque Thomas
16e01f6039 Pause enrichment workers during discovery to prioritize user-initiated API calls 2026-03-09 19:42:48 -07:00
Broque Thomas
d1890c768c cleanup staging folder same as download folder 2026-03-09 17:10:35 -07:00
Broque Thomas
07a79e7af6 Full Cleanup automation: combined housekeeping sweep for quarantine, downloads, staging, and search history 2026-03-09 16:39:29 -07:00
Broque Thomas
6e16596b9d update recent updates 2026-03-09 16:07:43 -07:00
Broque Thomas
eac97a6c2b Smart Spotify rate limit detection with global ban, auto-suppression, and frontend modal 2026-03-09 16:05:33 -07:00
Broque Thomas
1ea262c749 fix cover images not appearing in music player modal 2026-03-09 14:55:23 -07:00
Broque Thomas
cc4502e5f8 Add server sync option to enhanced library write-tags flow 2026-03-09 14:17:56 -07:00
Broque Thomas
7411bd1eab Clarify update notification for Docker users that image will follow 2026-03-09 13:15:03 -07:00
Broque Thomas
b3d607752b Add version tracking to database backup manager & Fix radio mode next track closing modal and losing playback state 2026-03-09 13:10:25 -07:00
Broque Thomas
abec2965ac Fix playlist folder downloads marked as failed despite successful processing 2026-03-09 12:04:57 -07:00
Broque Thomas
aebaa900c9 recent updates updated 2026-03-09 11:53:23 -07:00
Broque Thomas
8d46d3746b Fix Docker upgrade crashes from stale volume mounts and partial DB migrations 2026-03-09 11:44:00 -07:00
Broque Thomas
ea1441d09d "Write Tags to File" in the Enhanced Library Manager 2026-03-09 11:17:01 -07:00
Broque Thomas
5f58432ca4 Redesigned media player with expanded Now Playing modal and smart radio 2026-03-09 10:13:42 -07:00
Broque Thomas
acc88441c2 update latest updates. 2026-03-08 23:39:40 -07:00
Broque Thomas
7c50f350c0 Add a library management interface to the artist detail page with inline metadata editing, per-service manual matching, bulk operations, and full track/album management. 2026-03-08 23:37:02 -07:00
Broque Thomas
5f94352b40 Add cancellation support to all discovery workers 2026-03-08 18:12:37 -07:00
Broque Thomas
3f4770a735 Fix quality scanner stop button, rate limiting, and redundant Spotify client 2026-03-08 12:58:14 -07:00
Broque Thomas
b0761a6e62 update version modal 2026-03-08 12:33:41 -07:00
Broque Thomas
5daa8c0596 Add rich stats to automation run history 2026-03-08 12:20:50 -07:00
Broque Thomas
266d044797 Add Backup Manager dashboard tool card with list, download, restore & delete 2026-03-08 10:46:03 -07:00
Broque Thomas
b1cb9f9964 Add scheduled database backup system automation 2026-03-08 08:24:49 -07:00
Broque Thomas
2ef0c75a25 Fix sync completion not reaching UI after WebSocket reconnect 2026-03-07 22:53:15 -08:00
Broque Thomas
8b3b82702a Add deep library scan automation for enrichment-safe sync 2026-03-07 18:39:45 -08:00
Broque Thomas
ddd7f2d9b5 Persist mirrored playlist discovery results & retry failed 2026-03-07 17:28:17 -08:00
Broque Thomas
e11ee8622e Fix discovery modal persistence, artist dict handling, and rate limiter scope 2026-03-07 13:05:49 -08:00
Broque Thomas
d97b3d1846 Fix automation timezone bug 2026-03-07 11:42:44 -08:00
Broque Thomas
dbe9745794 Add new automations for refreshing beatport, cleaning download folder and cleaning search history. 2026-03-07 11:11:43 -08:00
Broque Thomas
93a83f0417 Guard against string album values in wishlist spotify_data to prevent AttributeError 2026-03-07 10:17:06 -08:00
Broque Thomas
b34e348937 keep a history of automation runs 2026-03-07 09:39:08 -08:00
Broque Thomas
ba6aea5435 Add rich progress tracking to all automation cards with stall detection and timeout handling 2026-03-07 00:57:03 -08:00
Broque Thomas
41e895d254 Batch watchlist status checks to eliminate rate limit errors 2026-03-06 23:41:01 -08:00
Broque Thomas
cdcaa245d1 Add post-scan phase progress to watchlist automation card 2026-03-06 23:15:30 -08:00
Broque Thomas
c2af4152ab Add live status feed to database update automation card 2026-03-06 21:42:43 -08:00
Broque Thomas
4fa66b8981 Fix batch completion detection for post-processing race condition 2026-03-06 20:53:06 -08:00
Broque Thomas
156c37d907 Replace hardcoded post-download chain with system automations 2026-03-06 19:48:48 -08:00
Broque Thomas
8b6a2c0adc allow multiple notification calls per automation as well as a new signal fire utility 2026-03-06 18:10:15 -08:00
Broque Thomas
7647ac22ed Add Discovery Pool dashboard tool card and revamp modal with premium category-card design 2026-03-06 11:59:45 -08:00
Broque Thomas
c9d83d5d13 Fix Tidal OAuth PKCE verification on Flask callback route 2026-03-06 10:27:17 -08:00
Broque Thomas
d264ec70f3 Add sync match cache and fix discovery clear to purge cache 2026-03-06 09:41:44 -08:00
Broque Thomas
b775d290ae Update web_server.py 2026-03-06 08:41:28 -08:00
Broque Thomas
7485ba8aa2 fix issue with tracking auto sync playlist node 2026-03-06 08:01:17 -08:00
Broque Thomas
69d16ec402 Fix sync playlist node 2026-03-05 22:18:58 -08:00
Broque Thomas
3af8c941b0 speed up discovery node 2026-03-05 22:10:28 -08:00
Broque Thomas
db03735183 Update web_server.py 2026-03-05 22:04:33 -08:00
Broque Thomas
17babb1fc8 fix spotify playlist discover automation 2026-03-05 21:17:58 -08:00
Broque Thomas
9f416475e2 Live automation progress tracking with real-time output panels 2026-03-05 20:39:26 -08:00
Broque Thomas
d57b48a62a Playlist discovery pipeline with official metadata enforcement for automated sync 2026-03-05 18:32:18 -08:00
Broque Thomas
f99f873d60 Replace hardcoded wishlist/watchlist timers with system automations + add Pushbullet & Telegram notifications 2026-03-05 16:50:09 -08:00
Broque Thomas
da707dcf0a Full automation engine expansion with scheduling, triggers, actions, and UI polish 2026-03-05 15:13:32 -08:00
Broque Thomas
75f9b7364a User configurable youtube rate limiting and optional cookies for bot detection 2026-03-05 10:50:06 -08:00
Broque Thomas
aef056cfcb DB-first metadata updater 2026-03-05 10:03:39 -08:00
Broque Thomas
5938f6fec7 Fix download retry fallback not cycling through available sources 2026-03-04 20:16:24 -08:00
Broque Thomas
60f93d5858 hydrabase changes 2026-03-04 19:48:12 -08:00
Broque Thomas
f051292e0d update version modal 2026-03-04 18:32:03 -08:00
Broque Thomas
b30e1f60bd Add Mirrored Playlists — persistent cross-service playlist archive
Automatically mirrors every parsed playlist (Spotify, Tidal, YouTube, Beatport) to a local database so they're always accessible — even if a service subscription lapses or the browser closes.
  - New "Mirrored" tab on the Sync page with source-branded cards showing discovery/download status
  - Auto-mirrors on successful parse (upsert — re-parsing updates the existing mirror, no duplicates)
  - Click any mirrored playlist to browse its full track list, then run it through the discovery pipeline
  - Cards dynamically reflect live state: Discovering → Discovered → Downloading → Downloaded
  - Download modal rehydrates after page refresh — click a "Downloading..." card to resume viewing progress
  - All phase transitions (start, complete, cancel, error, modal close) keep card and backend state in sync
  - Profile-scoped via profile_id, consistent with other features
2026-03-04 18:27:18 -08:00
Broque Thomas
114af496c7 Track version 2026-03-04 11:32:40 -08:00
Broque Thomas
1bec9320b4 update version modal 2026-03-04 11:11:31 -08:00
Broque Thomas
2d6c55e294 Fix chromaprint crash on surround audio and Spotify worker status display 2026-03-04 11:00:34 -08:00
Broque Thomas
4fee005dee Add multi-profile support with Netflix-style profile picker
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
2026-03-04 10:46:08 -08:00
Broque Thomas
84de4ad16b Redesign watchlist modal with enriched artist detail view 2026-03-03 20:26:21 -08:00
Broque Thomas
0f428dc45c Add WebSocket real-time updates with automatic HTTP polling fallback
Migrates 38 HTTP polling loops to WebSocket push events across 6 phases: service status, dashboard stats, enrichment workers, tool progress, sync/discovery progress, and scan status. All original HTTP polling is preserved as automatic fallback — if WebSocket is unavailable or disconnects, the app seamlessly reverts to its previous behavior. Includes 162 tests verifying event delivery, data shape, and HTTP parity. Also fixes a copy-paste bug in Beatport sync error cleanup.
2026-03-03 18:26:29 -08:00
Broque Thomas
7b854baba8 Detect and remove deleted content during incremental database updates
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.
2026-03-03 13:13:38 -08:00
Broque Thomas
65bae58cfe Reverse proxy fix 2026-03-03 12:04:53 -08:00
Broque Thomas
d9aa8303a7 Add SoulSync REST API (v1) with API key authentication
Adds a full public REST API at /api/v1/ with 32 endpoints covering library, search, downloads, wishlist, watchlist, playlists, system status, and settings. Includes API key authentication (Bearer token), per-endpoint rate limiting, and consistent JSON response format. API keys can be generated and managed from the Settings page. No changes to existing functionality — the API delegates to the same backend services the web UI uses.
2026-03-03 09:49:00 -08:00
Broque Thomas
7a4cbc066f Fix infinite monitor loop on post-processing completed tasks 2026-03-02 12:50:20 -08:00
Broque Thomas
c4778bc269 wishlist should always 'force download all' 2026-03-02 12:46:39 -08:00
Broque Thomas
df33adf6a7 include 'add to watchlist' button to each artist in library. 2026-03-02 10:04:10 -08:00
Broque Thomas
1f73ba4f94 view recommended artists. 2026-03-02 09:12:35 -08:00
Broque Thomas
8f2dd66aee add a 'watch all' button on hero slider to quickly add all artists in slider. 2026-03-02 08:40:22 -08:00
Broque Thomas
db2f7e999c Fix ListenBrainz database path not respecting DATABASE_PATH env var 2026-03-02 07:46:42 -08:00
Broque Thomas
c279f2e4fa Design retag layout 2026-03-01 22:52:27 -08:00
Broque Thomas
6df61d6ba1 use watchlist artist name 2026-03-01 19:24:12 -08:00
Broque Thomas
4fba18b25e Feat: Custom accent colors. 2026-03-01 15:29:37 -08:00
Broque Thomas
1aa6cdc9b6 Rebuild the import feature and move it to its own page. 2026-03-01 14:18:55 -08:00
Broque Thomas
e38c0adc57 Fix: Various artist compilations caused failure on acoustID check. 2026-03-01 11:39:04 -08:00
Broque Thomas
dced926a6e fixed issue where cancelled downloads wouldn't send album context to wishlist. 2026-03-01 09:22:50 -08:00
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