1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
use std::sync::Arc;
use futures_util::StreamExt;
use tokio::{sync::Mutex, task::JoinSet};
use zbus::Connection;
pub use crate::{
component::{Button, Component, Update},
error::{Error, Result},
};
use crate::{
dbus::{player::PlayerProxy, playerctld::PlayerctldProxy},
i3bar::{Block, Click},
};
pub mod component;
pub mod dbus;
pub mod error;
pub mod i3bar;
const IGNORED: [&str; 2] = ["playerctld", "kdeconnect"];
pub async fn run<C>() -> Result<(), Error>
where
C: Component,
{
let conn = Connection::session().await?;
tokio::spawn(listeners::<C>(conn.clone()));
for click in std::io::stdin()
.lines()
.map_while(Result::ok)
.flat_map(|s| serde_json::from_str::<Click>(&s))
{
if let Err(err) = <<C as Component>::Handler as Button>::handle(conn.clone(), click).await {
eprintln!("Error running button handler: {err}");
}
}
Ok(())
}
async fn listeners<C>(conn: Connection) -> Result<(), Error>
where
C: Component,
{
let mut join_set = JoinSet::new();
let (tx_player, mut rx_player) = tokio::sync::mpsc::channel(128);
let (tx_status, mut rx_status) = tokio::sync::mpsc::channel(128);
let (tx_value, mut rx_value) = tokio::sync::mpsc::channel(128);
let proxy = PlayerctldProxy::builder(&conn).build().await?;
tokio::spawn(async move {
let mut last = proxy
.player_names()
.await?
.into_iter()
.find(|s| s.split('.').nth(3).is_some_and(|s| !IGNORED.contains(&s)))
.unwrap_or_default();
tx_player.send(last.clone()).await?;
let mut stream = proxy.receive_active_player_change_end().await?;
while let Some(signal) = stream.next().await {
let name = signal.args()?.name.to_owned();
if name != last
&& name
.split('.')
.nth(3)
.is_some_and(|s| !IGNORED.contains(&s))
{
last.clone_from(&name);
tx_player.send(name).await?;
}
}
Result::<_, Error>::Ok(())
});
let block = Arc::new(Mutex::new(Block {
name: Some(format!("mpris-{}", C::NAME)),
..Default::default()
}));
loop {
let updated = tokio::select! {
Some(name) = rx_player.recv() => {
join_set.shutdown().await;
let mut block = block.lock().await;
block.full_text = String::new();
block.instance = None;
if !name.is_empty() {
block.instance.clone_from(&Some(name.clone()));
let proxy = PlayerProxy::builder(&conn)
.destination(name)?
.build()
.await?;
join_set.spawn(<<C as Component>::Colorer as Update>::listen(tx_status.clone(), proxy.clone()));
join_set.spawn(<<C as Component>::Updater as Update>::listen(tx_value.clone(), proxy));
false
} else {
true
}
}
Some(color) = rx_status.recv() => <<C as Component>::Colorer as Update>::update(color, block.clone()).await?,
Some(value) = rx_value.recv() => <<C as Component>::Updater as Update>::update(value, block.clone()).await?
};
if updated {
let s = block.lock().await;
s.write_stdout()?;
}
}
}
|