Commit Graph
4605 Commits
Author SHA1 Message Date
vicrodh 62cd6ae130 Merge refactor/qbz-app-download-settings: download settings store
cx
2026-05-15 17:54:54 -06:00
vicrodh 10b0e259f4 refactor(tauri): use qbz-app download settings
cx
2026-05-15 17:50:59 -06:00
vicrodh 26012e98c9 refactor(qbz-app): add download settings store
cx
2026-05-15 17:48:14 -06:00
vicrodh 74ce1c3201 Merge refactor/qbz-app-remote-control-settings: remote control settings store
cx
2026-05-15 14:23:27 -06:00
vicrodh faca837658 chore(tauri): update qbz-app lock dependencies
cx
2026-05-15 14:21:17 -06:00
vicrodh f527186ca7 refactor(tauri): use qbz-app remote control settings
cx
2026-05-15 14:20:35 -06:00
vicrodh 2e43831800 refactor(qbz-app): add remote control settings store
cx
2026-05-15 14:17:35 -06:00
vicrodh ebe03193c2 Merge refactor/qbz-app-ui-preferences-foundation: qbz-app UI preference stores
cx
2026-05-15 00:41:12 -06:00
vicrodh 7f8e3533cb Merge bugfix/pre-1.2.13: release watch filter, album tooltip, copyable settings text 2026-05-15 00:36:00 -06:00
vicrodh 0b83c5a01e fix(css): keep pre, code, kbd, samp selectable globally
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
2026-05-15 00:35:53 -06:00
vicrodh 29e70de58f feat(discovery-v2): tooltip with full album title on AlbumCardLite
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
2026-05-15 00:35:45 -06:00
vicrodh 3903086f36 fix(release-watch): drop upcoming and non-streamable albums
`/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
2026-05-15 00:35:38 -06:00
vicrodh 04d5b45134 docs(qbz-app): keep app comments frontend agnostic
cx
2026-05-15 00:12:22 -06:00
vicrodh 2d7639c637 refactor(tauri): use qbz-app ui preference stores
cx
2026-05-15 00:10:57 -06:00
vicrodh d1082317f5 refactor(qbz-app): add ui preference stores
cx
2026-05-15 00:04:36 -06:00
vicrodh 2b7b2312ea Merge bugfix/pre-1.2.13: offline-tolerant CoreBridge + Continue Listening hydration 2026-05-14 23:35:34 -06:00
vicrodh db39072488 fix(discovery-v2): hydrate Continue Listening tracks with full metadata and context
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
2026-05-14 23:35:21 -06:00
vicrodh a40b1b6c48 fix(core): make QbzCore::init tolerant to offline startup
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
2026-05-14 23:24:33 -06:00
vicrodh 7f38dbcc6f refactor(tauri): use qbz-app preference stores
cx
2026-05-14 19:49:11 -06:00
vicrodh 61d5715a22 refactor(qbz-app): add preference stores
cx
2026-05-14 19:48:54 -06:00
vicrodh d48a1019d2 chore(deps): bump svelte to 5.55.7
cx
2026-05-14 18:23:07 -06:00
vicrodh 917b2a8be8 fix(ui): avoid t shadow in mixtape detail
cx
2026-05-14 18:22:46 -06:00
vicrodh dac1b3a762 refactor(tauri): use qbz-app settings stores
cx
2026-05-14 17:08:57 -06:00
vicrodh 800447d33c refactor(qbz-app): add settings stores
cx
2026-05-14 17:08:45 -06:00
vicrodh dc74db6401 test(qbz-app): cover runtime state transitions 2026-05-14 11:54:16 -06:00
vicrodh 0877f4a5a2 refactor(tauri): use qbz-app runtime types 2026-05-14 11:52:43 -06:00
vicrodh d16ef003a5 refactor(qbz-app): move runtime core 2026-05-14 11:45:59 -06:00
vicrodh 4f008cd219 refactor(qbz-app): scaffold app crate 2026-05-14 11:40:19 -06:00
vicrodh 1bb8d53dd0 feat(graphics): NVIDIA Wayland compat toggle + watchdog fallback to CPU
Two-pronged improvement to the graphics safety net for users hitting
the NVIDIA + Wayland + WebKit GBM issue:

1) New opt-in toggle 'NVIDIA Wayland compatibility (experimental)' in
   Settings > Graphics. When ON:
   - Sets __NV_DISABLE_EXPLICIT_SYNC=1 to bypass libnvidia-egl-gbm's
     buggy implicit-sync paths that produce "Failed to create GBM
     buffer of size NxN: Invalid argument" on driver 550+.
   - Lifts the defensive compositing-mode shutdown that QBZ applies
     to NVIDIA-only Wayland sessions — the user is signaling the real
     fix is now in place, so the safety net is no longer needed.
   - Persisted in graphics_settings.db column nvidia_compat_mode (new,
     default off). Migrated via ALTER TABLE so existing installs don't
     pick up a behaviour change.

2) Reset-graphics CLI affordance, surfaced only when the toggle is on:
   inline copyable input + Copy button rendering `qbz --reset-graphics`
   (or `flatpak run com.blitzfc.qbz --reset-graphics` based on detected
   install method). Works around the global select-disable elsewhere
   in SettingsView via user-select: all + onclick={e.select()} + the
   explicit button. The boot watchdog still auto-reverts on crash, but
   this is the manual escape hatch when the user wants to recover
   without waiting for the watchdog to fire.

3) Watchdog recovery now lands in full CPU mode after ANY revert.
   The single-knob revert (hw_accel / dmabuf / preferred_gpu) still
   narrows the cause for the UI banner, but the safest post-crash
   state is full CPU mode (HW accel off + DMA-BUF off + preferred_gpu
   reset to auto). A partial revert can still hit the next crash if
   the failure was stack-wide (driver bug, missing extension); going
   all-the-way-CPU guarantees the user always reaches a paintable
   window after a recovery — they can selectively re-enable from the
   Settings banner.

4) preferred_gpu='software' now implies hardware_acceleration=off at
   env-var application time. Forcing Mesa llvmpipe while keeping
   WebKit GPU compositing on would just round-trip software pixels
   through a "GPU" path that has no GPU — nonsensical configuration
   that the watchdog had to clean up after. Now it's prevented at
   source.

i18n keys (en/es/de/fr/pt): settings.graphics.nvidiaCompatMode,
nvidiaCompatModeDesc, resetCmdTitle, resetCmdDesc;
actions.copiedToClipboard.

cc
2026-05-14 09:18:56 -06:00
vicrodh db45051c45 chore(security): patch file-type 16.5.4 ASF infinite-loop (GHSA, alert 56)
GitHub Security advisory for file-type < 21.3.1: malformed ASF input
with a zero-size sub-header triggers an infinite loop in the ASF parser
(medium severity). Our exposure is transitive — node-vibrant → jimp →
file-type — and only reached when extracting palette colors from album
artwork. Trusted Qobuz CDN + user-local library limit the practical
attack surface to near zero, but the alert is real and easy to close.

The upstream fix is a 6-line position-advance guard in core.js
(commit 319abf87). Cleanly backports to our 16.5.4 with identical
semantics. Applied via patch-package so the change survives every
`npm install` and is visible in the repo.

Direct upgrade to 21.3.1 wasn't viable: file-type went ESM-only at
17.0.0, and our jimp 0.22.x chain still uses CommonJS `require()` —
an override would have broken vibrant at runtime. Patch-package is
the right tool when upstream's only fix lives behind a breaking
module-system change.

Added `postinstall: patch-package` to package.json so the patch
applies automatically on fresh installs.

cc
2026-05-14 09:18:02 -06:00
Victor RH 2832213dac Merge pull request #424 from vicrodh/dependabot/npm_and_yarn/pre-release/types/node-25.7.0
chore(deps-dev): bump @types/node from 22.19.18 to 25.7.0
2026-05-14 09:02:29 -06:00
vicrodh 8b176a1848 chore(deps): bump discord-rich-presence 0.2.5 → 1.1.0 with API adjustment
DiscordIpcClient::new became infallible in 1.0 — it now returns Self
directly instead of Result<Self>. Failures surface at connect() time
where the catch already lives. Removed the now-spurious `if let Ok()`
wrap around the constructor.

Closes #428 (applied manually because the bump needed a code change
that Dependabot can't author).

cc
2026-05-14 08:59:02 -06:00
Victor RH 47c9c61894 Merge pull request #432 from vicrodh/dependabot/cargo/src-tauri/pre-release/tower-http-0.6.8
chore(deps): bump tower-http from 0.5.2 to 0.6.8 in /src-tauri
2026-05-14 08:46:48 -06:00
dependabot[bot] 875ad45268 chore(deps-dev): bump @types/node from 22.19.18 to 25.7.0
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.19.18 to 25.7.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.7.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-14 14:38:11 +00:00
Victor RH 7ee5359935 Merge pull request #429 from vicrodh/dependabot/npm_and_yarn/pre-release/vite-8.0.12
chore(deps-dev): bump vite from 8.0.10 to 8.0.12
2026-05-14 08:36:23 -06:00
Victor RH b165ddb073 Merge pull request #430 from vicrodh/dependabot/npm_and_yarn/pre-release/sveltejs/vite-plugin-svelte-7.1.2
chore(deps-dev): bump @sveltejs/vite-plugin-svelte from 7.0.0 to 7.1.2
2026-05-14 08:36:20 -06:00
Victor RH 69fbb1dff4 Merge pull request #426 from vicrodh/dependabot/npm_and_yarn/pre-release/tauri-apps/cli-2.11.1
chore(deps-dev): bump @tauri-apps/cli from 2.10.1 to 2.11.1
2026-05-14 08:36:16 -06:00
Victor RH 11854a9992 Merge pull request #427 from vicrodh/dependabot/npm_and_yarn/pre-release/tauri-apps/plugin-opener-2.5.4
chore(deps): bump @tauri-apps/plugin-opener from 2.5.3 to 2.5.4
2026-05-14 08:36:13 -06:00
Victor RH 0eae6a5609 Merge pull request #425 from vicrodh/dependabot/cargo/src-tauri/pre-release/tokio-1.52.3
chore(deps): bump tokio from 1.52.2 to 1.52.3 in /src-tauri
2026-05-14 08:35:07 -06:00
Victor RH dc6725b1da Merge pull request #431 from vicrodh/dependabot/cargo/src-tauri/pre-release/filetime-0.2.29
chore(deps): bump filetime from 0.2.27 to 0.2.29 in /src-tauri
2026-05-14 08:35:03 -06:00
Victor RH 91bfb05668 Merge pull request #433 from vicrodh/dependabot/cargo/src-tauri/pre-release/tauri-plugin-single-instance-2.4.2
chore(deps): bump tauri-plugin-single-instance from 2.4.1 to 2.4.2 in /src-tauri
2026-05-14 08:34:59 -06:00
vicrodh 921f8e1a49 fix(session): resume Qobuz streams at saved position without losing seek (#315)
Three bugs were stacking up to make session resume drop the saved offset
for streamed Qobuz tracks:

1. Position save was debounced, not throttled. Each playback tick reset
   the 5s timer, so the save never fired while a track played
   continuously — the persisted position froze at whatever value got
   written during the first quiet window after track start (typically
   ~2s). Switch to throttle: fire the first call immediately, then once
   per 5s window, with a tail call to flush the latest value when the
   window ends.

2. togglePlay tried to apply the restore offset via a separate cmdSeek
   right after cmdPlayTrack. For Qobuz streaming the audio thread's
   Seek handler bails when current_audio_data is unset — streaming
   uses current_streaming_source instead — so the seek was silently
   dropped and the track started at 0:00. Pass start_position_secs
   directly to v2_play_track. The streaming backend (legacy + V2
   player) waits for enough buffer to cover the offset plus 8s
   headroom, then eagerly decode-and-discards decoder output up to
   the offset before engaging the audio engine — no race, no
   first-pull underrun. Plex and local tracks keep the old play+seek
   path; they load full audio_data so Seek works as-is.

3. The seekbar showed 0:00 from app launch until the user hit play,
   even when a saved position was queued. setPendingSessionRestore
   now pre-positions currentTime when positionSecs > 0 so the UI
   reflects "paused at X" the moment the app opens.

Other plumbing:
- AudioCommand::PlayStreaming carries start_position_secs and
  content_length (used to estimate bytes-per-second for the resume
  buffer target).
- Player::play_streaming{,_dynamic} grow a start_position_secs
  parameter; QConnect and api_server callers pass 0 (remote-driven
  playback always starts fresh).
- cmdPlayTrack forwards startPositionSecs as a 5th optional arg.

cc
2026-05-14 02:18:59 -06:00
vicrodh b2960e8029 feat(graphics): smart GPU preference with boot watchdog and crash recovery
Solves the long-running performance complaints (especially Optimus
laptops where the dGPU silently hijacks WebKit). The end-to-end shape:

- graphics_detection enumerates physical GPUs from /sys/class/drm and
  cross-references EGL vendor JSONs under /usr/share/glvnd/egl_vendor.d
  to expose only stacks the running process can actually use. Works
  inside Flatpak/Snap because /sys is still mounted read-only and the
  sandbox-visible EGL vendor JSONs are the right thing to read.
- preferred_gpu column in graphics_settings.db (string: auto, integrated,
  discrete, software, or a specific PCI slot id). Migrated with
  ALTER TABLE ... DEFAULT 'auto'.
- env_vars_for_preferred_gpu returns Set/Unset actions applied at startup
  before WebKit init. Integrated/AMD path explicitly unsets
  __NV_PRIME_RENDER_OFFLOAD so KDE/Optimus sessions that pre-set it to 1
  no longer override the EGL pin and yank rendering back onto NVIDIA.
- Auto resolver: on hybrid systems (iGPU + dGPU both usable), Auto pins
  to the iGPU. Single-GPU and no-GPU systems remain no-op. The dropdown
  surfaces what Auto resolved to ("Auto (Intel Graphics)") so the user
  sees the decision without picking explicitly.
- boot_watchdog writes a pending.json before WebKit init listing the
  risky knobs in effect. Frontend calls v2_mark_boot_succeeded after
  first paint to clear it and promote to last-good.json. If the next
  launch sees pending without a success ack, it blames matching fields,
  reverts them in-DB, and increments per-knob failure counters; two
  consecutive failures lock the knob until the user clears it.
- Settings > Graphics gets a Rendering GPU dropdown (between HW accel
  and DMA-BUF) and a crash-recovery banner that lets the user re-enable
  any auto-disabled knob. Restart-required affordance shared with the
  other risky toggles.
- i18n keys for the dropdown, banner copy, and autoWithTarget label
  across all five locales.

cc
2026-05-14 00:36:52 -06:00
vicrodh 77754e168a feat(discovery): redesign Radio Station Lite cards to match iOS reference
180x180 card with a 114x114 artwork inset, palette extraction for the
background gradient and mix-blend-mode multiply on the PNG bezel so the
station artwork sits in front of a cohesive colored frame. RADIO label
uses padding-left compensation to align with the visible bezel edge,
not the raw container. Hover overlay blurs the artwork and surfaces a
play button — same pattern as the iOS reference shipped in c8cee326.

cc
2026-05-14 00:36:33 -06:00
vicrodh cd035a34a4 feat(graphics): detect hybrid NVIDIA+iGPU and surface GPU + DE in Diagnostics
autoconfig_graphics gains a hybrid Intel/AMD + NVIDIA branch that keeps
GSK renderer on Auto and DMA-BUF off so the iGPU handles compositing
without the dGPU getting dragged in. detect_gpu_name is exposed and
labels hybrid setups explicitly (e.g. "NVIDIA (driver 580) + Intel
(i915)"). RuntimeDiagnostics gets runtime_gpu_name and
runtime_desktop_environment so the Diagnostics panel can show what the
app sees at runtime, which is the first thing useful to triage
performance reports from log uploads.

cc
2026-05-14 00:36:27 -06:00
dependabot[bot] 5880744822 chore(deps): bump tauri-plugin-single-instance in /src-tauri
Bumps [tauri-plugin-single-instance](https://github.com/tauri-apps/plugins-workspace) from 2.4.1 to 2.4.2.
- [Release notes](https://github.com/tauri-apps/plugins-workspace/releases)
- [Commits](https://github.com/tauri-apps/plugins-workspace/compare/fs-v2.4.1...fs-v2.4.2)

---
updated-dependencies:
- dependency-name: tauri-plugin-single-instance
  dependency-version: 2.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-14 05:38:24 +00:00
dependabot[bot] 7ce112bae1 chore(deps): bump tower-http from 0.5.2 to 0.6.8 in /src-tauri
Bumps [tower-http](https://github.com/tower-rs/tower-http) from 0.5.2 to 0.6.8.
- [Release notes](https://github.com/tower-rs/tower-http/releases)
- [Commits](https://github.com/tower-rs/tower-http/compare/tower-http-0.5.2...tower-http-0.6.8)

---
updated-dependencies:
- dependency-name: tower-http
  dependency-version: 0.6.8
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-14 05:38:07 +00:00
dependabot[bot] 620a393b2d chore(deps): bump filetime from 0.2.27 to 0.2.29 in /src-tauri
Bumps [filetime](https://github.com/alexcrichton/filetime) from 0.2.27 to 0.2.29.
- [Commits](https://github.com/alexcrichton/filetime/compare/0.2.27...0.2.29)

---
updated-dependencies:
- dependency-name: filetime
  dependency-version: 0.2.29
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-14 05:37:51 +00:00
dependabot[bot] b33ce39f63 chore(deps-dev): bump @sveltejs/vite-plugin-svelte from 7.0.0 to 7.1.2
Bumps [@sveltejs/vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte/tree/HEAD/packages/vite-plugin-svelte) from 7.0.0 to 7.1.2.
- [Release notes](https://github.com/sveltejs/vite-plugin-svelte/releases)
- [Changelog](https://github.com/sveltejs/vite-plugin-svelte/blob/main/packages/vite-plugin-svelte/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/vite-plugin-svelte/commits/@sveltejs/vite-plugin-svelte@7.1.2/packages/vite-plugin-svelte)

---
updated-dependencies:
- dependency-name: "@sveltejs/vite-plugin-svelte"
  dependency-version: 7.1.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-14 05:37:50 +00:00
dependabot[bot] 9c83e1163e chore(deps-dev): bump vite from 8.0.10 to 8.0.12
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 8.0.10 to 8.0.12.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.0.12/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 8.0.12
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-14 05:37:44 +00:00