Build hardening:
- Add -fstack-protector-strong, -D_FORTIFY_SOURCE=2, PIE, full RELRO
- Enable overflow-checks in Rust release profile
Rust backend:
- Return null (not panic) if Tokio runtime or QobuzClient init fails
- Strip null bytes in FFI JSON callback to prevent CString panics
- Document MD5 and password-in-query as Qobuz API constraints
C++ frontend:
- Validate JSON document before accessing fields in onEvent()
- Handle null backend pointer from failed init
- Set biography label to PlainText and decode HTML entities to prevent
rendering injected content from API responses
- Clamp slider position and guard negative durations
- Use qint64 for duration formatting to avoid int truncation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Switch artist view to artist/page API (proper sections: Albums, Singles & EPs,
Live, Compilations; version in titles like "Deluxe")
- Fix artist sections categorization using releases[].type from artist/page
- Add getUser() backend call; fetch on session restore when userId=0 to fix
playlist ownership (Remove from playlist / Delete playlist were missing)
- Fix multi-disc double-click / Play Now queue start index (disc headers were
counted in row index but excluded from currentTracksJson)
- Hide redundant Album column when viewing an album
- Make artist name in context header clickable (navigates to artist page)
- Fix gap between title and artist name in context header (addStretch)
- Fix queue panel track titles to include version field
- Fix album list to show version in title column
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Artist profile: collapsible Albums / EPs & Singles / Other sections
keyed on release_type; fetches up to 200 albums per artist
- Favorites: starred icon on favorited tracks, context menu shows
Add or Remove (not both); IDs cached when fav tracks are loaded
- Shuffle button: one-time shuffle via shuffleNow() without touching
global shuffle flag, so double-click still plays in order
- Now-playing art: replaced setFixedHeight hack with ArtWidget that
overrides hasHeightForWidth() — scales smoothly up and down, no min-size
- Volume popup: replaced QMenu (laggy, broken drag) with Qt::Popup QFrame;
appears below button; fixed size locked at 100% label width
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Playlist management:
- Add/remove tracks from playlists via right-click context menu
- Create new playlists (right-click Playlists sidebar header)
- Delete playlists with confirmation dialog (right-click playlist item)
- Playlist view removes track immediately on delete (optimistic)
- Deleting currently-open playlist clears the track view
Gapless playback:
- Single long-running audio thread owns AudioOutput; CPAL stream stays
open between tracks eliminating device teardown/startup gap
- Decode runs inline on the audio thread; command channel polled via
try_recv() so Pause/Resume/Seek/Stop/Play all work without spawning
- New Play command arriving mid-decode is handled immediately,
reusing the same audio output for zero-gap transition
- Position timer reduced from 500 ms to 50 ms for faster track-end detection
- URL/metadata prefetch: when gapless is enabled Qt pre-fetches the next
track while the current one is still playing
ReplayGain:
- Toggled in Settings → Playback
- replaygain_track_gain (dB) from track audio_info converted to linear
gain factor and applied per-sample alongside volume
Qobuz dark theme:
- Background #191919, base #141414, accent #FFB232 (yellow-orange)
- Selection highlight, slider fill, scrollbar hover all use #FFB232
- Links use Qobuz blue #46B3EE
- Hi-res H badges updated to #FFB232 (from #FFD700)
- Now-playing row uses #FFB232 (was Spotify green)
- QSS stylesheet for scrollbars, menus, inputs, buttons, groups
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Lightweight Qt6 desktop client for Qobuz with a Rust audio backend
(Symphonia/CPAL via staticlib FFI). Mirrors the spotify-qt layout:
toolbar with playback controls, library/context docks on the left,
tabbed search side panel on the right, queue panel, now-playing dock.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>