Switch the session store SQLite connection from synchronous=NORMAL to
synchronous=FULL. With WAL + NORMAL the last writes can sit unsynced in
the WAL and be lost on a hard reboot / power loss, dropping the restored
session.
cc
Qobuz Connect renderer mode and casting are mutually exclusive output modes. While qbz is registered as a QConnect renderer, the Qobuz cloud drives playback through the renderer-command path, which bypasses the cast path entirely — the cast device receives no LOAD and stays silent.
connectToDevice() now checks QConnect status and, if it is on, suspends it (v2_qconnect_disconnect) before connecting the cast device. When the cast ends, disconnect() restores QConnect only if it was on beforehand; a failed cast connection restores it too. Applies to Chromecast and DLNA alike.
Fixes#439.
cc
TAG_DETAILS.md is the curated, user-facing release summary rendered by the website and the in-app About modal. CHANGELOG_FULL.md is the complete commit list for v1.2.12..v1.2.13, restoring the two-file release-docs layout last used at 1.2.5.
cc
Version bumped across Cargo.toml, tauri.conf.json, package.json, snapcraft.yaml (version + source-tag), flake.nix, and the lockfiles. metainfo.xml gains a 1.2.13 release entry, the About modal codename becomes "400+ stars", and the README contributors list adds @Vudgekek and @DoubleGate.
cc
Google Cast closes a control connection that goes roughly 10 seconds without a heartbeat PING. QBZ pinged every 25 seconds, so any cast connection left idle between connect and load — for example while the track downloads, or across a delayed second play attempt — was dropped by the receiver. The next LOAD then failed with EPIPE (broken pipe): the device chimed on connect but never played audio, and the heartbeat thread logged repeating broken-pipe warnings.
Pinging every 5s is the cadence the Cast protocol expects and keeps the connection alive through those idle gaps.
Fixes#439.
cc
Session resume of a Qobuz track no longer forces the streaming start-position path, which buffered the CMAF stream sequentially from byte 0 up to the saved offset (up to ~30s wait, with no buffering indication).
v2_play_track is now always called without a start position. The track resumes at the saved offset only on a cache hit (format_id === null), where the audio is a full in-memory buffer and Seek lands like a local file. On a cache miss it starts from 0:00 instead of blocking on a sequential buffer fill.
No backend or audio-engine change; the start_position_secs streaming path is now unused.
cc
The graphics recommendation banner no longer writes settings: the Apply button and the v2_apply_graphics_recommendation command are removed, so the banner only detects and explains. The user applies the change with the real toggles, matching the HiFi Wizard's advisory model. write_recommendation stays for the qbz --autoconfig-graphics CLI.
The Force DMA-BUF help text is now GPU-aware: the instability warning only shows on NVIDIA-only systems; non-NVIDIA and hybrid hosts are told it is safe to enable. On hybrid hosts the rendering GPU dropdown marks the integrated GPU as recommended.
cc
NVIDIA-only systems no longer get a hardware-acceleration recommendation that visibly stutters under WebKitGTK. The three NVIDIA-only branches (Wayland+GNOME, Wayland, X11) collapse into one CPU-rendering profile, since XWayland does not rescue the stutter either.
NVIDIA + iGPU hybrid now allows DMA-BUF: WebKit composites on the stable iGPU stack, so the instability that affects NVIDIA-only systems does not apply. The recommendation also tells the user to pick the iGPU explicitly in the rendering GPU selector instead of Auto.
cc
After the app-wide `user-select: none` on body, content the user
legitimately needs to copy stopped being selectable: HiFi Wizard
commands and paths, snap/flatpak/Pulse/PipeWire setup blocks in
Settings, graphics recovery commands, environment-variable hints, log
viewers, keyboard shortcut chips.
The HTML5 elements that wrap literal text — `pre`, `code`, `kbd`, `samp`
— are already the right escape hatch and every wizard/settings/logs
block in the codebase uses them. Adding a single rule alongside the
existing form-input exception restores selection everywhere it matters
without scattering `.selectable` classes through the views.
cc
The compact 220x220 cards in Discovery V2 truncate long album titles in
the metadata row. With the marquee scroll removed there was no way to
read the full title without opening the album detail.
Pipe the title and artist through a native `title` attribute on the
text-stack wrapper; the global SystemTooltip already mounted in the
layout intercepts that and renders the custom tooltip with adaptive
positioning. Shows the full "Title — Artist" string regardless of
truncation, no extra component, no per-card hover state.
cc
`/favorite/getNewReleases` includes albums whose stream availability is
still in the future, so they appear in the Release Watch grid even
though `get_album` 404s as soon as the user clicks them. Same shape for
regional restrictions and label takedowns surfaced via `streamable=false`.
Add `release_date_stream` and `streamable` to the Album struct (both
optional with serde defaults so existing call sites stay happy) and
filter the response inside `v2_get_release_watch` after the artist
blacklist pass: skip any album marked `streamable=false` or whose
`release_date_stream` is strictly greater than today (UTC). The total
count gets adjusted alongside so pagination math stays consistent.
cc
The TrackRowLite click handler was constructing a DisplayTrack with only
the fields shown on the row (id, title, artist, album, albumArt), masked
by an `as DisplayTrack` cast. duration, durationSeconds, hires, bitDepth,
samplingRate and isrc never reached the player, so the NowPlayingBar
showed no time and the seekbar was unusable. The legacy HomeView path
(home:continue_listening) also wired setPlaybackContext +
replacePlaybackQueue before the play call; the discovery-v2 rewrite
dropped both, which left a stale context label and a stale queue after
clicking a track from the section.
Backend already returns the full TrackDisplayMeta (duration_seconds,
hires, bit_depth, sampling_rate, isrc); the wire and the display types
just weren't carrying it. Extend RecoTrackDisplayMeta and
DiscoveryTrackCard with those fields, propagate them in
fetchHomeResolved, and rebuild the click handler to set the
home:continue_listening context and replace the queue with the full
section before emitting onTrackPlay with a complete DisplayTrack.
cc
Bundle token extraction requires the network. When the host is fully
offline at startup, the failure used to propagate out of CoreBridge::new
and leave the bridge as None, which made every queue/playback V2 command
panic at `bridge.get().expect("CoreBridge not initialized")`.
QbzCore::init() now treats bundle extraction as best-effort: on failure
the core still finishes initialization, the queue manager and player stay
usable for local/offline playback, and API methods return
CoreError::NotInitialized cleanly instead of crashing the runtime. Adds
is_api_initialized and try_init_api so callers can rebuild the API
client lazily once the network returns.
cc