QBZ wasn't appearing as a renderer on first connect because the
frontend snapshot was emitted before the deferred renderer join
completed. After joining as renderer, wait 500ms and re-request
session state so the server sends an updated renderer list that
includes QBZ.
cc
Nix sets HOME=/homeless-shelter during builds, which makes
dirs::config_dir() return a technically writable but unusable path.
The keyring/D-Bus is also unavailable in the sandbox.
Added detection for HOME containing "homeless-shelter" or
"/nix/store", and NIX_BUILD_TOP env var, to skip credential
roundtrip tests in Nix builds.
cc
MediaControlError doesn't impl Display on all platforms. Using {}
would fail to compile on non-Linux targets. Use {:?} (Debug) instead.
Cherry-picked from PR #181 by @afonsojramos.
cc
v2_query_dac_capabilities was returning hardcoded sample rates
(44.1-192kHz including 176.4kHz) instead of querying the actual
hardware. This caused incorrect configuration for DACs that don't
support all rates (e.g. DacMagic Plus doesn't support 176.4kHz).
Now queries /proc/asound/cardN/stream0 via PipeWire sink mapping
or ALSA device ID to get the real discrete rates from the USB
descriptor. Falls back to defaults only if detection fails.
cc
Discovered undocumented Qobuz API endpoints from bundle analysis:
- POST /playlist/subscribe { playlist_id }
- POST /playlist/unsubscribe { playlist_id }
This is the native "follow playlist" feature that syncs across all
Qobuz clients, separate from QBZ's existing "Copy to Library" (local
copy) and "Favorite" (local flag) features.
Added:
- subscribe_playlist/unsubscribe_playlist in both qbz-qobuz and legacy client
- v2_qobuz_subscribe_playlist / v2_qobuz_unsubscribe_playlist commands
- Bookmark toggle button in PlaylistDetailView (next to Copy button)
- i18n keys in all 5 locales
cc
mupdf 0.5 had struct size mismatches on Arch Linux (mupdf-sys bindings
incompatible with system MuPDF headers). Upgrading to mupdf 0.6 fixes
the bindings.
- Removed the booklet feature gate — mupdf is now a direct dependency
again, matching the v1.1.19 configuration
- Removed stub implementation (always compile real MuPDF backend)
- sys-lib-libjpeg remains excluded (cross-distro libjpeg incompatibility)
cc
xdpyinfo returns combined multi-monitor resolution (e.g. 6000x1600 for
dual monitors), causing false positives like clamping 1926x1590 to
5700x1520. The 95% multiplier made things worse — the fallback size was
larger than any single monitor.
Replace with simple corruption guard: only clamp values above 8K
(obviously corrupt DB entries), fallback to 1920x1080. The window
manager already handles fitting windows to the actual display.
cc
The KWin window rule approach (kwinrulesrc + qdbus reconfigure) was
never actually active because GDK_BACKEND is unset on most KDE Wayland
sessions. In v1.1.18 this meant decorations(use_system_titlebar) was
used directly — GTK CSD appeared (ugly but functional, no CPU issues).
The hack itself, when triggered, caused double titlebar and a CPU busy
loop that blocked networking. Remove all KDE-specific detection and
KWin rule setup. Window now simply uses decorations(use_system_titlebar)
on all platforms, matching the effective behavior of v1.1.18.
The one-time cleanup of stale kwinrulesrc entries is preserved so users
who had the rule from v1.1.14-v1.1.19 get it cleaned up automatically.
cc
With ALSA Direct hw: there is no software mixer — volume must be
controlled at the DAC/hardware level. Software volume attenuation
would reduce bit depth and defeat the purpose of bit-perfect playback.
Backend: v2_set_volume forces volume to 1.0 when backend=Alsa+plugin=Hw
Frontend: volume slider disabled (grayed out at 100%), mute/step buttons
hidden, handleVolumeChange and handleToggleMute return early.
Settings callbacks notify +page.svelte when backend/plugin changes to
update the lock state in real-time.
i18n: volumeLockedHw tooltip added to all 5 locales.
cc
Two additional gaps found during audio settings sync audit:
1. convert_to_qbz_audio_settings() hardcoded alsa_hardware_volume to
false instead of reading settings.alsa_hardware_volume. This meant
the player never received the user's ALSA hardware volume preference.
2. v2_reset_audio_settings saved defaults to DB but never synced them
to the CoreBridge player, leaving stale settings in memory.
cc
Two bugs caused the exclusive mode to not work when QConnect was active:
1. Critical audio setters (backend_type, exclusive_mode, dac_passthrough,
output_device, alsa_plugin, pw_force_bitperfect, sample_rate,
alsa_hardware_volume) saved to the per-user store but never called
reload_settings() on the CoreBridge player. The Player kept using
stale settings (often defaults with backend_type=None), falling back
to CPAL/PipeWire instead of ALSA Direct.
2. After login, per-user audio settings were loaded into AudioSettingsState
but never pushed into the CoreBridge player, which was created at
startup with flat-path defaults.
Fix: Add sync_audio_settings_to_player() helper and call it from all
critical audio setters. Also sync settings in activate_session() and
activate_offline_session() right after audio_settings.init_at().
cc
Developer Mode: toggle to show/hide QConnect dev panel button in
the player bar (hidden by default, persisted in localStorage).
Integrations: editable device name input for Qobuz Connect with
default "Qbz - {hostname}". Backend commands v2_qconnect_get/set
_device_name and v2_get_hostname. Custom name is used during the
WS bootstrap handshake.
cc
resolve_core_shuffle_order was reordering the server's shuffle_order
to put the current track first. This destroyed the server's concept
of "already played" vs "upcoming" — CoreBridge showed all tracks as
upcoming while the web player correctly split them.
Now the server's raw shuffle_order is passed through unchanged.
CoreBridge's set_queue_with_order finds shuffle_position from
current_index, preserving the played/upcoming split.
cc
mupdf-sys 0.5.0 bindings are incompatible with the current system
MuPDF library (struct size assertions overflow). Gate mupdf behind
a booklet feature flag (disabled by default). When disabled, booklet
commands return an error instead of crashing the build.
cc
Backend _if_remote methods for QConnect autoplay protocol:
- set_autoplay_mode_if_remote: toggles autoplay on the QConnect server
- autoplay_load_tracks_if_remote: loads track IDs into the autoplay pool
Both follow the established _if_remote pattern with diagnostics.
Prevents double-bootstrap on initial connect. The Subscribed
handler now only calls bootstrap_remote_presence when the
connection was previously lost (has_disconnected=true), not
on the first connect where connect() already bootstraps.
Also sets has_disconnected=true in the Disconnected handler.
New _if_remote backend commands for set_volume and mute_volume.
handleVolumeChange and handleToggleMute in both main view and miniplayer
now check for peer renderer before setting volume locally. Media
control set_volume also routed through the guard. When no peer is
active, volume is set locally and reported to QConnect server.
When a peer renderer is active, the MPRIS/media-key stop command now
sends SetPlayerState(STOPPED) to the QConnect server instead of stopping
local playback. Falls back to local stop on error or when no peer is
active.
When a peer renderer is active, shuffle/repeat/queue-play/history-play
commands are now routed to the QConnect server instead of being applied
locally. Two new backend commands (toggle_shuffle_if_remote,
cycle_repeat_if_remote) follow the existing _if_remote pattern.
Guards added to both +page.svelte (main + immersive) and miniplayer.