- Center spectrum bars in album art with subtle glow effect
- Add dismissible banner when infinite play is enabled
- Add detailed tooltip for infinite play button
- Fix missing playback context when using Play All in playlists
- Add Queue/History tabs with new layout
- Implement Now Playing card with spectrum animation
- Add History tab showing recently played tracks from backend
- Add Infinite Play toggle (persisted to localStorage)
- Relocate search to footer (expands left)
- Add Up Next counter (X/Y format)
- Implement 20-track pagination with load more
- Add proper i18n keys for new features
- Add new SVG icons (add-to-list, trash-list)
- Move queue button to far right of NowPlayingBar (after volume)
- Add vertical separator between volume control and queue button
- Replace ListMusic icon with custom queue-list SVG
- Add active state: play symbol changes to accent color when panel open
- Pass queueOpen prop to track panel visibility state
Add 50ms delay after stopping the previous playback engine to allow
the rodio Sink to fully release its reference to the OutputStreamHandle.
This prevents "resource busy" errors when rapidly switching tracks,
especially when selecting from search while radio is playing.
Ensure album_id and artist_id are passed through all queue track creation paths:
- trackActions.ts build functions (Qobuz, album, playlist, local tracks)
- Session persistence (both frontend and Rust backend)
- buildAlbumQueueTrack wrapper function
- Session restoration
Radio improvements:
- Increase initial tracks from 15 to 50
- Add refill_radio_queue command (generates 20 more when queue low)
- Add get_queue_remaining command to check queue size
- Add create_infinite_radio command for "Keep Playing" feature
- Add InfiniteRadio autoplay mode based on last 5 tracks
Backend infrastructure ready for:
- Auto-refill when queue drops below 10 tracks
- Infinite playback when normal queue ends
Restructure artist header layout:
- Move favorite and radio buttons below the artist photo
- Remove album count line from header
- Artist name now left-aligned in its own row
- Create artist-image-column for photo + actions grouping
Change artist info section to align content to top of the image
instead of vertically centering. This positions the artist name
closer to the photo. Also move margin from h1 to the row container
to fix alignment between name and action buttons.
Add album_id and artist_id fields to QueueTrack struct so that
radio tracks have proper navigation metadata. This enables
clicking artist/album in the main player to navigate correctly
when playing tracks from artist or track radio.
Changes:
- Add album_id/artist_id to Rust QueueTrack struct
- Update track_to_queue_track to extract IDs from Qobuz Track
- Add fields to frontend BackendQueueTrack interface
- Pass IDs in ArtistDetailView radio playback
- Pass IDs in playQueueTrack to playTrack service
Replace Lucide Pause component with inline SVG wrapped in span.
The Lucide component's rendered SVG doesn't receive Svelte's scoped
CSS attribute, so the CSS rules for .pause-icon weren't applying.
Now consistent with the "All" tab implementation.
Use canonical names (from Qobuz/Discogs) when grouping albums and
tracks by artist to merge variants like "Alice in Chains" and
"Alice In Chains" into a single group.
- groupAlbumsOptimized uses canonical names for artist key
- groupAlbums uses canonical names for sorting and grouping
- groupTracks uses canonical names for artist sorting and grouping
- Use VirtualizedTrackList's scrollToGroup method instead of DOM queries
- Add overflow: hidden to track-sections and virtualized-container
- Fix navigation not working with virtualized lists
Add optional accessor functions and props to support different track
data structures (FavoriteTrack vs LocalTrack). Includes:
- Customizable track property accessors (id, number, title, artist, etc.)
- Download status/progress support
- Additional menu actions (share, download, go to album/artist)
- isLocal, hideFavorite, isFavoriteOverride options
Use encodeURIComponent instead of slugify for group IDs to preserve
case sensitivity. This prevents collisions like "Aki" and "AKI" both
becoming "aki" which caused each_key_duplicate errors.
- Remove non-virtualized fallbacks for albums, artists, and tracks
- Virtualization now based on max(albums, tracks) count
- Standardize BUFFER_ITEMS to 5 across all virtualized components
- Reduces code by ~280 lines of duplicate rendering logic
- Ensures consistent performance regardless of library size
- Backend now supports limit=0 meaning "no limit"
- Frontend passes limit=0 to fetch all tracks
- Search now works across entire library regardless of size
- Virtualization handles rendering efficiently
- Remove max-width constraint on album cards to fill grid cells
- Increase GRID_ROW_HEIGHT to 270px for better row spacing
- Remove 1000 track limit (now 100000) for large libraries
Set GTK_APPLICATION_ID for proper WM_CLASS and add desktop template
with StartupWMClass for correct process identification on Linux.
Also add window label for Tauri window configuration.
- Add canonical_name column to artist_images table (migration)
- Store canonical names from Qobuz when fetching artist images
- Display canonical names (properly capitalized) in artist views
- Group and sort artists by canonical name when available
- Source priority: Qobuz -> Discogs -> Metadata
This ensures "Alice in chains" displays as "Alice In Chains" based on
Qobuz's authoritative naming.
- Add guard to prevent concurrent executions
- Make requests sequential (1 per second) instead of parallel batches
- Limit to 50 artists per session
- Disable Discogs fallback (caused rate limiting issues)
- Add abort flag on component destroy
- Update state less frequently (every 5 artists)
- Fix asset protocol scope for thumbnails in tauri.conf.json
- Homologate artist view controls to match album controls pattern
- Make artist grouping optional with dropdown (Off, A-Z)
- Change grid/list to single toggle button for artists
- Allow 3 lines for artist names in grid view
- Fix album card width to prevent title overflow
- Add throttling to artist image fetch to avoid rate limiting
- Create derived state `filteredAndGroupedAlbums` that caches results
- Add `matchesAlbumSearchFast` inline function to reduce overhead
- Add `groupAlbumsOptimized` that avoids unnecessary array copies
- Sort albums within groups instead of pre-sorting entire array
- Remove inline computation in template, use memoized results
This prevents repeated filtering and grouping on every render cycle.
Part of #13 - LocalLibrary performance optimization
Previously each AlbumCard created a ResizeObserver on mount to detect
text overflow for the ticker/marquee effect. With 10,000 cards, this
meant 10,000+ active observers causing significant overhead.
Changes:
- Remove ResizeObserver creation in onMount
- Measure overflow only on first mouseenter/focus event
- Reset measurement state when title/artist props change
- Ticker effect still works but only activates when user hovers
This significantly reduces CPU and memory overhead for large album
grids while preserving the visual effect when users interact with cards.
Part of #13 - LocalLibrary performance optimization
- Add 150ms debounce for album search to prevent filtering on every
keystroke (matches track search behavior)
- Memoize getArtworkUrl() with Map cache to avoid repeated
convertFileSrc() calls for the same artwork path
- Clear debounce timer and state when search is closed
Part of #13 - LocalLibrary performance optimization
Implement VirtualizedAlbumList.svelte for rendering large album
collections efficiently:
- Only renders items visible in viewport + buffer
- Supports both grid and list view modes
- Handles grouped albums with headers
- Alpha index integration for quick navigation
- Absolute positioning with calculated heights
- ResizeObserver for dynamic container sizing
Integration with LocalLibraryView:
- Import and use virtualization store settings
- Conditionally render virtualized vs standard list
- Performance mode activates when album count exceeds threshold
- Subscribe to performance settings changes
CSS additions:
- Virtualized container with proper height calculation
- Smooth scrolling support
Part of #13 - LocalLibrary performance optimization
Extend SQL-based filtering to artists and search:
- Add get_artists_with_filter() method that filters source and
network folders directly in SQL
- Replace library_get_artists N+1 loop that was calling
db.search(artist.name, 10000) for EACH artist
- Add search_with_filter() method for optimized track search
- Replace library_search post-query filtering with SQL predicates
These changes eliminate thousands of redundant database queries
when browsing large libraries with network folders or Qobuz downloads.
Part of #13 - LocalLibrary performance optimization