Fixed a bug that causes the player to crash

This commit is contained in:
MrDulfin 2025-01-01 03:13:53 -05:00
parent 64e41af96f
commit 3a8826bb5d
4 changed files with 104 additions and 74 deletions

2
.gitignore vendored
View file

@ -31,4 +31,4 @@ Cargo.lock
.cargo .cargo
test-config test-config
.txt *.txt

View file

@ -1,5 +1,5 @@
#![allow(while_true)] #![allow(while_true)]
use std::{sync::Arc, thread::sleep, time::{Duration, SystemTime, UNIX_EPOCH}}; use std::{sync::{atomic::{AtomicBool, Ordering}, Arc}, thread::sleep, time::{Duration, SystemTime, UNIX_EPOCH}};
use chrono::TimeDelta; use chrono::TimeDelta;
use crossbeam::{scope, select}; use crossbeam::{scope, select};
@ -34,6 +34,10 @@ pub(super) struct ControllerConnections {
pub inner: ConnectionsInput pub inner: ConnectionsInput
} }
static DC_ACTIVE: AtomicBool = AtomicBool::new(false);
static LB_ACTIVE: AtomicBool = AtomicBool::new(false);
impl Controller { impl Controller {
pub(super) fn handle_connections( pub(super) fn handle_connections(
config: Arc<RwLock<Config>>, config: Arc<RwLock<Config>>,
@ -48,6 +52,7 @@ impl Controller {
let (dc_song_rx, dc_song_tx) = bounded::<Song>(1); let (dc_song_rx, dc_song_tx) = bounded::<Song>(1);
let (lb_song_rx, lb_song_tx) = bounded::<Song>(1); let (lb_song_rx, lb_song_tx) = bounded::<Song>(1);
let (lb_eos_rx, lb_eos_tx) = bounded::<()>(1); let (lb_eos_rx, lb_eos_tx) = bounded::<()>(1);
scope(|s| { scope(|s| {
s.builder().name("Notifications Sorter".to_string()).spawn(|_| { s.builder().name("Notifications Sorter".to_string()).spawn(|_| {
use ConnectionsNotification::*; use ConnectionsNotification::*;
@ -55,14 +60,14 @@ impl Controller {
match notifications_tx.recv().unwrap() { match notifications_tx.recv().unwrap() {
Playback { position, duration } => {} Playback { position, duration } => {}
StateChange(state) => { StateChange(state) => {
dc_state_rx.send(state.clone()).unwrap(); if DC_ACTIVE.load(Ordering::Relaxed) { dc_state_rx.send(state.clone()).unwrap(); }
} }
SongChange(song) => { SongChange(song) => {
dc_song_rx.send(song.clone()).unwrap(); if DC_ACTIVE.load(Ordering::Relaxed) { dc_song_rx.send(song.clone()).unwrap(); }
lb_song_rx.send(song).unwrap(); if LB_ACTIVE.load(Ordering::Relaxed) { lb_song_rx.send(song).unwrap(); }
} }
EOS => { EOS => {
lb_eos_rx.send(()).unwrap(); if LB_ACTIVE.load(Ordering::Relaxed) { lb_eos_rx.send(()).unwrap(); }
} }
} }
} }
@ -84,73 +89,73 @@ impl Controller {
fn discord_rpc(client_id: u64, song_tx: Receiver<Song>, state_tx: Receiver<PrismState>) { fn discord_rpc(client_id: u64, song_tx: Receiver<Song>, state_tx: Receiver<PrismState>) {
// TODO: Handle seeking position change and pause // TODO: Handle seeking position change and pause
std::thread::spawn(move || { let mut client = discord_presence::Client::with_error_config(client_id, Duration::from_secs(5), None);
let mut client = discord_presence::Client::with_error_config(client_id, Duration::from_secs(5), None); client.start();
client.start(); while !Client::is_ready() { sleep(Duration::from_millis(100)); }
while !Client::is_ready() { sleep(Duration::from_millis(100)); } println!("discord connected");
println!("discord connected");
let mut state = "Started".to_string(); let mut state = "Started".to_string();
let mut song: Option<Song> = None; let mut song: Option<Song> = None;
let mut now = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards?").as_secs(); let mut now = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards?").as_secs();
DC_ACTIVE.store(true, Ordering::Relaxed);
while true { while true {
let state = &mut state; let state = &mut state;
let song = &mut song; let song = &mut song;
select! { select! {
recv(state_tx) -> res => { recv(state_tx) -> res => {
if let Ok(state_) = res { if let Ok(state_) = res {
*state = match state_ { *state = match state_ {
PrismState::Playing => "Playing", PrismState::Playing => "Playing",
PrismState::Paused => "Paused", PrismState::Paused => "Paused",
PrismState::Stopped => "Stopped", PrismState::Stopped => "Stopped",
_ => "I'm Scared, Boss" _ => "I'm Scared, Boss"
}.to_string(); }.to_string();
} }
}, },
recv(song_tx) -> res => { recv(song_tx) -> res => {
if let Ok(song_) = res { if let Ok(song_) = res {
*song = Some(song_); *song = Some(song_);
now = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards?").as_secs(); now = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards?").as_secs();
} }
}, },
default(Duration::from_millis(99)) => () default(Duration::from_millis(99)) => ()
} }
client.set_activity(|activity| { client.set_activity(|activity| {
let a = activity.state( let a = activity.state(
song.as_ref().map_or(String::new(), |s| format!( song.as_ref().map_or(String::new(), |s| format!(
"{}{}{}", "{}{}{}",
s.get_tag(&Tag::Artist).map_or(String::new(), |album| album.clone()), s.get_tag(&Tag::Artist).map_or(String::new(), |album| album.clone()),
if s.get_tag(&Tag::Album).is_some() && s.get_tag(&Tag::Artist).is_some() { " - " } else { "" }, if s.get_tag(&Tag::Album).is_some() && s.get_tag(&Tag::Artist).is_some() { " - " } else { "" },
s.get_tag(&Tag::Album).map_or(String::new(), |album| album.clone()) s.get_tag(&Tag::Album).map_or(String::new(), |album| album.clone())
)
) )
)._type(discord_presence::models::ActivityType::Listening) )
.details( )._type(discord_presence::models::ActivityType::Listening)
if let Some(song) = song { .details(
song.get_tag(&Tag::Title).map_or(String::from("Unknown Title"), |title| title.clone()) if let Some(song) = song {
} else { song.get_tag(&Tag::Title).map_or(String::from("Unknown Title"), |title| title.clone())
String::new() } else {
} String::new()
); }
if let Some(s) = song { );
if state.as_str() == "Playing" { if let Some(s) = song {
a.timestamps(|timestamps| { if state.as_str() == "Playing" {
timestamps.start(now) a.timestamps(|timestamps| {
.end(now + s.duration.as_secs()) timestamps.start(now)
}) .end(now + s.duration.as_secs())
} else { })
a
}
} else { } else {
a a
}.assets(|a| { }
a.large_text(state.clone()) } else {
}).instance(true) a
}).unwrap(); }.assets(|a| {
} a.large_text(state.clone())
}); }).instance(true)
}).unwrap();
}
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>, eos_tx: Receiver<()>) {
@ -161,25 +166,48 @@ impl Controller {
} }
let mut song: Option<Song> = None; let mut song: Option<Song> = None;
LB_ACTIVE.store(true, Ordering::Relaxed);
while true { while true {
let song = &mut song; let song = &mut song;
let client = &client; let client = &client;
select! { select! {
recv(song_tx) -> res => { recv(song_tx) -> res => {
if let Ok(_song) = res { if let Ok(_song) = res {
client.playing_now(_song.get_tag(&Tag::Artist).map_or("", |tag| tag.as_str()), _song.get_tag(&Tag::Title).map_or("", |tag| tag.as_str()), None).unwrap(); let artist = if let Some(tag) = _song.get_tag(&Tag::Artist) {
tag.as_str()
} else {
continue
};
let title = if let Some(tag) = _song.get_tag(&Tag::Title) {
tag.as_str()
} else {
continue
};
client.playing_now(artist, title, None).unwrap();
*song = Some(_song); *song = Some(_song);
println!("Song Listening") println!("Song Listening")
} }
}, },
recv(eos_tx) -> _ => { recv(eos_tx) -> _ => {
if let Some(song) = song { if let Some(song) = song {
client.listen(song.get_tag(&Tag::Artist).map_or("", |tag| tag.as_str()), song.get_tag(&Tag::Title).map_or("", |tag| tag.as_str()), None).unwrap(); let artist = if let Some(tag) = song.get_tag(&Tag::Artist) {
tag.as_str()
} else {
continue
};
let title = if let Some(tag) = song.get_tag(&Tag::Title) {
tag.as_str()
} else {
continue
};
client.listen(artist, title, None).unwrap();
println!("Song Scrobbled"); println!("Song Scrobbled");
} }
} }
} }
} }
LB_ACTIVE.store(false, Ordering::Relaxed);
} }
} }

View file

@ -656,6 +656,7 @@ impl Controller {
if let Ok(song) = res { if let Ok(song) = res {
notify_next_song.send(song.clone()).unwrap(); notify_next_song.send(song.clone()).unwrap();
notify_connections.send(ConnectionsNotification::SongChange(song)).unwrap(); notify_connections.send(ConnectionsNotification::SongChange(song)).unwrap();
notify_connections.send(ConnectionsNotification::EOS).unwrap();
} }
} }
std::thread::sleep(Duration::from_millis(100)); std::thread::sleep(Duration::from_millis(100));

View file

@ -294,8 +294,8 @@ function PlayBar({ playing, setPlaying }: PlayBarProps) {
const pos_ = Array.isArray(info.position) ? info.position![0] : 0; const pos_ = Array.isArray(info.position) ? info.position![0] : 0;
const dur_ = Array.isArray(info.duration) ? info.duration![0] : 0; const dur_ = Array.isArray(info.duration) ? info.duration![0] : 0;
setPosition(dur_); setPosition(pos_);
setDuration(pos_); setDuration(dur_);
let progress = ((dur_/pos_) * 100); let progress = ((dur_/pos_) * 100);
setSeekBarSize(progress) setSeekBarSize(progress)
}) })
@ -332,10 +332,11 @@ function PlayBar({ playing, setPlaying }: PlayBarProps) {
invoke('set_volume', { volume: volume.target.value }).then(() => {}) invoke('set_volume', { volume: volume.target.value }).then(() => {})
}} /> }} />
<p id="timeDisplay"> <p id="timeDisplay">
{ Math.floor(+position / 60).toString().padStart(2, "0") }:
{ (+position % 60).toString().padStart(2, "0") }/
{ Math.floor(+duration / 60).toString().padStart(2, "0") }: { Math.floor(+duration / 60).toString().padStart(2, "0") }:
{ (+duration % 60).toString().padStart(2, "0") } { (+duration % 60).toString().padStart(2, "0") }/
{ Math.floor(+position / 60).toString().padStart(2, "0") }:
{ (+position % 60).toString().padStart(2, "0") }
</p> </p>
</div> </div>
</div> </div>