diff options
Diffstat (limited to 'src/mpris.rs')
-rw-r--r-- | src/mpris.rs | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/src/mpris.rs b/src/mpris.rs new file mode 100644 index 0000000..3cb29af --- /dev/null +++ b/src/mpris.rs @@ -0,0 +1,101 @@ +use futures_util::StreamExt; +use tokio::{ + sync::mpsc::{self, Sender}, + task::JoinSet, +}; +use zbus::{ + fdo::{DBusProxy, NameOwnerChangedArgs, NameOwnerChangedStream}, + names::OwnedBusName, + Connection, +}; + +use crate::dbus::player::PlayerProxy; + +const IGNORED: [&str; 1] = ["playerctld"]; +const PREFIX: &str = "org.mpris.MediaPlayer2."; + +pub async fn block() -> anyhow::Result<()> { + let mut join_set = JoinSet::new(); + let (tx, mut rx) = mpsc::channel(128); + + let connection = Connection::session().await?; + + let dbus_proxy = DBusProxy::new(&connection).await?; + let names: Vec<OwnedBusName> = dbus_proxy.list_names().await?; + + let players = names.iter().filter(|s| valid_player(s)).collect::<Vec<_>>(); + + for player in players { + tx.send(Message::Add(player.to_string())).await?; + } + + let name_owner_changed = dbus_proxy.receive_name_owner_changed().await?; + + join_set.spawn(listen_name_owner_change(tx.clone(), name_owner_changed)); + + while let Some(msg) = rx.recv().await { + let res = match msg { + Message::Add(s) => add_player(&connection, &s).await, + Message::Remove(s) => remove_player(&s).await, + }; + } + + while let Some(res) = join_set.join_next().await { + res??; + } + + Ok(()) +} + +enum Message { + Add(String), + Remove(String), +} + +fn valid_player(name: &str) -> bool { + name.strip_prefix(PREFIX) + .and_then(|s| s.split('.').next()) + .is_some_and(|s| !IGNORED.contains(&s)) +} + +async fn add_player(connection: &Connection, name: &str) -> Result<(), anyhow::Error> { + dbg!("Adding: {name}"); + let proxy = PlayerProxy::builder(connection) + .destination(name)? + .build() + .await?; + Ok(()) +} + +async fn remove_player(name: &str) -> Result<(), anyhow::Error> { + dbg!("Removing: {name}"); + Ok(()) +} + +async fn listen_name_owner_change( + tx: Sender<Message>, + mut stream: NameOwnerChangedStream<'static>, +) -> anyhow::Result<()> { + let tx = tx.clone(); + while let Some(signal) = stream.next().await { + let Ok(NameOwnerChangedArgs { + name, + old_owner, + new_owner, + .. + }) = signal.args() + else { + continue; + }; + + if !valid_player(&name) { + continue; + } else if old_owner.is_some() { + tx.send(Message::Remove(name.to_string())).await?; + } else if new_owner.is_some() { + tx.send(Message::Add(name.to_string())).await?; + } + } + + Ok(()) +} |