diff options
Diffstat (limited to 'src/printer.rs')
-rw-r--r-- | src/printer.rs | 201 |
1 files changed, 70 insertions, 131 deletions
diff --git a/src/printer.rs b/src/printer.rs index db5a554..5a6b0ae 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -1,8 +1,9 @@ -use std::{collections::HashMap, io::Write, sync::Arc, time::Duration}; +use std::{collections::HashMap, sync::Arc, time::Duration}; use futures_util::stream::StreamExt; +use serde::{Deserialize, Serialize}; use tokio::{ - sync::{Mutex, Notify}, + sync::{watch::Sender, Mutex}, task::{JoinHandle, JoinSet}, }; use zbus::{proxy::PropertyStream, zvariant::OwnedValue}; @@ -21,226 +22,163 @@ const BLACK: &str = "#1d2021"; const YELLOW: &str = "#fabd2f"; const CYAN: &str = "#8ec07c"; -#[derive(Debug, Clone)] -pub enum Signal { - Print, -} - -pub async fn printer(proxy: PlayerProxy<'static>) -> Result<()> { +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 notify = Arc::new(Notify::new()); - - let status = Arc::new(Mutex::new(Status { - title: 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(), - indexes: Vec::new(), - })); + ..Default::default() + }; + + wtx.send_modify(|s| *s = status); process_metadata( - notify.clone(), - status.clone(), + wtx.clone(), proxy.metadata().await?, &mut rotator, + &mut None, ) .await; - notify.notify_one(); - join_set.spawn(metadata( - notify.clone(), + wtx.clone(), proxy.receive_metadata_changed().await, - status.clone(), rotator, )); join_set.spawn(can_go_previous( - notify.clone(), + wtx.clone(), proxy.receive_can_go_previous_changed().await, - status.clone(), )); join_set.spawn(playback_state( - notify.clone(), + wtx.clone(), proxy.receive_playback_status_changed().await, - status.clone(), )); join_set.spawn(can_go_next( - notify.clone(), + wtx.clone(), proxy.receive_can_go_next_changed().await, - status.clone(), )); - join_set.spawn(volume( - notify.clone(), - proxy.receive_volume_changed().await, - status.clone(), - )); + join_set.spawn(volume(wtx.clone(), proxy.receive_volume_changed().await)); - loop { - notify.notified().await; - let mut status = status.lock().await; - - //let (color, background) = match proxy.playback_status().await.ok() { - // Some(PlaybackStatus::Playing) => (Some(BLACK.into()), Some(CYAN.into())), - // Some(PlaybackStatus::Paused) => (Some(BLACK.into()), Some(YELLOW.into())), - // Some(PlaybackStatus::Stopped) => (None, None), - //}; - - //let s = match instance { - // Instance::Icon => " ", - // Instance::Title => &status.title, - // Instance::Prev => " ", - // Instance::Play => " ", - // Instance::Pause => " ", - // Instance::Next => " ", - // Instance::Volume => { - // if let Some(volume) = self.volume.map(|v| (v * 100_f64) as u32) { - // match volume { - // v @ 66.. => &format!(" {v}% "), - // v @ 33.. => &format!(" {v}% "), - // v @ 0.. => &format!(" {v}% "), - // } - // } - // } - //}; - // - //let block = Block { - // full_text, - // ..Default::default() - //}; - - let mut w = std::io::stdout().lock(); - let mut v = serde_json::to_vec(&status.build()).unwrap(); - v.push(b'\n'); - w.write_all(&v)?; - w.flush()?; + while let Some(res) = join_set.join_next().await { + res??; } + + Ok(()) } async fn process_metadata( - notify: Arc<Notify>, - status_lock: StatusLock, + wtx: Sender<Status>, metadata: HashMap<String, OwnedValue>, rotator: &mut Option<JoinHandle<Result<()>>>, -) -> Option<()> { - let title: String = metadata - .get("xesam:title")? - .try_to_owned() - .ok()? - .try_into() - .ok()?; - - if (status_lock.lock().await) - .title - .as_ref() - .is_some_and(|s| *s == title) - { - return None; + 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; } - if let Some(h) = rotator.take() { - h.abort() + *old_title = title.clone(); + let Some(title) = title else { + wtx.send_modify(|s| { + s.title = None; + }); + return; }; - let status = status_lock.clone(); - 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; - let mut status = status.lock().await; - status.title = Some(chars[0..10].iter().collect()); - notify.notify_one(); + wtx.send_modify(|s| s.title = Some(chars[0..10].iter().collect())); chars.rotate_left(1); } })); } else { - let mut status = status.lock().await; - status.title = Some(title); - notify.notify_one(); + wtx.send_modify(|s| s.title = Some(title)); } - - Some(()) } async fn metadata( - notify: Arc<Notify>, + wtx: Sender<Status>, mut stream: PropertyStream<'_, HashMap<String, OwnedValue>>, - status_lock: StatusLock, 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(notify.clone(), status_lock.clone(), metadata, &mut rotator).await; + process_metadata(wtx.clone(), metadata, &mut rotator, &mut old_title).await }; } Ok(()) } -async fn can_go_previous( - notify: Arc<Notify>, - mut stream: PropertyStream<'_, bool>, - status_lock: StatusLock, -) -> Result<()> { +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 { - let mut status = status_lock.lock().await; - status.can_go_previous = val; - notify.notify_one(); + wtx.send_modify(|status| status.can_go_previous = val); }; } Ok(()) } async fn playback_state( - notify: Arc<Notify>, + wtx: Sender<Status>, mut stream: PropertyStream<'_, PlaybackStatus>, - status_lock: StatusLock, ) -> Result<()> { while let Some(signal) = stream.next().await { if let Ok(val) = signal.get().await { - let mut status = status_lock.lock().await; - status.playback_status = val; - notify.notify_one(); + 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( - notify: Arc<Notify>, - mut stream: PropertyStream<'_, bool>, - status_lock: StatusLock, -) -> Result<()> { +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 { - let mut status = status_lock.lock().await; - status.can_go_next = val; - notify.notify_one(); + wtx.send_modify(|status| status.can_go_next = val); }; } Ok(()) } -async fn volume( - notify: Arc<Notify>, - mut stream: PropertyStream<'_, f64>, - status_lock: StatusLock, -) -> Result<()> { +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 { - let mut status = status_lock.lock().await; - status.volume = Some(val); - notify.notify_one(); + wtx.send_modify(|status| status.volume = Some(val)); }; } Ok(()) @@ -258,14 +196,15 @@ pub enum Component { Space, } -#[derive(Debug, Clone, Default)] +#[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>, - indexes: Vec<(usize, Component)>, + color: Option<String>, + background: Option<String>, } impl Status { |