git/grrs/main

fix: solve notification album art race condition

removed arbitrary 1.5s sleep time for the main loop and put notification dispatch inside of ArtUpdate. added notified_song_id to AppState to prevent duped notifs. added fallback notifs for when art downloads fail. closes 9b88450
diff --git a/src/app.rs b/src/app.rs
index 86609a7..10df600 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -65,6 +65,7 @@ pub struct AppState {
pub volume: u8,
pub volume_time: Option<Instant>,
pub config_scroll: u16,
+ pub notified_song_id: i64,
}
impl AppState {
@@ -171,6 +172,7 @@ impl AppState {
volume: startup_volume,
volume_time: None,
config_scroll: 0,
+ notified_song_id: 0,
}
}
diff --git a/src/main.rs b/src/main.rs
index 6b9c792..697ddcb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -359,31 +359,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.await;
}
});
-
- if state.config.system.notifications && song.id != 0 {
- let title = song.title.clone();
- let artist = song.artist.clone();
- let art_path = state
- .likes_file
- .parent()
- .expect("likes_file has no parent directory")
- .join("current_art.jpg");
-
- tokio::spawn(async move {
- tokio::time::sleep(Duration::from_millis(1500)).await;
- let _ = tokio::task::spawn_blocking(move || {
- let mut notif = notify_rust::Notification::new();
- notif.summary(&title).body(&artist).appname("grrs");
-
- if art_path.exists() {
- notif.icon(art_path.to_str().unwrap_or(""));
- }
-
- let _ = notif.show();
- })
- .await;
- });
- }
}
state.song = song;
@@ -391,6 +366,21 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
state.status_message = String::new();
state.refresh_until = None;
+ if state.config.system.notifications
+ && state.song.id != 0
+ && state.notified_song_id != state.song.id
+ && state.song.art_url.is_empty()
+ {
+ state.notified_song_id = state.song.id;
+ let title = state.song.title.clone();
+ let artist = state.song.artist.clone();
+ tokio::task::spawn_blocking(move || {
+ let mut notif = notify_rust::Notification::new();
+ notif.summary(&title).body(&artist).appname("grrs");
+ let _ = notif.show();
+ });
+ }
+
if let Some(ref mut c) = controls {
let art_path = state
.likes_file
@@ -420,8 +410,26 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
state.art_protocol = Some(protocol);
let path =
state.likes_file.parent().expect("likes_file has no parent directory").join("current_art.jpg");
+
+ let title = state.song.title.clone();
+ let artist = state.song.artist.clone();
+ let send_notif = state.config.system.notifications && state.notified_song_id != state.song.id;
+
+ if send_notif {
+ state.notified_song_id = state.song.id;
+ }
+
tokio::spawn(async move {
- let _ = tokio::fs::write(path, bytes).await;
+ let _ = tokio::fs::write(&path, bytes).await;
+ if send_notif {
+ let _ = tokio::task::spawn_blocking(move || {
+ let mut notif = notify_rust::Notification::new();
+ notif.summary(&title).body(&artist).appname("grrs");
+ notif.icon(path.to_str().unwrap_or(""));
+ let _ = notif.show();
+ })
+ .await;
+ }
});
},
AppEvent::LocalArtLoaded(id, protocol) => {
@@ -452,6 +460,16 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
AppEvent::KosuzuBusy(busy) => {
if busy {
state.refresh_until = Some(Instant::now() + REFRESH_WINDOW);
+ if state.config.system.notifications && state.notified_song_id != state.song.id {
+ state.notified_song_id = state.song.id;
+ let title = state.song.title.clone();
+ let artist = state.song.artist.clone();
+ tokio::task::spawn_blocking(move || {
+ let mut notif = notify_rust::Notification::new();
+ notif.summary(&title).body(&artist).appname("grrs");
+ let _ = notif.show();
+ });
+ }
} else {
state.refresh_until = None;
}