Commit Graph
7041 Commits
Author SHA1 Message Date
vicrodh e58ec85eb2 fix(qt): restore the Exclusive mode row on macOS (#748)
System default on macOS is the CoreAudio exclusive backend: with
`exclusive_mode` set, qbz-audio takes Hog Mode, pins the device and switches
its nominal rate to the track (PR #391, shipped in 1.2.11 and never removed).
The Tauri settings gated the toggle on `ALSA || (macos && SystemDefault)`;
the Slint port copied only the ALSA half, and fc0d35e29 then hid the row on
macOS on the premise that no backend there could honour it. So 2.0.x showed
a grey row and 2.1.0 none, while the DB flag still engaged Hog Mode.

- SettingsDoc publishes `backendIsCoreAudio` (macOS && System default); the
  row is visible and enabled on it. Linux and Windows are unchanged.
- The backend-switch cascade goes through one predicate
  (`output_labels::backend_honours_exclusive`), so re-selecting Auto or
  System default on macOS no longer clears the flag.
- The output LED reads EXCL on macOS System default + exclusive_mode instead
  of DEFAULT while the device is hogged.
- Node test `scripts/test_qt_exclusive_gate.mjs` evaluates the row's real
  gate expressions across platforms; added to qt-runtime-gate.sh. Rust tests
  cover the predicate, the LED and the serde name QML reads.

Verified by smoke on the Mac mini with a USB DAC: the row appears, Hog Mode
is acquired, and browser audio moves to the built-in speakers while QBZ
plays. qbz-qt suite 782/782 on Linux; 13/13 with cfg(macos) on the Mac.

cc
2026-09-09 22:44:16 -06:00
vicrodh 7c4310d8fb merge: integrate Qt window lifecycle and grid artwork improvements
cx
2026-09-09 21:58:39 -06:00
vicrodh 2fc03d325d fix(qt): restore window lifecycle and improve grid artwork
Restore tray-aware close and quit confirmation, circular label covers, and missing label artist portraits. Publish artwork progressively, preload two grid rows, and skip redundant motion reports while preserving data refreshes.

Include regression tests and isolated artwork benchmarks. Verified Linux build, QML checks, and scrolling smoke tests.

cx
2026-09-09 21:58:25 -06:00
vicrodh 5fab503eb7 feat(media): integrate validated Quick Connect and connection guards
cx
2026-09-09 17:12:46 -06:00
vicrodh 75b8eee1c6 feat(media): add Jellyfin Quick Connect and harden remote connections
Add cancellable Quick Connect pairing and shared connection guards for Jellyfin and Subsonic. Bound connection attempts, validate library access before saving credentials, and report per-provider connection and synchronization status.

cx
2026-09-09 17:12:45 -06:00
vicrodh a097b7bf76 fix(library): integrate validated library visibility and toolbar updates
cx
2026-09-09 17:08:42 -06:00
vicrodh 17e08e93de fix(library): restore offline visibility and unify filters and sorting
Recover missing offline library entries, recognize cached-only libraries, and refresh availability after cache changes. Unify per-tab filters, compact the toolbar, and add reversible sort criteria with complete available purchase metadata.

cx
2026-09-09 17:08:33 -06:00
vicrodh 9504139dec fix(qconnect): integrate validated playback and queue hardening
cx
2026-09-09 13:08:52 -06:00
vicrodh d82602e2c7 fix(qconnect): preserve playback state and queue occurrence identity
Keep queue edits from resetting the playback clock, preserve Play next and Play later batches, and report observed renderer state and owned output telemetry. Guard duplicate-track gapless transitions by queue occurrence.

cx
2026-09-09 13:08:39 -06:00
vicrodh 45b745a6d1 fix(qt): integrate validated natural wheel scrolling
cx
2026-09-08 22:19:32 -06:00
vicrodh 55ddc2c768 fix(qt): make mouse wheel scrolling predictable
Accumulate wheel distance with short easing instead of kinetic acceleration. Preserve rapid and fractional wheel input, immediate direction changes, nested scroll chaining and scroll-memory takeover.

Validated with 38 Qt Quick tests and desktop smoke testing.

cx
2026-09-08 22:19:32 -06:00
vicrodh 49247f2ee7 fix(qt): integrate validated input focus and shortcut fixes
cx
2026-09-08 21:40:28 -06:00
vicrodh 0e76c1f486 fix(qt): preserve navigation shortcuts and release text input focus
Keep search, settings and link shortcuts usable while editing, dismiss focus on outside clicks and navigation, and guard deferred focus against hidden inputs. Add Qt Quick regression coverage.

Refs #753

cx
2026-09-08 21:40:28 -06:00
vicrodh bc6a795980 Merge ALAC format and ALSA buffering fixes into pre-release
cx
2026-09-08 20:54:37 -06:00
vicrodh e0755fe2d6 fix(audio): apply rate-scaled ALSA callback buffering
Apply the period after Rodio resets stream configuration, respect device bounds, and timestamp stream errors.

cx
2026-09-08 20:54:37 -06:00
vicrodh b2ca4d7be6 fix(player): derive ALAC signal format from codec configuration
Keep device setup and streaming sources consistent with the decoded ALAC rate and bit depth. Verify real hi-res files and exact synthetic samples.

cx
2026-09-08 20:54:30 -06:00
vicrodh 5c0d62f108 fix(qt): integrate validated playback and library fixes
cx
2026-09-08 18:28:03 -06:00
vicrodh 0b6b111c74 fix(qt): correct playback commands and library browsing
Handle explicit MPRIS Play/Pause without toggling paused playback, remove the 10,000-favorite cutoff, and sort albums by original release dates. Isolate Library filters by tab, include purchased release dates, and support server-ranked artist popularity with safe pagination.

Validated with 766 Qt tests, QML checks, release-sort regressions, and a release build. Refs #750, #751.

cx
2026-09-08 18:27:51 -06:00
vicrodh 09d640138c fix(library): integrate remote album and SACD artwork fixes
Integrate the combined build containing the remote album ID correction and SACD artwork sidecars. The KEF DLNA fix remains on its separate branch pending reporter feedback.

cx
2026-09-08 15:26:15 -06:00
vicrodh 0ebcab6d3e fix(library): support SACD artwork fallback and image sidecars
Refresh missing artwork for unchanged SACD images when a folder cover is added after scanning. Enable image-specific metadata and cover sidecars in the Qt editor while preserving physical track numbers and never writing the ISO.

Validated with SACD regressions, the real Heathen image, 13 Qt editor tests, QML audits and the combined release build.

cx
2026-09-08 15:26:03 -06:00
vicrodh 357f2373fa fix(library): omit remote albums without a server album ID
Keep orphan Jellyfin and Subsonic tracks indexed without exposing internal grouping keys as server album IDs. Align album cards, artist counts and track navigation, and rebuild derived catalogs with schema 8.

Regression fails on the previous projection (three cards for one real album) and passes with the fix for both providers. Catalog suite: 45 passed, 2 ignored scale benchmarks.

cx
2026-09-08 14:38:36 -06:00
vicrodh 6b0561c5cd fix(library): merge validated remote album artwork fallback
cx
2026-09-08 13:39:51 -06:00
vicrodh ff49cbd2ab fix(library): retain album artwork fallback for remote catalogs
Use collection artwork when Jellyfin or Subsonic tracks have no image, preserving existing track artwork. Rebuild derived catalogs so existing libraries receive the correction.

cx
2026-09-08 13:39:50 -06:00
vicrodh 3aed91fa0a fix(cast): localize UPnP URL compatibility and harden crash diagnostics
Keep http 1.5 and tolerate empty or relative service URLs in a local rupnp patch. Cover standard DLNA SOAP requests and malformed descriptions.

Avoid logger locks in fatal handlers, flush emitted log batches, and preserve CI symbols after smoke failures.

cx
2026-09-08 12:08:53 -06:00
vicrodh a7629dc962 feat(log): report fatal signals instead of dying as a bare status
The packaged AppDir has an intermittent SIGSEGV during startup, in the
window between QGuiApplication construction and the QML engine coming up,
with the tokio workers, the audio thread, the loudness analyzer, the
visualizer producer and connectivity all running beside it. It hit twice
on 2026-09-08 on unrelated commits: the v2.1.0 tag's own release-flatpak
attempt 1, which then passed on a re-run of the identical commit, and the
#745 bugfix branch. Both left the same evidence - "status -11" and a log
that stops mid-startup - which is nothing to act on, and a user who hits
this has no re-run to reach for.

The process now reports its own death. A handler for SIGSEGV, SIGBUS,
SIGILL, SIGFPE and SIGABRT writes the signal, the faulting address, the
thread and a backtrace to stderr and flushes the file sink, so the next
occurrence names a frame instead of costing another round trip. It runs
on a dedicated signal stack so a stack-overflow fault can still report,
latches against re-entry, and arms alarm() BEFORE capturing anything:
taking a backtrace allocates and takes loader locks, so a fault inside
malloc could otherwise deadlock the handler and turn a crash into a hang.

The signal is re-raised with the default disposition restored, so the
wait status stays the signal and CI, the smoke harness and any core dump
still see a crash. The integration test asserts exactly that pair on a
child segfaulted on purpose, and it is a named gate in test-crates and
its local mirror.

qbzd installs it too: a headless daemon that dies of a signal leaves even
less behind than the GUI.

cc
2026-09-08 09:51:12 -06:00
vicrodh d1ef21225f fix(log): stop the preflight children from eating the on-disk log
qbz_log::install rotates qbz.log to qbz.log.prev and creates a fresh
file. The internal preflight children (QBZ_INTERNAL_AUTO_PREFLIGHT_CHILD,
QBZ_INTERNAL_GPU_PREFLIGHT_CHILD) re-enter main and ran it too, so a
child renamed the LIVE log out from under the parent, which kept writing
to the renamed inode. On Linux that happens on every launch: qbz.log
ended at the child's own first two lines while the whole session went to
qbz.log.prev, unread. Reported in #749, where the second of those two
lines ("explicit QT_SCALE_FACTOR preserved") was the child inheriting the
variable the parent had just set, not a user setting.

main now reads the child env markers before installing the logger and
takes install_without_file_sink, which keeps stderr and the ring. A child
loses nothing: the parent already captures its stdout proof line and logs
its output tail on failure. The in-app diagnostics export reads the ring
and was never affected.

Second half of the same problem: the file sink is an 8 KiB BufWriter that
only flushed on exit or on a repeat summary, so a process force-killed
while wedged - the state every hang report is filed from - lost the last
and most interesting lines. It now flushes on WARN or worse and otherwise
at most every 200 ms, which bounds the loss without turning a log burst
into one write syscall per record.

Tests cover the rotation contract (a second open renames the live file
away) and the flush policy (bounded window, urgent records never wait).

cc
2026-09-08 08:37:32 -06:00
vicrodh a995025f4e fix(cast): pin http to 1.4.0 so DLNA renderers stop vanishing
rupnp parses a device description's SCPDURL / controlURL / eventSubURL as
http::uri::PathAndQuery. http 1.5.0 rewrote scan_path_and_query and now
rejects two shapes 1.4.0 accepted: an empty element (ErrorKind::Empty,
printed as "empty string") and any relative URL without a leading slash
(PathDoesNotStartWithSlash). Both are common in old UPnP firmware, so the
transitive bump made rupnp drop those renderers during discovery.

Measured in the lockfiles: v2.0.2 resolved http 1.4.0, v2.1.0 resolved
1.5.0, and nothing in qbz-cast changed between them. A KEF LSX gen 1 that
worked in 2.0.2 reported "Visible Renderers: 0" in 2.1.0 with
"Invalid response: empty string", which is exactly
InvalidResponse(InvalidUri(Empty)) reproduced by the new test.

qbz-cast takes http as a direct dependency at "=1.4.0" so cargo unifies
the workspace on it, and device.rs now uses that crate instead of the
rupnp re-export. The new integration test serves two renderer
descriptions over loopback, one with empty and one with relative service
sub-URLs, and requires both to parse: it is red on 1.5.0 and green on
1.4.0, so it fails loudly if the pin is ever lifted. test-crates and its
local mirror gain the named gate.

Closes-when-confirmed: #745

cc
2026-09-08 08:37:20 -06:00
vicrodh 572ce4e16d fix(flake): set the real 2.1.0 srcHash
The flake shipped with srcHash = lib.fakeHash, so consuming it with
inputs.qbz.url = "github:vicrodh/qbz" failed to evaluate. Set the
published v2.1.0 tag hash (verified with nix-prefetch-url --unpack).

Closes #744.

cc
2026-09-08 00:33:21 -06:00
vicrodh 30a778f2f6 fix(flake): set the real 2.1.0 srcHash
The flake shipped with srcHash = lib.fakeHash, so consuming it with
inputs.qbz.url = "github:vicrodh/qbz" failed to evaluate. Set the
published v2.1.0 tag hash (verified with nix-prefetch-url --unpack).

Closes #744.

cc
2026-09-08 00:24:07 -06:00
vicrodh 04fdc186c9 packaging(aur): drop debuginfo from source PKGBUILDs
The qbz/qbzd source builds set only !lto; makepkg then injects -C
debuginfo=2 for its debug package, which inflates the final rustc link
enough to trip the OOM killer on the qbz-qt binary. Add !debug so the
source packages link within a normal builder's memory. Verified by
clean container builds of qbz and qbzd 2.1.0.

cc
2026-09-07 23:40:57 -06:00
vicrodh 61d58f3ead ci(release): fix aarch64 tarball naming and gentoo metadata validation
Two release-pipeline fixes surfaced by the 2.1.0 tag:

- release-linux-aarch64: the GUI and qbzd tarballs (and their internal dirs)
  were named with DEB_ARCH (arm64), but every source consumer — release-aur,
  the Gentoo binary ebuilds, the Flathub manifest — fetches them as aarch64,
  which matches the rpm/AppImage suffix. They 404'd on the tag and needed a
  manual re-upload. Name the tarballs and dirs with ARCH (aarch64); the .deb
  files keep DEB_ARCH (arm64), the Debian convention.
- release-gentoo: the metadata validation step calls xmllint, which is not on
  the runner by default; install libxml2-utils before using it.

cc
2026-09-07 23:40:57 -06:00
vicrodh 0668868a28 packaging(aur): drop debuginfo from source PKGBUILDs
The qbz/qbzd source builds set only !lto; makepkg then injects -C
debuginfo=2 for its debug package, which inflates the final rustc link
enough to trip the OOM killer on the qbz-qt binary. Add !debug so the
source packages link within a normal builder's memory. Verified by
clean container builds of qbz and qbzd 2.1.0.

cc
2026-09-07 23:40:18 -06:00
vicrodh 80a13d75c1 ci(release): fix aarch64 tarball naming and gentoo metadata validation
Two release-pipeline fixes surfaced by the 2.1.0 tag:

- release-linux-aarch64: the GUI and qbzd tarballs (and their internal dirs)
  were named with DEB_ARCH (arm64), but every source consumer — release-aur,
  the Gentoo binary ebuilds, the Flathub manifest — fetches them as aarch64,
  which matches the rpm/AppImage suffix. They 404'd on the tag and needed a
  manual re-upload. Name the tarballs and dirs with ARCH (aarch64); the .deb
  files keep DEB_ARCH (arm64), the Debian convention.
- release-gentoo: the metadata validation step calls xmllint, which is not on
  the runner by default; install libxml2-utils before using it.

cc
2026-09-07 21:40:34 -06:00
vicrodh a32cbb22ea release: 2.1.0 — Rebuild Q (You Can (Not) Redo)
Merge the Qt frontend release (pre-release) into main for 2.1.0.

Conflicts resolved by taking pre-release's versions, verified equivalent:
- .github/workflows/release-windows.yml: main's copy was a verbatim older
  snapshot ('No behavior change'); pre-release carries the current workflow.
- README.md: pre-release's Qt rewrite already covers main's Aug-31 additions
  (native/not-a-web-player, bit-perfect DAC, no EQ/DSP, TDL/SPTFY/DZR, offline
  locks) in its dedicated 'What QBZ is and what it is not' section.

cc

# Conflicts:
#	.github/workflows/release-windows.yml
#	README.md
2026-09-07 18:50:54 -06:00
vicrodh 9857c1992b docs(release): 2.1.0 feature inventory and tag details
Release copy for 2.1.0 "Rebuild Q (You Can (Not) Redo)": the feature inventory
that feeds the Discussion and the tag details rendered by the website and the
in-app About modal. The Discussion link points to discussions/743; the h1
codename matches the About modal literal (about_qt.rs CODENAME).

cc
2026-09-07 18:12:19 -06:00
vicrodh b56e4f9b74 fix(qt): remove an unavailable sidecar row from a mixed playlist
A mixed Qobuz playlist whose Plex (or Jellyfin/Subsonic) sidecar track no
longer resolves renders an "Unavailable track" row, and "Remove from playlist"
from the row menu did nothing:

  playlist remove: no plex key for row plex:47032
  playlist remove: non-numeric row id plex:47032

remove_sidecar_row resolved the ref ONLY through the live queue
(local_picker_ref_for_row), but an unavailable row has no queue entry, so the
lookup returned None, the plex arm bailed, and the fallthrough tried to parse
the "plex:<key>" display id as a Qobuz u64 and failed. Nothing was removed —
and it must not depend on Plex being reachable, since the removal is a local
SQLite delete.

Derive the removal target from the display id itself, which already encodes
"<source>:<reference>", falling back to it when the queue ref is absent. This
also closes the same gap for Jellyfin/Subsonic sidecars (previously unhandled),
via remove_remote_track_from_playlist. Pure helper `sidecar_removal` with unit
tests covering resolved, unavailable-plex, unavailable-remote, local and Qobuz
rows.

cc
2026-09-07 17:36:54 -06:00
vicrodh 06770cfd4c fix(build): qt-cargo.py runs cargo via subprocess, not os.execvpe
os.exec* is emulated on Windows (spawn + terminate the caller) and crashed
the release-windows build: it died with "Segmentation fault ... exit code
139" immediately after the wrapper printed the SDK fingerprint, before cargo
produced any output. The POSIX Linux and macOS builds using the same wrapper
were unaffected, which localised it to the Windows exec emulation.

Spawn cargo with subprocess.run and propagate its exit code. Portable across
all three targets; cargo output still streams through the inherited stdio and
CXXFLAGS/QMAKE plumbing is unchanged. Verified locally: the wrapper reaches
cargo and returns its status.

cc
2026-09-07 15:58:21 -06:00
vicrodh e4ad325744 fix(qt): unique id for the kiosk history queue delegate
The Up Next and History delegates in KioskNowPlaying both declared
`id: queueRow`. qmlcachegen and the runtime tolerate the collision, but
qmllint fails to resolve the inline QueueRowLite type in the second delegate
and the pre-release qt gate rejected it. Give the history delegate its own id.

cc
2026-09-07 12:46:58 -06:00
vicrodh db950139eb chore(about): merge Ko-fi supporter Jan into pre-release 2026-09-07 12:34:11 -06:00
vicrodh 58cd3b70e7 chore(about): add Ko-fi supporter Jan
cc
2026-09-07 12:33:45 -06:00
vicrodh 31da9c57bb fix(qt): kiosk feedback round — chrome, search, album, artists, lyrics
Address the owner's kiosk feedback on top of the release hardening:

- Chrome: the back bar is a drag surface and shrank to 44px with one shared
  button form for Back/Forward/Connect/Cast; Qobuz Connect and Cast are a
  permanent cluster in the bar; the dead Share-logs button left the kiosk
  Settings header.
- Transport bar: the hidden overflow menu is gone; Volume is always visible
  with a vertical sheet, and Desktop mode has its own button.
- Now Playing: one centred transport row (New-bar order); lyrics are centred
  (shared LyricsLinesView gains an opt-in centered, desktop default false).
- Local Library: the media funnel and an Open (ephemeral) entry point reach
  the kiosk; Artists is its own multi-column round-card grid (kiosk-only, the
  desktop LocalArtistsTab is untouched); the Artists drill-down query no
  longer hangs off a stale derived guard.
- Search: the All-tab dashboard shelves render again — they were mounted in a
  Loader Component that read the delegate id under reuse and bound an empty
  model; they are direct children now.
- Album detail: icon actions the height of the quality badge plus play next /
  later / queue, an inline floating quality badge, and zebra rows; both album
  headers show a quality badge.
- Immersive: a quiet auto-hiding kiosk exit moved to the bottom, clear of the
  window controls.

Regression coverage in scripts/test_qt_kiosk_feedback.mjs (wired into the
runtime gate). Verified on a private authenticated Xvfb; QML audits 6/6,
Node gate 5/5, release build 0 warnings.

cc
2026-09-07 12:33:28 -06:00
vicrodh b1dba198c9 feat(qt): kiosk profile release hardening
Integrate the Kiosk profile hardening round: 12 dedicated Kiosk views plus
22 shared opt-in hosts, shared navigation history with Back/Forward, Albums
as the default library tab, native paged Local Library (artists/tracks),
lightweight MyQBZ grid and detail, Ephemeral lifecycle, bounded lists and
artwork sized to the physical frame, static skeletons, 64px transport bar,
Settings touch reflow and a persistent Immersive exit.

Desktop keeps its prior behavior: every shared component defaults to the
desktop path and only opts into Kiosk behavior through explicit properties
(origin-relative ScrollMemory, viewport-bounded artwork requests).

Regression coverage: kiosk navigation and artwork Node tests added to the
runtime gate, scroll-origin fixtures for fixed and grouped rows, i18n
strings for all eight locales.

Verified by 750 release tests, six QML audits, Kiosk smokes at 800x480 and
1280x800 and a Desktop A/B with seven pixel-identical captures.

cc
2026-09-07 08:23:11 -06:00
vicrodh c1c463dc94 refactor(about): load sponsor credits from release data
cx
2026-09-06 23:44:22 -06:00
vicrodh 834dc7826d docs(community): clarify Windows and sponsor support
cx
2026-09-06 23:14:21 -06:00
vicrodh 7b90b30d38 docs(contributing): require workflow context in PRs
cx
2026-09-06 23:06:15 -06:00
vicrodh a6649f3bdc docs(contributing): keep model disclosure future-proof
cx
2026-09-06 22:58:52 -06:00
vicrodh 4eea00a61a chore(issue-templates): simplify contributor intake
cx
2026-09-06 22:56:59 -06:00
vicrodh 654ebc5722 docs(contributing): require model-specific LLM disclosure
cx
2026-09-06 22:56:54 -06:00
vicrodh d024013168 docs(readme): update distribution and macOS guidance
cx
2026-09-06 22:33:46 -06:00
vicrodh 24a0f5331d docs: expand platform build requirements and AI documentation note
Add the Windows experimental badge and source build prerequisites for Arch, Gentoo, NixOS and Windows. Clarify how to build against an installed Windows Qt SDK and invite help with documentation.

cx
2026-09-06 22:21:13 -06:00