summaryrefslogtreecommitdiffstats
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs139
1 files changed, 90 insertions, 49 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 0bdb7de..35e7f5b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,68 +1,109 @@
-use dbus::{
- player::{PlaybackStatus, PlayerProxy},
- playerctld::PlayerctldProxy,
-};
-pub use error::{Error, Result};
+use std::sync::Arc;
use futures_util::StreamExt;
-use tokio::sync::mpsc::Sender;
+use tokio::{sync::Mutex, task::JoinSet};
+use zbus::Connection;
-pub mod color;
+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 BLACK: &str = "#1d2021";
-const YELLOW: &str = "#fabd2f";
-const CYAN: &str = "#8ec07c";
-
const IGNORED: [&str; 2] = ["playerctld", "kdeconnect"];
-impl From<PlaybackStatus> for (Option<String>, Option<String>) {
- fn from(value: PlaybackStatus) -> Self {
- match value {
- PlaybackStatus::Playing => (Some(BLACK.into()), Some(CYAN.into())),
- PlaybackStatus::Paused => (Some(BLACK.into()), Some(YELLOW.into())),
- PlaybackStatus::Stopped => (None, None),
- }
- }
-}
+pub async fn run<C>(mut block: Block) -> Result<(), Error>
+where
+ C: Component,
+{
+ let conn = Connection::session().await?;
-pub async fn color_listener(
- tx: Sender<(Option<String>, Option<String>)>,
- proxy: PlayerProxy<'_>,
-) -> Result<()> {
- let mut stream = proxy.receive_playback_status_changed().await;
- while let Some(signal) = stream.next().await {
- if let Ok(value) = signal.get().await {
- tx.send(value.into()).await?;
- }
+ block.name = Some(format!("mpris-{}", C::NAME));
+ tokio::spawn(listeners::<C>(conn.clone(), block));
+
+ for click in std::io::stdin()
+ .lines()
+ .map_while(Result::ok)
+ .flat_map(|s| serde_json::from_str::<Click>(&s))
+ {
+ <<C as Component>::Handler as Button>::handle(conn.clone(), click).await?;
}
+
Ok(())
}
-pub async fn player_listener(tx: Sender<String>, proxy: PlayerctldProxy<'_>) -> Result<(), Error> {
- let mut last = proxy
- .player_names()
- .await?
- .into_iter()
- .next()
- .unwrap_or_default();
+async fn listeners<C>(conn: Connection, block: Block) -> 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?;
- tx.send(last.clone()).await?;
+ tokio::spawn(async move {
+ let mut last = proxy
+ .player_names()
+ .await?
+ .into_iter()
+ .next()
+ .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));
- 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.send(name).await?;
+ loop {
+ let updated = tokio::select! {
+ Some(name) = rx_player.recv() => {
+ join_set.shutdown().await;
+ if name.is_empty() {
+ let mut block = block.lock().await;
+ block.full_text = String::new();
+ block.instance = None;
+ true
+ } else {
+ 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
+ }
+ }
+ 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()?;
}
}
- Ok(())
}