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
- 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
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
Download tracks via Qobuz Akamai CDN with encrypted CMAF segments.
Derives session key (HKDF), unwraps content key (AES-CBC), decrypts
frames (AES-CTR), reassembles into standard FLAC. Falls back to legacy
track/getFileUrl if CMAF fails.
- Add qbz-cmaf dependency to src-tauri
- Make ensure_cmaf_session public on QobuzClient
- Add ensure_cmaf_session and get_file_url passthroughs to CoreBridge
- Add download_audio_cmaf and try_cmaf_download helpers
- Wire CMAF as primary download path in v2_play_track with legacy fallback
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
Qobuz redirects to play.qobuz.com/discover?code_autorisation=XXX
not ?code=XXX. Both the navigation intercept and the /oauth/callback
API call were using the wrong parameter name, so the code was never
captured and the exchange request was malformed.
Replace the flat album grid LabelView with a rich detail page featuring:
- Header with label image, name, description, and play button
- Popular Tracks section (5/10/all expand, same UX as ArtistDetailView)
- Releases horizontal scroll row with "See all" → LabelReleasesView
- Critics' Picks section from second releases container
- Playlists, Artists, and More Labels sections
Backend: add /label/page and /label/explore API endpoints with V2
commands (v2_get_label_page, v2_get_label_explore). Models use
serde_json::Value for flexible section parsing.
Old LabelView renamed to LabelReleasesView for the "See all" flow.
i18n keys added to all 4 locales (en, es, de, fr).
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