- Translated modal title and form labels
- Translated search buttons and results text
- Translated table headers (track, title, disc)
- Translated persistence options (sidecar vs direct)
- Translated progress states (writing tags, saving)
- Added placeholder translations for year and genre examples
- Update play menu items (Play now, Play next, Add to queue)
- Update navigation items (Go to artist, Go to album)
- Translate View more buttons
- Add noPlaylistsFor translation key
cc
- Update Last.fm API key and shared secret labels
- Update Last.fm authorize button text
- Update ListenBrainz labels and token hint
- Add translations for connecting/opening states
- Add apiKey, sharedSecret, userToken translation keys
cc
- Update Dropdown.svelte with search placeholder translation
- Update DeviceDropdown.svelte with searchDevices placeholder
- Update GenreFilterPopup.svelte with searchGenres placeholder
- Update PlaylistModal.svelte with name and description labels
- Add playlist.name and playlist.descriptionOptional keys
cc
- Add translations for loading/error states
- Translate empty states for albums, artists, tracks views
- Translate header titles and subtitle
- Update button titles (Scan, Settings, Play All, Shuffle)
- Translate offline mode notice
- Translate filter panel labels
- Add editAlbumMetadataTitle key for tooltips
cc
- Add t import and use translations for all empty state messages
- Translate loading states (favorites, playlists, albums)
- Translate section headers (Discography, EPs & Singles, Live Albums)
- Translate button titles (Play All, Shuffle, More, Search, Clear)
- Add hint translations for liking items to favorites
- Update getSortLabel to use sort.* translation keys
- Update getTabLabel to use favorites.tabLabels.* keys
cc
- Add time-based greeting translations (goodMorning, goodAfternoon,
goodEvening, goodNight) to homeSettings section
- Update homeSettingsStore to export getGreetingInfo for i18n support
- Update HomeView.svelte to use translated greetings
- Add comprehensive toast translations (~60 keys) for all user-facing
notifications including queue, playback, offline, favorites, etc.
- Update +page.svelte to use $t() for all showToast calls
- Complete Spanish translations for all new keys
- Create BlacklistManagerView component with list of blocked artists
- Add enable/disable toggle, search filter, and clear all function
- Integrate navigation to blacklist manager from Settings
- Add Content Filtering section in Settings with artist count
- Add i18n translations for English and Spanish
- Wire up view routing in +page.svelte
Added onTrackClick handler to NowPlayingBar that opens TrackInfoModal when
the track title is clicked. Uses cursor: help for informative visual cue.
Only works for non-local tracks.
Issue #34 - Max quality setting not respected
Changes:
- Remove 'Prefer Highest Available' toggle (was dead code, conflicted with quality dropdown)
- Clear playback cache (L1+L2) when streaming quality changes
- Show toast notification when cache is cleared
- Add description to streaming quality setting
- Update i18n for new messages (en/es)
This ensures the quality setting takes effect immediately, important for:
- Users with metered internet connections
- Users with hardware sample rate limitations (e.g., DACs limited to 96kHz)
The Qobuz API respects format_id and downsamples server-side, so this
change guarantees the correct quality is fetched for new streams.
- Add TrackReplacementModal to search for replacement tracks
- Add onFindReplacement action to TrackMenu context menu
- Show replacement option only for owned playlists with unavailable tracks
- Replacement searches by track title + artist
- Shows quality info (bit depth, sample rate) to help user choose
- Supports preview playback before confirming
- Replace old track with new one in playlist
Also fix tooltip for unavailable tracks to show a complete message
instead of "is no longer available" (now shows "Track no longer
available in Qobuz library")
Backend:
- Add TrackUnavailable error type for tracks removed from Qobuz
- Validate stream URL response - detect missing URL with restrictions
- Add SampleRestrictedByRightHolders to restriction check
- Return specific error when track is unavailable vs quality unavailable
Frontend:
- Detect track unavailable errors in playTrack()
- Show friendly toast: Track title is no longer available
- Auto-skip to next track in queue after 500ms delay
- Add i18n translations (en/es) for trackUnavailable message
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
- 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
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
- 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
Add sort dropdown for favorite albums with options:
- Default (API order)
- Newest First (by release date)
- Oldest First (by release date)
- Title (A-Z / Z-A)
- Artist
Sort preference is persisted to localStorage.
Add tray icon configuration options:
- Enable/disable tray icon (requires restart)
- Minimize to tray: hide window when clicking minimize
- Close to tray: hide window instead of quitting
Rust backend: TraySettingsState with SQLite persistence
Frontend: SettingsView tray subsection with toggles
Related to #15 (title bar settings)
Remove "Use QBZ title bar" toggle since switching to system decorations
doesn't work reliably on Linux when the window was created without
decorations. Keep only "Hide title bar" option for tiling WM users.
Phase 1 implementation:
- Add titleBarStore.ts for managing title bar visibility
- "Use QBZ title bar" toggle (default ON) - switches between custom and system decorations
- "Remove title bar" toggle (default OFF) - hides title bar completely for tiling WM users
- Dynamically adjust layout heights when title bar is hidden
- Add i18n translations (en/es)
- Settings integrate with Tauri window.setDecorations() API
- Add sidebarStore.ts for expanded/collapsed state with localStorage persistence
- Modify NavigationItem to support collapsed mode (icon-only with tooltip)
- Update Sidebar component with toggle button and collapsed styles
- Width transitions from 280px (expanded) to 64px (collapsed)
- Add i18n translations for collapse/expand actions (en/es)
- Update en.json and es.json with new terminology
- Change "Download" to "Make available offline"
- Change "Downloads" section to "Offline Library"
- Update notifications: cachingStarted, cachedForOffline, cachingFailed
- Update UI copy in SettingsView, TrackMenu, AlbumMenu
- Update toast messages in +page.svelte to use offline terminology
- Change DownloadButton tooltips to use offline language
cc
- Show format: (20 of 139, 135 left) for normal playback
- Show format: (20 of ∞) for infinite play or radio mode
- Remove Load More from Queue section (not needed)
- Add Load More to History section for tracks > 20
- Add isRadioMode prop to detect radio context
- Pass both queueTotalTracks and queueRemainingTracks
- 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)
- Create FavoritesEditModal with preset icon grid
- Add custom image upload button
- Add tab reorder UI with up/down buttons
- Integrate edit button in Favorites page header (top-right)
- Add i18n keys for EN and ES
- Wire modal save handler to backend
cc
Added translations for:
- Autoplay behavior setting
- Continue within source / Play only selected track options
- Show context icon setting and tooltip
Both English and Spanish translations added.
Changed StackIcon tooltip to use native browser title (matches QualityBadge style).
Removed arrow indicator from context icon (cursor change is sufficient).
cp
All API requests now go through Cloudflare Workers proxy.
User-provided credentials were collected but never used.
Removed:
- src-tauri/src/api_keys.rs (entire module)
- API Keys section from Settings UI
- ApiKeysState and related commands
- User credential parameters from providers
- Simplified DiscogsClient (removed with_user_credentials)
- Cleaned up imports and translations
Moved documentation:
- CHANGELOG-api-keys-refactor.md
- HANDOFF-MERGE.md
- MERGE-PREP.md
- POST-MERGE-CLEANUP.md
Moved to: qbz-nix-docs/feature-api-keys-refactor/
This cleanup reduces codebase by ~715 lines and removes
confusing UI that promised functionality that didn't work.
Backend changes:
- Add audio_diagnostics module to read actual hardware sample rate from /proc/asound
- New command get_hardware_audio_status() parses hw_params for real-time monitoring
- Add glob dependency for file pattern matching
Frontend (AudioOutputBadges):
- Implement 3-state DAC badge system:
- Green: DAC passthrough working correctly (rates match)
- Yellow: DAC passthrough ON but resampling detected (warning)
- Gray: DAC passthrough OFF (intentionally disabled)
- Dynamic tooltips showing actual hardware sample rate
- Compare file sample rate vs hardware sample rate
- Increase tooltip z-index to 9999 to prevent occlusion issues
- Add pointer-events: none to tooltip to prevent interaction issues
Frontend (SettingsView):
- Replace hardcoded "192 kHz" with dynamic hardware sample rate
- Load and display actual hardware audio status
- Show format details (e.g., S32_LE) when available
- Display "No active playback" when no audio is playing
- Add muted styling for inactive state
Frontend (QualityBadge):
- Add native tooltip showing tier and format
- Add cursor: help to indicate interactivity
i18n:
- Add "noActivePlayback" translations (EN/ES)
This allows users to verify bit-perfect playback is working and detect
resampling issues that would compromise audio quality.
- Remove wifi-off icon from unavailable tracks in playlist detail view,
keeping only the disabled styling for a cleaner look
- Rename "Available Offline" filter to "Fully Available Offline" to
clarify it shows only playlists where all tracks are available
- Update filter logic to only show all_local playlists in the fully
available filter, not partially available ones
- Fix visible filter in offline mode to respect showPartialPlaylists
setting by using isPlaylistAvailableOffline function