QBZ 2.0 "Rebuild". Workspace, Tauri manifests, npm manifests and the Flatpak metainfo all move to 2.0.0; TAG_DETAILS for the release notes. snapcraft.yaml uses version: git and needs no bump. cc
20 KiB
QBZ 2.0.0 — Technical Changelog (v1.2.15 → v2.0.0)
824 commits on slint-mvp (2026-05-18 → 2026-07-03). This release replaces the
Tauri 2.0/WebView (SvelteKit) frontend with a native Slint UI running in the
same process as the Rust core — no web engine, no IPC bridge. Nearly every
feature below was rebuilt from scratch against the new shell; the sections
group work by area rather than by commit date.
1. Architecture
- Frontend rewrite: the SvelteKit/WebView frontend is replaced by a native
Slint UI (
qbz-uilibrary crate +qbzbinary crate). Single Rust process, no embedded browser, no Tauri IPC — the UI calls into the core crates directly (f1748383,c8ef2a1b). qbzdremoved: the dormant standalone TUI/daemon crate was dropped from the workspace; it pinned an oldunicode-widththat blocked the Slint upgrade past 1.14 (eddfaed4).- Frontend-agnostic core crates extracted from
src-tauri(ADR-005/006 — no legacy dependency, notauri::Statein core logic), so the same code runs headless (Slint, future TUI/CLI):qbz-credentials— keyring + AES-256-GCM encrypted token store (aa64f3fa).qbz-radio— smart-radio builder/db/engine (4a9cbdeb).qbz-offline-cache— offline download pipeline, metadata/migration,CacheEventsink, purge logic (d6e9345f…c8158bf4).qbz-plex— Plex integration, ~1700 lines moved out of Tauri (2fe7008e).qbz-mixtape— Mixtapes/Collections backend (5458f3aa).qbz-lyrics— synced-lyrics provider chain and cache (46c15f50).qbz-theme— theme/token registry with WCAG/APCA contrast math (ff5536a0).qbz-i18n— pure-Rust gettext bundling (f92c95ee).qbz-reco— recommendation/taste-vector engine (65de9849).qbz-dsd— DSD demux/decode/output engine (landing in the 2.0.0 tag).qbz-dac-wizard,qbz-text-utils,qbz-slint-common— further splits offqbz-uifor build parallelism (7678bceb,6f9ad466,d1437c70).
- In-process communication model: state that used to cross the Tauri IPC
boundary (
tauri::State,invoke/event channels) is now shared directly between the Slint controller layer andQbzCore/qbz-app— no serialization boundary between UI and playback/session state. - Qobuz Connect cross-frontend seam: a 16-method
QconnectRendererEnginetrait is implemented once by each frontend (CoreBridgefor Tauri,SlintRendererEnginefor Slint) so renderer orchestration (echo-seek rejection, cursor align, queue materialize) lives inqconnect-appa single time instead of being re-derived per shell (e5e8d4a8,e8ac6185,88e72c3e). - CMAF streaming, playback caches, and the offline-tier resolver moved into
the frontend-agnostic
qbz-player/qbz-core, so both frontends share one playback path (29b6c205,d0a4a329,506ba5ef).
2. UI shell & views
- Three-state sidebar (open/mini/closed), right-flyout section nav, live theme
switching, Discovery-style segmented tab bar, browser-like back/forward
navigation history (
682719ca,12ed5a7c). - Custom title bar: frameless window with drawn controls, drag-to-move,
double-click-to-maximize, edge resize (Linux opt-in, macOS overlay default
on), plus an opt-in compact icon-only header nav (
a7f538b3). - Theming: 24 standard themes transcribed 1:1 from the old
app.cssinto a Rust registry, alpha polarity resolved per-theme rather than by a flat light/dark flag, plus 6 redesigned high-contrast accessibility themes with WCAG/APCA contrast tests and a broadTheme.is-high-contrasttokenization pass across sliders, tabs, toasts, badges and focus rings (40bd77f7,48eefa3c,ff5536a0). - NowPlayingBar: rebuilt with four selectable layouts — New, Classic,
Small ("Mode C", 42px compact row with floating art-hover preview), and
Large ("Mode B") — plus a borderless miniplayer window with 5 surfaces
(micro/compact/artwork/queue/lyrics), mirror-driven state, no extra poll
loop (
da7758b9,1ad0d7c1,8fa03a8c,9d6b3533,c974b8a9). - System tray, MPRIS/SMTC media controls, and notifications: Linux tray via
ksni(Wayland-safe hide/show, since winit'sset_visibleis a no-op on Wayland), macOS/Windows tray icon (later hand-rolled objc2 menu for correct icon sizing), MPRIS on Linux and SMTC/MediaRemote on Windows/macOS with content-sniffed album art, now-playing system notifications (8a78c225,a91d629c,7a7e5f82,d08c5f65). - UI scale presets (XS/S/Default/L/XL via a settings-driven scale factor)
shipped for interface density (
b7549790).
3. Playback & audio engine
- CMAF streaming ported into
qbz-player:play_trackfetches the init segment first, derives sample rate/bit depth, then background-fetches and decrypts subsequent segments, falling back to the legacy path on setup failure (29b6c205,74ab627c,655a90f4). - Gapless + prefetch: L1+L2 instant-replay cache and gapless-prefetch
helpers wired into the Slint playback controller (
7b84fa9a,3a6aae19). - Device routing (issue #263): a three-tier fix stops the PipeWire global
clock
force-ratewrite from firing while a device lock is held, fixes aclock.force-rateleak on stop, resumes a suspended sink after exclusive access ends, and finally routes locked output to the actually-selected sink viaPIPEWIRE_NODEinstead of silently following the system default (d19312fe,b139392b,64fb77ad,d2c4aaf9). - New JACK backend: lock-free SPSC ring buffer, allocation-free RT process
callback, feeder thread resampling to the JACK graph rate, auto-connect to
physical ports — offered as an opt-in backend, explicitly not bit-perfect
(single fixed graph rate) (
fbc03f41,68bc9bd6). - PulseAudio works out of the box alongside the existing ALSA/PipeWire
backends, with output-device list dedup, a searchable device selector, and
Flatpak
--device=allfor direct/dev/sndaccess (c75a0af5,bdb9cada,f98d92d8). - Bit-perfect playback preserved throughout the rewrite: format-first quality badges, per-device bit-perfect-capable marking, and a HiFi Wizard self-test with bit-perfect read-back (see section 12).
4. DSD support (landing in the 2.0.0 tag)
New qbz-dsd crate with in-house DSF/DFF demuxers. Three playback modes are
selectable in Settings (ALSA backend):
- Convert — dsd2pcm (Gesemann-derived 6x256 LUT engine) with halfband decimation down to 88.2 kHz/24-bit PCM. Works on any output device.
- DoP — DSD-over-PCM packing (0x05/0xFA markers over an S32 carrier) via direct ALSA hardware access, with gapless DSD playback and a pause mode that keeps the DAC locked using DSD silence bytes.
- Native — raw DSD_U32_BE/LE output for DACs and kernels that support it, covering DSD64/128/256.
Also included: ID3 tag and artwork extraction for DSF/DFF, library-scanner
recognition of .dsf/.dff with DSD64/128/256 quality badges, 5.1 SACD rips
played back via ITU BS.775 stereo downmix in Convert mode, and a local-FLAC
gapless bug fixed along the way. This work lands just ahead of the 2.0.0 tag
and is uncommitted at the time of writing.
5. Search
- "Intelligent Search": a frontend-agnostic
SearchServiceinqbz-appwith a result cache (Capa A) and interaction-based ranking (Capa B), a live header dropdown with skeleton loading, stale-while-revalidate, 220ms debounce, keyboard nav, per-section caps, and an opt-out setting (22fb4162). - Search "cortinilla" — a glass search overlay for Albums/Artists/
Playlists that swaps playback without leaving Immersive mode, with a
configurable action (replace queue / play next / add to queue), later
extended to Local Library, Plex, and per-source artwork (
22fb4162,b1ac402c). - Hardening: the dropdown no longer resurrects on navigation, auto-closes
after 4.5s idle, and a typing guard was extended across remaining text
inputs so hotkeys don't fire while typing (
12b1b312,31436325,c65bd9c2).
6. Offline mode & Local Library
- Offline mode: a new frontend-agnostic
qbz_app::offline_modestate machine (Online / RealOffline session-scoped / InducedOffline persisted) backed by a layered connectivity actor (default-route signal, audio-liveness window, vendor-diverse probes, hysteresis, captive-portal/suspend-resume handling), with all Qobuz HTTP traffic routed through a single offline gate (edae9d24,ba702bc3). Slint wiring covers offline session entry, a recovery banner, tri-state Settings, offline artwork policy, disk-first cached favorites, first-class local/offline-only playlists, and QConnect offline gating. - Local Library (new feature area, folder-based/self-managed music):
server-paginated Albums/Tracks tabs with local+offline playback and
source-aware auto-advance, Folders tab (flat then flat+tree), Artists tab as
a two-column master/detail browser, folder management in Settings, and a
library scan engine with progress (
835a6cad,56b3ca79,df351ec6,aa7c320b). - Tag editing: a full tag editor built on
lofty(sidecar-default, opt-in write-to-file), a manual-edit modal, and remote metadata lookup against MusicBrainz + Discogs (7e0d970f,4e79386d,3c2f46b7). - Plex integration ported end to end: credential store, Settings auth/PIN,
albums/artists/tracks in Local Library, progressive/fast-play streaming,
source-aware artwork everywhere (now-playing bar, queue, MPRIS),
server-transcoded thumbnails, and same-title album disambiguation into
selectable versions (
f7619a92,a45840d1,06b2bea9,334ddf31). - Offline cache manager: a Settings view for remove/redownload, covers,
sort, and a failed-only filter, plus per-row offline buttons on every track
row and whole-playlist caching (
3e0a718e,a7f2283c). - Scrobbling: Last.fm and ListenBrainz scrobblers wired to the player and
Settings (
952846b6).
7. Qobuz Connect
- Hardening (merged
f3d37dac): unified cast-eligibility checks, strict source parsing (unknown sources blocked, not allowed through), mixed-queue guards with a Rust-side per-track origin backstop, a 12s renderer-liveness watchdog, half-open WebSocket detection via keepalive pong-timeout, idle-retry/startup-backoff recovery, takeover arbitration onSESSION_STATE, and full resync (state + queue) on reconnect (f3686c19,434c2218,a05e8abc,7628c284,ed1d7aee,6c48266a). - Cross-frontend extraction: session/liveness logic,
device_uuidpersistence, and diagnostics relocated to shared crates; theQconnectRendererEnginetrait now carries renderer orchestration once for both frontends (see Architecture) (f100cf4d,e5e8d4a8). - Slint port: renderer + controller integration, device picker with
cast-aware now-playing state, peer-renderer playback reflected on the
now-playing bar, peer volume with a 50% safety clamp, bit-perfect volume
lock/force-100 parity, per-device-type icons, and takeback resume at the
handed-off position (
44876d01,0d7ac793,9bb5e6db,8e1bf18f).
8. Discovery & recommendations
qbz-reco(new crate, ADR-006):SparseVectormath, relationship weights, a 3-table SQLiteArtistVectorStore, and a direct-weight-ranking suggestions engine, trained from per-user play events (favorite-add, playlist-add) to back DailyQ/WeeklyQ mixes, a Rediscover row, and reordered "For You" favorites (65de9849,4828e54c).- External recommendations: a Last.fm + ListenBrainz → Qobuz resolution
engine wired as a 4th Discover tab, redesigned artist/album-centric with
common/recent split and a 48h results cache, plus a Last.fm similar-albums
carousel on AlbumView (
408b3c83,124d97e7). - Playlist "Suggested Songs" shipped, and a Discover section configurator
lets users reorder/toggle Home/For You sections (
2e1d8e43,2a37f2ad).
9. Lyrics
- New
qbz-track-lyricsQobuz endpoint with verified wire DTOs, feeding a headlessqbz-lyricsengine: Qobuz-first provider chain, LRCLIB (search + scorer) fallback, then lyrics.ovh; LRC parser/emitter preserving word-level wsync, a per-user SQLite cache (WAL, additive migration), offline cache-only mode, in-flight dedupe, and 55 unit tests (46c15f50,d1203937). - Slint UI: static rendering evolved into a full sync engine with karaoke
fill and auto-center scroll, plus a controls flyout for prefs and cache
settings (
5a4dbd87,5f9fd5bd,eea336fd).
10. Content blocking
- Artist blacklist: headless service extracted from
src-tauri, applied across search, track rows (greyout/inert), albums/playlists/favorites/ suggest rows, all play/queue builders, and a dedicated Blacklist Manager view (ef93c864,836dd249). - Album blacklist: a parallel String-keyed
album_blacklisttable alongside the artist table, sharing the same enabled flag, enforced across the same consumers with a Manager "Albums" tab (3fbb166b,c85ad5f6,66889af4).
11. Immersive mode & visualizers
- Full-screen "Immersive" now-playing experience (new epic, not present in
Tauri): reusable atmosphere generation (art-derived blur/vignette), a
zero-IPC 30fps visualizer feed (
VizFrame/VizSink) lifted offtauri::AppHandleintoqbz-audio(3adb5172). - Visual modes: Album Reactive, Static, Coverflow (2D fan), Spectrum
Visualizer (~2240 to ~28 gradient bars for performance) (
92052a3c,c067d237,03dfd661). - wgpu fragment-shader underlay: renderer swapped femtovg(GL) to
femtovg-wgpu, with a WGSL plasma shader driven by the visualizer feed, then
extended to Tunnel and Aurora "milkdrop" scenes plus a scene picker; macOS
stays on the Skia renderer since femtovg-wgpu pegs CPU on Metal
(
e46e8554,653a449d,fb0aa619). Later scenes added: Wave Bed, Spectral Ribbon, Line Bed (226c2118); shader scenes hide automatically on non-wgpu renderer tiers (a050e639). - Focus/split layouts: lyrics panel, queue/history panel, track-info panel,
and a live-query suggestions panel (
77068e3b…e6f9c3b4).
12. HiFi Wizard revamp
Built headless-first: native pw-dump device enumeration with pactl
fallback, DAC negotiated-rate probing via /proc/asound, audio-stack health
and distro/init-system detection (systemd/antiX/Artix/NixOS), and
Flatpak/Snap sandbox-aware host detection (381eafdf, f08943ad, 93da676f).
Slint UI: a 6-step guided modal (check → select DACs → test → review/apply →
done) with a self-service playback test and bit-perfect read-back (9bb392c2,
9c5febda, f87f2986).
13. Internationalization
- New pure-Rust
qbz-i18ncrate: gettext.pocatalogs bundled at compile time (no gettext C dependency), plural rules, and at/tn/t_args/tfAPI (f92c95ee). - Full extraction and seeding pipeline from the old Tauri JSON strings across
every module (local library, MyQBZ, discover/home/search, artist/album/
label, playback/offline, integrations/DAC wizard) (
f14c5130…e167936c). - Live language switching without restart, locale-aware dates, and dynamic
msgid registration via
mark()(69d85f19,8243f2a8). - Seven bundled locales at full coverage: English, Spanish, German, French,
Portuguese, Russian, Japanese — the last two (
be487dca) plus a macOS CJK font-fallback fix (vendoredi-slint-common,fa3ee1e4) so Japanese kanji render correctly on Mac builds.
14. Performance
- Renderer tier auto-detect (wgpu → GL → software) with a Settings
override and auto-revert if a tier misbehaves (
fe111c3f). - Artwork memory bounding: decoded-artwork memory capped and covers
decoded at display size instead of full resolution (
f37b6b6a). - Leak/idle fixes: shader-underlay GPU leak and idle 30Hz wakeups fixed,
palette computation moved off the UI thread, idle now-playing pushes
skipped, immersive atmosphere animation stopped while paused (
dbe818c7,d7716d7c,e71f0ded). - Viewport windowing (phase 1) applied to the Local Library albums grid;
virtualized
ListViews (instead ofFlickable+for) applied to Favorites Tracks and Playlist track lists for 2000+ item lists (23b572e5,85223b03,4465a367). - Reduced motion on GL/software renderer tiers (
d9b82e7b).
15. macOS
- Stable native build with a dedicated dev build/run script (
85518699). - CJK font fallback fix so Japanese/Chinese/Korean text renders correctly
(vendored
i-slint-common,fa3ee1e4). - macOS Dock policy handling for the tray icon, then a hand-rolled objc2
tray menu for correct icon sizing/click routing (
a91d629c,b9434a50). - Overlay title bar as the macOS default, distinct from the Linux
frameless mode (
a7f538b3). - Renderer forced to Skia on macOS since femtovg-wgpu pegs CPU under Metal
(
fb0aa619). - Contributor work from Afonso on macOS-specific fixes throughout the range.
16. Build, CI & packaging
- Crate split for build memory:
qbz-slintsplit into aqbz-uilibrary crate (owns the full.slinttree + bundled translations) and aqbzbinary crate reclaiming theqbzbinary name from the retired Tauri app — halves the ~20GB single-craterustcpeak into two independently cacheable units, with further extractions (qbz-dac-wizard,qbz-text-utils,qbz-slint-common) (c8ef2a1b,7678bceb). - aarch64 Linux build script added (native ARM runner + x86-64 cross
path); documents the ~30GB
qbz_uiRAM wall that rules out 8GB Macs and 4GB Raspberry Pis for native builds (b89ee385,5fdbdb3a). - CI rewrite: GitHub Actions build for
qbz-slinton Linux stood up and hardened (runner disk exhaustion fixed, swap sized for the ~30GB peak, mupdf-sys system libs added), then moved to a self-hosted runner for real artifact builds (5806b0c0…b9eb3005). - All-hosted Snap pipeline added; deb/rpm packaging metadata added for the
Slint
qbzbinary; release workflows rewritten and channel packagers repointed at the Slint binary; release profile now strips symbols (77a476c8,9c37e456,1b933299,6e6153b2). - Linux binary kept compatible with glibc older than 2.43 (
cafd521b). - Faster local dev builds via the mold linker and a memory-aware
slint-run.shto dodge the OOM wall (ec4b10fc,14e800ea).
17. Other new features
- Purchases ("My Purchases", 13-slice epic): wire models, HTTP + CDN
fetch, pagination, download state machine, list/detail views with format
and quality pickers, Settings toggle (default off) (
aceaf9b0…9fbfcb55). - Awards pages ported (landing, album listing, follow) (
9ccfbd38). - Playlist importer ported (Open Playlist Importer) (
3689a5fd). - Keyboard multi-select ported and extended to Mix/Label/Local Library
Albums, with a three-column shortcuts cheatsheet and matching customize
editor (
53e1e8cd,1a9c1327). - Chromecast/DLNA casting: a shared external-stream resolver
(CMAF-first, UltraHiRes-first),
qbz-castcrate, picker modal, and offline-gate routing (fdf2fec3,3e1101ff). - Discord Rich Presence (opt-in) ported from Tauri (
ef38e7a0). - Session persistence across restarts: startup page, window geometry,
and playback state (
dd32f573).
Fixes
- Output-device routing/locking bugs from issue #263 (see Playback section).
- Local-FLAC gapless playback fixed (landed alongside the DSD work).
- Half-open QConnect WebSocket sessions now detected via keepalive
pong-timeout instead of hanging indefinitely (
7628c284). - Startup now restores the exact last view, not just the top-level tab
(
e44aa07a). - Album credit fixed to read the album-level composer field instead of
per-track (
0ddcad40); missing pagination fields in album responses are now tolerated instead of erroring (9e2a1d12). - Single-click bug on button primitives (a
FocusScopeate the first press) fixed app-wide (88f1967d); single-click album context menus (8c182875). - Secret-vault open moved off the async pool to avoid a zbus panic
(
40414991). - Artist follow heart made a real working toggle, reflected across every
card surface (
d906e556). - Qobuz playlist Follow/Copy state fixed across surfaces, with owner-aware
remove (delete vs. unfollow) (
bf4ffbd6,de32c168). /radio/*deserialization repaired and every radio entry point rewired (6520c007).- rustls
CryptoProviderinstalled at startup for Qobuz Connect (90705471). - Don't cache empty ListenBrainz results, which previously made Weekly
mixes vanish (
1e78884e).
Full changelog: https://github.com/vicrodh/qbz/compare/v1.2.15...v2.0.0