Add notification customization (#893)
* Add custom notification formatting * Added `notification_format` to README * cleaned up code formatting * Fix typo Co-authored-by: Henrik Friedrichsen <henrik@affekt.org>
This commit is contained in:
15
README.md
15
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<sup>[4]</sup> | 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"
|
||||
|
||||
</details>
|
||||
|
||||
### 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
|
||||
|
||||
@@ -50,6 +50,21 @@ impl TrackFormat {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
|
||||
pub struct NotificationFormat {
|
||||
pub title: Option<String>,
|
||||
pub body: Option<String>,
|
||||
}
|
||||
|
||||
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<char>,
|
||||
@@ -73,6 +88,7 @@ pub struct ConfigValues {
|
||||
pub cover_max_scale: Option<f32>,
|
||||
pub playback_state: Option<PlaybackState>,
|
||||
pub track_format: Option<TrackFormat>,
|
||||
pub notification_format: Option<NotificationFormat>,
|
||||
pub statusbar_format: Option<String>,
|
||||
pub library_tabs: Option<Vec<LibraryTab>>,
|
||||
pub hide_display_names: Option<bool>,
|
||||
|
||||
@@ -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(),
|
||||
|
||||
33
src/queue.rs
33
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<Config>,
|
||||
#[cfg(feature = "notify")]
|
||||
notification_id: Arc<AtomicU32>,
|
||||
library: Arc<Library>,
|
||||
}
|
||||
|
||||
impl Queue {
|
||||
pub fn new(spotify: Spotify, cfg: Arc<Config>) -> Queue {
|
||||
pub fn new(spotify: Spotify, cfg: Arc<Config>, library: Arc<Library>) -> 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<String>,
|
||||
notification_id: Arc<AtomicU32>,
|
||||
) {
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user