feat(qbzd): MPRIS metadata from CoreEvent::TrackStarted

Spawns a dedicated event bus listener that updates MPRIS metadata
(title, artist, album, duration) when a new track starts playing.
Clears metadata on logout.

MPRIS now fully functional: media keys (play/pause/next/prev) +
metadata display (track info in system media widget).

cc
This commit is contained in:
vicrodh committed 2026-04-09 05:35:52 -06:00
1 parent a5efd6ae19
commit b3e5be39eb
1 file changed
+40 -1
+40 -1
View File
@@ -106,7 +106,12 @@ pub async fn run(mut config: DaemonConfig) -> Result<(), String> {
};
// Start playback state polling loop (broadcasts to event bus + MPRIS)
spawn_playback_loop(daemon.core.clone(), daemon.event_bus.clone(), mpris_handle);
spawn_playback_loop(daemon.core.clone(), daemon.event_bus.clone(), mpris_handle.clone());
// Spawn MPRIS metadata updater (listens to event bus for TrackStarted)
if let Some(ref mc) = mpris_handle {
spawn_mpris_metadata_updater(daemon.event_bus.subscribe(), mc.clone());
}
// Register mDNS service for LAN discovery
let _mdns_handle = if config.mdns.enabled {
@@ -248,6 +253,40 @@ fn register_mdns(config: &DaemonConfig) -> Result<mdns_sd::ServiceDaemon, String
Ok(mdns)
}
/// Listen for CoreEvent::TrackStarted on the event bus and update MPRIS metadata.
fn spawn_mpris_metadata_updater(
mut rx: broadcast::Receiver<DaemonEvent>,
mc: Arc<std::sync::Mutex<souvlaki::MediaControls>>,
) {
tokio::spawn(async move {
loop {
match rx.recv().await {
Ok(DaemonEvent::Core(qbz_models::CoreEvent::TrackStarted { track, .. })) => {
crate::mpris::update_mpris_metadata(
&mc,
&track.title,
&track.artist,
&track.album,
track.duration_secs,
);
log::debug!("[qbzd/mpris] Metadata: {} - {}", track.artist, track.title);
}
Ok(DaemonEvent::Core(qbz_models::CoreEvent::LoggedOut)) => {
// Clear metadata on logout
if let Ok(mut controls) = mc.lock() {
let _ = controls.set_playback(souvlaki::MediaPlayback::Stopped);
}
}
Err(broadcast::error::RecvError::Lagged(n)) => {
log::debug!("[qbzd/mpris] Lagged {} events", n);
}
Err(broadcast::error::RecvError::Closed) => break,
_ => {}
}
}
});
}
/// Spawn the playback state polling loop.
/// Reads player state and broadcasts PlaybackSnapshot events.
/// Also updates MPRIS metadata when track changes.