Fixes dependabot alerts #25 and #26 (high severity):
- CRL Distribution Point Scope Check Logic Error
- X.509 Name Constraints Bypass via Wildcard/Unicode CN
cc
Replace fixed 500ms delays with 1s/2s/4s exponential backoff.
Add 4th retry attempt at fallen-back quality level.
Return QualityExhausted structured error when all attempts fail.
Add force_lowest_quality param to v2_play_track.
cc
When image cache is disabled or unavailable, images were returned
as original HTTPS URLs for WebKit to load directly. On AppImage
distros where GnuTLS can't find system CA certs, this fails silently.
Now all images go through reqwest (rustls, bundled CA) and are
written to temp files as file:// URLs. WebKit never needs to
resolve HTTPS for images.
cc
main.rs GPU conditions checked has_nvidia && !has_amd but not
has_intel, so hybrid laptops (Intel iGPU + NVIDIA dGPU) had
compositing and DMA-BUF disabled unnecessarily.
Also remove duplicate DMABUF/compositing logic from lib.rs that
ran before main.rs and conflicted with its GPU-aware decisions.
cc
apply_linux_webkit_workarounds() was unconditionally disabling
DMABUF renderer and compositing mode, ignoring what the user
configured in Appearance > Composition settings.
Now reads graphics_settings.db and developer_settings.db at startup
(readonly, before Tauri state init) so toggles actually take effect.
- Add new_readonly() to GraphicsSettingsStore and DeveloperSettingsStore
- Hardware Acceleration ON = compositing enabled
- Force DMA-BUF toggle respected for WEBKIT_DISABLE_DMABUF_RENDERER
- Env vars still override saved settings
cc
Replace 8+ sequential per-section IPC calls with a single batch
command. Backend reads all tracks once instead of N times.
- Add v2_check_albums_fully_cached_batch (single DB read, HashMap return)
- Remove per-section await tick() + loadAllAlbumDownloadStatuses() calls
- Single batch call at end of loadHome() after all data resolves
- Keep individual check for on-click refresh (single album)
cc
activate_offline_session was only initializing library, offline,
offline_cache, audio_settings, and playback_prefs. Missing stores
caused "No active session" errors for:
- download_settings (Show in Local Library toggle)
- session_store (session persistence)
- favorites_cache/prefs (favorites view)
- tray_settings (tray icon settings)
Now mirrors activate_session but skips online-only services
(MusicBrainz, ListenBrainz, Last.fm, API cache, artist vectors).
cc
Two bugs:
1. mainContentEl teardown crash on logout — the $effect cleanup used
non-null assertion (!) on an element that becomes null when the DOM
is destroyed during logout. Changed to optional chaining (?.).
This TypeError was blocking the render, causing the spinner to hang
instead of showing the login form.
2. deactivate_session was clearing last_user_id, which broke offline
mode after logout. The user's data stays on disk — only factory
reset should clear the last_user_id marker.
cc
Three bugs prevented offline mode from working after V2 migration:
1. activate_offline_session used user_id=0 (empty profile) instead of
the last known user_id, so the user's library/settings were invisible
2. setManualOffline was called BEFORE activate_offline_session, but it
requires the offline store to be initialized (which happens during
session activation). Reordered: activate session first, then set
manual offline.
3. LoginView called setManualOffline directly instead of delegating to
the parent's handleStartOffline which has the correct order.
Also added "noPreviousSession" i18n message for users who never logged
in — they need to create a profile first before offline mode works.
cc
When get_stream_url_with_fallback internally falls back from UltraHiRes
to HiRes (due to restrictions), the retry logic was requesting a fresh
URL at the original UltraHiRes quality — triggering another fallback
cycle and CDN connection issues.
Now tracks the effective quality from stream_url.format_id and retries
at that quality directly. Applied to both streaming and standard
download paths.
cc
In Flatpak, the default temp dir is inside the sandbox and invisible
to the host's KDE StatusNotifierWatcher. libayatana-appindicator writes
the PNG to temp dir and calls set_icon_theme_path, but KDE can't see
sandbox paths. Use ~/.local/share/icons which is exported to the host
via Flatpak filesystem permissions.
Non-Flatpak installs continue using XDG_RUNTIME_DIR.
cc
- Gate XDG/desktop handler commands with macOS fallbacks
- Gate KWin window rule functions and cleanup to Linux
- Gate Linux-only notification helpers and constants
- Force native decorations on macOS (fixes WKWebView event delivery)
- Use overlay title bar style with dark background color
- Add macOS notifications via notify-rust with bundle identifier
Rust:
- Remove unused get_screen_resolution() function
- Remove unused DEFAULT_QCONNECT_DEVICE_NAME constant
Svelte:
- Add tabindex=-1 to TitleBarNav menu dropdowns (a11y)
- Make volumeRef reactive with $state() in NowPlayingBar
- Remove unused .section-separator CSS from NowPlayingBar
- Remove unused .artist-albums CSS from SearchView and Grid
- Remove unused .artist-list-meta CSS from ArtistList
cc
rcgen 0.14 breaking changes:
- CertificateParams::new() takes Vec<String> not Vec<SanType>
- Certificate::from_params() replaced by params.self_signed(&key_pair)
- cert.serialize_pem() replaced by cert.pem()
- cert.serialize_private_key_pem() replaced by key_pair.serialize_pem()
- Ia5String no longer public, DNS SANs passed as strings
Also prefixed unused _envelope variable in qconnect_service.rs.
cc
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