Commit Graph
3635 Commits
Author SHA1 Message Date
vicrodh 5aa0df1cbc feat(api): sign all remaining Qobuz API endpoints
Add request_ts + request_sig to every API call matching the mobile
app interceptor pattern. Introduces signed_get/signed_get_auth
helpers and a generic sign_request function.

Endpoints now signed:
- album/get, album/getFeatured
- track/get, track/getList
- artist/get, artist/getSimilarArtists, artist/page, artist/getReleasesGrid
- discover/index, discover/playlists, discover/* browse endpoints
- genre/list
- label/page, label/explore, label/get
- playlist/get, playlist/getUserPlaylists, playlist/create,
  playlist/delete, playlist/addTracks, playlist/deleteTracks,
  playlist/update, playlist/subscribe, playlist/unsubscribe
- playlist/getTags
- favorite/create, favorite/delete

Excluded (pre-auth, cannot sign): user/login, oauth/callback.
Already signed (unchanged): track/getFileUrl, favorite/getUserFavorites,
session/start, file/url, all search endpoints.

cc
2026-04-08 09:41:57 -06:00
vicrodh e62b160d5d feat(login): add cancel buttons and captcha hint to OAuth flows
WebView OAuth: cancel button appears during loading, captcha hint
shows after 25s or when user closes WebView. Hint suggests trying
system browser instead with one-click action.

System browser OAuth: cancel link appears next to loading text,
immediately aborts the wait.

i18n: new keys captchaHint and trySystemBrowser in all 5 locales.

cc
2026-04-08 08:55:02 -06:00
vicrodh 6efdca0ea8 feat(oauth): add cancel commands for both OAuth flows
Add OAuthCancelState with shared Notify for system browser flow.
v2_start_system_browser_oauth uses tokio::select! to race between
code received, 120s timeout, and user cancel signal.

New commands:
- v2_cancel_system_browser_oauth: triggers cancel notify
- v2_cancel_oauth_login: closes all OAuth WebView windows

Timeout reduced from 300s to 120s for system browser flow.

cc
2026-04-08 08:49:51 -06:00
vicrodh 814bf8b968 fix(oauth): detect WebView window close to unblock login wait
When the user closes the OAuth WebView window manually, the
Destroyed event now triggers notify to unblock the 5-minute
timeout immediately, returning oauth_cancelled instead of
hanging until timeout.

cc
2026-04-08 08:37:02 -06:00
vicrodh dbc97d6bd1 feat(search): add request signing to all search endpoints
Add request_ts + request_sig (MD5 signature) to catalog/search,
album/search, track/search, artist/search, and playlist/search
endpoints matching the mobile app authentication pattern.

Migrate v2_search_all from legacy AppState to CoreBridge, removing
the last direct API call that bypassed the V2 crate architecture.

cc
2026-04-08 08:34:32 -06:00
vicrodh fb7c2a440a docs: add NixOS installation instructions, update snap note
Add NixOS/Nix flake install instructions (system-wide + Home Manager).
Update snap note since MPRIS was approved.

cc
2026-04-07 21:46:52 -06:00
vicrodh 59b34132c3 fix(lyrics): use theme accent color for active line highlight
Replace hardcoded purple (#a78bfa / rgb(99,102,241)) with
var(--accent-primary) so the karaoke gradient and glow adapt
to the active theme.

cc
2026-04-07 19:34:00 -06:00
vicrodh 42b429e86d fix(ui): enable multi-select drag in all views
Pass dragTrackIds to TrackRow in album, playlist, favorites, top-q,
weekly suggest, dynamic suggest, and fav-q views. VirtualizedTrackList
also passes selected IDs for multi-drag.

cc
2026-04-07 18:07:11 -06:00
vicrodh a7cdcd6f3d feat(ui): enable track drag & drop in artist and search views
Artist popular tracks and search results now support dragging tracks
onto sidebar playlists. Artist view also supports multi-select drag.

cc
2026-04-07 18:00:29 -06:00
vicrodh e71d634cdf fix(ui): show artist and album in track drag ghost
Single track: title (bold) + artist · album (subtle subtitle).
Multi-select: "N tracks" count as before.

cc
2026-04-07 17:55:39 -06:00
vicrodh 73b0da44ad fix(ui): use compact drag ghost for track drag & drop
Replaces the default full-row drag image with a small semi-transparent
pill showing the track title or "N tracks" count for multi-select.

cc
2026-04-07 17:50:33 -06:00
vicrodh ae8990f4a2 feat(ui): drag & drop tracks onto sidebar playlists
Tracks are now draggable from any view. Dropping onto a playlist in the
sidebar adds them directly via v2_add_tracks_to_playlist. Supports
multi-select: when tracks are selected in playlist view, dragging any
selected track carries all selected IDs.

cc
2026-04-07 17:39:45 -06:00
vicrodh 7faa4e467a fix(audio): default alsa_plugin to Hw when switching to ALSA backend
When selecting ALSA Direct as backend, alsa_plugin was never persisted
to the DB if the user didn't explicitly change it. The UI showed
"hw (Direct Hardware)" as a visual default but the DB stayed NULL,
causing isAlsaDirect to evaluate false and showing a gray DAC badge
instead of the blue HW badge.

cc
2026-04-07 17:20:17 -06:00
vicrodh b5bb2bbe03 fix(player): lock volume slider in immersive player when ALSA Direct hw active
The NowPlayingBar correctly locked the volume slider but the immersive
player (fullscreen/focus mode) was missing the volumeLocked prop chain,
allowing the slider to move visually even though the volume change was
blocked. Respects Qobuz Connect peer renderer override.

cc
2026-04-07 15:18:10 -06:00
vicrodh acd283a1a7 feat(snap): restore mpris slot after snapcraft approval
Adds back the mpris slot with name "qbz" that was removed to unblock
store updates. Now approved per forum request #50654.

cc
2026-04-07 14:35:30 -06:00
vicrodh e2fd2a11b7 feat(snap): restore mpris slot after snapcraft approval
Adds back the mpris slot with name "qbz" that was removed to unblock
store updates. Now approved per forum request #50654.

cc
2026-04-07 14:35:16 -06:00
vicrodh 20440c6110 Revert "feat(snap): restore mpris slot after snapcraft approval"
This reverts commit 3c104ce223.
2026-04-07 14:34:56 -06:00
vicrodh 3c104ce223 feat(snap): restore mpris slot after snapcraft approval
Adds back the mpris slot with name "qbz" that was removed to unblock
store updates. Now approved per forum request #50654.

cc
2026-04-07 14:33:04 -06:00
vicrodh 6624b70574 chore(snap): add exclusive audio note to description
Snapcraft reviewer requested clarifying that ALSA exclusive mode
may block other apps from playing sound.

cc
2026-04-07 13:55:58 -06:00
vicrodh c8a3a648f5 chore(alsa): lower device enumeration logs to debug, add 5th retry
Reduce log noise by demoting ALSA device enumeration from info to debug.
Add a 5th backoff retry at 800ms for both hw and plughw paths as a
safety net for any EBUSY cases that slip through the lifecycle fix.

cc
2026-04-07 11:53:23 -06:00
vicrodh 426a4d0dba fix(player): stop engine before dropping ALSA stream on format change
In the Play and PlayStreaming handlers, the old engine's writer thread
still holds an Arc<AlsaDirectStream> when the stream_opt is dropped and
a new snd_pcm_open() is attempted. This causes EBUSY on track switches
with sample rate changes. Reorder to: stop engine -> drop stream -> open
new stream, matching the Stop handler's correct lifecycle.

cc
2026-04-07 11:53:17 -06:00
vicrodh 17919cccad chore: bump flake.nix to 1.2.4
cc
2026-04-07 10:15:22 -06:00
vicrodh ee70268332 merge: v1.2.4 - Hardening playback (fix-tag) 2026-04-07 09:48:37 -06:00
vicrodh d1278e12ad chore: bump version to 1.2.4 - Hardening playback
cc
2026-04-07 09:48:04 -06:00
vicrodh 74e3ba9519 chore(logging): reduce noise in default log level
- Device enumeration (48 CPAL devices): info → debug
- Playlist fetch completion: info → debug
- Playlist command invocation: info → debug
- zbus socket_reader/tracing: filtered to warn level

These remain visible with RUST_LOG=debug or verbose log capture.

cc
2026-04-07 08:39:18 -06:00
vicrodh a279e04881 feat(credentials): use XDG portal secret for key derivation
Add per-app secret from org.freedesktop.portal.Secret as entropy
in the AES-256-GCM key derivation. DE-agnostic (works with GNOME,
KDE, etc.) and Flatpak-safe (portals auto-accessible in sandbox).

Falls back to machine_id + salt when portal is unavailable (headless,
old DEs, non-Linux). Cached for session lifetime via OnceLock.

Users will need to re-login once on upgrade (key derivation changed).

cc
2026-04-07 08:22:28 -06:00
vicrodh 6da5092605 fix(credentials): encrypt OAuth token in keyring
Token was stored as plaintext in the system keyring, visible via
secret-tool. Now AES-256-GCM encrypted before storing — keyring
entry shows ciphertext, not the raw token.

Handles migration from both plaintext keyring entries and encrypted
files from previous versions.

cc
2026-04-07 07:38:57 -06:00
vicrodh 04eab0d880 fix(credentials): keyring-only storage, no redundant file
OAuth token was saved to BOTH keyring and encrypted file, making the
keyring pointless. Now:
- Save: keyring first. Only writes file if keyring unavailable.
- Load: keyring first. If found in file, migrates to keyring and
  deletes the file.
- Result: when keyring works, no token file exists on disk.

cc
2026-04-07 07:19:44 -06:00
vicrodh 4505312280 fix(security): remove hardcoded crypto seed from cmaf crate
Move the CMAF app seed from a hardcoded constant in qbz-cmaf to a
parameter passed by callers. The seed now lives in qbz-qobuz::auth
where other app-level constants are defined. This resolves CodeQL
alerts for hard-coded cryptographic values.

Also truncate session_id in logs to avoid cleartext logging of
sensitive session identifiers.

cc
2026-04-07 07:04:33 -06:00
vicrodh 5f154aaf98 fix(logout): clear stored credentials on logout
Logout was not clearing OAuth tokens or credentials from keyring
and encrypted files. Users had to manually delete files to fully
sign out. Now clears both keyring and file storage.

cc
2026-04-07 06:52:32 -06:00
vicrodh 192f681d25 fix: bump Cargo.toml version to 1.2.3
Cargo.toml was left at 1.2.2 because the version bump sed command
only matched JSON format ("version": "1.2.2") not TOML format
(version = "1.2.2"). This caused CARGO_PKG_VERSION to report 1.2.2
at runtime, triggering the update-available modal on every launch.

cc
2026-04-07 06:41:19 -06:00
vicrodh 2a6bb658b1 fix(credentials): improve keyring failure logging visibility
Keyring save/load failures were logged at debug level, making them
invisible in normal logs. Users on KDE Plasma 6 reported the keyring
feature not working (#276) but couldn't see why.

Promoted keyring failures to warn level with actionable messages
(e.g., KDE users need org.freedesktop.secrets enabled in KWallet).

cc
2026-04-07 06:29:28 -06:00
vicrodh 11bffe7071 fix(cmaf): fetch all audio segments (off-by-one in segment loop)
Loop used 1..n_segments (exclusive) but n_segments is the count of
audio segments, not the last index. Segments are numbered 1 through
n_segments, so the loop must be 1..=n_segments (inclusive).

This caused the last ~9 seconds of every CMAF-streamed track to be
missing. Confirmed with diagnostic logging: table_total_samples
exceeded actual decoded frames by exactly one segment's worth.

cc
2026-04-07 06:17:37 -06:00
vicrodh 89c29195fb chore: bump flake.nix to 1.2.3
Hashes left empty — nix build will report correct values on first run.

cc
2026-04-06 17:56:21 -06:00
vicrodh 38ffd8d82f chore: bump version to 1.2.3 - Hardening playback
cc
2026-04-06 17:28:06 -06:00
vicrodh c9d628a966 merge: v1.2.3 - Hardening playback
CMAF segmented streaming, quality negotiation, ALSA hardening,
offline playback controls, system keyring, security updates.
2026-04-06 17:24:34 -06:00
vicrodh 7ff5e9593e fix(gentoo): align source ebuild template with working overlay
Template had a different src_compile (npm run build + cargo build)
than the overlay's working ebuild (npx tauri build --no-bundle).
Now they match exactly, preventing the release workflow from
breaking the overlay.

cc
2026-04-06 17:24:19 -06:00
vicrodh c86fe7de9e docs: add release 1.2.3 notes and update contributors
Add AdamArstall to README and About modal (scroll restoration fixes).
Release docs for 1.2.3 - Hardening playback.

cc
2026-04-06 17:18:54 -06:00
vicrodh e14e0a14a1 fix(logout): stop playback before deactivating session
Logout left audio playing through the ALSA/PipeWire backend while
tearing down the session. Now explicitly stops playback and clears
MPRIS state as the first step of logout.

cc
2026-04-06 16:59:27 -06:00
vicrodh 241dcf0814 feat(security): store OAuth token in system keyring
OAuth token save/load/clear now use the system keyring (GNOME Keyring,
KDE Wallet) as primary storage, with the existing AES-256-GCM
encrypted file as automatic fallback.

On first load from file, the token is migrated to the keyring
automatically for future use.

The previous commit enabled the keyring backend but only wired it
for email+password credentials (no longer used). This wires it
for the OAuth token which is the active auth method.

cc
2026-04-06 16:56:22 -06:00
vicrodh c37f3d7595 feat(security): enable system keyring for credential storage
Enable async-secret-service + crypto-rust features on the keyring
crate, activating GNOME Keyring and KDE Wallet support. The keyring
integration code was already written but the crate was compiled
without any platform backend, so it silently failed every time.

OAuth tokens will now be stored in the system keyring when available,
with encrypted file as automatic fallback.

Added org.freedesktop.secrets to Flatpak finish-args for sandbox
keyring access.

Fixes #215

cc
2026-04-06 16:20:26 -06:00
vicrodh 54139ad4d3 fix(offline): allow playback controls without API client init
pause, resume, stop, seek, and volume commands required
RequiresClientInit which fails when offline (no internet = no bundle
extraction = client not initialized). These commands only use the
local Player/CoreBridge, not the Qobuz API client.

Changed to RequiresUserSession which passes in offline mode since
the offline session activates from cached user data.

Fixes #173

cc
2026-04-06 16:07:59 -06:00
vicrodh a7da06341f chore(deps-dev): bump svelte 5.55.0 -> 5.55.1
Closes #253

cc
2026-04-06 15:16:57 -06:00
vicrodh 3eab5b72ac chore(deps-dev): bump jsdom 27.4.0 -> 29.0.1
Closes #254

cc
2026-04-06 15:16:46 -06:00
vicrodh 2c0f42b885 chore(deps): bump dirs 5 -> 6 across all crates
Zero API changes, only bumps internal deps (windows-sys, redox_users).
Eliminates duplicate dirs versions in Cargo.lock.

Closes #257

cc
2026-04-06 15:16:34 -06:00
vicrodh a98d3d953a chore(deps): bump vite 8.0.3 -> 8.0.5 (security)
Fixes 3 dev server vulnerabilities:
- Path traversal in optimized deps .map handling
- Arbitrary file read via WebSocket
- server.fs.deny bypass with queries

Closes #274

cc
2026-04-06 15:14:10 -06:00
vicrodh f86bc9607e merge: CMAF segmented streaming pipeline
New encrypted CMAF streaming via Akamai CDN, replacing legacy nginx
direct downloads that were failing with "1 byte EOF" for many tracks.

Key changes:
- qbz-cmaf crate: HKDF key derivation, AES-CBC/CTR decryption, CMAF parsing
- qbz-qobuz: session/start + file/url endpoints
- Streaming playback: init segment fetch (~500ms) then background segment download
- CMAF-first with legacy fallback on all download paths
- Quality matching: request track's actual quality, not always UltraHiRes

cc
2026-04-06 15:10:01 -06:00
vicrodh 3df84f81e7 fix(quality): request track's actual quality instead of always UltraHiRes
playTrack() was always sending the user's max quality setting (Hi-Res+)
regardless of what the track actually offers. A 44.1kHz/24bit track
would trigger 3 API fallback calls (UltraHiRes -> HiRes -> Lossless)
and the cache was discarded as "lower quality" for re-download.

New effectiveQuality() picks the minimum of user max and track metadata
(bit_depth + sampling_rate), so a 24bit/96kHz track requests Hi-Res
directly (1 API call) and cache matches perfectly.

cc
2026-04-06 15:07:41 -06:00
vicrodh 6103044a2e fix(quality): parse track metadata quality instead of defaulting to UltraHiRes
Frontend sends "24bit/44.1kHz" format from track metadata, but
parse_quality fell through to default UltraHiRes for unknown formats.
This caused unnecessary API quality fallback cascades (3 calls per
track) and cache mismatches where cached 24bit/44.1kHz data was
discarded for re-download that returns the same quality.

Now parses "XXbit/YYYkHz" format and maps to the correct Quality
level, requesting exactly what the track offers.

cc
2026-04-06 15:03:23 -06:00
vicrodh 8b9abdea58 Revert "fix(cache): don't discard 24-bit cache for sample rate mismatch"
This reverts commit 49fc2ae41e.
2026-04-06 14:56:54 -06:00