summaryrefslogtreecommitdiffstats
path: root/src/mpris.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mpris.rs')
-rw-r--r--src/mpris.rs101
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(())
+}