Updated Discord tracker to keep proper time when seeking or paused

This commit is contained in:
MrDulfin 2025-03-23 17:30:59 -04:00
parent 7b5d811102
commit 7a9ee5c22a

View file

@ -2,14 +2,12 @@ use std::{
sync::{ sync::{
atomic::{AtomicBool, Ordering}, atomic::{AtomicBool, Ordering},
Arc, Arc,
}, }, thread::sleep, time::{Duration, Instant, SystemTime, UNIX_EPOCH}
thread::sleep,
time::{Duration, SystemTime, UNIX_EPOCH},
}; };
use chrono::TimeDelta; use chrono::TimeDelta;
use crossbeam::select; use crossbeam::select;
use crossbeam_channel::{unbounded, Receiver, Sender}; use crossbeam_channel::{bounded, unbounded, Receiver, Sender};
use discord_presence::Client; use discord_presence::Client;
use listenbrainz::ListenBrainz; use listenbrainz::ListenBrainz;
use parking_lot::RwLock; use parking_lot::RwLock;
@ -75,6 +73,7 @@ pub(super) fn handle_connections(
) { ) {
let (dc_state_rx, dc_state_tx) = unbounded::<PrismState>(); let (dc_state_rx, dc_state_tx) = unbounded::<PrismState>();
let (dc_now_playing_rx, dc_now_playing_tx) = unbounded::<Song>(); let (dc_now_playing_rx, dc_now_playing_tx) = unbounded::<Song>();
let (dc_position_rx, dc_position_tx) = bounded::<Option<TimeDelta>>(0);
let (lb_now_playing_rx, lb_now_playing_tx) = unbounded::<Song>(); let (lb_now_playing_rx, lb_now_playing_tx) = unbounded::<Song>();
let (lb_scrobble_rx, lb_scrobble_tx) = unbounded::<()>(); let (lb_scrobble_rx, lb_scrobble_tx) = unbounded::<()>();
let (last_now_playing_rx, last_now_playing_tx) = unbounded::<Song>(); let (last_now_playing_rx, last_now_playing_tx) = unbounded::<Song>();
@ -82,10 +81,19 @@ pub(super) fn handle_connections(
let mut song_scrobbled = false; let mut song_scrobbled = false;
//TODO: update scrobble position on seek
// /// The position at which you can scrobble the song. changes on seek
// struct ScrobblePosition {
// percent: f32,
// position: i32
// }
// let mut scrobble_position = ScrobblePosition { percent: f32::MAX, position: i32::MAX };
use ConnectionsNotification::*; use ConnectionsNotification::*;
while true { while true {
match notifications_tx.recv().unwrap() { match notifications_tx.recv().unwrap() {
Playback { position: _position, duration: _duration } => { Playback { position: _position, duration: _duration } => {
_ = dc_position_rx.send_timeout(_position.clone(), Duration::from_millis(0));
if song_scrobbled { continue } if song_scrobbled { continue }
let Some(position) = _position.map(|t| t.num_milliseconds()) else { continue }; let Some(position) = _position.map(|t| t.num_milliseconds()) else { continue };
@ -126,12 +134,12 @@ pub(super) fn handle_connections(
AboutToFinish => { continue } AboutToFinish => { continue }
TryEnableConnection(c) => { match c { TryEnableConnection(c) => { match c {
TryConnectionType::Discord(client_id) => { TryConnectionType::Discord(client_id) => {
let (dc_song_tx, dc_state_tx) = (dc_now_playing_tx.clone(), dc_state_tx.clone()); let (dc_song_tx, dc_state_tx, dc_position_tx) = (dc_now_playing_tx.clone(), dc_state_tx.clone(), dc_position_tx.clone());
std::thread::Builder::new() std::thread::Builder::new()
.name("Discord RPC Handler".to_string()) .name("Discord RPC Handler".to_string())
.spawn(move || { .spawn(move || {
// TODO: add proper error handling here // TODO: add proper error handling here
discord_rpc(client_id, dc_song_tx, dc_state_tx); discord_rpc(client_id, dc_song_tx, dc_state_tx, dc_position_tx);
}) })
.unwrap(); .unwrap();
}, },
@ -175,8 +183,7 @@ pub(super) fn handle_connections(
} }
} }
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>, position_tx: Receiver<Option<TimeDelta>>) {
// TODO: Handle seeking position change and pause
let mut client = let mut client =
discord_presence::Client::with_error_config(client_id, Duration::from_secs(5), None); discord_presence::Client::with_error_config(client_id, Duration::from_secs(5), None);
client.start(); client.start();
@ -185,26 +192,24 @@ fn discord_rpc(client_id: u64, song_tx: Receiver<Song>, state_tx: Receiver<Prism
} }
println!("discord connected"); println!("discord connected");
let mut state = "Started".to_string(); let mut state = None;
let mut song: Option<Song> = None; let mut song: Option<Song> = None;
let mut now = SystemTime::now() let mut now = SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
.expect("Time went backwards?") .expect("Time went backwards?")
.as_secs(); .as_secs();
let mut tick = Instant::now();
DC_ACTIVE.store(true, Ordering::Relaxed); DC_ACTIVE.store(true, Ordering::Relaxed);
while true { while true {
let state = &mut state; let state: &mut Option<PrismState> = &mut state;
let song = &mut song; let song: &mut Option<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 = Some(state_);
PrismState::Playing => "Playing",
PrismState::Paused => "Paused",
PrismState::Stopped => "Stopped",
_ => "I'm Scared, Boss"
}.to_string();
} }
}, },
recv(song_tx) -> res => { recv(song_tx) -> res => {
@ -213,12 +218,26 @@ fn discord_rpc(client_id: u64, song_tx: Receiver<Song>, state_tx: Receiver<Prism
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)) => () recv(position_tx) -> pos => {
let elapsed = tick.elapsed().as_secs();
if elapsed >= 5 {
if let Ok(Some(pos)) = pos {
// set back the start position to where it would be if it hadn't been paused / seeked
now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards?")
.as_secs() - u64::try_from(pos.num_seconds()).unwrap() - 1;
tick = Instant::now();
}
}
}
default(Duration::from_millis(1000)) => {}
} }
client client
.set_activity(|activity| { .set_activity(|activity| {
let a = activity let activity = activity
.state(song.as_ref().map_or(String::new(), |s| { .state(song.as_ref().map_or(String::new(), |s| {
format!( format!(
"{}{}{}", "{}{}{}",
@ -243,17 +262,23 @@ fn discord_rpc(client_id: u64, song_tx: Receiver<Song>, state_tx: Receiver<Prism
String::new() String::new()
}); });
if let Some(s) = song { if let Some(s) = song {
if state.as_str() == "Playing" { if *state == Some(PrismState::Playing) {
a.timestamps(|timestamps| { activity.timestamps(|timestamps| {
timestamps.start(now).end(now + s.duration.as_secs()) timestamps.start(now).end(now + s.duration.as_secs())
}) })
} else { } else {
a activity
} }
} else { } else {
a activity
} }
.assets(|a| a.large_text(state.clone())) .assets(|a| a.large_text(match state {
Some(PrismState::Playing) => "Playing",
Some(PrismState::Paused) => "Paused",
Some(PrismState::Stopped) => "Stopped",
None => "Started",
_ => "I'm Scared, Boss"
}))
.instance(true) .instance(true)
}) })
.unwrap(); .unwrap();