Commit Graph
5989 Commits
Author SHA1 Message Date
vicrodh 09380d4634 Merge branch 'pre-release' into chore/internal/smoke-2026-07-25 2026-07-26 16:45:03 -06:00
b0bbywan 82fea6257c fix(qbz-audio): use alsa::pcm::Frames for ALSA buffer and period sizes
HwParams::set_buffer_size_near and set_period_size_near take alsa::pcm::Frames, which is libc::c_long: i64 on 64-bit targets but i32 on 32-bit ones. The three buffer_size computations in alsa_direct.rs cast to i64 explicitly, so the crate does not compile for any 32-bit target.

Casting to the alsa type instead is a no-op on 64-bit, where Frames already is i64, and correct on 32-bit. No behavioural change on any currently supported target: every value involved is a sample rate divided by 2, 4 or 8, so at most 96000, far below an i32 overflow.

Verified with cargo check -p qbz-audio:
  x86_64-unknown-linux-gnu       passes before and after
  arm-unknown-linux-gnueabihf    6 x E0308 before, passes after
2026-07-26 16:42:38 -06:00
Victor RH fe2be63f0f Merge pull request #663 from fengalin/fix/external/qbzd-add-tls-provider
fix(qbzd): add tls provider
2026-07-26 16:42:35 -06:00
vicrodh 6ca5813fb1 feat(mpris): expose xesam:url with the public Qobuz track link (#658)
playerctl scripts/widgets can now identify the exact song:
https://open.qobuz.com/track/<id> on every Qobuz catalog row (offline
qobuz_download keeps the real id, so it qualifies too). Local/Plex rows
omit the field — QueueTrack carries no file path to map to file:// and
a synthetic local id would mint a bogus Qobuz link. Wired in both the
app (refresh_now_playing_meta) and qbzd (track_meta).

