Commit Graph
100 Commits
Author SHA1 Message Date
vicrodh f02e19258b Merge branch 'pre-release' into bugfix/pre-1.2.13 2026-05-16 10:16:42 -06:00
vicrodh 2ebb874f43 fix(icons): improve Linux tray display and refresh assets (#362)
Returning an empty `icon_name` in `tray_linux_ksni.rs` forces SNI
panels (e.g., KDE Plasma) to render the explicit `IconPixmap` data.
This prevents panels from incorrectly resolving the full-color app icon
from the system theme instead of the intended monochrome tray glyph.

Also updates `src-tauri/icons/icon-symbolic.svg` and regenerates
all `tray-dark-*.png` and `tray-light-*.png` assets.
Adds `static/logo.svg` as the main application logo.
2026-04-28 07:37:48 -06:00
vicrodh 87194ca1eb Merge remote-tracking branch 'origin/main' 2026-04-05 09:40:01 -06:00
vicrodh 3366c2e8d9 ci(gentoo): use APT_REPO_TOKEN instead of OVERLAY_PAT
cc
2026-03-22 23:10:36 -06:00
vicrodh 346db3785e ci: add release-gentoo workflow for overlay auto-update
Triggered by release-linux completion (same as AUR).
Updates ebuilds in vicrodh/qbz-overlay with new version.
Requires OVERLAY_PAT secret for cross-repo push.

cc
2026-03-22 22:55:49 -06:00
vicrodh 72b794a81c docs: add Gentoo overlay installation to README
cc
2026-03-22 22:49:30 -06:00
vicrodh c3accf7e93 fix: allow network folders in manual offline mode
loadFolders was marking ALL network folders as inaccessible when
offline, regardless of the reason. Manual offline mode and
not-logged-in still have LAN access for NAS/Plex — only no_network
should hide them. Now uses shouldExcludeNetworkFolders() which
already had the correct logic.

cc
2026-03-21 14:35:51 -06:00
vicrodh eeb155641c fix: initialize all user stores in offline session activation
activate_offline_session was only initializing library, offline,
offline_cache, audio_settings, and playback_prefs. Missing stores
caused "No active session" errors for:
- download_settings (Show in Local Library toggle)
- session_store (session persistence)
- favorites_cache/prefs (favorites view)
- tray_settings (tray icon settings)

Now mirrors activate_session but skips online-only services
(MusicBrainz, ListenBrainz, Last.fm, API cache, artist vectors).

cc
2026-03-21 14:32:02 -06:00
vicrodh 86520df919 feat: make offline notice banner dismissible in Local Library
cc
2026-03-21 14:28:01 -06:00
vicrodh 8316e1f4c9 fix: logout spinner hang and last_user_id preservation
Two bugs:

1. mainContentEl teardown crash on logout — the $effect cleanup used
   non-null assertion (!) on an element that becomes null when the DOM
   is destroyed during logout. Changed to optional chaining (?.).
   This TypeError was blocking the render, causing the spinner to hang
   instead of showing the login form.

2. deactivate_session was clearing last_user_id, which broke offline
   mode after logout. The user's data stays on disk — only factory
   reset should clear the last_user_id marker.

cc
2026-03-21 14:25:28 -06:00
vicrodh fb74f318a1 fix: restore offline mode — use last known user profile
Three bugs prevented offline mode from working after V2 migration:

1. activate_offline_session used user_id=0 (empty profile) instead of
   the last known user_id, so the user's library/settings were invisible

2. setManualOffline was called BEFORE activate_offline_session, but it
   requires the offline store to be initialized (which happens during
   session activation). Reordered: activate session first, then set
   manual offline.

3. LoginView called setManualOffline directly instead of delegating to
   the parent's handleStartOffline which has the correct order.

Also added "noPreviousSession" i18n message for users who never logged
in — they need to create a profile first before offline mode works.

cc
2026-03-21 11:01:25 -06:00
vicrodh c766357870 fix: detect BundleExtractionFailed in catch block for offline mode
runtime_bootstrap returns Err(RuntimeDegraded) when bundle extraction
fails (no network), which throws an exception in the frontend. The
catch block was formatting the raw error object as JSON instead of
showing the connection failed message with the offline button.

Now detects BundleExtractionFailed/Network error in the catch block
and shows the proper i18n connection error, making the "Start Offline"
button accessible.

cc
2026-03-21 08:41:04 -06:00
vicrodh 0416198557 fix: retry download with effective quality after fallback (#196)
When get_stream_url_with_fallback internally falls back from UltraHiRes
to HiRes (due to restrictions), the retry logic was requesting a fresh
URL at the original UltraHiRes quality — triggering another fallback
cycle and CDN connection issues.

Now tracks the effective quality from stream_url.format_id and retries
at that quality directly. Applied to both streaming and standard
download paths.

cc
2026-03-20 17:41:22 -06:00
vicrodh dde7c192dc fix: allow volume control when QConnect peer renderer is active on ALSA hw:
When ALSA Direct hw: is active but a remote device (phone, speaker) is
the active renderer via QConnect, volume changes go to the remote device
not the local DAC. The 100% lock should only apply to local playback.

cc
2026-03-20 17:34:47 -06:00
vicrodh a4782c645e fix(qconnect): refresh session snapshot when badge popup opens
In compiled builds, the session snapshot can be stale when the badge
popup opens — the deferred_renderer_join completes after the initial
snapshot was fetched, so QBZ doesn't appear in the renderer list.

Now fetches a fresh snapshot from the backend every time the popup
opens, ensuring the renderer list is always current. Uses a local
$state copy that syncs from the prop but can be updated independently.

cc
2026-03-20 10:06:29 -06:00
vicrodh f1f084c994 fix: use ~/.local/share/icons for Flatpak tray icon temp path
In Flatpak, the default temp dir is inside the sandbox and invisible
to the host's KDE StatusNotifierWatcher. libayatana-appindicator writes
the PNG to temp dir and calls set_icon_theme_path, but KDE can't see
sandbox paths. Use ~/.local/share/icons which is exported to the host
via Flatpak filesystem permissions.

Non-Flatpak installs continue using XDG_RUNTIME_DIR.

cc
2026-03-20 09:35:01 -06:00
vicrodh 8b85e0bad2 fix: add libclang-dev to snap build-packages for mupdf-sys bindgen
cc
2026-03-19 19:50:02 -06:00
vicrodh b73a910f99 fix: add unzip to snap build-packages for mupdf-sys ODT extraction
cc
2026-03-19 19:22:10 -06:00
vicrodh e900261ffe fix: increase album grid minmax to 220px to prevent card overlap
AlbumCard large is 210px but the grids used minmax(180px, 1fr),
causing cards to squeeze and overlap. Updated to minmax(220px, 1fr)
with 24px gap in both LocalLibrary artist view and Favorites artist
sidebar.

cc
2026-03-19 18:25:48 -06:00
vicrodh 0287a1feb8 fix: revert vite-plugin-svelte 7.0.0 -> 5.1.1 (requires vite 8)
Dependabot PR #189 bumped to 7.0.0 which requires vite ^8.0.0 but
we're on vite 6.4.1. Revert to 5.1.1 which is compatible.

cc
2026-03-19 18:17:01 -06:00
vicrodh 95bc788c5a chore: clean up all warnings — zero Rust warnings, zero Svelte warnings
Rust:
- Remove unused get_screen_resolution() function
- Remove unused DEFAULT_QCONNECT_DEVICE_NAME constant

Svelte:
- Add tabindex=-1 to TitleBarNav menu dropdowns (a11y)
- Make volumeRef reactive with $state() in NowPlayingBar
- Remove unused .section-separator CSS from NowPlayingBar
- Remove unused .artist-albums CSS from SearchView and Grid
- Remove unused .artist-list-meta CSS from ArtistList

cc
2026-03-19 17:44:53 -06:00
vicrodh 352d589276 fix: update rcgen 0.12 -> 0.14 API and suppress unused variable warning
rcgen 0.14 breaking changes:
- CertificateParams::new() takes Vec<String> not Vec<SanType>
- Certificate::from_params() replaced by params.self_signed(&key_pair)
- cert.serialize_pem() replaced by cert.pem()
- cert.serialize_private_key_pem() replaced by key_pair.serialize_pem()
- Ia5String no longer public, DNS SANs passed as strings

Also prefixed unused _envelope variable in qconnect_service.rs.

cc
2026-03-19 17:34:12 -06:00
vicrodh 63b0136b5d Merge remote-tracking branch 'origin/pre-release' into pre-release 2026-03-19 17:25:19 -06:00
vicrodh 52d724a7e4 Merge branch 'pre-release' 2026-03-19 17:13:37 -06:00
vicrodh af23efb3c1 chore: bump version to 1.2.0
Updated:
- src-tauri/Cargo.toml
- src-tauri/tauri.conf.json
- package.json + package-lock.json
- snapcraft.yaml (root + packaging/)
- flake.nix
- Cargo.lock
- metainfo.xml (new release entry)
- README: Snap MPRIS limitation note with forum link

cc
2026-03-19 17:12:31 -06:00
vicrodh d0476dd5ab fix(qconnect): fix renderer handoff args and TransportConnected type check
QconnectBadge was passing { rendererId } instead of
{ request: { renderer_id: rendererId } } to v2_qconnect_set_active_renderer,
causing "missing required key request" error on every handoff attempt.

Also fixed TypeError when event.payload is a string ("TransportConnected")
instead of an object — the 'in' operator requires an object operand.

cc
2026-03-19 16:43:32 -06:00
vicrodh 024c1fe98e diag(qconnect): add click logging and pressed effect to renderer button
cc
2026-03-19 16:11:09 -06:00
vicrodh 768b9c118c fix(qconnect): re-request session state after renderer join
QBZ wasn't appearing as a renderer on first connect because the
frontend snapshot was emitted before the deferred renderer join
completed. After joining as renderer, wait 500ms and re-request
session state so the server sends an updated renderer list that
includes QBZ.

cc
2026-03-19 16:07:28 -06:00
vicrodh 3fcecd80b1 docs: clarify offline cache vs local library in README
cc
2026-03-19 15:54:17 -06:00
vicrodh 9d54a19439 docs: move QConnect below Audio, add wiki link
cc
2026-03-19 15:41:05 -06:00
vicrodh 989eb3faf5 docs: rewrite README for 1.2.0
Major rewrite reflecting current state of the project:
- Qobuz Connect as headline feature
- No API keys needed (proxy-based architecture)
- API proxy self-hosting instructions for source builds
- Updated tech stack (rodio 0.22, MuPDF 0.6, ashpd, 5 locales)
- 13 crates including 4 QConnect crates
- Removed outdated sections (KWin title bar, vendored rodio, data migration)
- Streamlined installation and known issues

cc
2026-03-19 15:30:35 -06:00
vicrodh 6245ac9633 docs: add 1.2.0 release documents
TAG_DETAILS.md, CHANGELOG_HIGHLIGHTS.md, CHANGELOG_FULL.md for the
Qobuz Connect release. 185 commits covering QConnect protocol, Linebed
visualizer, playlist follow/unfollow, audio settings sync overhaul, and
dozens of fixes.

cc
2026-03-19 15:21:22 -06:00
vicrodh ac9d38b2a9 fix: linebed canvas no longer overflows into player area
Offset canvas upward and reduce height by 154px (player height + margin)
so the bed ends above the player controls and track info area.

cc
2026-03-19 15:14:40 -06:00
vicrodh 73af66986e fix: adjust linebed camera to show full bed within viewport
Camera raised (y: 1738 -> 2200) and tilted steeper (x: -0.65 -> -0.78)
so the entire bed is visible without overflowing the bottom edge.
Also avoids covering the track info in the lower-right corner.

cc
2026-03-19 15:02:21 -06:00
vicrodh 780f75158a fix: skip credential tests in Nix build sandbox (#154)
Nix sets HOME=/homeless-shelter during builds, which makes
dirs::config_dir() return a technically writable but unusable path.
The keyring/D-Bus is also unavailable in the sandbox.

Added detection for HOME containing "homeless-shelter" or
"/nix/store", and NIX_BUILD_TOP env var, to skip credential
roundtrip tests in Nix builds.

cc
2026-03-19 14:52:24 -06:00
vicrodh 6261f312be fix: use {:?} for souvlaki MediaControlError formatting
MediaControlError doesn't impl Display on all platforms. Using {}
would fail to compile on non-Linux targets. Use {:?} (Debug) instead.

Cherry-picked from PR #181 by @afonsojramos.

cc
2026-03-19 14:42:12 -06:00
vicrodh 026dd0a53a chore: remove mpris slot from snapcraft to unblock Snap Store review
The mpris slot requires an auto-connect review from Canonical that has
been pending for 9+ days. Remove it to unblock the version bump from
1.1.18 to 1.1.20. MPRIS media controls will not work in the snap
build until the review is approved in a future release.

cc
2026-03-19 14:16:40 -06:00
vicrodh 9cdd1521b9 feat: add no-telemetry note to MusicBrainz integration description
MusicBrainz is a one-way pull — QBZ fetches public data but never
sends user data back. Added this clarification to the help text in
all 5 locales and to the wiki Integrations page.

cc
2026-03-19 14:13:00 -06:00
vicrodh a985be3134 feat: add Documentation link to sidebar gear menu
Opens https://github.com/vicrodh/qbz/wiki in browser.
Also updated Report Issue URL to use .yml template.

cc
2026-03-19 14:09:26 -06:00
vicrodh 388fc45116 chore: fix dependabot alerts — update devalue 5.6.4, sveltekit 2.53.3
- devalue 5.6.3 -> 5.6.4: fixes prototype pollution in parse/unflatten
  (GHSA #23, #24)
- @sveltejs/kit -> 2.53.3: fixes deserialization DoS in form actions

cc
2026-03-19 14:05:35 -06:00
vicrodh f055f53ed5 chore: migrate issue templates from markdown to YAML forms (#171)
Replaces placeholder-text markdown templates with structured YAML
issue forms. Dropdowns for installation method, display server, and
audio backend. Required fields for description, steps, and version.
Same output format when reading submitted issues.

cc
2026-03-19 13:56:44 -06:00
vicrodh 50b9ecb85e feat: add (?) help tooltips to bit-perfect audio settings (#166)
Exclusive Mode, DAC Passthrough, and Force Bit-Perfect now have (?)
help icons that show detailed explanations on hover:
- What backend each setting requires (ALSA Direct vs PipeWire)
- What PipeWire properties they affect (clock.force-rate, quantum)
- How they relate to each other (dependency chain)
- What happens without them (resampling to default rate)

i18n help texts added to all 5 locales.

cc
2026-03-19 12:53:04 -06:00
vicrodh 1f1e729db8 fix: HiFi Wizard now detects real DAC sample rates from /proc/asound
v2_query_dac_capabilities was returning hardcoded sample rates
(44.1-192kHz including 176.4kHz) instead of querying the actual
hardware. This caused incorrect configuration for DACs that don't
support all rates (e.g. DacMagic Plus doesn't support 176.4kHz).

Now queries /proc/asound/cardN/stream0 via PipeWire sink mapping
or ALSA device ID to get the real discrete rates from the USB
descriptor. Falls back to defaults only if detection fails.

cc
2026-03-19 12:41:24 -06:00
vicrodh b795d59f1f fix: show actual error message instead of [object Object] on playback failure (#182)
Tauri invoke errors are objects with { code, details, message } fields.
Template literal interpolation with ${err} produces [object Object].
Extract .message or .details, falling back to JSON.stringify().

The quality fallback itself (UltraHiRes -> HiRes) is already handled
by get_stream_url_with_fallback in qbz-core.

cc
2026-03-19 12:30:11 -06:00
vicrodh d676a5cb96 fix: Following playlists tab not loading — use authStore for userId
loadFollowingPlaylists was calling non-existent v2_get_runtime_status
command. Fixed to use getUserInfo() from authStore instead.

Also fixed loadFavoritePlaylists early return when no favorites exist
— it was skipping the loadFollowingPlaylists() call entirely.

cc
2026-03-19 12:04:58 -06:00
vicrodh 697c31053b feat: add Favorites/Following sub-tabs in Favorites > Playlists (#172)
Separates playlists into two sub-tabs:
- Favorites: playlists marked with the heart icon (local QBZ feature)
- Following: playlists subscribed on Qobuz (owner.id != current user)

The Following tab shows playlists from getUserPlaylists where the
owner is not the current user, matching Qobuz's subscription model.

i18n keys added to all 5 locales.

cc
2026-03-19 12:00:08 -06:00
vicrodh 6caeae2d8e fix: remove misleading artist album counts (#169)
Qobuz API's albums_count on Artist objects includes compilations,
tributes, appearances, and other non-album releases, showing
exaggerated numbers (e.g. 647 albums for an artist with ~20 releases).

Removed the count display from:
- Favorites artist list view
- Favorites artist grid view
- Search results artist cards

The accurate album count is available inside ArtistDetailView where
the actual releases are loaded and filtered.

cc
2026-03-19 11:54:08 -06:00
vicrodh 1ad16338fa feat: add Qobuz playlist follow/unfollow (#172)
Discovered undocumented Qobuz API endpoints from bundle analysis:
- POST /playlist/subscribe { playlist_id }
- POST /playlist/unsubscribe { playlist_id }

This is the native "follow playlist" feature that syncs across all
Qobuz clients, separate from QBZ's existing "Copy to Library" (local
copy) and "Favorite" (local flag) features.

Added:
- subscribe_playlist/unsubscribe_playlist in both qbz-qobuz and legacy client
- v2_qobuz_subscribe_playlist / v2_qobuz_unsubscribe_playlist commands
- Bookmark toggle button in PlaylistDetailView (next to Copy button)
- i18n keys in all 5 locales

cc
2026-03-19 11:36:56 -06:00
vicrodh 5488839e97 fix: increase PipeWire rate switch delay and verify after stream creation (#180)
USB hubs/docks (e.g. Razer USB4 Dock) may need longer than 300ms for
sample rate switching. When PipeWire hasn't finished reconfiguring,
96K/192K tracks play at wrong speed (half/quarter) and sound distorted.

Changes:
- Increase initial clock.force-rate delay from 300ms to 500ms
- After stream creation, query pw-metadata clock.rate to verify the
  actual graph rate matches what was requested
- If mismatch detected, retry with additional 500ms delay and re-force
- Log warnings when rate can't be verified so users can report

cc
2026-03-19 10:57:21 -06:00
vicrodh 509426ebcf fix: restore booklet viewer with mupdf 0.6 (#170)
mupdf 0.5 had struct size mismatches on Arch Linux (mupdf-sys bindings
incompatible with system MuPDF headers). Upgrading to mupdf 0.6 fixes
the bindings.

- Removed the booklet feature gate — mupdf is now a direct dependency
  again, matching the v1.1.19 configuration
- Removed stub implementation (always compile real MuPDF backend)
- sys-lib-libjpeg remains excluded (cross-distro libjpeg incompatibility)

cc
2026-03-19 09:28:07 -06:00
vicrodh c2e9a4f0ba fix: replace broken screen resolution clamping with sane fallback
xdpyinfo returns combined multi-monitor resolution (e.g. 6000x1600 for
dual monitors), causing false positives like clamping 1926x1590 to
5700x1520. The 95% multiplier made things worse — the fallback size was
larger than any single monitor.

Replace with simple corruption guard: only clamp values above 8K
(obviously corrupt DB entries), fallback to 1920x1080. The window
manager already handles fitting windows to the actual display.

cc
2026-03-19 08:44:29 -06:00
vicrodh 2439b5f4d8 fix: remove KDE KWin SSD hack entirely (#170)
The KWin window rule approach (kwinrulesrc + qdbus reconfigure) was
never actually active because GDK_BACKEND is unset on most KDE Wayland
sessions. In v1.1.18 this meant decorations(use_system_titlebar) was
used directly — GTK CSD appeared (ugly but functional, no CPU issues).

The hack itself, when triggered, caused double titlebar and a CPU busy
loop that blocked networking. Remove all KDE-specific detection and
KWin rule setup. Window now simply uses decorations(use_system_titlebar)
on all platforms, matching the effective behavior of v1.1.18.

The one-time cleanup of stale kwinrulesrc entries is preserved so users
who had the rule from v1.1.14-v1.1.19 get it cleaned up automatically.

cc
2026-03-19 08:29:49 -06:00
vicrodh 6722e6f59a fix: add offline mode button to network error screen (#173)
When BundleExtractionFailed (no network), the error box only showed
"Retry" with no way to enter offline mode. The timeout case and login
form both had the offline button, but the error state was missing it.

Added "Start Offline" button using existing offline-btn CSS and
i18n keys. Also replaced hardcoded strings with $t() calls.

cc
2026-03-19 03:32:29 -06:00
vicrodh 8a8c709c1b feat: lock volume at 100% when ALSA Direct hw: is active
With ALSA Direct hw: there is no software mixer — volume must be
controlled at the DAC/hardware level. Software volume attenuation
would reduce bit depth and defeat the purpose of bit-perfect playback.

Backend: v2_set_volume forces volume to 1.0 when backend=Alsa+plugin=Hw
Frontend: volume slider disabled (grayed out at 100%), mute/step buttons
hidden, handleVolumeChange and handleToggleMute return early.
Settings callbacks notify +page.svelte when backend/plugin changes to
update the lock state in real-time.

i18n: volumeLockedHw tooltip added to all 5 locales.

cc
2026-03-19 00:10:59 -06:00
vicrodh 9bcafe26fb fix: alsa_hardware_volume was hardcoded false + v2_reset_audio_settings sync
Two additional gaps found during audio settings sync audit:

1. convert_to_qbz_audio_settings() hardcoded alsa_hardware_volume to
   false instead of reading settings.alsa_hardware_volume. This meant
   the player never received the user's ALSA hardware volume preference.

2. v2_reset_audio_settings saved defaults to DB but never synced them
   to the CoreBridge player, leaving stale settings in memory.

cc
2026-03-18 22:20:04 -06:00
vicrodh e490010e58 fix: sync audio settings to CoreBridge player on change and session activation
Two bugs caused the exclusive mode to not work when QConnect was active:

1. Critical audio setters (backend_type, exclusive_mode, dac_passthrough,
   output_device, alsa_plugin, pw_force_bitperfect, sample_rate,
   alsa_hardware_volume) saved to the per-user store but never called
   reload_settings() on the CoreBridge player. The Player kept using
   stale settings (often defaults with backend_type=None), falling back
   to CPAL/PipeWire instead of ALSA Direct.

2. After login, per-user audio settings were loaded into AudioSettingsState
   but never pushed into the CoreBridge player, which was created at
   startup with flat-path defaults.

Fix: Add sync_audio_settings_to_player() helper and call it from all
critical audio setters. Also sync settings in activate_session() and
activate_offline_session() right after audio_settings.init_at().

cc
2026-03-18 22:03:23 -06:00
vicrodh bf91822b4d feat: add QConnect dev toggle and device name settings
Developer Mode: toggle to show/hide QConnect dev panel button in
the player bar (hidden by default, persisted in localStorage).

Integrations: editable device name input for Qobuz Connect with
default "Qbz - {hostname}". Backend commands v2_qconnect_get/set
_device_name and v2_get_hostname. Custom name is used during the
WS bootstrap handshake.

cc
2026-03-18 21:31:11 -06:00
vicrodh 2953b86062 feat: add QconnectBadge as full-height badge in song card
Place QConnect badge as direct child of badges-group with 3px gap
matching DAC/EXC spacing. Two-row vertical layout: icon on top,
Qobuz/Connect text below. Wire props from +page.svelte to both
NowPlayingBar instances. Add qconnect i18n keys to de/fr/pt locales.

cc
2026-03-18 21:03:56 -06:00
vicrodh d4fa6f4210 feat(qconnect): add debug-level diagnostics for shuffle order tracking
Logs QueueUpdated shuffle_order validity and resolve_core_shuffle_order
results at debug level for verbose troubleshooting.

cc
2026-03-16 19:16:10 -06:00
vicrodh 8330dd08ed Revert "Reapply "fix(qconnect): pass server shuffle order through to CoreBridge""
This reverts commit 2bb72455d1.
2026-03-16 11:05:12 -06:00
vicrodh 2bb72455d1 Reapply "fix(qconnect): pass server shuffle order through to CoreBridge"
This reverts commit d9f112390f.
2026-03-16 11:01:53 -06:00
vicrodh d9f112390f Revert "fix(qconnect): pass server shuffle order through to CoreBridge"
This reverts commit 065cf734d2.
2026-03-16 10:54:02 -06:00
vicrodh 065cf734d2 fix(qconnect): pass server shuffle order through to CoreBridge
resolve_core_shuffle_order was reordering the server's shuffle_order
to put the current track first. This destroyed the server's concept
of "already played" vs "upcoming" — CoreBridge showed all tracks as
upcoming while the web player correctly split them.

Now the server's raw shuffle_order is passed through unchanged.
CoreBridge's set_queue_with_order finds shuffle_position from
current_index, preserving the played/upcoming split.

cc
2026-03-16 10:52:41 -06:00
vicrodh b4ebad20c5 Revert "fix(qconnect): suppress local playback automation when connected"
This reverts commit b5ab4cd148.
2026-03-15 23:23:57 -06:00
vicrodh 9c14a76975 fix: make mupdf optional to unblock build on Arch Linux
mupdf-sys 0.5.0 bindings are incompatible with the current system
MuPDF library (struct size assertions overflow). Gate mupdf behind
a booklet feature flag (disabled by default). When disabled, booklet
commands return an error instead of crashing the build.

cc
2026-03-15 13:48:35 -06:00
vicrodh a3cde0449d feat: wire autoplay mode sync to QConnect
- setAutoplayMode now sends autoplay preference to QConnect server
- queue_load_tracks syncs local autoplay mode after loading
- QConnect panel shows autoplay_mode status
2026-03-15 10:32:59 -06:00
vicrodh 87be5fbf16 feat: add set_autoplay_mode and autoplay_load_tracks remote commands
Backend _if_remote methods for QConnect autoplay protocol:
- set_autoplay_mode_if_remote: toggles autoplay on the QConnect server
- autoplay_load_tracks_if_remote: loads track IDs into the autoplay pool
Both follow the established _if_remote pattern with diagnostics.
2026-03-15 09:46:01 -06:00
vicrodh 8e2bb021c2 fix: guard re-bootstrap with has_disconnected flag
Prevents double-bootstrap on initial connect. The Subscribed
handler now only calls bootstrap_remote_presence when the
connection was previously lost (has_disconnected=true), not
on the first connect where connect() already bootstraps.
Also sets has_disconnected=true in the Disconnected handler.
2026-03-15 09:21:41 -06:00
vicrodh 8e87b414db feat(qconnect): route volume/mute to peer renderer when remote is active
New _if_remote backend commands for set_volume and mute_volume.
handleVolumeChange and handleToggleMute in both main view and miniplayer
now check for peer renderer before setting volume locally.  Media
control set_volume also routed through the guard.  When no peer is
active, volume is set locally and reported to QConnect server.
2026-03-15 09:14:07 -06:00
vicrodh 1fc2e79391 feat(qconnect): add stop_if_remote guard for media control stop action
When a peer renderer is active, the MPRIS/media-key stop command now
sends SetPlayerState(STOPPED) to the QConnect server instead of stopping
local playback.  Falls back to local stop on error or when no peer is
active.
2026-03-15 07:27:32 -06:00
vicrodh e5155f2baa refactor: homologate seek to preview+commit in ImmersivePlayer and Miniplayer
Replace immediate seek-on-drag with the NowPlayingBar pattern:
preview the position visually during drag, commit the seek only on
mouseup.  Both PlayerControlsCompact and MiniPlayerFooter now use
dragPreviewTime/effectiveTime, matching NowPlayingBar behavior.
2026-03-14 23:22:09 -06:00
vicrodh 6bb416f854 refactor: centralize mute in ImmersivePlayer and Miniplayer via playerStore.toggleMute
Replace local isMuted/previousVolume state in PlayerControlsCompact and
MiniPlayerFooter with the global toggleMute from playerStore.  Muted
state is now derived from volume === 0, matching NowPlayingBar behavior.
Pre-mute volume is persisted in localStorage by the store.
2026-03-14 22:53:43 -06:00
vicrodh d21f2253bc feat(qconnect): add QConnect guards to shuffle, repeat, queue play, and history play handlers
When a peer renderer is active, shuffle/repeat/queue-play/history-play
commands are now routed to the QConnect server instead of being applied
locally.  Two new backend commands (toggle_shuffle_if_remote,
cycle_repeat_if_remote) follow the existing _if_remote pattern.
Guards added to both +page.svelte (main + immersive) and miniplayer.
2026-03-14 22:44:31 -06:00
vicrodh b5ab4cd148 fix(qconnect): suppress local playback automation when connected
When QBZ is the local renderer in a QConnect session and the web player
presses next, the server sends SET_STATE with the new track. The backend
correctly starts playback, but the frontend's gapless transition handler
saw the track_id change, treated it as a local gapless event, and called
nextTrack() — which advanced the CoreBridge queue every 1s polling cycle,
flooding the queue and destroying the shuffle order.

Root cause: shouldQconnectSuppressLocalPlaybackAutomation only suppressed
when a peer renderer was active (activeRendererId !== localRendererId).
When QBZ IS the renderer, remoteControlMode stayed false, so all local
automation (gapless, auto-advance, resume-from-stop) remained active and
fought the server.

Fix: suppress local playback automation whenever QConnect is connected,
regardless of which renderer is active. The server is the authority for
track transitions in all QConnect scenarios.

cc
2026-03-14 22:09:50 -06:00
vicrodh 3b3dbc7ce1 fix(qconnect): trigger resync on reorder and remove server events
SrvrCtrlQueueTracksReordered and SrvrCtrlQueueTracksRemoved were not
triggering AskForQueueState, so the local queue never reflected
reorder/remove actions performed via QConnect. Same pattern as the
existing shuffle resync.

cc
2026-03-14 21:34:03 -06:00
vicrodh 66b5288150 fix(qconnect): use authoritative queue mutations
cx
2026-03-14 19:29:11 -06:00
vicrodh 311b7269ee fix(qconnect): keep gapless enabled for local renderer
cx
2026-03-14 17:57:46 -06:00
vicrodh 52e3653dc3 fix(qconnect): complete repeat pending on loop ack
cx
2026-03-14 13:25:22 -06:00
vicrodh 8a468ed725 fix(qconnect): restore local repeat renderer flow
cx
2026-03-14 13:09:23 -06:00
vicrodh f47f691063 fix(qconnect): allow rapid repeat toggles
cx
2026-03-14 12:07:11 -06:00
vicrodh e6a20b02e8 fix(qconnect): align repeat loop mode mapping
cx
2026-03-14 11:43:31 -06:00
vicrodh 0529f355e8 fix(qconnect): reanchor repeat state before toggles
cx
2026-03-14 07:55:42 -06:00
vicrodh 7a11b6548c fix(qconnect): anchor remote shuffle projection
cx
2026-03-14 07:32:46 -06:00
vicrodh 8b950da5c9 fix(qconnect): honor remote shuffle order for next
cx
2026-03-14 00:59:51 -06:00
vicrodh f693d1c61a fix(qconnect): wait for authoritative repeat mode
cx
2026-03-14 00:12:47 -06:00
vicrodh 6805b4f61a fix(qconnect): reapply authoritative queue snapshots
cx
2026-03-13 23:22:25 -06:00
vicrodh a59daf43dc fix(qconnect): resync queue after shuffle mode changes
cx
2026-03-13 23:13:16 -06:00
vicrodh cf2447f4b2 fix(qconnect): stop deriving remote shuffle locally
cx
2026-03-13 23:07:22 -06:00
vicrodh af7652c86b fix(qconnect): wait for authoritative shuffle queue
cx
2026-03-13 22:54:27 -06:00
vicrodh 19b4182dd6 fix(qconnect): render connect queue in remote shuffle order
cx
2026-03-13 22:45:56 -06:00
vicrodh 4312bf0524 fix(qconnect): refresh queue store from backend events
cx
2026-03-13 20:51:44 -06:00
vicrodh 1fc7a0a1a3 fix(qconnect): materialize remote shuffle atomically
cx
2026-03-13 20:43:56 -06:00
vicrodh b28fd39737 fix(qconnect): trust remote shuffle order
cx
2026-03-13 20:35:56 -06:00
vicrodh 09c6d8f1f8 fix(qconnect): route shuffle and repeat through runtime
cx
2026-03-13 20:28:11 -06:00
vicrodh 2efa1b0809 fix(qconnect): route clear queue through runtime
cx
2026-03-13 20:00:57 -06:00
vicrodh f72a4db7be chore(qconnect): checkpoint stable handoff state
cx
2026-03-13 19:52:12 -06:00
vicrodh d3d0fe491a fix(qconnect): stream local handoff playback
cx
2026-03-13 18:52:30 -06:00
vicrodh f18bd10aa4 fix(qconnect): complete active-renderer pending on session ack
cx
2026-03-13 18:50:04 -06:00
vicrodh 0a9064aa24 fix(qconnect): keep local renderer queue ids in interval reports
cx
2026-03-13 17:38:52 -06:00
vicrodh de29f1e2e0 chore(qconnect): checkpoint current poc state
cx
2026-03-13 17:28:05 -06:00