Updated Prismriver and fixed scrobbling timing

This commit is contained in:
MrDulfin 2025-01-01 16:38:41 -05:00
parent 2ac3acdf5a
commit b8f942feb1
4 changed files with 57 additions and 52 deletions

View file

@ -9,7 +9,7 @@ use std::{
use chrono::TimeDelta; use chrono::TimeDelta;
use crossbeam::{scope, select}; use crossbeam::{scope, select};
use crossbeam_channel::{bounded, Receiver}; use crossbeam_channel::{unbounded, Receiver};
use discord_presence::Client; use discord_presence::Client;
use listenbrainz::ListenBrainz; use listenbrainz::ListenBrainz;
use parking_lot::RwLock; use parking_lot::RwLock;
@ -30,6 +30,7 @@ pub(super) enum ConnectionsNotification {
}, },
StateChange(PrismState), StateChange(PrismState),
SongChange(Song), SongChange(Song),
AboutToFinish,
EOS, EOS,
} }
@ -56,10 +57,11 @@ impl Controller {
}, },
}: ControllerConnections, }: ControllerConnections,
) { ) {
let (dc_state_rx, dc_state_tx) = bounded::<PrismState>(1); let (dc_state_rx, dc_state_tx) = unbounded::<PrismState>();
let (dc_song_rx, dc_song_tx) = bounded::<Song>(1); let (dc_song_rx, dc_song_tx) = unbounded::<Song>();
let (lb_song_rx, lb_song_tx) = bounded::<Song>(1); let (lb_song_rx, lb_song_tx) = unbounded::<Song>();
let (lb_eos_rx, lb_eos_tx) = bounded::<()>(1); let (lb_abt_fin_rx, lb_abt_fn_tx) = unbounded::<()>();
let (lb_eos_rx, lb_eos_tx) = unbounded::<()>();
scope(|s| { scope(|s| {
s.builder() s.builder()
@ -87,6 +89,11 @@ impl Controller {
lb_eos_rx.send(()).unwrap(); lb_eos_rx.send(()).unwrap();
} }
} }
AboutToFinish => {
if LB_ACTIVE.load(Ordering::Relaxed) {
lb_abt_fin_rx.send(()).unwrap();
}
}
} }
} }
}) })
@ -105,7 +112,7 @@ impl Controller {
s.builder() s.builder()
.name("ListenBrainz Handler".to_string()) .name("ListenBrainz Handler".to_string())
.spawn(move |_| { .spawn(move |_| {
Controller::listenbrainz_scrobble(&token, lb_song_tx, lb_eos_tx); Controller::listenbrainz_scrobble(&token, lb_song_tx, lb_abt_fn_tx, lb_eos_tx);
}) })
.unwrap(); .unwrap();
} }
@ -199,7 +206,7 @@ impl Controller {
DC_ACTIVE.store(false, Ordering::Relaxed); DC_ACTIVE.store(false, Ordering::Relaxed);
} }
fn listenbrainz_scrobble(token: &str, song_tx: Receiver<Song>, eos_tx: Receiver<()>) { fn listenbrainz_scrobble(token: &str, song_tx: Receiver<Song>, abt_fn_tx: Receiver<()>, eos_tx: Receiver<()>) {
let mut client = ListenBrainz::new(); let mut client = ListenBrainz::new();
client.authenticate(token).unwrap(); client.authenticate(token).unwrap();
if !client.is_authenticated() { if !client.is_authenticated() {
@ -207,10 +214,14 @@ impl Controller {
} }
let mut song: Option<Song> = None; let mut song: Option<Song> = None;
let mut last_song: Option<Song> = None;
LB_ACTIVE.store(true, Ordering::Relaxed); LB_ACTIVE.store(true, Ordering::Relaxed);
println!("ListenBrainz connected");
while true { while true {
let song = &mut song; let song = &mut song;
let last_song = &mut last_song;
let client = &client; let client = &client;
select! { select! {
recv(song_tx) -> res => { recv(song_tx) -> res => {
@ -225,13 +236,19 @@ impl Controller {
} else { } else {
continue continue
}; };
client.playing_now(artist, title, None).unwrap(); let release = _song.get_tag(&Tag::Key(String::from("MusicBrainzReleaseId"))).map(|id| id.as_str());
client.playing_now(artist, title, release).unwrap();
println!("Song Listening = {artist} - {title}");
*song = Some(_song); *song = Some(_song);
println!("Song Listening")
} }
}, },
recv(abt_fn_tx) -> _ => {
*last_song = song.take();
println!("song = {:?}", last_song.as_ref().map(|s| s.get_tag(&Tag::Title).map_or("No Title", |t| t.as_str())));
},
recv(eos_tx) -> _ => { recv(eos_tx) -> _ => {
if let Some(song) = song { if let Some(song) = last_song {
let artist = if let Some(tag) = song.get_tag(&Tag::Artist) { let artist = if let Some(tag) = song.get_tag(&Tag::Artist) {
tag.as_str() tag.as_str()
} else { } else {
@ -242,7 +259,9 @@ impl Controller {
} else { } else {
continue continue
}; };
client.listen(artist, title, None).unwrap(); let release = song.get_tag(&Tag::Key(String::from("MusicBrainzReleaseId"))).map(|id| id.as_str());
client.listen(artist, title, release).unwrap();
println!("Song Scrobbled"); println!("Song Scrobbled");
} }
} }
@ -251,33 +270,3 @@ impl Controller {
LB_ACTIVE.store(false, Ordering::Relaxed); LB_ACTIVE.store(false, Ordering::Relaxed);
} }
} }
#[cfg(test)]
mod test_super {
use std::thread::{sleep, spawn};
use crossbeam_channel::unbounded;
use crate::config::tests::read_config_lib;
use super::*;
#[test]
fn lb_test() {
let (song_rx, song_tx) = unbounded();
let (eos_rx, eos_tx) = unbounded();
let (config, lib) = read_config_lib();
song_rx.send(lib.library[0].clone()).unwrap();
spawn(|| {
Controller::listenbrainz_scrobble(
config.connections.listenbrainz_token.unwrap().as_str(),
song_tx,
eos_tx,
);
});
sleep(Duration::from_secs(10));
eos_rx.send(()).unwrap();
sleep(Duration::from_secs(10));
}
}

View file

@ -277,6 +277,7 @@ impl Controller {
let player = Prismriver::new(); let player = Prismriver::new();
let player_state = player.state.clone(); let player_state = player.state.clone();
let player_timing = player.get_timing_recv(); let player_timing = player.get_timing_recv();
let about_to_finish_tx = player.get_about_to_finish_recv();
let finished_tx = player.get_finished_recv(); let finished_tx = player.get_finished_recv();
let (notifications_rx, notifications_tx) = let (notifications_rx, notifications_tx) =
crossbeam_channel::unbounded::<ConnectionsNotification>(); crossbeam_channel::unbounded::<ConnectionsNotification>();
@ -325,6 +326,7 @@ impl Controller {
Controller::player_monitor_loop( Controller::player_monitor_loop(
player_state, player_state,
player_timing, player_timing,
about_to_finish_tx,
finished_tx, finished_tx,
player_mail.0, player_mail.0,
notify_next_song, notify_next_song,

View file

@ -20,7 +20,8 @@ impl Controller {
pub(super) fn player_monitor_loop( pub(super) fn player_monitor_loop(
playback_state: Arc<std::sync::RwLock<PrismState>>, playback_state: Arc<std::sync::RwLock<PrismState>>,
playback_time_tx: Receiver<(Option<TimeDelta>, Option<TimeDelta>)>, playback_time_tx: Receiver<(Option<TimeDelta>, Option<TimeDelta>)>,
finished_recv: Receiver<()>, about_to_finish_tx: Receiver<()>,
finished_tx: Receiver<()>,
player_mail: async_channel::Sender<PlayerCommandInput>, player_mail: async_channel::Sender<PlayerCommandInput>,
notify_next_song: Sender<Song>, notify_next_song: Sender<Song>,
notify_connections_: Sender<ConnectionsNotification>, notify_connections_: Sender<ConnectionsNotification>,
@ -45,14 +46,25 @@ impl Controller {
} }
}); });
let notify_connections = notify_connections_.clone();
s.spawn(move || {
println!("AboutToFinish monitor started");
futures::executor::block_on(async {
while true {
_ = about_to_finish_tx.recv();
notify_connections.send(ConnectionsNotification::AboutToFinish).unwrap();
println!("About to Finish");
}
})
});
// Thread for End of Track // Thread for End of Track
let notify_connections = notify_connections_.clone(); let notify_connections = notify_connections_.clone();
s.spawn(move || { s.spawn(move || {
futures::executor::block_on(async {
println!("EOS monitor started"); println!("EOS monitor started");
futures::executor::block_on(async {
while true { while true {
let _ = finished_recv.recv(); _ = finished_tx.recv();
println!("End of song");
let (command, tx) = PlayerCommandInput::command(PlayerCommand::NextSong); let (command, tx) = PlayerCommandInput::command(PlayerCommand::NextSong);
player_mail.send(command).await.unwrap(); player_mail.send(command).await.unwrap();
@ -64,12 +76,13 @@ impl Controller {
notify_connections notify_connections
.send(ConnectionsNotification::SongChange(song)) .send(ConnectionsNotification::SongChange(song))
.unwrap(); .unwrap();
}
notify_connections notify_connections
.send(ConnectionsNotification::EOS) .send(ConnectionsNotification::EOS)
.unwrap(); .unwrap();
println!("End of song");
} }
}
std::thread::sleep(Duration::from_millis(100));
}); });
}); });

View file

@ -2,7 +2,7 @@
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "Dango Music Player", "productName": "Dango Music Player",
"version": "0.0.1", "version": "0.0.1",
"identifier": "com.dango-music-player.app", "identifier": "com.dmp.app",
"build": { "build": {
"beforeDevCommand": "npm run dev", "beforeDevCommand": "npm run dev",
"devUrl": "http://localhost:1420", "devUrl": "http://localhost:1420",
@ -14,13 +14,14 @@
{ {
"title": "Dango Music Player", "title": "Dango Music Player",
"width": 800, "width": 800,
"height": 600 "height": 600,
"decorations": true
} }
], ],
"security": { "security": {
"assetProtocol": { "assetProtocol": {
"enable": true, "enable": true,
"scope": { "allow": ["asset://localhost*", "http://localhost*"] } "scope": { "allow": ["asset://localhost*"] }
}, },
"csp": { "csp": {
"default-src": "'self' customprotocol: asset:", "default-src": "'self' customprotocol: asset:",