implemented signals for mpris
This commit is contained in:
+78
-40
@@ -201,39 +201,99 @@ impl MprisDaemon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn listen_loop(tx: &watch::Sender<MprisState>) -> anyhow::Result<()> {
|
async fn listen_loop(tx: &watch::Sender<MprisState>) -> anyhow::Result<()> {
|
||||||
|
use futures::StreamExt;
|
||||||
|
|
||||||
let connection = Connection::session().await?;
|
let connection = Connection::session().await?;
|
||||||
|
|
||||||
info!("Connected to D-Bus for MPRIS monitoring");
|
info!("Connected to D-Bus for MPRIS monitoring");
|
||||||
|
|
||||||
// Periodically poll for the active player and update the MPRIS state.
|
|
||||||
// This avoids complex dynamic signal tracking across ephemeral player instances.
|
|
||||||
|
|
||||||
let dbus_proxy = DBusProxy::new(&connection).await?;
|
let dbus_proxy = DBusProxy::new(&connection).await?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
// Discovery pass: find an active MPRIS player.
|
||||||
let names = dbus_proxy.list_names().await?;
|
let names = dbus_proxy.list_names().await?;
|
||||||
let mut active_player = None;
|
let active_player = names
|
||||||
|
.into_iter()
|
||||||
|
.find(|n| n.starts_with("org.mpris.MediaPlayer2."));
|
||||||
|
|
||||||
for name in names {
|
let Some(player_name) = active_player else {
|
||||||
if name.starts_with("org.mpris.MediaPlayer2.") {
|
send_stopped_if_changed(tx);
|
||||||
active_player = Some(name);
|
// No player — wait and re-discover.
|
||||||
break; // Just grab the first active player for now
|
tokio::time::sleep(Duration::from_secs(5)).await;
|
||||||
}
|
continue;
|
||||||
}
|
};
|
||||||
|
|
||||||
if let Some(player_name) = active_player {
|
let player_proxy = match MprisPlayerProxy::builder(&connection)
|
||||||
if let Ok(player_proxy) = MprisPlayerProxy::builder(&connection)
|
|
||||||
.destination(player_name.clone())?
|
.destination(player_name.clone())?
|
||||||
.build()
|
.build()
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
let status = player_proxy.playback_status().await.unwrap_or_default();
|
Ok(p) => p,
|
||||||
let metadata = player_proxy.metadata().await.unwrap_or_default();
|
Err(_) => {
|
||||||
|
tokio::time::sleep(Duration::from_secs(2)).await;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initial fetch and then signal-driven updates via PropertiesChanged.
|
||||||
|
update_from_player(&player_proxy, tx).await;
|
||||||
|
|
||||||
|
let mut status_stream = player_proxy.receive_playback_status_changed().await;
|
||||||
|
let mut metadata_stream = player_proxy.receive_metadata_changed().await;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
tokio::select! {
|
||||||
|
Some(_) = status_stream.next() => {
|
||||||
|
update_from_player(&player_proxy, tx).await;
|
||||||
|
}
|
||||||
|
Some(_) = metadata_stream.next() => {
|
||||||
|
update_from_player(&player_proxy, tx).await;
|
||||||
|
}
|
||||||
|
_ = tokio::time::sleep(Duration::from_secs(10)) => {
|
||||||
|
// Heartbeat: verify the player is still on the bus.
|
||||||
|
let current = dbus_proxy.list_names().await.unwrap_or_default();
|
||||||
|
if !current.iter().any(|n| n == &player_name) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update_from_player(player: &MprisPlayerProxy<'_>, tx: &watch::Sender<MprisState>) {
|
||||||
|
let status = player.playback_status().await.unwrap_or_default();
|
||||||
|
let metadata = player.metadata().await.unwrap_or_default();
|
||||||
|
|
||||||
let is_playing = status == "Playing";
|
let is_playing = status == "Playing";
|
||||||
let is_paused = status == "Paused";
|
let is_paused = status == "Paused";
|
||||||
let is_stopped = status == "Stopped";
|
let is_stopped = status == "Stopped";
|
||||||
|
|
||||||
|
let (artist, title, album) = parse_metadata(&metadata);
|
||||||
|
|
||||||
|
let current = tx.borrow();
|
||||||
|
if current.is_playing != is_playing
|
||||||
|
|| current.is_paused != is_paused
|
||||||
|
|| current.is_stopped != is_stopped
|
||||||
|
|| current.title != title
|
||||||
|
|| current.artist != artist
|
||||||
|
|| current.album != album
|
||||||
|
{
|
||||||
|
drop(current);
|
||||||
|
let _ = tx.send(MprisState {
|
||||||
|
is_playing,
|
||||||
|
is_paused,
|
||||||
|
is_stopped,
|
||||||
|
artist,
|
||||||
|
title,
|
||||||
|
album,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_metadata(
|
||||||
|
metadata: &std::collections::HashMap<String, zbus::zvariant::Value<'_>>,
|
||||||
|
) -> (String, String, String) {
|
||||||
let mut artist = String::new();
|
let mut artist = String::new();
|
||||||
let mut title = String::new();
|
let mut title = String::new();
|
||||||
let mut album = String::new();
|
let mut album = String::new();
|
||||||
@@ -262,27 +322,10 @@ impl MprisDaemon {
|
|||||||
album = a.to_string();
|
album = a.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only send if changed
|
(artist, title, album)
|
||||||
let current = tx.borrow();
|
|
||||||
if current.is_playing != is_playing
|
|
||||||
|| current.is_paused != is_paused
|
|
||||||
|| current.is_stopped != is_stopped
|
|
||||||
|| current.title != title
|
|
||||||
|| current.artist != artist
|
|
||||||
|| current.album != album
|
|
||||||
{
|
|
||||||
drop(current); // Drop borrow before send
|
|
||||||
let _ = tx.send(MprisState {
|
|
||||||
is_playing,
|
|
||||||
is_paused,
|
|
||||||
is_stopped,
|
|
||||||
artist,
|
|
||||||
title,
|
|
||||||
album,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
fn send_stopped_if_changed(tx: &watch::Sender<MprisState>) {
|
||||||
let current = tx.borrow();
|
let current = tx.borrow();
|
||||||
if !current.is_stopped || !current.title.is_empty() {
|
if !current.is_stopped || !current.title.is_empty() {
|
||||||
drop(current);
|
drop(current);
|
||||||
@@ -296,8 +339,3 @@ impl MprisDaemon {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user