summaryrefslogtreecommitdiffstats
path: root/src/bin/title.rs
diff options
context:
space:
mode:
authorToby Vincent <tobyv@tobyvin.dev>2024-07-19 17:14:42 -0500
committerToby Vincent <tobyv@tobyvin.dev>2024-07-19 17:14:42 -0500
commite12cd9dfb9f20f432edd69414b4ff83325226995 (patch)
tree986e640f3c6355215d36958476be605819da1c22 /src/bin/title.rs
parent28bcf144224838e9e93d5926dcdbb20a4d45a8bf (diff)
feat: working
Diffstat (limited to 'src/bin/title.rs')
-rw-r--r--src/bin/title.rs183
1 files changed, 95 insertions, 88 deletions
diff --git a/src/bin/title.rs b/src/bin/title.rs
index 165e715..3daee26 100644
--- a/src/bin/title.rs
+++ b/src/bin/title.rs
@@ -1,113 +1,120 @@
-use std::{sync::Arc, time::Duration};
+use std::{collections::HashMap, sync::Arc, time::Duration};
-use futures_util::StreamExt;
use i3blocks::{
- color_listener,
- dbus::{player::PlayerProxy, playerctld::PlayerctldProxy},
+ dbus::player::{PlaybackStatus, PlayerProxy},
i3bar::Block,
- player_listener, Error,
+ Component, Error, Update,
};
use tokio::{
sync::{mpsc::Sender, Mutex},
task::{AbortHandle, JoinSet},
};
-use zbus::Connection;
+use zbus::zvariant::OwnedValue;
const TICK_RATE: Duration = Duration::from_millis(500);
#[tokio::main]
async fn main() -> Result<(), main_error::MainError> {
- 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 conn = Connection::session().await?;
- let proxy = PlayerctldProxy::builder(&conn).build().await?;
-
- tokio::spawn(player_listener(tx_player, proxy));
-
- let status: Arc<Mutex<Block>> = Default::default();
- let mut rotator: Option<AbortHandle> = None;
-
- let mut interval = tokio::time::interval(TICK_RATE);
- let mut chars = Vec::new();
-
- loop {
- tokio::select! {
- Some(name) = rx_player.recv() => {
- join_set.shutdown().await;
- if name.is_empty() {
- let mut status = status.lock().await;
- status.full_text = Default::default();
- } else {
- let proxy = PlayerProxy::builder(&conn)
- .destination(name)?
- .build()
- .await?;
- join_set.spawn(color_listener(tx_status.clone(), proxy.clone()));
- join_set.spawn(value_listener(tx_value.clone(), proxy));
- }
- }
- Some((color, background)) = rx_status.recv() => {
- let mut status = status.lock().await;
- status.color = color;
- status.background = background;
- }
- Some(mut value) = rx_value.recv() => {
- if let Some(h) = rotator.take() {
- h.abort();
- }
+ i3blocks::run::<Title>(Default::default())
+ .await
+ .map_err(Into::into)
+}
- value.push(' ');
- if value.len() >= 10 {
- chars = value.chars().collect::<Vec<char>>();
- let mut status = status.lock().await;
- status.full_text = format!("{} ", String::from_iter(chars[0..10].iter()));
- } else {
- chars = Default::default();
- let mut status = status.lock().await;
- status.full_text = value;
- }
- }
- _ = interval.tick(), if !chars.is_empty() => {
- let mut status = status.lock().await;
- status.full_text = format!("{} ", String::from_iter(chars[0..10].iter()));
- chars.rotate_left(1);
+pub struct Title;
+
+impl Component for Title {
+ const NAME: &'static str = "title";
+ type Updater = Self;
+ type Colorer = PlaybackStatus;
+ type Handler = ();
+}
+
+impl Update for Title {
+ type Value = String;
+
+ async fn listen(tx: Sender<Self::Value>, proxy: PlayerProxy<'_>) -> Result<(), Error> {
+ use futures_util::StreamExt;
+
+ let mut join_set = JoinSet::new();
+ let mut rotator = None;
+ let mut old_title = None;
+
+ Self::handle_metadata(
+ tx.clone(),
+ proxy.metadata().await?,
+ &mut old_title,
+ &mut rotator,
+ &mut join_set,
+ )
+ .await?;
+
+ let mut stream = proxy.receive_metadata_changed().await;
+ while let Some(signal) = stream.next().await {
+ if let Ok(metadata) = signal.get().await {
+ Self::handle_metadata(
+ tx.clone(),
+ metadata,
+ &mut old_title,
+ &mut rotator,
+ &mut join_set,
+ )
+ .await?;
}
}
+ Ok(())
+ }
+
+ async fn update(mut value: Self::Value, block: Arc<Mutex<Block>>) -> Result<bool, Error> {
+ value.push(' ');
+ let mut block = block.lock().await;
+ block.full_text = value;
- let s = status.lock().await;
- s.write_stdout()?;
+ Ok(true)
}
}
-pub async fn value_listener(tx: Sender<String>, proxy: PlayerProxy<'_>) -> Result<(), Error> {
- let mut old_title = if let Some(value) = proxy.metadata().await?.get("xesam:title") {
- let title: String = value.try_to_owned()?.try_into()?;
- tx.send(title.clone()).await?;
- Some(title)
- } else {
- None
- };
-
- let mut stream = proxy.receive_metadata_changed().await;
- while let Some(signal) = stream.next().await {
- if let Ok(value) = signal.get().await {
- let Some(owned_value) = value.get("xesam:title") else {
- continue;
- };
-
- let title: String = owned_value.try_to_owned()?.try_into()?;
-
- if old_title.as_ref().is_some_and(|s| *s == title) {
- continue;
- }
+impl Title {
+ async fn handle_metadata(
+ tx: Sender<<<Self as Component>::Updater as Update>::Value>,
+ metadata: HashMap<String, OwnedValue>,
+ old_title: &mut Option<String>,
+ rotator: &mut Option<AbortHandle>,
+ join_set: &mut JoinSet<Result<(), Error>>,
+ ) -> Result<(), Error> {
+ let Some(owned_value) = metadata.get("xesam:title") else {
+ return Ok(());
+ };
+
+ let title: String = owned_value.try_to_owned()?.try_into()?;
+
+ if old_title.as_ref().is_some_and(|s| *s == title) {
+ return Ok(());
+ }
+
+ if let Some(h) = rotator.take() {
+ h.abort();
+ };
- old_title = Some(title.clone());
+ *old_title = Some(title.clone());
+
+ if title.len() >= 10 {
+ let mut chars = title.clone().chars().collect::<Vec<char>>();
+ let tx = tx.clone();
+
+ *rotator = Some(join_set.spawn(async move {
+ let mut interval = tokio::time::interval(TICK_RATE);
+ loop {
+ interval.tick().await;
+ tx.send(format!("{} ", String::from_iter(chars[0..10].iter())))
+ .await
+ .unwrap();
+ chars.rotate_left(1);
+ }
+ }));
+ } else {
tx.send(title).await?;
}
+
+ Ok(())
}
- Ok(())
}