diff --git a/README.md b/README.md index 5d40623..730b370 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ You **must** have an existing premium Spotify subscription to use `ncspot`. - [Proxy](#proxy) - [Theming](#theming) - [Track Formatting](#track-formatting) + - [Notification Formatting](#notification-formatting) - [Cover Drawing](#cover-drawing) - [Authentication](#authentication) @@ -349,6 +350,7 @@ Possible configuration values are: | `hide_display_names` | Hides spotify usernames in the library header and on playlists | `true`, `false` | `false` | | `statusbar_format` | Formatting for tracks in the statusbar | See [track_formatting](#track-formatting) | `%artists - %track` | | `[track_format]` | Set active fields shown in Library/Queue views | See [track formatting](#track-formatting) | | +| `[notification_format]` | Set the text displayed in notifications[4] | See [notification formatting](#notification-formatting) | | | `[theme]` | Custom theme | See [custom theme](#theming) | | | `[keybindings]` | Custom keybindings | See [custom keybindings](#custom-keybindings) | | @@ -506,6 +508,19 @@ right = "%album" +### Notification Formatting +`ncspot` also supports customizing the way notifications are displayed +(which appear when compiled with the `notify` feature and `notify = true`). +The title and body of the notification can be set, with `title` and `body`, or the default will be used. +The formatting options are the same as those for [track formatting](#track-formatting) (`%artists`, `%title`, etc) + +Default configuration: +```toml +[notification_format] +title = "%title" +body = "%artists" +``` + ## Cover Drawing When compiled with the `cover` feature, `ncspot` can draw the album art of the diff --git a/src/config.rs b/src/config.rs index 6ad2925..a7ed946 100644 --- a/src/config.rs +++ b/src/config.rs @@ -50,6 +50,21 @@ impl TrackFormat { } } +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +pub struct NotificationFormat { + pub title: Option, + pub body: Option, +} + +impl NotificationFormat { + pub fn default() -> Self { + NotificationFormat { + title: Some(String::from("%title")), + body: Some(String::from("%artists")), + } + } +} + #[derive(Clone, Serialize, Deserialize, Debug, Default)] pub struct ConfigValues { pub command_key: Option, @@ -73,6 +88,7 @@ pub struct ConfigValues { pub cover_max_scale: Option, pub playback_state: Option, pub track_format: Option, + pub notification_format: Option, pub statusbar_format: Option, pub library_tabs: Option>, pub hide_display_names: Option, diff --git a/src/main.rs b/src/main.rs index 753447b..f0d9fba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -175,10 +175,14 @@ async fn main() -> Result<(), String> { println!("Connecting to Spotify.."); let spotify = spotify::Spotify::new(event_manager.clone(), credentials, cfg.clone()); - let queue = Arc::new(queue::Queue::new(spotify.clone(), cfg.clone())); - let library = Arc::new(Library::new(&event_manager, spotify.clone(), cfg.clone())); + let queue = Arc::new(queue::Queue::new( + spotify.clone(), + cfg.clone(), + library.clone(), + )); + #[cfg(feature = "mpris")] let mpris_manager = Arc::new(mpris::MprisManager::new( event_manager.clone(), diff --git a/src/queue.rs b/src/queue.rs index 84bb5f3..b3ed7a7 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -10,10 +10,11 @@ use notify_rust::{Hint, Notification, Urgency}; use rand::prelude::*; use strum_macros::Display; -use crate::config::PlaybackState; +use crate::config::{Config, NotificationFormat, PlaybackState}; +use crate::library::Library; use crate::model::playable::Playable; +use crate::spotify::PlayerEvent; use crate::spotify::Spotify; -use crate::{config::Config, spotify::PlayerEvent}; #[derive(Display, Clone, Copy, PartialEq, Debug, Serialize, Deserialize)] pub enum RepeatSetting { @@ -38,10 +39,11 @@ pub struct Queue { cfg: Arc, #[cfg(feature = "notify")] notification_id: Arc, + library: Arc, } impl Queue { - pub fn new(spotify: Spotify, cfg: Arc) -> Queue { + pub fn new(spotify: Spotify, cfg: Arc, library: Arc) -> Queue { let queue_state = cfg.state().queuestate.clone(); let playback_state = cfg.state().playback_state.clone(); let queue = Queue { @@ -52,6 +54,7 @@ impl Queue { cfg, #[cfg(feature = "notify")] notification_id: Arc::new(AtomicU32::new(0)), + library, }; if let Some(playable) = queue.get_current() { @@ -285,13 +288,27 @@ impl Queue { if self.cfg.values().notify.unwrap_or(false) { let notification_id = self.notification_id.clone(); std::thread::spawn({ - let track_name = track.to_string(); + // use same parser as track_format, Playable::format + let format = self + .cfg + .values() + .notification_format + .clone() + .unwrap_or_default(); + let default_title = NotificationFormat::default().title.unwrap(); + let title = format.title.unwrap_or_else(|| default_title.clone()); + + let default_body = NotificationFormat::default().body.unwrap(); + let body = format.body.unwrap_or_else(|| default_body.clone()); + + let summary_txt = Playable::format(track, &title, self.library.clone()); + let body_txt = Playable::format(track, &body, self.library.clone()); let cover_url = if cfg!(feature = "cover") { track.cover_url() } else { None }; - move || send_notification(&track_name, cover_url, notification_id) + move || send_notification(&summary_txt, &body_txt, cover_url, notification_id) }); } } @@ -432,7 +449,8 @@ impl Queue { #[cfg(feature = "notify")] pub fn send_notification( - track_name: &str, + summary_txt: &str, + body_txt: &str, cover_url: Option, notification_id: Arc, ) { @@ -441,7 +459,8 @@ pub fn send_notification( let mut n = Notification::new(); n.appname("ncspot") .id(current_notification_id) - .summary(track_name); + .summary(summary_txt) + .body(body_txt); // album cover image if let Some(u) = cover_url {