diff --git a/src/bin/cmus-notify.rs b/src/bin/cmus-notify.rs index e659547..f525bbb 100644 --- a/src/bin/cmus-notify.rs +++ b/src/bin/cmus-notify.rs @@ -77,10 +77,12 @@ fn main() { // Update the previous response. previous_response = response; - match notifications_handler.show_notification(events, &previous_response) { - Ok(_) => {} - Err(e) => { - eprintln!("Error: {}", e); + if !events.is_empty() { + match notifications_handler.show_notification(events, &previous_response) { + Ok(_) => {} + Err(e) => { + eprintln!("Error: {}", e); + } } } } diff --git a/src/cmus/events.rs b/src/cmus/events.rs index 574801d..cde1535 100644 --- a/src/cmus/events.rs +++ b/src/cmus/events.rs @@ -1,13 +1,13 @@ -use crate::cmus::player_settings::{AAAMode, Shuffle}; +use crate::cmus::player_settings::{AAAMode, PlayerSettings, Shuffle}; use crate::cmus::{Track, TrackStatus}; #[derive(Debug, PartialEq)] pub enum CmusEvent { - StatusChanged(Track), - TrackChanged(Track), - VolumeChanged { left: u8, right: u8 }, - PositionChanged(u32), - ShuffleChanged(Shuffle), - RepeatChanged(bool), - AAAMode(AAAMode), + StatusChanged(Track, PlayerSettings), + TrackChanged(Track, PlayerSettings), + VolumeChanged(Track, PlayerSettings), + PositionChanged(Track, PlayerSettings), + ShuffleChanged(Track, PlayerSettings), + RepeatChanged(Track, PlayerSettings), + AAAMode(Track, PlayerSettings), } diff --git a/src/cmus/mod.rs b/src/cmus/mod.rs index 164bbfa..d1249b1 100644 --- a/src/cmus/mod.rs +++ b/src/cmus/mod.rs @@ -12,12 +12,12 @@ use std::str::FromStr; use thiserror::Error; use typed_builder::TypedBuilder; -#[derive(Debug, PartialEq, Default)] +#[derive(Debug, PartialEq, Default, Clone)] pub struct TrackMetadata { tags: HashMap, } -#[derive(Debug, PartialEq, Default)] +#[derive(Debug, PartialEq, Default, Clone)] pub enum TrackStatus { Playing, Paused, @@ -25,7 +25,7 @@ pub enum TrackStatus { Stopped, } -#[derive(Debug, TypedBuilder, PartialEq, Default)] +#[derive(Debug, TypedBuilder, PartialEq, Default, Clone)] pub struct Track { pub status: TrackStatus, pub path: String, diff --git a/src/cmus/player_settings.rs b/src/cmus/player_settings.rs index 053793c..b75adce 100644 --- a/src/cmus/player_settings.rs +++ b/src/cmus/player_settings.rs @@ -4,7 +4,7 @@ use log::{debug, info}; use std::num::ParseIntError; use std::str::FromStr; -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone)] pub struct PlayerSettings { pub repeat: bool, pub repeat_current: bool, @@ -13,7 +13,7 @@ pub struct PlayerSettings { pub volume: Volume, } -#[derive(Debug, PartialEq, Default)] +#[derive(Debug, PartialEq, Default, Clone)] pub enum Shuffle { #[default] Off, @@ -21,13 +21,13 @@ pub enum Shuffle { Albums, } -#[derive(Debug, PartialEq, Default)] +#[derive(Debug, PartialEq, Default, Clone)] pub struct Volume { pub left: u8, pub right: u8, } -#[derive(Debug, PartialEq, Default)] +#[derive(Debug, PartialEq, Default, Clone)] pub enum AAAMode { #[default] All, diff --git a/src/cmus/query.rs b/src/cmus/query.rs index 5f09a35..ddf00aa 100644 --- a/src/cmus/query.rs +++ b/src/cmus/query.rs @@ -51,7 +51,7 @@ impl CmusQueryResponse { if self.track_row.is_empty() || self.player_settings_row.is_empty() { #[cfg(feature = "debug")] info!("Cmus response is empty, returning empty events"); - return Err(CmusError::NoEvents) + return Ok(Vec::new()) } let mut events = Vec::new(); @@ -59,6 +59,8 @@ impl CmusQueryResponse { let track = self.track()?; let other_track = other.track()?; + let other_player_settings = other.player_settings()?; + if track != other_track { #[cfg(feature = "debug")] debug!("Track changed: {:?} -> {:?}", other_track, track); @@ -66,7 +68,10 @@ impl CmusQueryResponse { if track.path != other_track.path { #[cfg(feature = "debug")] debug!("Track changed: {:?} -> {:?}", other_track, track); - events.push(CmusEvent::TrackChanged(other_track)); + events.push(CmusEvent::TrackChanged( + other_track.clone(), + other_player_settings.clone(), + )); // We don't need to check for other changes, since the track changed. return Ok(events); } else if track.status != other_track.status { @@ -75,19 +80,24 @@ impl CmusQueryResponse { "Status changed: {:?} -> {:?}", other_track.status, track.status ); - events.push(CmusEvent::StatusChanged(track)); + events.push(CmusEvent::StatusChanged( + track.clone(), + other_player_settings.clone(), + )); } else if track.position != other_track.position { #[cfg(feature = "debug")] debug!( "Position changed: {:?} -> {:?}", other_track.position, track.position ); - events.push(CmusEvent::PositionChanged(other_track.position)); + events.push(CmusEvent::PositionChanged( + track.clone(), + other_player_settings.clone(), + )); } } let player_settings = self.player_settings()?; - let other_player_settings = other.player_settings()?; if player_settings != other_player_settings { #[cfg(feature = "debug")] @@ -103,7 +113,10 @@ impl CmusQueryResponse { other_player_settings.shuffle, player_settings.shuffle ); - events.push(CmusEvent::ShuffleChanged(player_settings.shuffle)); + events.push(CmusEvent::ShuffleChanged( + other_track.clone(), + other_player_settings.clone(), + )); } if player_settings.repeat != other_player_settings.repeat { @@ -113,7 +126,10 @@ impl CmusQueryResponse { other_player_settings.repeat, player_settings.repeat ); - events.push(CmusEvent::RepeatChanged(player_settings.repeat)); + events.push(CmusEvent::RepeatChanged( + other_track.clone(), + other_player_settings.clone(), + )); } if player_settings.aaa_mode != other_player_settings.aaa_mode { @@ -123,7 +139,10 @@ impl CmusQueryResponse { other_player_settings.aaa_mode, player_settings.aaa_mode ); - events.push(CmusEvent::AAAMode(player_settings.aaa_mode)); + events.push(CmusEvent::AAAMode( + other_track.clone(), + other_player_settings.clone(), + )); } if player_settings.volume != other_player_settings.volume { @@ -133,10 +152,7 @@ impl CmusQueryResponse { other_player_settings.volume, player_settings.volume ); - events.push(CmusEvent::VolumeChanged { - left: player_settings.volume.left, - right: player_settings.volume.right, - }); + events.push(CmusEvent::VolumeChanged(other_track, other_player_settings)); } } diff --git a/src/notification.rs b/src/notification.rs index 85dc1ac..1d4b702 100644 --- a/src/notification.rs +++ b/src/notification.rs @@ -1,4 +1,5 @@ use crate::cmus::events::CmusEvent; +use crate::cmus::player_settings::PlayerSettings; use crate::cmus::query::CmusQueryResponse; use crate::cmus::{Track, TrackStatus}; use crate::settings::Settings; @@ -7,6 +8,12 @@ use crate::{process_template_placeholders, track_cover, TrackCover}; use log::{debug, info}; use notify_rust::Notification; +enum Action { + Show, + Update, + None, +} + pub struct NotificationsHandler { cover_set: bool, notification: Notification, @@ -33,26 +40,29 @@ impl NotificationsHandler { //FIXME: Should check if the user has enabled the cover feature or use a static cover. self.update_cover(&events[0], response); + let mut action = Action::None; + for event in events { #[cfg(feature = "debug")] info!("event: {:?}", event); match event { - CmusEvent::StatusChanged(track) => { + CmusEvent::StatusChanged(track, player_settings) => { #[cfg(feature = "debug")] debug!("Status changed: {:?}", track.status); - self.build_status_notification(track); - self.notification.show()?; + action = self.build_status_notification(track, player_settings); } - CmusEvent::TrackChanged(track) => { + CmusEvent::TrackChanged(track, player_settings) => { #[cfg(feature = "debug")] debug!("Track changed: {:?}", track); - self.build_track_notification(track)? + action = self.build_track_notification(track, player_settings); } + CmusEvent::VolumeChanged(track, player_settings) + if self.settings.show_player_notifications => + { + action = self.build_volume_notification(track, player_settings); + } /* - CmusEvent::VolumeChanged { left, right } if settings.show_player_notifications => { - build_volume_notification(left, right, settings, notification)? - } CmusEvent::PositionChanged(position) => todo!(), CmusEvent::ShuffleChanged(shuffle) if settings.show_player_notifications => { build_shuffle_notification(shuffle, settings, notification)? @@ -66,12 +76,26 @@ impl NotificationsHandler { */ _ => {} } + + match action { + Action::Show => { + let _ = self.notification.show()?; + } + Action::None => {} + _ => todo!(), + }; } + + Ok(()) } #[inline(always)] - fn build_status_notification(&mut self, track: Track) { + fn build_status_notification( + &mut self, + track: Track, + player_settings: PlayerSettings, + ) -> Action { // Set the summary and body of the notification. self.notification .summary( @@ -83,25 +107,47 @@ impl NotificationsHandler { .as_str(), ) .timeout(self.settings.status_notification_timeout as i32 * 1000); + Action::Show } #[inline(always)] - fn build_track_notification(&mut self, track: Track) -> Result<(), notify_rust::error::Error> { + fn build_track_notification( + &mut self, + track: Track, + player_settings: PlayerSettings, + ) -> Action { // Set the summary and body of the notification. self.notification .summary(process_template_placeholders(&self.settings.summary, &track).as_str()) .body(process_template_placeholders(&self.settings.body, &track).as_str()); - let n = self.notification.show()?; + Action::Show + } - Ok(()) + #[inline(always)] + fn build_volume_notification( + &mut self, + track: Track, + player_settings: PlayerSettings, + ) -> Action { + self.notification + .summary( + process_template_placeholders(&self.settings.volume_notification_summary, &track) + .as_str(), + ) + .body( + process_template_placeholders(&self.settings.volume_notification_body, &track) + .as_str(), + ); + + Action::Show } #[inline(always)] fn update_cover(&mut self, first_event: &CmusEvent, response: &CmusQueryResponse) { // If the track is changed, we need to update the cover. match first_event { - CmusEvent::TrackChanged(track) => { + CmusEvent::TrackChanged(track, _) => { self.set_cover(track); } _ => { @@ -133,7 +179,7 @@ impl NotificationsHandler { self.settings.force_use_external_cover, self.settings.no_use_external_cover, ) - .set_notification_image(&mut self.notification); + .set_notification_image(&mut self.notification); // Flip the change flag self.cover_set = true; }