- Backend now emits playback:state events every 250ms when state changes
- PlayerStore uses listen() instead of setInterval for real-time updates
- Added Vitest testing framework with mocked Tauri APIs
- Added 53 unit tests for playerStore and queueStore
Move core playback operations to centralized service:
- playTrack() - unified track playback with all side effects
- MPRIS metadata updates
- System notifications
- Last.fm scrobbling and now playing
- Favorite status checking and toggling
Simplifies handlers: handlePlaylistTrackPlay, handleLocalTrackPlay, toggleFavorite.
Reduces +page.svelte from 1675 to 1525 lines.
handlePlaylistTrackPlay and handleLocalTrackPlay were still using
local state variables directly instead of playerStore functions,
causing the UI to not react to playback state changes.
- Create navigationStore.ts for view navigation and history
- Implement navigateTo, goBack, goForward actions
- Add selectPlaylist for playlist detail navigation
- Update +page.svelte to use store subscription and functions
- Simplify navigation wrapper functions
- Create authStore.ts for managing login state and user info
- Implement setLoggedIn and setLoggedOut actions
- Update +page.svelte to use store subscription
- Simplify handleLoginSuccess and handleLogout handlers
- Create uiStore.ts for overlay and modal visibility states
- Centralize queue panel, fullscreen, focus mode, cast picker states
- Add playlist modal state management with mode and track IDs
- Implement handleEscapeKey for prioritized overlay closing
- Update +page.svelte to use store subscription and functions
- Create toastStore.ts with centralized toast state management
- Add auto-hide functionality with configurable durations per type
- Update +page.svelte to use store subscription instead of local state
- Maintains existing toast behavior with improved separation of concerns
- Add Seek command to AudioCommand enum
- Store audio data in audio thread for re-seeking
- Use rodio's skip_duration to seek to desired position
- Preserve play/pause state after seeking
- Update playback timer to account for seek position
- Create AddToPlaylistModal component for selecting playlists
- Update PlaylistDetailView to merge local and Qobuz tracks
- Add visual indicator (HardDrive icon) for local tracks
- Show notice that local tracks are device-specific
- Add "Add to Playlist" option in Local Library track menu
- Connect local track play handlers for playlists
- Hide download button for local tracks in playlists
- Update CastPicker to show protocol tabs with device counts
- Register DLNA and AirPlay state and commands in lib.rs
- Add Deserialize derive to DlnaMetadata and AirPlayMetadata
- Fix capabilities file (remove unavailable fs permissions)
- Remove unused IpAddr import in media_server.rs
- Restore Last.fm session on app startup (not just when visiting Settings)
- Fix LocalLibrary artwork: use asset://localhost/ instead of file://
- Add fs:allow-read capability for asset protocol
- Enable assetProtocol in tauri.conf.json
- Add download functionality to FavoritesView tracks tab
- Add search input for each tab (tracks, albums, artists)
- Filter displayed items based on search query
- Show "no results" message when search has no matches
- Display filtered/total counts in toolbar
- Use buildDisplayTrack helper for cleaner code
- Add downloadStateVersion prop to trigger reactivity in child components
- Use version in each block keys to force re-evaluation when state changes
- Ensures download status persists whether track was downloaded from
album view or playlist view
- DownloadButton component with status indicators
- TrackRow now shows download button on hover
- downloadState store for managing download states
- Tauri event listeners for download progress
- Integration with AlbumDetailView
- SQLite-based index for tracking cached tracks
- Disk-based storage for audio files (~/.cache/qbz-nix/audio/)
- Download progress events via Tauri events
- LRU eviction with configurable cache size limit
- Integration with play_track for automatic local playback
- Open cache folder command for system file manager
1. Credential storage fallback - when keyring (KWallet) unavailable,
falls back to obfuscated file in config directory
2. Heart icon always visible - shows outlined when not favorite,
filled when favorite, with hover states
3. Player favorite state - checks favorite status when track plays
and updates the heart icon in NowPlayingBar
4. Song.link ISRC lookup - uses Spotify/Deezer search URLs with ISRC
since Qobuz isn't directly supported by Odesli
Odesli API doesn't support direct ISRC lookup. Changed to use
Qobuz track URL (https://open.qobuz.com/track/{id}) which Odesli
can properly resolve to song.link.
- Support both LAST_FM_* and LASTFM_* naming conventions
- Match .env.example variable names (LAST_FM_API_KEY, LAST_FM_API_SHARED_SECRET)
- Add detailed logging for auth.getSession to help troubleshoot failures
- Include raw response in error messages for debugging
- Add Cast icon from lucide-svelte
- Add onCast callback prop to both components
- Show "Casting coming soon" toast when clicked
- Backend cast module is disabled pending fixes
- Add isFavorite prop to TrackRow component
- Show filled heart icon for favorited tracks
- Fetch favorite tracks on mount in AlbumDetailView
- Fetch favorite tracks on mount in PlaylistDetailView
- Always show heart in FavoritesView tracks (already favorited)
- Create QualityBadge component with tier detection
- CD badge shows disc icon for 16-bit lossless
- HR badge for 24-bit Hi-Res audio
- MAX badge for 24-bit >96kHz Hi-Res+
- Update NowPlayingBar and FullScreenNowPlaying to use badges
- Pass bitDepth and samplingRate props through components
- Remove blue circle from fullscreen play button (match other controls)
- Add icons to TrackMenu items (Play, ListPlus, Heart, Share2, Disc3, User)
- Check album favorite status on mount in AlbumDetailView
- Improve control button styling with flexbox alignment