Add dependencies on extracted crates and create TauriAdapter.
Changes:
- Add qbz-models, qbz-audio, qbz-player, qbz-qobuz, qbz-core as deps
- Add async-trait dependency for FrontendAdapter impl
- Create tauri_adapter.rs implementing FrontendAdapter
- TauriAdapter emits CoreEvents to frontend via Tauri event system
This is the first step of integration. The old modules still exist
but the new crates are now available for gradual migration.
Add QbzCore<A: FrontendAdapter> as the main orchestrator that ties
all subsystems together and provides a unified API for frontends.
Changes:
- Add core.rs with QbzCore struct
- Add error.rs with CoreError enum
- Update lib.rs with re-exports
QbzCore provides:
- Initialization and shutdown
- Authentication (login/logout)
- Queue operations (shuffle, repeat, clear)
- Event emission through FrontendAdapter
- Access to underlying subsystems (client, queue)
Full workspace compiles with cargo check.
Extract player/mod.rs, playback_engine.rs, and streaming_source.rs to
qbz-player crate. Also adds settings.rs and visualizer module to
qbz-audio (Tauri-specific code removed, core functionality retained).
Changes:
- Add settings.rs to qbz-audio with AudioSettings, AudioSettingsStore
- Add visualizer/ to qbz-audio with RingBuffer, TappedSource, VisualizerTap
- Add player module files to qbz-player
- Update all imports from crate::audio to qbz_audio
- Add serde_json dependency to qbz-audio
Full workspace compiles with cargo check.
Extracted QueueManager from qbz-nix to qbz-player crate.
Features:
- Queue manipulation (add, remove, reorder, clear)
- Current track tracking
- Shuffle mode with Fisher-Yates algorithm
- Repeat modes (off, all, one)
- Play history for going back
- Full test coverage preserved
Uses types from qbz-models:
- QueueTrack
- QueueState
- RepeatMode
Phase 3b (player module extraction) deferred - requires:
- Trait abstraction for API client
- Trait abstraction for audio backend
- Config system refactoring
Tier 0 crate with no dependencies on other qbz-* crates:
- types.rs: Core API types (Track, Album, Artist, Playlist, Quality, etc.)
- playback.rs: Playback types (QueueTrack, RepeatMode, PlaybackState, etc.)
- events.rs: CoreEvent enum for frontend communication
- traits.rs: FrontendAdapter trait enabling multiple frontends
- error.rs: QbzError enum with error codes and recovery flags
All types extracted from qbz-nix/src-tauri/src/api/models.rs and
queue/mod.rs. Ready for use by Tier 1 crates (qbz-audio, qbz-qobuz).
Create the foundational workspace structure for the multi-crate
architecture refactor. This phase establishes placeholder crates
that will be populated in subsequent phases.
Crates created:
- qbz-models: Shared types, events, and traits (Tier 0)
- qbz-audio: Audio backend system (Tier 1)
- qbz-player: Playback engine and queue (Tier 1)
- qbz-qobuz: Qobuz API client (Tier 1)
- qbz-core: Orchestrator (Tier 3)
All crates compile successfully with placeholder implementations.
The workspace uses shared dependencies via workspace.dependencies.
cc
- Track failed batches and retry them once after initial load
- Detect playlist change and abort background loading if user navigates
- Log final status (COMPLETE vs INCOMPLETE with missing count)
- Prevents silent failures that left playlists partially loaded
- Add remove_upcoming_track command that correctly maps upcoming index
to actual queue index (handles shuffle mode properly)
- Update frontend to use remove_upcoming_track instead of remove_from_queue
- Add working context menu for history tracks (Add to Playlist, Track Info)
- Remove unused .track-menu CSS class
- Add refresh button next to device dropdown to re-enumerate devices
without app restart (fixes#69)
- Re-enable quality limiting with per-device sample rate storage
- User can manually set max sample rate per DAC (44.1k to 384k)
- Quality limiting is opt-in (disabled by default)
- Streaming Quality dropdown always takes priority (fixes#72)
Backend: HashMap<device_id, max_rate> stored as JSON in SQLite
Frontend: Conditional UI shows rate dropdown when limit is enabled
Adds a help text showing which device is the current system default.
This helps users understand what "System Default" will actually use.
Backend:
- New command `get_default_device_name` that uses pactl for PipeWire/Pulse
and CPAL for ALSA to get the current default device
Frontend:
- Shows "(System Default is: <device name>)" under the output device setting
- Styled as secondary description text (italic, muted)
Translations added for en, es, de, fr.
Previously, CPAL was the primary source and /proc/asound supplemented
missing devices. This caused inconsistent device lists because CPAL
cannot enumerate devices that are in exclusive mode.
New architecture:
- /proc/asound = PRIMARY source (always complete, stable IDs)
- CPAL = OPTIONAL enrichment (sample rates, may be unavailable)
Benefits:
- Device list is now consistent regardless of playback state
- No more devices appearing/disappearing when entering settings
- Stable device IDs using card NAMES instead of numbers (fixes#69)
Tradeoff:
- Sample rates may be unavailable when device is in exclusive mode
- This is acceptable: consistency > sample rate display
When adding devices from /proc/asound (because CPAL couldn't enumerate
them during exclusive mode), use the same description format as CPAL:
"{card_name}, {device_id}" instead of the longer format with
"Direct Hardware - Bit-perfect" suffix.
This ensures the device dropdown shows consistent names regardless
of whether the device was found by CPAL or added from /proc.
Skip the 'default' device from backend enumeration since we already
add an explicit "System Default" entry. This prevents showing
"System Default" twice in the dropdown.
ALSA hw:X,Y device IDs use card NUMBERS which are unstable and change
between boots depending on USB enumeration order. This caused saved
devices to become unrecognized after reboot (issue #69).
Now only enumerate front:CARD=name,DEV=Y devices which use the card
NAME instead of number. Both formats are functionally equivalent for
bit-perfect playback, but front: format is stable across reboots.
Fixes#69
Changed the keyed each block in DeviceDropdown.svelte from device.value
to device.id. This fixes the each_key_duplicate error when multiple
devices have the same display name (e.g., "System Default").
Remove dependency on alsa-utils package by reading device information
directly from /proc/asound filesystem:
- /proc/asound/cards for card list with names
- /proc/asound/cardX/ for detailed card info
- /proc/asound/cardX/pcmXp/ for PCM device info
This addresses Flathub reviewer feedback about not using CLI tools
when API alternatives exist. The /proc/asound interface provides
all the information we need for device enumeration and descriptions.
Changes:
- alsa_backend.rs: New enumerate_with_proc_descriptions() using /proc
- audio_backends.rs: Remove aplay calls from DAC capabilities query
- check_alsa_utils_installed() now always returns true (no longer needed)
Changes since 1.1.13:
- Fix MPRIS dbus name to use appid (Flathub compliance)
- Fix SQLite WAL mode for all connections (UI lag fix)
- Add volume +/- step buttons in player bar
- Add playlist search in sidebar with folder auto-expand
- New playlist collage layout (3+1 grid)
Change dbus_name from "qbz" to "com.blitzfc.qbz" so the MPRIS name
matches the appid pattern. This eliminates the need for the explicit
--own-name permission as Flatpak allows apps to own names under their
appid namespace automatically.
cc
- Change 4-cover layout from 2x2 to 3 small left + 1 large right
- Always use track artwork collage instead of low-res API image
- Upscale images to 600px for better quality
cc
- Remove border from volume step buttons (no circles in player)
- Remove separator between volume and queue button
- Make playlist search input taller using negative margins
- Auto-expand folders with matching results during search
- Hide folders without matches during search
cc
- Add +/- buttons to volume control for 5% increments
- Reduce SongCard min-width from 508px to 436px
- Add playlist search in sidebar header with expandable input
- Add translations for new features in all 4 locales
cc
- Desktop entry file
- AppStream metainfo with screenshots
- Screenshot images for Flathub listing
These files are required by Flathub reviewers to be in upstream.
- Change trigger from release:published to workflow_run on release-linux
- Only run if the triggering workflow succeeded
- Increase timeout to 30 minutes for aarch64 build to complete
- Extract version from workflow's head branch (the tag)
- Add Hardware Acceleration toggle to Composition section
- Move Force DMA-BUF toggle from Developer Mode to Composition
- Add i18n keys for new composition toggles (en, es, de, fr)
These settings logically belong together since they both control
GPU rendering behavior. Hardware Acceleration is the broad switch
that enables GPU; Force DMA-BUF controls the specific buffer-sharing
mechanism with the compositor.
The localStorage->backend sync only ran when useSystemTitleBar was true,
so toggling it OFF never persisted to the database. On restart, the
backend read the old 'true' value and created the window with system
decorations, while the UI showed 'false' from localStorage.
Now syncs the value unconditionally on init.
The $effect watching outputStatus.is_playing would call loadStatus(),
which updates outputStatus, triggering the effect again. This caused
~30 calls per second when hovering over the audio badges.
Removed the problematic $effect - mouseenter handler and 1s polling
for hardware status are sufficient.
Only capture log/info levels in dev builds or when verbose mode is
explicitly enabled in Developer Mode. Always capture error/warn for
bug tracking. Reduces GC/CPU overhead in production builds.
Adds toggle in Settings > Developer Mode to enable verbose capture
when debugging production issues.
Apply disposed flag pattern to prevent listener leaks when component
unmounts before async listen() calls complete.
+page.svelte:
- Add disposed flag for tray/media control listeners
- Check disposed after each await listen(), cleanup immediately if true
- Set disposed=true at start of cleanup function
offlineCacheState.ts:
- Add listenersDisposed flag
- Check flag after each listener registration
- Cleanup any registered listeners if disposed during async sequence
- Set flag in stopOfflineCacheEventListeners()
This prevents memory leaks during HMR and fast navigation.
QueuePanel:
- Add vertical ... icon to the right of track duration
- Context menu with 3 options:
- Remove from Queue (calls backend remove_from_queue)
- Add to Playlist (reuses existing playlist modal)
- Show Track Info (reuses existing track info modal)
- Menu shows on button click, closes on click outside
+page.svelte:
- Add handlers: handleRemoveFromQueue, handleQueueTrackAddToPlaylist,
handleQueueTrackInfo
- Wire up new QueuePanel props
i18n: Add toast messages for remove from queue (all 4 locales)
Backend:
- Add static atomics to track graphics startup state
- Add set_startup_graphics_state() called from main.rs
- Add get_graphics_startup_status command for frontend
Frontend (SettingsView):
- Query graphics startup status on mount
- Show prominent red warning in Composition section when
using fallback graphics settings
- Display recovery command (qbz --reset-graphics)
i18n: Add fallbackWarning/fallbackDesc to all 4 locales
This helps users understand when graphics settings failed to
load and may be causing performance degradation.
When graphics settings fail to load from DB:
- Logs warning to stderr (visible in terminal)
- Logs to startup log with recovery instructions
- Tracks fallback state for potential UI exposure
- Adds summary log of graphics config at startup
Helps users diagnose performance degradation caused by
silent graphics settings failures.
- Hide MiniPlayer button in NowPlayingBar when not provided
- Comment out miniplayer IPC emissions in player state subscriber
- Removes unnecessary IPC overhead during playback
MiniPlayer needs significant work before re-enabling.
Removes vinyl from the focus mode tab options while keeping the
VinylPanel component intact for potential future use. Users can
now choose from coverflow, static, visualizer, lyrics, and queue.