- Fix $derived to $derived.by for complex logic (was causing CPU spike)
- Remove badge backgrounds from QBZ and Qobuz icons
- Move info icon (i) to top-left corner of radio card
- Add play button to radio card
- Increase badge icon sizes for visibility
- Dedupe recommended tracks by normalized title (filters remasters/editions)
- Use actual QBZ logo SVG instead of text "Q"
- Add playlist icon and "Playlist" label for clarity
- Add diamond-style collage layout for Song Radio card
- Pass currentArtwork for radio collage images
- Clean up unused error-text CSS in LyricsPanel
Layout:
- Top section: Artist curated playlists (from Qobuz) + Song Radio card (QBZ)
- Bottom section: Recommended tracks from artist's discography
Features:
- Artist playlists fetched via get_artist_detail (includes curated playlists)
- Song Radio card with experimental badge and tooltip
- Recommended tracks shuffled from artist's tracks_appears_on
- Single API call per artist (efficient loading)
- Loading state with spinner, empty state handling
- Play buttons with hover effects
Technical:
- Uses existing create_track_radio command for radio generation
- Tracks loadedArtistId to prevent duplicate requests
- Added translations for songRadio, radioExperimental, recommendedTracks
- Track loadedTrackId to avoid re-fetching same track
- Only request when trackId actually changes from loaded one
- Clear state only when track ends (trackId becomes null)
- Remove broken common.loading translation (spinner is enough)
- Create TrackInfoPanel with full track metadata and credits
- Display: duration, quality, ISRC, label, and all performer credits
- Uses same backend as TrackInfoModal (get_track_info command)
- Rename tab from 'Credits' to 'Track Info' (player.trackInfo)
- Update keyboard shortcut from 'C' to 'T' for Track Info tab
- Fix actions.clearQueue -> player.clearQueue translation key
- Add i18n translations for trackInfo in EN/ES
- Delete old placeholder CreditsPanel
- Increase canvas size from 8x8 to 64x64 to reduce visible pixelation
- Add small CSS blur(40px) to smooth the result
- Key: blur(40px) on 64x64 is much cheaper than blur(120px) on full image
- Adjusted brightness slightly darker (0.55x) for better text contrast
Performance problem:
- WebKitWebProcess consuming 97% CPU on one core
- Cause: CSS filter: blur(120px) on large image is extremely expensive
in WebKit/GTK which cannot GPU-accelerate this operation
Solution:
- Replace CSS blur with Canvas-based tiny thumbnail approach
- Draw image to 8x8 canvas, apply color adjustments, scale up via CSS
- Natural pixelation creates blur-like effect with ZERO CPU cost
- Remove backdrop-filter: blur() from header elements (use solid bg)
Also fixed:
- Change Mic icon to Mic2 to match rest of app
- Add missing i18n translations for player.credits and player.suggestions
- Remove track info (artwork, title, artist) from ImmersiveControls bottom bar
- Add track title and artist below album artwork in split view mode
- Change Lyrics Focus icon from MessageSquareText to Mic (microphone)
- Remove unused compact mode from ImmersiveControls
- Simplify props and cleanup CSS
- Rewrite VisualizerPanel for full-screen display with 3 modes:
- Bars: vertical audio bars with rounded corners
- Wave: smooth waveform with mirrored reflection
- Circular: radial bars emanating from center
- Extract colors from album artwork for dynamic coloring
- Add performance optimizations: 32 bars, 20fps throttling
- Pass artwork prop to enable color extraction
- Add mode switcher button to cycle through visualizations
Display modes:
- Coverflow: centered album art with track info
- Split: artwork + panel side by side (current default)
- Lyrics Focus: single line at a time, large centered text
- Queue Focus: full screen queue view
- Visualizer Focus: full screen visualizer
Background:
- Heavy CSS blur (120px) for abstract color blobs
- No recognizable image, just colors
Keyboard shortcuts: 1-5 to switch modes
Inspired by Cider 3's immersive player design.
Replace blur approach with full resolution artwork:
- Artwork scaled 115% to hide edges
- Strong vignette overlay fading to black at edges
- Gradient overlays for text readability (header, controls, lyrics)
- Slight desaturation for better contrast
- Simpler and more visually impactful
- Increase canvas blur size from 64x64 to 256x256 for smoother background
- Fix lyrics horizontal scroll by adding word-wrap and overflow-x: hidden
- Remove queue button from controls (use header tab instead)
- Add queue sync effect when immersive player is open
Addresses visual quality issues with pixelated background and long
German lyrics causing horizontal overflow.
- Create QueuePanel component for immersive mode
- Add queue tab to ImmersiveHeader with ListMusic icon
- Update ImmersivePlayer to render QueuePanel and pass queue data
- Add Q keyboard shortcut to switch to queue tab
- Pass queue tracks from +page.svelte to ImmersivePlayer
Users can now manage their queue without leaving immersive mode.
ToS acceptance was stored in localStorage which gets cleared on app
updates, causing users to re-login frequently. Now stores ToS state
in SQLite (~/.local/share/qbz/legal_settings.db) which survives
updates.
- Add legal_settings.rs with SQLite storage for ToS acceptance
- Update qobuzLegalStore.ts to use Rust invoke commands
- LoginView now loads ToS from Rust before auto-login check
- Migration from localStorage for existing users
Closes#31
Digital outputs like S/PDIF transmit audio as-is without DA/AD conversion,
making them bit-perfect by nature. Now iec958: devices get the BP badge.
Updated group label to "Bit-perfect (Hardware / Digital)" to reflect
both direct hardware access (hw:) and digital outputs (iec958:).
- Add check_alsa_utils_installed and get_linux_distro Tauri commands
- Detect Linux distribution from /etc/os-release
- Show appropriate package manager command for each distro
- Add (?) help icon next to ALSA Direct device dropdown in Settings
- Modal explains why alsa-utils is needed for bit-perfect detection
- Updated PKGBUILDs to list alsa-utils as optdepend
Backend changes:
- Add device_bus and is_hardware fields to AudioDevice
- Parse PipeWire Flags (HARDWARE) and device.bus property from pactl output
Frontend changes:
- DeviceDropdown now supports both ALSA and PipeWire backends
- ALSA grouping: Defaults, Bit-perfect, Plugin Hardware, Other
- PipeWire grouping: Defaults, USB Audio (BP capable), HDMI/DisplayPort, Other HW, Virtual
- BP badge shown for USB Audio devices in PipeWire mode
Backend changes:
- Add supported_sample_rates field to AudioDevice struct
- Detect common audio sample rates (44.1, 48, 88.2, 96, 176.4, 192, 352.8, 384 kHz)
- Use CPAL's supported_output_configs() to check rate support for hw: devices
Frontend changes:
- Display sample rates as subtitle in DeviceDropdown (e.g., "44.1, 48, 96, 192 kHz")
- Only shown for bit-perfect devices where detection is available
- Search not sensitive to sample rates field (per user request)
- New DeviceDropdown component with grouped options:
- Defaults (System Default, default ALSA)
- Bit-perfect (Auto-detected) - hw:X,Y devices with BP badge
- Plugin Hardware - plughw:X,Y devices
- Other Outputs - remaining devices
- Only shows for ALSA Direct backend, other backends use regular dropdown
- Pure UI change, no backend modifications
- Artist names in sidepanel now animate with ticker effect on hover when text overflows
- Each album section (Discography, EPs & Singles, Live Albums) now has a sort dropdown
- Sort options: Default, Newest, Oldest, A-Z, Z-A
- Use sorted arrays for rendering instead of raw grouped arrays
- Group albums by category: Discography, EPs & Singles, Live Albums
- Exclude tributes and compilations (others) from display
- Each section has its own header that scrolls with content
- Updated footer: "To view compilations and other content, go to..."
- All content scrolls together (sections + footer)
- Add no-outer-scroll class when sidepanel mode is active
- Set up proper flex container hierarchy for full height:
- .favorites-view becomes flex column container
- .content gets flex: 1 with min-height: 0
- ViewTransition wrapper gets flex: 1 via :global selector
- Fix negative margins to match parent padding (was -32px, now -8px/-18px)
- Reduce artist column width to 240px (matches LocalLibrary)
- Fix album column right padding to 8px
- Add artist count header like LocalLibrary
- Remove sticky positioning from group headers (caused overlap)
- Restructure albums area with scroll wrapper containing both grid and footer
- Footer now scrolls with album grid (visible at bottom after scrolling)
- Match LocalLibrary CSS patterns for proper independent scrolling
- Fix toggle button to use control-btn icon-only style (matches Library)
- Add proper background/hover states to the toggle button
- Fix two-column layout for independent scrolling:
- Artist list scrolls independently from albums grid
- Added scroll optimization properties (overscroll-behavior, contain)
- Adjusted padding and margins for edge-to-edge layout
- Increased album card grid size to 180px (matches LocalLibrary)
Implements a two-column sidepanel view for Favorites > Artists:
- Left column shows artists grouped A-Z with sticky headers
- Right column shows selected artist's Discography albums
- Albums are filtered to show only studio albums (not EPs, Singles, Live)
- Proper AlbumCard with artwork, favorite button, and quality badge
- Footer link to navigate to full artist page for other album types
- Alpha index in toolbar for quick navigation
- Toggle button to switch between grid and browse views
- View mode persists to localStorage
Also exports categorizeAlbum from qobuzAdapters for reuse.
- Add Kurosaki light theme (cream/gold color palette)
- Add theme type filter button (dark/light/all) to cycle through themes
- Make Offline Library and Storage sections collapsible with descriptions
- Compact Account section with inline layout and subscription badge
- Navigation items now use i18n translation keys for reactive labels