New toggle in Settings > Appearance disables backdrop blur (220
instances), animations (238), transitions (961), and box shadows
(804) across the entire UI via a single body class. Significantly
reduces GPU/CPU usage on low-end devices. Default off — no change
for existing users. Applied from localStorage on load to prevent
flash.
Library page: new dropdown filter to show artists matched or unmatched
to any metadata source (Spotify, MusicBrainz, Deezer, Discogs, etc).
Select "No Discogs" to find artists needing manual Discogs matching.
Filter applied as WHERE clause on the source ID columns.
Discogs enrichment: added to valid_services whitelist, _enrichment_locks,
and _run_single_enrichment handler. The Enrich button was returning an
error when Discogs was selected from the dropdown.
Entries are now compact cards that expand on click to reveal source
details. Shows expected vs downloaded title/artist with red mismatch
highlighting. Source artist column added to DB. Streaming track IDs
extracted from the id||name filename pattern. File and ID always on
their own line to avoid edge-case misplacement.
Track original source filename, track ID, and AcoustID verification
result for every download. Helps debug wrong-file downloads from
streaming sources like Tidal. Each column migrated independently
for crash safety. Frontend shows source detail line and color-coded
AcoustID badge per entry. Button renamed to "Download History".
Visual overhaul of the API Configuration section: each service frame
is now a collapsible accordion with brand-colored dots, chevron
indicators, and smooth expand/collapse animations. Includes an
Expand All / Collapse All toggle. No functional changes — all element
IDs, save/load logic, and tab switching preserved.
New download_source column on library_history table records which source
(Soulseek, Tidal, Qobuz, HiFi, YouTube, Deezer) each track was downloaded
from. Extracted from context username during post-processing.
Frontend shows source badge alongside quality badge on each download entry.
Source breakdown bar below tabs shows per-source totals with color-coded
chips (e.g., "Soulseek: 847 | Tidal: 203"). Includes DB migration for
existing installs. Existing entries show quality only (source is NULL).
Replaced single "Change" button with per-source rows showing match
status for each provider (Spotify, Apple Music, Deezer, Discogs).
Each row has Fix/Match button that searches that specific source API,
plus clear button to remove individual matches.
- Per-source search uses _search_service (same as enrichment modal)
- Backend: added Discogs to valid providers, empty ID clears match
- Fixed provider validation to accept 'discogs' alongside others
- Clear sets DB column to NULL instead of rejecting empty string
Initial load fetches 200 tracks instead of all. "Load More" button at
bottom shows (200 of 5,000) and loads next batch on click. Backend now
returns total count alongside limited results for both album and singles
categories. Rendering logic unchanged — just operates on smaller sets.
Playlist Pipeline — single automation that runs the full playlist lifecycle:
refresh → discover → sync → download missing. Replaces 4-automation signal
chains. Phase-aware progress display (Phase 1/4, 2/4, etc.), guard function
prevents concurrent runs, fire-and-forget wishlist at end. Re-sync loop
catches newly downloaded tracks on next scheduled run.
- New action type 'playlist_pipeline' with handler, blocks endpoint config,
builder UI (playlist select, process all, skip wishlist checkboxes),
help modal, result display map, and Hub template
- Removed 3 redundant Hub templates (Release Radar, Discovery Weekly,
Playlist Auto-Sync) — all replaced by the pipeline
- Fixed sync completion polling (status is 'finished' not 'complete')
- Fixed refresh handler progress hijack (null out _automation_id)
- Fixed matched_tracks field access from sync_states result
Also in this commit:
- Wishlist badges on enhanced search and global search tracks (amber)
- Discogs added to manual enrichment modal search + artist/album dropdowns
- Profile PIN forgot recovery on profile selection dialog
cover.jpg was always written from Spotify/iTunes URL (640x640) when the
first track in an album reached _download_cover_art before MusicBrainz
lookup completed. Later tracks with MBID skipped because file existed.
Fix: when cover.jpg exists but is small (<200KB) and we now have a CAA
MBID, attempt to upgrade it with the high-res CAA version. If CAA fetch
fails, keep existing cover — no pointless overwrites.
Also adds Forgot PIN recovery to the profile selection PIN dialog,
reusing the same credential verification flow as the launch lock screen.
Backend reset endpoint now accepts profile_id parameter.
- Image proxy endpoint (/api/image-proxy) for canvas CORS — allowlisted CDNs,
browser-like UA for Deezer, 24h cache headers. Direct CORS first, proxy fallback.
- Server-side 5-min cache on all artist map endpoints with auto-invalidation
on watchlist add/remove, scan complete, and new MusicMap discoveries.
- Explorer fetches similar artists from MusicMap on-the-fly when none stored,
saves to DB for instant future visits. Validates artist names against
Spotify/iTunes API before loading map — rejects gibberish with 404.
- Genre map per-genre cap removed (was 300 backend, 400 frontend).
- Center node in Explorer uses type 'center' not 'watchlist' — no longer
misidentified as a watchlist artist.
- Error overlay auto-dismisses after 2.5s and returns to Discover page.
- Helper What's New restructured with dated sections (April 4/3/2/1, March),
trimmed from ~80 to ~38 entries, date headers styled as purple dividers.
- Version modal updated with Artist Map section and recent fixes.
Full-width section with three mode cards: Watchlist (existing), Genres
(placeholder), and Explorer (placeholder). Dark gradient background
with purple/blue ambient glow, animated dot grid overlay, and polished
card hover effects. Replaces the old small hero button.
Responsive: 3-column desktop, 1-column mobile.
Toolbar redesigned: three-section layout (back+brand / centered search
with icon / tool buttons). Brand icon in accent purple. Zoom buttons in
compact pill group. Tool labels visible on desktop, icon-only on mobile.
Added keyboard shortcuts modal (keyboard icon button): lists all 10
shortcuts with styled kbd elements.
Fixes:
- Mouse wheel zoom min matched to button zoom min (0.02)
- Right-click no longer triggers left-click info modal (button filter)
- Removed external "Open on Spotify" link from context menu
- Search results dropdown centered under search bar
- Keyboard: Escape close, +/- zoom, F fit, S search, H toggle similar
- Right-click context menu: Artist Info, View Discography, Watchlist,
Open on Spotify — glass-style with auto-close
- Filter toggle button + H key: hide/show similar artists for clean
watchlist-only overview
- Removed node dragging (caused visual desync with offscreen buffer)
- Better loading progress text
- Cleanup: keyboard handler removed on close, context menu hidden
- Metadata cache backfill: batch-lookup all node names across all sources
to fill missing IDs, images, and genres
- Source-aware navigation: View Discography passes correct source to
artist page so non-active-source artists load correctly
- Constellation hover effect: 800ms delay, fade in/out animation, dim
overlay with glowing connection lines to related artists
- Click ripple animation on node selection
- Related artists list in info modal with clickable navigation
- Rich tooltip with artist photo, name, genres on hover
- Removed node dragging (caused visual desync with offscreen buffer)
- Performance: cached constellation lookups, lighter cache query
(no raw_json), canvas.width for proper DPR overlay coverage
Visual canvas map on Discover page showing watchlist artists as large
anchor bubbles surrounded by their similar artists, sized by relevance.
Layout: golden angle spiral for watchlist nodes with push-apart guarantee,
spiral packing with spatial grid collision detection for similar artists.
Offscreen buffer rendering for smooth pan/zoom (single drawImage blit).
Features:
- 320px watchlist bubbles, similar sized 25-55% by rank/occurrence
- Search bar with instant filter + animated zoom-to-node
- Tooltip with artist photo, name, genre tags on hover
- Touch support: single finger pan, pinch zoom, tap to click
- Zoom +/- buttons and fit-to-screen with smooth 250ms animation
- Click opens artist info modal (same as Your Artists)
- Loading overlay with image count progress
- Async image loading via createImageBitmap (non-blocking)
YOUR ARTISTS (major feature):
- Aggregates liked/followed artists from Spotify, Tidal, Last.fm, Deezer
- Matches to ALL metadata sources (Spotify, iTunes, Deezer, Discogs)
- DB-first matching: library → watchlist → cache → API search (capped)
- Image backfill from Spotify API for artists missing artwork
- Carousel on Discover page with 20 random matched artists
- View All modal with search, source filters, sort, pagination
- Artist info modal: hero image, matched source badges, genres, bio,
listeners/plays from Last.fm, watchlist toggle, view discography
- Auto-refresh with loading state on first load, polls until ready
- Deduplication by normalized name across all services
DEEZER OAUTH:
- Full OAuth flow: /auth/deezer + /deezer/callback
- Settings UI on Connections tab (App ID, Secret, Redirect URI)
- Token stored encrypted, auto-included in API calls
- get_user_favorite_artists() for liked artists pool
SERVICE CLIENTS:
- Spotify: added user-follow-read scope + get_followed_artists()
- Tidal: get_favorite_artists() with V2/V1 fallback
- Last.fm: get_authenticated_username() + get_user_top_artists()
FAILED MB LOOKUPS MANAGER:
- Manage button on Cache Health modal
- Browse/filter/search all failed MusicBrainz lookups
- Search MusicBrainz directly and manually match entries
- Optimized cache health queries (11 → 4 consolidated)
- Dashboard cache stats now poll every 15s
EXPLORER IMPROVEMENTS:
- Discover button on undiscovered playlist cards
- Status badges: explored/wishlisted/downloaded/ready
- Auto-refresh during discovery via polling
- Redesigned controls: prominent Explore button, icons
BUG FIXES:
- Fix album artist splitting on collab albums (collab mode fed
album-level artists instead of per-track)
- Fix cover.jpg not moving during library reorganize (post-pass sweep)
- Fix cover.jpg missing when album detection takes fallback path
- Fix wishlist auto-processing toast spam (was firing every 2s)
- Fix media player collapsing on short viewports
- Fix watchlist rate limiting (~90% fewer API calls)
- Configurable spotify.min_api_interval setting
- Better Retry-After header extraction
- Encrypt Last.fm and Discogs credentials at rest
- Add $discnum template variable (unpadded disc number)
Added min-height and flex-shrink: 0 to prevent the sidebar flex layout
from compressing the player to zero height. Desktop 120px, tablet 100px,
phone 90px. The sidebar-spacer absorbs compression instead.
Explore button moved to its own row below playlist cards with gradient,
search icon, and "Explore Selected Playlist" label. Impossible to miss.
Mode toggle redesigned as pill segmented control with grid/list icons.
Action bar buttons get inline SVG icons (checkmark, square, heart).
Primary buttons use gradient + glow shadow treatment.
Build hint shows "Select a playlist above, then explore" → updates to
"Ready: [name]" when playlist selected. Discovery poller refreshes
cards every 5s while active. Button re-enables as "Open" after modal
launch so user can reopen closed discovery modal.
1. Discover button on undiscovered playlist cards — triggers discovery
directly from Explorer instead of redirecting to Sync page. Button
changes to "Open" to reopen modal after closing.
2. Status badges on playlist cards: checkmark (in library), heart
(wishlisted), star (fully discovered), percentage (needs discovery).
Meta line shows "N in library · M wishlisted" counts.
3. Auto-refresh: polls every 5s during active discovery to update cards.
WebSocket listener for discovery:progress events. Cards refresh when
discovery completes.
4. Explored tracking: playlists get green checkmark badge after tree is
built (session-only, resets on reload).
Backend: new get_mirrored_playlist_status_counts with fail-safe design —
core discovery counts use simple reliable queries, library/wishlist
counts are best-effort extras that won't break discovery detection.
Card layout redesigned: badges inline with playlist name, discover
button below meta text, no more absolute positioning overlaps.
New feature: Failed MusicBrainz Lookups management modal accessible
from Cache Health. Browse all failed lookups with type filter tabs,
search bar, pagination. Click any entry to search MusicBrainz and
manually match — saves MBID at 100% confidence. Clear individual
entries or bulk clear all.
Backend: 4 new endpoints — failed-mb-lookups list, mb-entry delete,
musicbrainz/search (artist/release/recording), mb-match save.
Performance: Cache health stats consolidated from 11 queries to 4
using CASE expressions. Added partial index on musicbrainz_cache for
failed lookups. Dashboard cache stats now poll every 15s instead of
single fire-and-forget fetch. Failed MB type counts cached on frontend,
only re-fetched after mutations.
Also includes: library reorganize now moves cover.jpg via post-pass
sidecar sweep, and changelog updates.
- Watchlist artist list: discogs_artist_id in API response
- Watchlist source badges: Discogs badge on artist cards
- Watchlist config modal: discogs_artist_id in SQL query, WHERE clause,
response, and linked provider section with badge
- CSS for watchlist-source-discogs and watchlist-provider-badge.discogs
- Add _extract_discogs_fields to metadata cache — handles Discogs field
names (title vs name, images array, Artist - Title format)
- Worker uses _fetch_and_cache_artist/_fetch_and_cache_album helpers
that cache raw data while returning it for enrichment
- All search/lookup methods cache results for repeat queries
- Cache browser: Discogs stat pill, source filter, clear button, badge
- Fixes albums showing as 'Unknown' and artists missing images in cache
- SpotifyClient: add _discogs lazy-load property, route _fallback to
DiscogsClient when configured (requires token, falls back to iTunes)
- web_server: _get_metadata_fallback_client returns DiscogsClient when
selected and token present
- Enhanced search: Discogs added as source tab with NDJSON streaming,
only available when token configured
- Alternate sources list includes Discogs when token is set
- Frontend: source labels, tab styling, fetch list all include Discogs
- Consistent with iTunes/Deezer pattern — same interfaces, same routing
- Add Discogs to WORKER_DEFS in worker-orbs.js so it participates
in the floating orb animation like all other enrichment workers
- Use SVG logo image instead of text
- Fix spinner and state CSS to match exact pattern of other workers
- Circular button with "dc" logo text, matching exact pattern of
AudioDB/Deezer/Spotify/iTunes/Last.fm/Genius/Tidal/Qobuz buttons
- Spinner animation when active, dimmed when paused, green when complete
- Hover tooltip showing status, current item, and progress stats
- Click to toggle pause/resume with config persistence
- WebSocket status handler updates button state in real-time
- Merge enrichment worker status into rate monitor WebSocket payload
- Hide old enrichment pills — rate monitor cards now show: service name,
worker status badge, arc gauge, calls/min, 1h/24h counts, budget bar
- Debounce idle detection with 5s grace period — prevents status
flickering between Running and Idle on every worker cycle
- Responsive grid layout with richer card design
- New core/api_call_tracker.py — centralized tracker with rolling 60s
timestamps (speedometer) and 24h minute-bucketed history (charts)
- Instrument all 9 service client rate_limited decorators to record
actual API calls with per-endpoint tracking for Spotify
- 1-second WebSocket push loop for real-time gauge updates
- Modern radial arc gauges with service brand colors, glowing active
arc, endpoint dot, 0/max scale labels, smooth CSS transitions
- Click any gauge to open detail modal with 24h call history chart
(Canvas 2D, HiDPI, gradient fill, grid lines, danger zone band)
- Spotify modal shows per-endpoint history lines with color legend
and live per-endpoint breakdown bars
- Rate limited state indicator — blinking red badge with countdown
timer appears on gauge card when Spotify ban is active
- REST endpoint GET /api/rate-monitor/history/<service> for chart data
- Responsive grid layout (5 cols desktop, 3 tablet, 2 phone)
- Per-section loading spinners (artists/albums/tracks) shown until each
NDJSON chunk arrives, auto-replaced with real content on receipt
- Active tab content auto-re-renders as streaming data arrives for both
enhanced search and global search
- Global search lazy-loads artist images for iTunes/Deezer via
/api/artist/{id}/image fallback (album art), matching enhanced search
- Change <int:track_id> to <track_id> on 5 library track endpoints —
Jellyfin uses GUID strings, int converter rejected them with 404 (#237)
- Add PUT /api/library/clear-match endpoint — sets service ID to NULL
and match status to not_found, allowing users to undo wrong matches (#236)
- Add "Clear Match" button in the manual match modal for all services
- Add bottom padding to .page to prevent floating buttons (bell, help)
from overlapping track action buttons at page bottom (#237)
- New discovery_artist_blacklist table with NOCASE name matching
- Filter blacklisted artists from all 6 discovery pool queries, hero
endpoint, and recent releases via SQL subquery and Python set check
- Name-based filtering means one block covers all sources (Spotify/iTunes/Deezer)
- Hover any discovery track row → ✕ button to quick-block that artist
- 🚫 button on Discover hero opens management modal with search-to-add
(powered by enhanced search) and list of blocked artists with unblock
- CRUD API: GET/POST/DELETE /api/discover/artist-blacklist
- Updated changelogs
- Add MusicBrainz to Cache Browser: stats pill, source filter, dedicated
browse endpoint, cards with matched/failed status indicators
- Add Clear MusicBrainz and Clear Failed MB Only to cache clear dropdown
- Move MusicBrainz into Cache Health "By Source" bar chart alongside
Spotify/iTunes/Deezer instead of isolated metric row
- Rename ambiguous "Failed Lookups" to "Failed MB Lookups" in summary cards
- Add browse-musicbrainz and clear-musicbrainz API endpoints
- Add musicbrainz_total/musicbrainz_failed to cache stats response
- Add Global Search Bar and MusicBrainz cache to changelogs
Persistent Spotlight-style search bar at bottom-center, accessible
from any page via click, /, or Ctrl+K. Hidden on Downloads page
where enhanced search already exists.
Features matching enhanced search:
- Clear button when input has text
- Source tabs with live switching
- Source badges, library check, play buttons
- Album click opens download modal directly
- Artist click navigates to detail page
- Tab switching stays open (timestamp guard)
- Mobile responsive
1. LB Discover page cards now use the dropdown (Download/Sync) instead
of the old single button with full choice dialog
2. Dropdown position auto-flips downward when button is near viewport top
3. Dropdown centered on button instead of right-aligned
4. Sync completion toast now includes playlist name and ⚡ indicator
5. Download modal already shows ⚡ prefix on playlist name as indicator
All changes purely additive — existing flows unaffected.
Live status: updateYouTubeModalSyncProgress was hardcoded to youtube-*
element IDs but each source uses its own prefix (listenbrainz-*, tidal-*,
deezer-*, etc). Now tries all prefixes to find the correct elements.
Fixes Wing It sync progress AND a pre-existing bug where normal LB/Tidal
sync from the modal wouldn't show live progress.
Wing It button added to sync_complete phase so it persists after sync.
Fixed tracks lookup with state.playlist?.tracks fallback. Increased
button size in modal to match other action buttons.
Wing It bypasses Spotify/iTunes/Deezer matching and uses raw track
names directly. User chooses Download or Sync from a choice dialog.
Download: opens Download Missing modal with force-download-all
pre-checked. wing_it flag skips wishlist for failed tracks.
Sync: new POST /api/wing-it/sync endpoint runs _run_sync_task with
raw track dicts. Live inline sync status display on the LB card
using the same progress elements as normal sync. Unmatched tracks
skip wishlist via _skip_wishlist flag on sync_service.
Button in three places:
- Next to "Start Discovery" in all discovery modals (fresh phase)
- Next to "Download Missing"/"Sync" after discovery (discovered phase)
- Next to "Download" on ListenBrainz cards (Discover page)
Fixed force-download toggle ID, sync progress field names
(total_tracks/matched_tracks not total/matched). All changes
purely additive — normal flows unaffected.
Complete replacement of the old bottom-center stacking toast system:
Compact Toasts: Single toast at a time, bottom-right above buttons.
Pill shape with type-colored left border stripe, icon, message, and
optional "Learn more" link. Slides in, fades out after 3.5s. Click
to dismiss. New toasts replace the current one smoothly.
Notification Bell: 44px circle button next to the helper (?), with
red badge counter for unread notifications. Click opens panel.
Notification Panel: Glass popover above bell button showing history
of last 50 notifications. Each entry has type icon, message, relative
timestamp, and optional help link. Unread dot indicator. Clear All
button. Marks all as read when panel opens.
Same showToast(message, type, helpSection) signature — all 842
callers unchanged. Deduplication preserved. Updated version modal
and helper What's New.
New tool card shows blocked source count. "View Blacklist" opens a
modal listing all blacklisted sources with track name, filename,
username, service icon, and time ago. Each entry has a remove button
to unblock. Empty state explains how to blacklist from Source Info.
Bar was using var(--accent) which can be dark/invisible against the
modal background. Now uses bright green gradient with glow shadow.
Also thicker (8px) and queries DOM fresh each poll tick to prevent
stale references.
Three separate table cells with fixed widths replaced by one compact
cell with a flex group. Buttons are 24px each, 2px gap, fade in on
row hover. Removes ~70px of wasted horizontal space per track row.
Artist Radio and Enhance Quality buttons moved from the page header
into the artist hero section (after badges, before genres). Add to
Watchlist stays in the top-right header where it was.
Step 1 and Step 2 action buttons (Cancel, Search/Download) now render
in a sticky footer outside the scrollable body — always visible
regardless of how many results are shown. Footer has backdrop blur
and top border separator matching the modal glass theme.
Step 2 of the redownload modal now streams results as each download
source responds instead of waiting for all sources to finish. Tidal/
YouTube/Qobuz columns appear instantly while Soulseek searches.
Backend: search-sources endpoint uses ThreadPoolExecutor + NDJSON
streaming — one JSON line per source as it completes.
Frontend: reads the NDJSON stream, appends columns with fade-in
animation as each source responds. Download button enables as soon
as any results arrive.
Each source gets its own column with results grouped and sorted by
confidence. Visual confidence bars, format badges, and source-specific
metadata (Soulseek username/slots). Best overall match auto-selected.
Major redesign:
- All metadata sources shown as side-by-side columns (not tabs)
- Frosted glass modal background with blur(40px) saturate(1.4)
- Album cover art in header from DB thumb_url (resolved for Plex)
- 1100px width, all elements scaled up, white text on accent buttons
Bug fixes:
- Deezer: use global singleton client, title-only fallback search,
strip version suffixes from query
- Track.__init__: added missing popularity=0 parameter
- Overlay: dedicated .redownload-overlay class avoids CSS conflicts
New track_downloads table records every download with full source data:
service type (soulseek/youtube/tidal/etc), username, remote filename,
file size, and audio quality. Recorded at all 3 post-processing
completion points.
Source Info button (ℹ) on each track in the enhanced library view shows
a popover with download provenance: service, username, original filename,
size, quality, download date. Includes "Blacklist This Source" button
that stores the real username+filename (not guessed local filenames).
Removed broken "Delete & Blacklist" option from Smart Delete since it
had no access to real source data. Blacklisting now done exclusively
from the Source Info popover where actual provenance data exists.
Added blacklist CRUD API endpoints (GET/POST/DELETE /api/library/blacklist).
Three-step redownload flow in the enhanced library view:
1. Metadata Source — searches Spotify/iTunes/Deezer simultaneously,
shows results with match scores, flags current match
2. Download Source — searches all active download sources (Soulseek,
YouTube, Tidal, etc.), shows candidates with format/bitrate/size/
confidence, flags blacklisted sources
3. Download — starts download, polls for progress, deletes old file
on success, updates DB path
Also integrates the download blacklist into the download pipeline —
_attempt_download_with_candidates now skips blacklisted sources
automatically during all downloads (wishlist, playlist sync, etc.).
New redownload button (↻) on each track row in enhanced library view.
Post-processing hook deletes old file and updates DB track path after
successful redownload.
Track delete in the enhanced library now shows three options:
- Remove from Library: DB record only (existing behavior)
- Delete File Too: DB + os.remove() the file from disk
- Delete & Blacklist: DB + file removal + add source to blacklist
New download_blacklist table stores rejected sources (username + filename)
with CRUD methods. Blacklist will be checked by the download pipeline
and the upcoming track redownload modal.
Smart delete modal styled with the same glass/dark theme as other
SoulSync modals, with color-coded destructive options.
New "Server Playlists" tab (default on Sync page) lets users compare
mirrored playlists against their media server and fix match issues.
- Dual-column comparison: source tracks (left) vs server tracks (right)
- Smart matching: exact title first, then fuzzy artist+title (≥75%)
- Find & Add: search library to fill missing slots at correct position
- Swap: replace matched tracks with different versions
- Remove: delete tracks from server playlists with confirmation
- Title similarity percentage badge on each match
- Disambiguation modal when multiple mirrored playlists share a name
- Album art on source tracks, server tracks, and search results
- Cross-column click-to-scroll highlighting
- Filter buttons (All/Matched/Missing/Extra) with live counts
- Escape key and backdrop click to close modals
- Mobile responsive (stacked columns under 768px)
- Works with Plex, Jellyfin, and Navidrome
New dashboard section shows recent syncs as scrolling cards with
playlist art, source badge, match percentage bar, and health color.
Click any card to open a detail modal showing every track's match
status, confidence score, album art, and download/wishlist status.
Per-track data is now cached in sync_history.track_results for all
sync paths: server-sync (playlist→media server), download missing
tracks, and wishlist processing. SyncResult carries match_details
from the sync service. Both image URLs and matched track info are
preserved for review.
Features:
- Staggered card entrance animation, delete button on hover
- Filter bar: All/Matched/Unmatched/Downloaded
- Color-coded confidence badges (green/amber/red)
- Unmatched tracks show "→ Wishlist" status
- 32px album art thumbnails per track row
- Auto-refreshes every 30 seconds on dashboard
- Falls back gracefully for old syncs without track_results
Status text and indicators now use fixed Material Design colors
instead of accent-dependent values — green for running/idle, amber
for paused, red for stopped, dim white for not configured. Readable
regardless of the user's chosen accent color.