diff options
author | Toby Vincent <tobyv@tobyvin.dev> | 2024-07-19 17:14:42 -0500 |
---|---|---|
committer | Toby Vincent <tobyv@tobyvin.dev> | 2024-07-19 17:14:42 -0500 |
commit | e12cd9dfb9f20f432edd69414b4ff83325226995 (patch) | |
tree | 986e640f3c6355215d36958476be605819da1c22 /src/printer.rs | |
parent | 28bcf144224838e9e93d5926dcdbb20a4d45a8bf (diff) |
feat: working
Diffstat (limited to 'src/printer.rs')
-rw-r--r-- | src/printer.rs | 255 |
1 files changed, 0 insertions, 255 deletions
diff --git a/src/printer.rs b/src/printer.rs deleted file mode 100644 index 5a6b0ae..0000000 --- a/src/printer.rs +++ /dev/null @@ -1,255 +0,0 @@ -use std::{collections::HashMap, sync::Arc, time::Duration}; - -use futures_util::stream::StreamExt; -use serde::{Deserialize, Serialize}; -use tokio::{ - sync::{watch::Sender, Mutex}, - task::{JoinHandle, JoinSet}, -}; -use zbus::{proxy::PropertyStream, zvariant::OwnedValue}; - -use crate::{ - dbus::player::{PlaybackStatus, PlayerProxy}, - i3bar::Block, - Result, -}; - -type StatusLock = Arc<Mutex<Status>>; - -const TICK_RATE: Duration = Duration::from_millis(500); - -const BLACK: &str = "#1d2021"; -const YELLOW: &str = "#fabd2f"; -const CYAN: &str = "#8ec07c"; - -pub async fn printer( - proxy: PlayerProxy<'static>, - wtx: tokio::sync::watch::Sender<Status>, -) -> Result<()> { - let mut join_set: JoinSet<Result<()>> = JoinSet::new(); - let mut rotator = None; - - let status = Status { - can_go_previous: proxy.can_go_previous().await.unwrap_or_default(), - playback_status: proxy.playback_status().await.unwrap_or_default(), - can_go_next: proxy.can_go_next().await.unwrap_or_default(), - volume: proxy.volume().await.ok(), - ..Default::default() - }; - - wtx.send_modify(|s| *s = status); - - process_metadata( - wtx.clone(), - proxy.metadata().await?, - &mut rotator, - &mut None, - ) - .await; - - join_set.spawn(metadata( - wtx.clone(), - proxy.receive_metadata_changed().await, - rotator, - )); - - join_set.spawn(can_go_previous( - wtx.clone(), - proxy.receive_can_go_previous_changed().await, - )); - - join_set.spawn(playback_state( - wtx.clone(), - proxy.receive_playback_status_changed().await, - )); - - join_set.spawn(can_go_next( - wtx.clone(), - proxy.receive_can_go_next_changed().await, - )); - - join_set.spawn(volume(wtx.clone(), proxy.receive_volume_changed().await)); - - while let Some(res) = join_set.join_next().await { - res??; - } - - Ok(()) -} - -async fn process_metadata( - wtx: Sender<Status>, - metadata: HashMap<String, OwnedValue>, - rotator: &mut Option<JoinHandle<Result<()>>>, - old_title: &mut Option<String>, -) { - let title: Option<String> = metadata - .get("xesam:title") - .and_then(|o| o.try_to_owned().ok()) - .and_then(|o| o.try_into().ok()); - - if *old_title == title { - return; - } - - *old_title = title.clone(); - let Some(title) = title else { - wtx.send_modify(|s| { - s.title = None; - }); - return; - }; - - if title.len() > 10 { - if let Some(h) = rotator.take() { - h.abort() - }; - - let wtx = wtx.clone(); - *rotator = Some(tokio::spawn(async move { - let mut interval = tokio::time::interval(TICK_RATE); - let mut chars = title.chars().collect::<Vec<char>>(); - chars.push(' '); - loop { - interval.tick().await; - wtx.send_modify(|s| s.title = Some(chars[0..10].iter().collect())); - chars.rotate_left(1); - } - })); - } else { - wtx.send_modify(|s| s.title = Some(title)); - } -} - -async fn metadata( - wtx: Sender<Status>, - mut stream: PropertyStream<'_, HashMap<String, OwnedValue>>, - mut rotator: Option<JoinHandle<Result<()>>>, -) -> Result<()> { - let mut old_title = None; - while let Some(signal) = stream.next().await { - if let Ok(metadata) = signal.get().await { - process_metadata(wtx.clone(), metadata, &mut rotator, &mut old_title).await - }; - } - Ok(()) -} - -async fn can_go_previous(wtx: Sender<Status>, mut stream: PropertyStream<'_, bool>) -> Result<()> { - while let Some(signal) = stream.next().await { - if let Ok(val) = signal.get().await { - wtx.send_modify(|status| status.can_go_previous = val); - }; - } - Ok(()) -} - -async fn playback_state( - wtx: Sender<Status>, - mut stream: PropertyStream<'_, PlaybackStatus>, -) -> Result<()> { - while let Some(signal) = stream.next().await { - if let Ok(val) = signal.get().await { - let (color, background) = match val { - PlaybackStatus::Playing => (Some(BLACK.into()), Some(CYAN.into())), - PlaybackStatus::Paused => (Some(BLACK.into()), Some(YELLOW.into())), - PlaybackStatus::Stopped => (None, None), - }; - - wtx.send_modify(|status| { - status.playback_status = val; - status.color = color; - status.background = background; - }); - } - } - Ok(()) -} - -async fn can_go_next(wtx: Sender<Status>, mut stream: PropertyStream<'_, bool>) -> Result<()> { - while let Some(signal) = stream.next().await { - if let Ok(val) = signal.get().await { - wtx.send_modify(|status| status.can_go_next = val); - }; - } - Ok(()) -} - -async fn volume(wtx: Sender<Status>, mut stream: PropertyStream<'_, f64>) -> Result<()> { - while let Some(signal) = stream.next().await { - if let Ok(val) = signal.get().await { - wtx.send_modify(|status| status.volume = Some(val)); - }; - } - Ok(()) -} - -#[derive(Debug, Clone, Copy)] -pub enum Component { - Icon, - Title, - Prev, - Play, - Pause, - Next, - Volume, - Space, -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct Status { - title: Option<String>, - can_go_previous: bool, - playback_status: PlaybackStatus, - can_go_next: bool, - volume: Option<f64>, - color: Option<String>, - background: Option<String>, -} - -impl Status { - fn build(&mut self) -> Block { - let mut full_text = String::new(); - full_text.push_str(" "); - - if let Some(title) = self.title.as_ref() { - full_text.push_str(title); - full_text.push(' '); - } - - if self.can_go_previous { - full_text.push_str(" "); - } - - if self.playback_status == PlaybackStatus::Playing { - full_text.push_str(" "); - } else { - full_text.push_str(" "); - } - - if self.can_go_next { - full_text.push_str(" "); - } - - if let Some(volume) = self.volume.map(|v| (v * 100_f64) as u32) { - match volume { - v @ 66.. => full_text.push_str(&format!(" {v}% ")), - v @ 33.. => full_text.push_str(&format!(" {v}% ")), - v @ 0.. => full_text.push_str(&format!(" {v}% ")), - } - } - - let (color, background) = match self.playback_status { - PlaybackStatus::Playing => (Some(BLACK.into()), Some(CYAN.into())), - PlaybackStatus::Paused => (Some(BLACK.into()), Some(YELLOW.into())), - PlaybackStatus::Stopped => (None, None), - }; - - Block { - full_text, - color, - background, - ..Default::default() - } - } -} |