Commit Graph
6014 Commits
Author SHA1 Message Date
vicrodh 142142e317 fix(cast): clear residual DLNA transport state on connect
A renderer left mid-playback by a previous session re-requests its
orphaned CurrentURI against the fresh media server (new path token ->
403 loop) and reports a stale PLAYING position. That poisons
cast_max_position and trips the premature-STOPPED end-detection guard
into auto-advancing the first cast track. Issue a best-effort AVTransport
Stop right after connect so the transport starts clean.

cc
2026-07-17 21:22:35 -06:00
vicrodh 1638da05dc chore(deps): bump getrandom to 0.4 in qbz-cast
getrandom::getrandom() was renamed to getrandom::fill() in 0.3; adopt fill() at the cast token call site. Consolidates onto the getrandom 0.4.2 that tempfile and rand already pull in.

cc
2026-07-17 20:20:51 -06:00
vicrodh b8ee89b85c chore(deps): bump tempfile to 3.27.0
cc
2026-07-17 20:19:31 -06:00
vicrodh c15c71449a chore(deps): bump actions/github-script from 7 to 9
cc
2026-07-17 20:14:33 -06:00
vicrodh 6620dd769b chore(deps): bump actions/upload-artifact from 4 to 7
cc
2026-07-17 20:14:25 -06:00
vicrodh 0692048833 chore(deps): bump actions/download-artifact from 4 to 8
cc
2026-07-17 20:14:18 -06:00
vicrodh 0f829ab62f chore(deps): bump actions/checkout from 4 to 7
cc
2026-07-17 20:14:06 -06:00
vicrodh 1f608cddc9 fix(qobuz): back off between bundle-extraction retries
The 3 bundle-extraction attempts fired back-to-back, so a brief network hiccup
(DNS blip, dropped connection, captive-portal redirect) failed all of them in a
few ms and the retries were effectively useless — surfacing as "Failed to
extract bundle tokens: Network error" at sign-in. Add a short growing delay
(600ms, 1200ms) between attempts so a transient failure has time to clear.

cc
2026-07-17 19:36:49 -06:00
vicrodh 3b0d8e7641 polish(shader): soften ambient metaball edges
The metaball iso-surface + a strong high-frequency domain-warp octave produced
hard, clashing edges between the color lobes (visible over the translucent UI).
Gentle the high-freq warp (lower freq + amplitude), widen the iso-surface
smoothstep so lobes melt into the base with a long gradient instead of a hard
rim, ease the bright/dark contrast, and add a touch more dither against banding
— the flowing motion stays, the ugly edges go.

