Files
qbz/crates/qbz-media-controls/Cargo.toml
T
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

48 lines
2.0 KiB
TOML

[package]
name = "qbz-media-controls"
version.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
description = "Frontend-agnostic system media controls: MPRIS (mpris-server) on Linux with a DesktopEntry so GNOME shows the app icon; SMTC/MediaRemote (souvlaki) on Windows/macOS"
[dependencies]
log = { workspace = true }
# Notifications (all platforms): the async entry point spawns the HTTP download
# + image resize on `spawn_blocking`, so a tokio runtime must be present.
tokio = { workspace = true }
# Artwork download + cache + (Linux) resize for the notification icon. Matches
# the Tauri notification helpers so output is identical.
reqwest = { workspace = true, features = ["blocking"] }
image = { version = "0.25", default-features = false, features = [
"png",
"jpeg",
"webp",
] }
dirs = "6"
md-5 = { workspace = true }
urlencoding = "2"
# Linux: mpris-server publishes the full MPRIS interface INCLUDING the
# org.mpris.MediaPlayer2.DesktopEntry property (RootInterface::desktop_entry),
# which is the only way GNOME Shell resolves the app icon. souvlaki never sets
# it. tokio feature so the server shares the app's tokio runtime.
[target.'cfg(target_os = "linux")'.dependencies]
mpris-server = "0.8"
async-channel = "2"
# XDG notification portal (goes over D-Bus). Same crate + tokio runtime the
# secret portal already pulls in (qbz-credentials uses ashpd 0.13/tokio).
ashpd = { version = "0.13", default-features = false, features = [
"tokio",
"notification",
] }
# macOS (MediaRemote / MPNowPlayingInfoCenter) + Windows (SMTC) via souvlaki —
# there is no DesktopEntry concept there (macOS keys the icon off the app
# bundle), so souvlaki stays the right tool off-Linux.
[target.'cfg(any(target_os = "macos", target_os = "windows"))'.dependencies]
souvlaki = "0.8"
# macOS desktop notifications (NSUserNotification / UserNotifications). Windows
# is a no-op for now (parity with Tauri, which never implemented it).
notify-rust = "4"