km
2026-07-26 16:38:38 -06:00
vicrodh def93528bc fix(audio): open ALSA mixer on the card ctl id, not the PCM alias (#659)
set_hardware_volume attached the mixer to the stream's raw PCM id
(iec958:/hdmi:/front:/DEV-qualified hw:) — snd_mixer_attach needs the
per-card ctl device, so hardware volume silently no-oped on plugin-alias
devices (HiFiBerry Digi as iec958:CARD=sndrpihifiberry,DEV=0). Derive
hw:CARD=<name> / hw:<n> first. With this, qbzd's 'Hardware volume'
toggle reaches the DAC's mixer control (e.g. 'Digital') as intended;
with the toggle off, ALSA Direct stays fixed-volume by design
(bit-perfect, no software gain).

km
2026-07-26 16:32:30 -06:00
vicrodh 4d2ddec66e fix(ui): heart-crack icon for Remove from Library/favorites actions
Replaces the trash can (Favorites bulk bars, tracks + albums) and the
plain heart (Local Library bulk bar) with Lucide heart-crack — trash
reads as file deletion, not as un-favorite.

NOTE: touches .slint, so the next build recompiles qbz-ui (long path).

km
2026-07-26 16:26:58 -06:00
vicrodh 64fe89cf52 feat(qconnect): play-later positional insert on peer + queue sync on add
Controller mode: play-later now routes to the peer's manual-block tail
(insert_after steered via a new ControllerManualBlock tracker that
confirms echo positions) instead of degrading to play-next; play-next
inserts also feed the tracker. Single + batch variants.

Local renderer mode: every queue ADD (enqueue/play-next/play-later,
album/playlist/artist/favorites/local batches) now pushes the queue to
the session immediately via sync_local_queue_if_changed, so controllers
see new items at their position instead of waiting for the next track
transition. Adds containing local/plex rows skip the push (all-or-
nothing admission would refuse the whole queue anyway).

km
2026-07-26 15:45:00 -06:00
vicrodh 449f2470f6 fix(ui): mixtape row menu play-next/add-to-queue icons (list-start/list-end)
km
2026-07-26 15:45:00 -06:00
vicrodh 3f1a7d074a fix(build): move the bulk-unfav toast closure (E0373)
km
2026-07-26 15:00:50 -06:00
vicrodh 5dc4d553dc fix(favorites): bulk un-favorite without the UI freeze, with feedback
- Local Library bulk un-favorite was O(selected x visible) on the UI
  thread and froze on big libraries (owner: 'se ciclo'). Now: one model
  pass (hearts hollow instantly), store mutations on a blocking thread,
  'Removing…' info toast up front and a success toast at the end.
- Favorites > Tracks bulk remove: 150 ms courtesy delay between Qobuz
  API calls (no burst) + the same progress toasts.

km
2026-07-26 14:59:29 -06:00
vicrodh 8c1750a78f fix(ux+audio): #661 pause-during-load, anti-alias ring, menu icons, bulk unfav
- #661: a pause issued during the load window fell into the toggle's
  resume branch and got swallowed — the track started anyway and the
  sleep inhibitor stayed held. stop() now cancels the in-flight play
  (PENDING_PLAY_ID), so nothing plays and no inhibitor is acquired.
- Accent ring on the playing row: 1px -> 1.5px border (femtovg 1px
  stroked circles alias; CircleAction's header rings use 1.5px).
- Menu position hints (#N) removed from the track context menu (owner).
- Icon mapping across menus: list-start = Play next, list-end = Add to
  queue, list-plus = Play later; new list-start.svg +
  list-indent-increase.svg (queue manual-block section marker).
- Local Library > Tracks multi-select gains bulk Remove from favorites
  (local-favorites store, live heart flip, toast).

km
2026-07-26 13:22:53 -06:00
François Laignel 62cc4f9200 remove ring from the dependency tree
The crate `ring` was transitively pulled due to the feature `rustls-tls` being
selected for `reqwest`. In order to ensure `ring` is not pulled,
`rustls-tls-webpki-roots-no-provider` must be used instead.
2026-07-26 21:12:44 +02:00
François Laignel a01097708e qbzd: install the rustls process-level CryptoProvider
The rustls crypto provider was not installed for `qbzd`, which caused the
process to panic:

> thread 'tokio-rt-worker' (15737) panicked at [...]/rustls-0.23.37/src/crypto/mod.rs:249:14:
>
> Could not automatically determine the process-level CryptoProvider from
> Rustls crate features.
> Call CryptoProvider::install_default() before this point to select a
> provider manually, or make sure exactly one of the 'aws-lc-rs' and 'ring'
> features is enabled.
> See the documentation of the CryptoProvider type for more information.

The function `ensure_crypto_provider()` was defined in the `qbz-cast` crate
which is obviously not a dependency of `qbzd`.

This commit moves `ensure_crypto_provider()` to `qbz-app`, calls it from `qbzd`
and updates `qbz` accordingly.
2026-07-26 21:12:44 +02:00
vicrodh 51b5f3bec7 fix(build): compile errors from the round
- with_db closures return the raw Result (not Option) in the all-local
  feed loader.
- build_tree takes sort_asc (its own scope, not rebuild's).
- reconcile_sidebar_after_import captures first/single before the
  closures move ids.

km
2026-07-25 20:45:03 -06:00
vicrodh 83b0ada9b9 Merge branch 'bugfix/internal/local-library-tag-fallback' into chore/internal/smoke-2026-07-25
# Conflicts:
#	crates/qbz-library/src/database.rs
2026-07-25 12:07:56 -06:00
vicrodh cb1ae7db6f i18n: strings for the round (8 locales)
Library-All scope selector + settings rows, play-indicator/swipe
toggles, sidebar/manager sort carets, Play later + queue sections +
menu hints.

km
2026-07-25 12:05:56 -06:00
vicrodh efa486ba4f feat(packaging+log): standalone qbzd packages, IP masking in logs
- nfpm-qbzd.yaml (deb/rpm, libasound-only dep) + release workflows build
  the standalone qbzd packages per arch; dual dispatch to the future
  qbz-rpm repo (continue-on-error until token scope lands).
- Gentoo overlay templates: qbzd (source build) + qbzd-bin (tarball
  repack) with systemd user unit + completions.
- Log redaction layer 3: IPv4 -> *.*.*.<last>, IPv6 -> *:*:<last>, with
  version/timestamp false-positive guards (qbz-log 10/10 tests).

km
2026-07-25 12:05:56 -06:00
vicrodh a8919cbadf feat(app): the round's wiring — gamescope, watchdog, geometry, hearts
- Steam PR1/PR3/PR4 wiring: apply_gamescope_quirks at the top of main(),
  tray + miniplayer suppression, gilrs spawn, UiFocusState OSK hook.
- #558 watchdog arm at window-ready; #654 monitor-DPR geometry clamp;
  local-heart routing in the favorite arms; play-later media-action arm;
  sort-flip handlers with direction (#657/Library All pattern); gilrs +
  wayland-data-control deps (#514).

km
2026-07-25 12:05:56 -06:00
vicrodh 953ba39e77 feat(playlists+queue): sort directions (#657), import refresh, Play later (#442)
- Sidebar + playlist manager sorts gain both directions with a caret on
  the active row (re-select flips); 'recent' keeps the API order
  (newest-first — the old reverse was the #657 bug).
- Import now inserts the new playlist optimistically and bounded-retries
  until the API lists it (read-after-write lag forced a manual refresh).
- Play later: tracks land at the end of the manual block (after every
  play-next/later, before the source resumes); Play next and Add to
  queue are untouched. The queue sidebar shows the section divider
  (Next in queue / Next up) with drag-math compensation, and the context
  menu shows the landing position of each queue action.

km
2026-07-25 12:05:27 -06:00
vicrodh d99419f22d fix(renderer+ux): frame-liveness watchdog (#558), dup-add button (#655)
- #558: a backend can be alive yet wedged (zero presented frames forever
  on legacy stacks). Vendored femtovg counts presented frames; a watchdog
  8s after window-ready re-arms the renderer sentinel and restarts, so
  the existing ladder degrades wgpu -> alt adapter -> GL -> software on
  its own instead of stranding the user on a blank window.
- #655: 'Add only new tracks' stays enabled with all-dupes (adds zero
  and closes) instead of disappearing as the primary action.

km
2026-07-25 12:05:27 -06:00
vicrodh f1eeaf9126 feat(steam-deck): game mode support (plan PR1-PR5)
- PR1: gamescope detection at boot — X11 backend, scale 1, kiosk
  fullscreen; tray + miniplayer suppressed (click-offset fix).
- PR2: full keyboard navigation for the kiosk (3 zones, focus ring,
  scroll-into-view; typing never navigates).
- PR3: native gamepad via gilrs — D-pad/stick/A/B to synthetic Slint
  keys with hysteresis, repeat and debounce; B suppresses Escape while
  a text field is focused (closes the Steam OSK).
- PR4: Steam OSK via the steam://open/keyboard deeplink on text focus.
- PR5: scripts/qbz-add-to-steam (stdlib-only, 19/19 unit tests) with
  artwork assets + pure-gamepad controller layout.

Spec: qbz-nix-docs/steam-deck/STEAM_DECK_GAME_MODE_PLAN.md

km
2026-07-25 12:04:58 -06:00
vicrodh 55caada4c4 feat(ui): play-indicator toggle, swipe inversion, accent-ring row mark
- Appearance > Play indicator animation (default OFF): static play glyph
  in an accent ring on the playing row, pause on hover, accent edge pill;
  the 8fps eq-bars clock no longer runs while playing with the pref off
  (CPU complaint on some machines).
- Appearance > Invert swipe navigation direction for the two-finger
  touchpad back/forward gesture (#653 follow-up).

km
2026-07-25 12:04:57 -06:00
vicrodh 54c2779eb5 feat(library-all): windowed feed, show-local default + scope, local hearts
- Viewport windowing for the All grid + list (AlbumGrid-class sampler);
  thousands of items no longer mount eagerly (owner's 2200-item library
  was unscrollable, even typing in search lagged).
- Artwork is id-keyed (kind:id) + generation-guarded + band eviction,
  ending wrong-cover races and per-keystroke image churn; covers persist
  on the full model across derives.
- show-local defaults ON (persisted) with the filter toggle kept in the
  view toolbar; Settings gains the scope selector (hearted items vs the
  whole local library, loaded with Local-Library query parity).
- Cards respect favorite/followed state; hearts of local/Plex items route
  to the local-favorites store instead of the Qobuz API.

km
2026-07-25 12:04:22 -06:00
vicrodh 6fff4aae31 docs(readme): note QBZ has no built-in EQ/DSP by design (use EasyEffects/JACK)
cc
2026-07-24 01:14:19 -06:00
vicrodh 70aca326fd docs(readme): add the "what QBZ is and isn't" statement to Why QBZ
Aligns the README with the wiki and website: QBZ exists to give Linux users the
Qobuz client they deserve, and is explicitly not a web wrapper and not a
download tool. Keeps the technical native-pipeline explanation below it.
2026-07-23 23:42:48 -06:00
vicrodh e7aaeb33f9 chore: bump flake to 2.0.2
cc
2026-07-23 16:05:37 -06:00
vicrodh 93ae499f38 ci(release): install jack headers for the build-qbzd jobs
qbzd pulls qbz-audio whose jack-sys build script requires jack.pc; the
desktop build job already installs libjack-jackd2-dev, the new qbzd jobs
did not.

cc
2026-07-23 14:00:23 -06:00
vicrodh 0328a38b2f docs(readme): count Dutch among the bundled languages
cc
2026-07-23 13:09:47 -06:00
vicrodh d8f43cc4a3 docs(readme): qbzd and kiosk sections, drop diagram and star history
Promote the headless daemon to its own section with a screenshot and the
wiki link, add a Kiosk Mode section for Raspberry screens and handheld
consoles, remove the mermaid architecture diagram and the star-history
chart.

cc
2026-07-23 13:07:06 -06:00
vicrodh 116adbdd3e docs: fix TAG_DETAILS formatting for 2.0.2
Split the intro highlights into separate paragraphs, restore the em-dash
bullet pattern in the Casting entry, add the missing section separator
before What Won't Be Developed.

cc
2026-07-23 12:15:33 -06:00
vicrodh f434ed02cf merge: 2.0.2 final round — lyrics translation, Discover reco fixes, gestures/share/sandbox
Three owner-smoked feature/bugfix lines, validated together on
chore/internal/smoke-lyrics-discover (one build):

- feature/internal/lyrics-translation (15): Qobuz v10 lyrics translation
  (language param, translation-only doc merge, per-track toggle,
  bilingual lines, floating ghost-square toggle, language setting,
  account country/language capture, i18n x8, About +TerminalTilt).
- bugfix/internal/discover-reco-follow-state (11): reco follow-state
  seed+warm, followed/blacklisted/dismissed filter + cross-rail dedup +
  overflow backfill, Not interested (reco-scoped store + Blacklist
  settings tab), XDG deep-link navigation (argv + D-Bus OpenUrl).
- bugfix/internal/touch-gestures-share-url-sandbox (5): two-finger
  touchpad back/forward (#653), share links to open.qobuz.com for
  track/album (#514), Sandbox ReserveDevice1 note covers #652
  (device=all already in the published manifest).

km
2026-07-23 11:54:14 -06:00
vicrodh a31d3abf13 Merge branch 'bugfix/internal/touch-gestures-share-url-sandbox' into chore/internal/smoke-lyrics-discover 2026-07-23 09:35:09 -06:00
vicrodh 5b525b9e89 fix(settings): correct the #652 Sandbox row — device access is already granted
The published Flathub manifest has shipped --device=all since 2026-05-30
(flathub/com.blitzfc.qbz@11d38546), so /dev/snd IS exposed in the sandbox;
the device-override row added earlier on this branch was diagnosed against
the stale pre-repack local manifest clone and would have users grant what
they already have. The likely #652 mechanism is the ReserveDevice1 name
(qbz-audio device_reservation): PipeWire holds the DAC and Flatpak can't
own org.freedesktop.ReserveDevice1.* (Flathub linter blocks it), which is
exactly what the pre-existing Sandbox row fixes. Drop the device=all row
and make that row's note name the #652 symptom explicitly.

km
2026-07-23 09:35:09 -06:00
vicrodh 9db8bfd762 Merge branch 'bugfix/internal/touch-gestures-share-url-sandbox' into chore/internal/smoke-lyrics-discover 2026-07-23 09:23:32 -06:00
vicrodh cfa88098ee i18n(settings): translate the Flatpak ALSA device-access row (#652)
Hand-added the new Sandbox settings msgids (title + description) to all
8 locales; en msgstr = msgid. msgfmt --check passes on each.

km
2026-07-23 09:20:49 -06:00
vicrodh 3dca29fc62 feat(settings): document the Flatpak ALSA device-access grant (#652)
The Flathub manifest grants wayland/x11/pulseaudio/dri only, so /dev/snd
is not visible inside the sandbox: opening an ALSA hw:X,0 output fails
and exclusive mode silently falls back to PipeWire (other apps keep
mixing through the DAC). Per owner decision the manifest stays as-is
(Flathub reviewer friction); instead the Sandbox settings page gains a
third Flatpak row with the manual one-time grant
`flatpak override --user --device=all com.blitzfc.qbz`, following the
existing copyable-command-row pattern, and notes the required restart.

km
2026-07-23 09:20:49 -06:00
vicrodh 97adf3d3cf fix(share): use open.qobuz.com for track/album share links (#514)
The copied track and album links now use the canonical open.qobuz.com
form. Artist, label and playlist links are unchanged.

The builders also feed the Odesli (Song.link/Album.link) URL fallback;
that fallback never resolves Qobuz URLs anyway (every qobuz.com form
answers 400 could_not_resolve_entity, verified in-tree 2026-07-16) and
the working path stays ISRC/UPC -> Deezer, so the resolution machinery
is unaffected. open.qobuz.com is already accepted inbound by
qbz-qobuz's link_resolver.

km
2026-07-23 09:13:25 -06:00
vicrodh d6ed93280c feat(nav): two-finger touchpad swipe for back/forward history (#653)
Extend the AppShell bottom-layer TouchArea (the one already catching the
mouse back/forward buttons) with a scroll-event handler that accumulates
horizontal touchpad deltas and fires one NavState.request-back/forward
per gesture — the same callbacks the header nav buttons drive, so entry
swap, scroll restore and nav flags all follow the existing path.

Delivery is front-to-back, so a horizontal carousel Flickable consumes
horizontal deltas before they reach this layer (carousels keep scrolling
and never trigger navigation); a vertical-only page scroller rejects
horizontal-only deltas as an orthogonal direction, letting them fall
through to the gesture handler. The handler always returns reject, so
scroll routing is untouched everywhere. One navigation per gesture via
an idle-timeout/direction-flip reset and a fired latch; 70px threshold;
fingers-right = back / fingers-left = forward under libinput natural
scrolling (commented in code).

km
2026-07-23 09:10:28 -06:00
vicrodh e61318b286 Merge branch 'feature/internal/lyrics-translation' into chore/internal/smoke-lyrics-discover 2026-07-23 08:31:44 -06:00
vicrodh 6a7784366d feat(ui): restyle the lyrics translate toggle as a ghost square
Owner 2026-07-23: drop the mobile-parity circle — square, no border, no
shadow; bg lights up on hover, matching the Discover configurator gear
(GearButton in HomeView.slint). Glyph swapped to the owner-picked
translate-svgrepo icon (translate.svg; the Lucide languages.svg added
earlier on this branch is removed). Accent tint remains the ON state.

km
2026-07-23 08:31:20 -06:00
vicrodh d7a5c83c67 feat(lyrics): make the translation toggle per-track
Owner decision 2026-07-23: enabling translation applies only to the song
it was toggled on, in that playback — not a session/album-wide switch.
Every track change now resets the translation session and fetches
original-only (was: track-change requests rode the resolved target so
the translation followed across tracks). enable_translation/disable and
the fail-soft toast paths are unchanged.

km
2026-07-23 08:31:20 -06:00
vicrodh 7e40ff71db fix(deep-link): import ComponentHandle for Weak::as_weak
Static-review miss (qbz crate can't be check-built without the 30 GB
qbz-ui unit): as_weak() is a ComponentHandle trait method, so the trait
must be in scope. Found by the owner smoke build (E0599, qbz/src/
deep_link.rs:153) — the sole error in the crate.

km
2026-07-23 00:33:38 -06:00
vicrodh 3eb93ec4cb Merge branch 'bugfix/internal/discover-reco-follow-state' into chore/internal/smoke-lyrics-discover
# Conflicts:
#	crates/qbz-ui/translations/de/LC_MESSAGES/qbz-ui.po
#	crates/qbz-ui/translations/en/LC_MESSAGES/qbz-ui.po
#	crates/qbz-ui/translations/es/LC_MESSAGES/qbz-ui.po
#	crates/qbz-ui/translations/fr/LC_MESSAGES/qbz-ui.po
#	crates/qbz-ui/translations/ja/LC_MESSAGES/qbz-ui.po
#	crates/qbz-ui/translations/nl/LC_MESSAGES/qbz-ui.po
#	crates/qbz-ui/translations/pt/LC_MESSAGES/qbz-ui.po
#	crates/qbz-ui/translations/ru/LC_MESSAGES/qbz-ui.po
2026-07-22 23:05:16 -06:00
vicrodh 3a6e5960ac Merge branch 'feature/internal/lyrics-translation' into chore/internal/smoke-lyrics-discover 2026-07-22 23:03:15 -06:00
vicrodh 299a7c3237 chore(packaging): drop dead x-scheme-handler/qbz registration
qbz:// resolves nowhere in the link resolver, so the registration
advertised a scheme the app never handles. Keep
x-scheme-handler/qobuzapp (handled by the resolver) in all 7 desktop
files.

km
2026-07-22 22:56:14 -06:00
vicrodh 537cabbb99 fix(deep-link): forward Qobuz links to the running instance over D-Bus
A second launch carrying a deep link exited after a bare Present(),
taking the URL with it — focus worked, navigation didn't. Add
OpenUrl(url) to the SingleInstance D-Bus interface: the primary stashes
the URL, presents itself, and dispatches through the same pending/drain
path as a cold-start link (stays pending while no shell is up).
acquire_or_raise calls OpenUrl when argv carried a link and falls back
to bare Present() when the method is missing on an older primary
(version skew), then to MPRIS Raise as before; no-link launches keep
plain Present().

km
2026-07-22 22:56:00 -06:00
vicrodh fd8f8f4064 fix(deep-link): navigate Qobuz links passed via argv on cold start
xdg-open https://open.qobuz.com/album/<id> raised/focused QBZ but never
navigated: main() never read argv, so the desktop files' Exec=qbz %u URL
was silently dropped (Tauri parity gap — the old app scanned argv on
cold start and in its single-instance callback).

New deep_link module: capture_argv() at the top of main() stashes the
first Qobuz-link argv entry (legacy is_qobuz_link prefixes) BEFORE the
single-instance guard runs — a second launch must read its own argv
before deciding to raise+exit. enter_shell binds a shell context
(runtime, window weak, tokio handle, image cache; cleared on logout) and
drains the pending URL at its very end, after the startup-page/view
restore, so the restore can't re-root over the deep link. Session is
active and the AppWindow exists there, so no readiness sleep hack.
Dispatch is the existing Ctrl+L machinery (link_resolver::resolve ->
apply_resolved_link); failures surface as toasts. At the login screen or
in offline mode the URL stays pending for the next successful online
enter_shell.

km
2026-07-22 22:55:47 -06:00
vicrodh c8e37f937d refactor(discover): borrow-free upsert in the reco-dismiss store
position() + index instead of an iter_mut().find() borrow held across a
match arm — no NLL subtlety, and the lifecycle test passes against the
verbatim file (scratch-crate run, since the qbz crate itself is not
built here).

km
2026-07-22 22:31:00 -06:00
vicrodh 2b0cf33d2e i18n(discover): Not interested + Recommendations-tab strings (8 locales)
New msgids hand-added to all 8 qbz-ui catalogs: the tab description, the
empty-state heading + hint, and the dismiss/undo toasts. "Not
interested" and "Recommendations" reuse the pre-existing msgids
(PlaylistView / Discover). en msgstr = msgid; es/de/fr/pt/ru/ja/nl
translated. msgfmt --check clean on all 8.

km
2026-07-22 22:25:01 -06:00
vicrodh 6adb33fcef feat(settings): Recommendations tab in the Blacklist Manager
Manage the reco-scoped Not-interested dismissals: a third tab in
Settings > Blacklist lists dismissed artists (search-filtered like the
other axes, count badge, empty + no-results states) with a per-row undo
that removes the entry from the reco_dismiss store — the artist becomes
eligible for the Recommendations rails again on their next paint. Row
click reuses the existing artist-select navigation. No bulk Clear-All on
this tab (undo is per-row); the modal stays scoped to the blacklist axes.

km
2026-07-22 22:18:59 -06:00