cc
2026-07-17 19:36:49 -06:00
vicrodh 1ee2a6c963 fix(label)+ui: label top-track artist/album from real endpoint + album column
- label.rs parse_top_track: the /label/page top_tracks carry the main artist in
  a track-level `artists` array (roles=main-artist), not performer/artist (null
  here), and the album title in `album.title`. Read both (with legacy fallbacks)
  so label Popular Tracks show the artist name + album (discussion #631).
  TopTrack gains an `album` field, threaded to the row.
- Artist + Label Popular Tracks: show-album: true so the album-title column
  renders (owner: album required in all PopularTracks lists).

Note: "Add to Mixtape" is already present in the artist/label Popular-Tracks
multi-select bar (cassette icon, tooltip) and the per-track "..." menu
(mixtape-action = qobuz-row) — no code change needed there.

Base: 6c41f58f.

cc
2026-07-17 16:28:24 -06:00
vicrodh 6c41f58f44 fix(shader)+feat(ui): nvidia shader tiling fix + scrollbar/mixtape/track-listing batch
NVIDIA shader fix (root-caused via diagnostic bisection on the discrete GPU):
- ambient.wgsl + plasma.wgsl: replace the sin-based hash `fract(sin(dot(p,k))*N)`
  with the sin-free Dave Hoskins hash. On NVIDIA, as noise coords grow with
  time, sin's argument gets huge and range-reduction precision diverges from
  Intel's, degenerating the noise into big blocks. Confirmed via a solid-color
  clear (clean) then a uniform-passthrough (clean) — isolating it to the shader
  hash, not the texture handoff.
- ImmersiveView: the 3 immersive-exit paths (X button, in-menu exit, ESC) kept
  the drain alive only for the Large NPB dock, freezing the shader texture on
  the last immersive frame when the app-wide Ambient background was on. Now they
  also keep it alive for Ambient so it renders the ambient scene after exit.

UI batch:
- Auto-hide scrollbar (Discover's ListScrollbar auto-hide + pointer hit-test)
  on AlbumView, ArtistView, PlaylistView, PlaylistManagerView.
- #631: artist Popular Tracks now show the album cover thumbnail (thread
  artwork_url through TrackData -> track_data_to_item + a new
  ArtworkTarget::ArtistTopTrack decode job, mirroring LabelTopTrack); label
  Popular Tracks fall back to the album's main artist for the name+id. Quality
  badge already rendered by TrackRow — reused, not reinvented.
- #446: "Add to Mixtape/Collection" bulk button in the Favorites/Artist/Label/
  Mix selection bars, mirroring the existing add-to-mixtape path (track items
  auto-restrict the picker to mixtapes, not collections).

slintcheck + Opus Rust review green (no compile blockers). Base: 8c2f84b7.

cc
2026-07-17 14:51:18 -06:00
vicrodh 8c2f84b798 feat(shell): per-GPU selector, ambient scene in immersive, glass carousels/viewall
Smoke round 5 (owner feedback). Checkpoint.

- Preferred GPU selector (Settings > Renderer, Linux/wgpu): lists each detected
  GPU by name ("Auto" + e.g. "NVIDIA … (discrete)" / "Intel … (integrated)"),
  persisted (ui_prefs.gpu_power by device name), applied at startup via the wgpu
  adapter PowerPreference (WGPU_POWER_PREF env still wins). Fixes the iGPU running
  hot under the shader background on hybrid laptops — pick the discrete GPU.
  New gpu_adapters() enumerates+dedups adapters; gpu_power_from_prefs /
  _options / _seed_index / _value_for_index.
- Ambient metaball added to the IMMERSIVE scene picker (mode 7, wgpu-only opt-in);
  the non-shader atmosphere stays the fallback for GL/software tiers.
- Glass treatment on the surfaces that were still opaque: carousel < > nav
  buttons (6 carousels), "Filter by category" pill, "Filter by genre" buttons,
  and the PlaylistBrowseView (View-all) header band + category radio row.
- i18n: "Preferred GPU" + description + discrete/integrated + restart toast (8
  locales).

Base: 76ea5a82. Prior checkpoint: a0f5cf2b.

cc
2026-07-17 10:54:45 -06:00
vicrodh a0f5cf2bf5 feat(shell): metaball ambient + translucent bars/panels/controls, drop carousel fades
Smoke rounds 3-4 (owner feedback). Checkpoint during iteration.

Ambient (the big one): rewrote ambient.wgsl from translating gaussian blobs to a
METABALL field (r²/d² summed + smoothstep iso-surface) with 2-octave domain warp
— lobes fuse/stretch/split like an amoeba / lava lamp (the Cider motion that was
missing), faster clock, more contrast.

Surfaces made background-aware (translucent when the dynamic background is on):
- Search results view (root + toolbar), artist Network panel + its tab-row
  header (transparent to avoid double-translucent compounding), JUMP TO bar
  (JumpNavBar bar-bg passed in — can't import ShellState without a cycle).
- Discover toolbars + tab pill + BrowseHeaderTools; SearchResultsView toolbar.
- CircleAction (shared: playlist/album/artist/etc. action buttons) on-surface
  secondary fill goes glass; playlist Sort dropdown; QbzSelect closed control.
- New app-background-bar-alpha knob (0.3, env QBZ_BG_BAR_ALPHA): thin bars go
  MORE transparent than panels (surface-alpha 0.5).
- Content well: frosted tint (0.22) + 1px hairline border → distinct panel.
- Album/Artist header gradient auto-suppressed under the dynamic background
  (they clashed); header text stays light on the dynamic backdrop.
- Discover carousel edge-fade "shadows" hidden when active (Carousel /
  PlaylistCarousel / ArtistCarousel / PinnedCarousel).

Base: 76ea5a82. Prior checkpoint: 4e405338.

cc
2026-07-17 08:08:33 -06:00
vicrodh 4e40533870 feat(shell): dynamic background shows through content area + livelier ambient
Smoke round 2 (owner feedback: content area was an opaque black slab, motion
imperceptible, ambient≈blurred).

- Content-area sweep: 27 content-view roots go transparent when the app
  background is active (was opaque Theme.surface-main covering the background) —
  Home/Discover/Album/Artist/Search-adjacent/Favorites/Playlist/LocalLibrary/
  MyQBZ/managers/etc. Content well (AppShell) transparent too.
- SongCard (NPB classic), search input box, cortinilla panel go translucent so
  they stop reading as opaque slabs over the background.
- ambient.wgsl: much faster + bigger blob travel + stronger domain warp +
  brighter/more saturated so the flow is obviously moving and clearly distinct
  from the blurred-art mode.
- Defaults: dim 0.35, surface-alpha 0.5.

Checkpoint during smoke iteration (owner-requested). Base: 76ea5a82.

cc
2026-07-17 02:42:59 -06:00
vicrodh 76ea5a82bb feat(shell): app-wide dynamic album-art background ("modo Cider")
Opt-in album-art background composited behind the whole shell, wgpu-tier
only. Appearance mode picker: Off | Ambient (GPU shader) | Blurred art.

- ambient.wgsl: new calm, low-energy album-colored scene (mode 7), drifting
  mesh-gradient of the primary/secondary/accent triad, no beat/transient.
  Registered in shader_underlay SHADER_SOURCES[5] + render_frame idx math.
- state.slint: AppearanceState app-background {modes,mode-index,available,
  dim,surface-alpha}; ImmersiveState.app-shader-mode (derived 1->7);
  ShellState.app-background-active (mode>0 && wgpu && has-track).
- visualizer.rs: drain renders shader-mode when immersive OPEN, else
  app-shader-mode (7=ambient) into the same shader-texture sink.
- AppShell: background layer at root z-bottom (Ambient=shader texture,
  Blurred=ImmersiveAtmosphere) + tunable dark scrim; shell chrome surfaces
  go translucent when active; viz-should-run extended to drive the drain.
- Whole-shell translucency: Sidebar/HeaderBar/PlayerBar(Small)/QueueSidebar/
  LyricsSidebar/SidebarNowPlayingDock + AppShell content well/frame/column.
- ui_prefs: persisted `app_background` (off|ambient|blurred), String-key
  pattern; appearance-select("app-background") write-back.
- Live-tunable knobs QBZ_BG_DIM / QBZ_BG_SURFACE_ALPHA (seeded at startup)
  so the look is dialed in one smoke session without a rebuild.
- i18n: 8 locales for the picker + warning; reduce-motion / D4 (no-track ->
  opaque theme) handled via derived active flag.

Design + signed decisions: qbz-nix-docs/specs/2026-07-16-app-wide-dynamic-background.md

cc
2026-07-16 23:50:40 -06:00
vicrodh d8127356d3 fix(playback): recover stuck-load watchdog and seed transport state on restore
Two playback fixes:
- The 45s loading watchdog only cleared the spinner, so a load that hung
  on a network stall (not errored) left the track dead at 0:00 with no
  recovery — the legacy fallback only reacts to a setup *error*, never a
  hang. Re-start the stuck track up to twice, then skip to the next
  playable track. The counter is keyed per-track and resets the moment
  real audio plays.
- NowPlayingState shuffle/repeat were only set on a manual toggle, so the
  NPB Large shuffle indicator stayed dark after a session restore. Seed
  both from persisted state in refresh_now_playing_meta.

cc
2026-07-16 20:38:04 -06:00
vicrodh c4ddca0223 fix(input): gate hotkeys while text inputs are focused
A use-site `changed has-focus` on a std-widgets LineEdit/TextEdit never
fires — has-focus is an alias into the inner TextInput (slint#7747) — so
typing a letter that doubles as a shortcut ran the action instead of
inserting the character. Sweep every text-input surface (search, import,
create/edit playlist & folder, tag editor, colour picker, settings
fields, QConnect dev modal, kiosk shell) and drive
UiFocusState.text-input-focused from a `guard-focused` probe property
that the change tracker does observe.

cc
2026-07-16 20:37:57 -06:00
vicrodh 134eddc1ae fix(share): resolve Song.link/Album.link via Deezer ISRC/UPC (#514)
The 2.0 port kept only the Odesli-by-URL path, which rejects Qobuz URLs
(400 could_not_resolve_entity), so album.link/Song.link never resolved
while the raw Qobuz link still copied fine. Restore the Tauri behaviour:
look the track up on Deezer by ISRC (album by UPC, with a leading-zero
retry) and build song.link/d/{id} / album.link/d/{id} from the match.

cc
2026-07-16 20:37:51 -06:00
vicrodh 33f91adcca Merge branch 'bugfix/debug-batch-2026-07-15' into pre-release
2.0.2 batch: audio #508 + streaming fixes, #618 window identity/geometry +
single-instance, sub-genre filter, Qobuz Playlists View-all, Plex refresh,
searchable theme dropdown, ArtistGridCard app-wide, Pinned Home/For You section,
and shell UI polish (sidebar margins, queue count, macOS corner).

cc
2026-07-16 16:32:31 -06:00
vicrodh 8e57864bee fix(shell): #618 window identity/geometry + single-instance present; Plex refresh seed; wire discover/pinned state
Persist the Wayland app_id (set_xdg_app_id) and window geometry/maximized across
tray-hide and miniplayer round-trips so the pinned taskbar icon keeps grouping
and the size/position survive (#618); route the single-instance raise and MPRIS
Raise through a miniplayer-aware present() plus a dedicated D-Bus Present method.
Seed the Local Library Plex refresh button after login (not before, when the
per-user store is unbound). Also the shared wiring these features need in
main.rs / state.slint / app.slint / home.rs / artwork.rs (pinned globals + store
seed + mixed-artwork target, playlist-browse nav, sub-genre reload) and the
bundled i18n strings.

cc
2026-07-16 16:31:51 -06:00
vicrodh 288e982b44 fix(ui): sidebar dock margins, queue count footer, macOS NPB-small corner
Homologate the large-dock cover's side margins (16px each vs the visible content
bezel) and add a 4px bottom gap by trimming the FFT band 2px top/bottom. Move the
queue count out of the "Up Next" header into a fixed footer ("Showing X of Y
tracks", dropping the redundant "left"). On macOS, inset the flush-left NPB-small
art so the native rounded window corner stops clipping it.

cc
2026-07-16 16:31:39 -06:00
vicrodh f26d3e5e1d feat(settings): searchable theme dropdown
Enable the searchable QbzSelect on the theme picker (36 themes) — the search box
the migration deferred. Rides the #616 theme-filter (icon swap + list narrowing,
already on pre-release); the search filters within the active All/Dark/Light
facet.

cc
2026-07-16 16:31:39 -06:00
vicrodh 7138dafbdb feat(home): Pinned section — per-user store, mixed carousel, pin affordances
Users pin albums/artists/playlists to a configurable "Pinned" section on Home
and For You. New per-user SQLite pinned-items store (headless in qbz-app +
lifecycle wrapper), a mixed PinnedCarousel dispatching Album/ArtistGrid/Playlist
cards by kind, a rotated pin glyph (hover-only) on those cards, and Pin/Unpin
from the playlist header and the album/artist context menus. Local/Plex albums
resolve to their Local Library page (id-format routing) and render their real
covers via the mixed-source artwork dispatcher.

cc
2026-07-16 16:30:30 -06:00
vicrodh d87ae8a65f feat(discover): ArtistGridCard for mixed carousels, used app-wide
New 200x246 artist card (framed round portrait, follow/play/more hover overlay,
centered wrap-capable name with an optional reco subtitle) matching the album/
playlist card footprint. ArtistCarousel renders it by default across the app
(search "Most popular" hero included); the legacy 160x220 ArtistCard stays for
the label/award carousels whose artist actions don't apply.

cc
2026-07-16 16:30:30 -06:00
vicrodh 64920a76e4 feat(discover): Qobuz Playlists "View all" page + shared header tools
Port the Tauri playlist "View all": a new PlaylistBrowseView with the category
tag bar, search filter, genre filter and grid/list toggle, extracted into a
shared BrowseHeaderTools and a reusable PlaylistListRow. Restores the "Popular
albums" see-all and aligns PlaylistCarousel's "View all" affordance with the
standard carousels.

cc
2026-07-16 16:30:12 -06:00
vicrodh 6aa314b8ef fix(discover): sub-genre filter sends raw ids to the server (Tauri parity)
/discover/index honors sub-genre ids server-side, so send the raw selection
(parent or sub-genre, exactly as toggled) instead of mapping to the top-level
ancestor and narrowing client-side by genre.path — the previous hybrid widened
sub-genre selections back to their parent and dropped albums tagged only at top
level. Removes the client-side narrowing and its now-dead helpers; keeps a
diagnostic log of the outgoing genre_ids.

cc
2026-07-16 16:30:12 -06:00
vicrodh f778874fdd fix(audio): #508 ALSA-exclusive + streaming regression; flatpak ReserveDevice1 own-name
Store the CMAF duration at command-accept so the seek bar and progress can't
freeze at 0:00, backfill it on the Resume rebuild, and clear + surface the
zombie stream-create-failure path. Degrade every non-priority device-reservation
contention error (only a higher-priority holder stays fatal) so a sandboxed
D-Bus RequestName denial can't block bit-perfect playback. Honor the
stream_buffer_seconds floor in the dynamic CMAF path and wire the network
throttle (record_segment_bandwidth / record_underrun / prefetch cap) to tame the
#591 underrun loop. Grant --own-name=org.freedesktop.ReserveDevice1.* in the
repo flatpak manifest so WirePlumber releases the card cleanly.

cc
2026-07-16 16:29:58 -06:00
Victor RH 6e0d788259 Merge pull request #616 from afonsojramos/fix/theme-filter-icon-and-list
fix(settings): make the theme-list filter actually work
2026-07-15 21:55:22 -06:00
Afonso Jorge Ramos 84b3c9f970 fix(theme): update registry count for Catppuccin variants 2026-07-16 01:20:53 +02:00
Afonso Jorge Ramos 4e37b1370b fix(settings): make the theme-list filter swap its icon and narrow the list
The All/Dark/Light filter next to the theme dropdown did nothing: every
branch of the icon ternary rendered disc.svg, and the Rust `theme-filter`
handler was cosmetic (persisted the value but never filtered the list).

Add distinct sun-moon/moon/sun icons and a luminance-based filter-aware
theme API (filtered_dropdown_themes/labels + index helpers), then wire
startup seeding, the filter cycle, and theme selection through it. `All`
is a proven passthrough of the previous behaviour; Dark/Light narrow the
dropdown by the registry's `is_light` flag.
2026-07-16 01:20:44 +02:00
vicrodh 5ae5d8e651 docs(readme): add Headless Daemon (qbzd) feature section linking the wiki manual
cc
2026-07-15 15:51:40 -06:00
vicrodh b4bff581ae feat(qbzd): wide sidebar, wrapped descriptions and fixed control column in setup TUI
cc
2026-07-15 12:15:32 -06:00
vicrodh e6cb5114a9 fix(qbzd): posture voice on the TUI network screen and pinned boot note
cc
2026-07-15 11:41:29 -06:00
vicrodh e6cc082669 feat(qbzd): default control-plane and login binds to 0.0.0.0 for LAN-first posture
cc
2026-07-15 11:32:44 -06:00
vicrodh 2e9e6a35ac fix(qbzd): honest OSC 52 copy semantics, copy-all file artifact and wizard polish
cc
2026-07-15 11:09:17 -06:00
vicrodh 90412328be feat(qbzd): hifi wizard section with copyable config blocks in setup TUI
cc
2026-07-15 10:49:38 -06:00
vicrodh ff1dbf7425 feat(qbzd): frames layout for setup TUI — sidebar nav, content frame, header and breadcrumb
cc
2026-07-15 10:10:09 -06:00
vicrodh 927b5aa762 fix(qbzd): footer state mapping test, layout parity and help-tint precision in themed TUI
cc
2026-07-15 08:47:15 -06:00
vicrodh 74dcc60b18 feat(qbzd): themed setup TUI with section borders and accent palette
cc
2026-07-15 08:37:56 -06:00
vicrodh 6b444f9748 fix(qbzd): family-aware bind fallback, URL-first output and IP-validated callback host
cc
2026-07-15 08:17:39 -06:00
vicrodh 7799017c69 feat(qbzd): auto-detect LAN callback host from SSH sessions for login
cc
2026-07-15 08:08:49 -06:00
vicrodh 42b9e39992 feat(qbz): wire settings export modal to the bundle engine (04 §4.2)
SettingsExportActions.confirm() -> settings::export_settings: read the
include-auth gate, close the modal, then off the event loop build the bundle
via qbz_app::settings::bundle::export(ExportSource::Desktop, ..) (no new
export logic), open a native rfd save dialog seeded with
qbz-settings-YYYYMMDD.qbzb, write it 0600 via write_bundle_file, and toast
the "qbzd settings import <file>" step. Errors surface a toast; cancel is a
no-op.

cc
2026-07-15 07:50:27 -06:00
vicrodh 897ba7128c feat(qbz-ui): settings export modal + Developer row (04 §4.2)
Add the desktop "Export settings…" surface for the qbzd daemon epic (T18):
a Developer-settings row that opens a modal with the single default-off
"Include Qobuz login and integration tokens" gate, its warning line, and a
Cancel/Export footer. Confirm() is a Rust callback (wired next). New
SettingsExportState/SettingsExportActions globals, exported from app.slint
so the Rust layer binds them, and the modal mounted in AppShell. New strings
translated across all 8 locales (en es de fr pt ru ja nl).

cc
2026-07-15 07:50:27 -06:00
vicrodh d658a501ad fix(qbzd): store I/O failures in settings set exit 1 not 2
cc
2026-07-14 22:04:11 -06:00
vicrodh 722a0207ec fix(qbzd): latch network.online from real network-class outcomes
cc
2026-07-14 21:59:50 -06:00
vicrodh 47081b7666 fix(qbzd): drop qconnect control handle before device release in shutdown
cc
2026-07-14 21:54:55 -06:00
vicrodh ece9b1ebc6 fix(qbzd): confirmed-kill escalation in acceptance script stop path
cc
2026-07-14 21:41:41 -06:00
vicrodh f48fc6ceb8 test(qbzd): P0 acceptance script for exit codes, status contract and roundtrip
cc
2026-07-14 21:31:19 -06:00
vicrodh 601188a2c0 ci: build qbzd on ubuntu-22.04 with slint-free and glibc-floor gates
cc
2026-07-14 21:12:21 -06:00
vicrodh 39eb12fc45 feat(packaging): ship qbzd binary and user unit in deb/rpm and tarball
cc
2026-07-14 21:02:34 -06:00