Commit Graph
4 Commits
Author SHA1 Message Date
vicrodh 3c87df308b fix(media-controls): decode notification artwork by content, not extension
image::open resolves the format from the path extension only (no content
sniffing in image 0.25), so every notification artwork served from the
shared image cache - files named {md5}.img since slice 3b/B11 - failed as
Unsupported and the toast fired icon-less on online Qobuz plays. Decode
via fs::read + image::load_from_memory (magic bytes, extension-agnostic),
which also heals mislabeled downloads in the md5 cache. file:// paths now
percent-decode (cached_file_url_for builds them via Url::from_file_path),
fixing the latent spaces/non-ASCII fall-through to an HTTP GET of a
file:// URL. Offline semantics unchanged.

cc
2026-06-10 09:06:59 -06:00
vicrodh dee85faadb feat(slint): offline artwork policy and local media-controls art
Shared artwork HTTP client gains the missing 10s total timeout (half-up
networks could pin the 16-permit semaphore). fetch_cached_http short-
circuits while offline: disk hits serve, misses return the placeholder
immediately with zero network and no negative caching. Now-playing meta
resolves MPRIS art to a cached file:// URL (or none) instead of an
unfetchable https URL while offline; system notifications skip their
blocking artwork download offline via an injected flag, keeping
qbz-media-controls frontend-agnostic.

Part of offline-mode slice 3; main.rs wiring rides the slice-3 wiring
commit.

cc
2026-06-09 21:00:33 -06:00
vicrodh d08c5f6569 feat(slint): system "now playing" notifications on track change
Port the Tauri desktop-notification path to a frontend-agnostic crate so the
Slint app (and any future TUI/CLI) fires it from native Rust instead of a
webview invoke.

New qbz-media-controls::notify module:
- Linux: XDG notification portal via ashpd (D-Bus); album art passed as
  Icon::Bytes after center-crop + downscale to <=512px + PNG re-encode (<=4 MiB).
- macOS: notify_rust with image_path (cover cached to disk).
- Windows: no-op (parity with Tauri).
- Self-contained artwork download + md5 cache + resize, matching the Tauri
  helpers, with no dependency on the frontend (ADR-006).

Wired in playback::refresh_now_playing_meta (the same point that pushes the
tray tooltip + OS media controls):
- De-dupe by track id so only an actual track change fires (the refresh also
  runs on resume/seek).
- Skip while a remote QConnect renderer drives playback (matches the Svelte
  skipIfRemote). Fire-and-forget on a tokio task.

Enabled by default, matching the Tauri default; a settings toggle is a
follow-up.

cc
2026-06-06 16:45:04 -06:00
vicrodh 7a7e5f82c4 feat(slint): system media controls — MPRIS with GNOME app icon + SMTC/MediaRemote
New frontend-agnostic crate qbz-media-controls (ADR-006): one MediaIntegration
trait, cfg-split backends. Linux uses mpris-server and publishes the MPRIS
org.mpris.MediaPlayer2.DesktopEntry property as com.blitzfc.qbz — the only way
GNOME Shell resolves the app icon for its media widget (souvlaki, the old
cross-platform crate, never set it, so GNOME showed no icon; KDE is lenient).
macOS/Windows keep souvlaki (MediaRemote/SMTC), where the icon comes from the
app bundle, not a DesktopEntry. The Linux server runs on a dedicated thread
with its own tokio runtime; state arrives over an async channel.

Wired into qbz-slint via src/media_controls.rs: started on shell entry,
metadata/playback pushed from the playback paths (mirroring the tray), and
inbound control events (media keys, the desktop media widget, Now Playing)
dispatched to the player through the existing QConnect-aware helpers. Both
Linux and macOS compile clean.

cc
2026-06-06 11:03:11 -06:00