diff --git a/src/commands.rs b/src/commands.rs index 30c9b39..9c019eb 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -108,7 +108,15 @@ impl CommandManager { Command::Quit => { let queue = self.queue.queue.read().expect("can't readlock queue"); self.config.with_state_mut(move |mut s| { - s.queue = queue.clone(); + debug!( + "saving state, {} items, current track: {:?}", + queue.len(), + self.queue.get_current_index() + ); + s.queuestate.queue = queue.clone(); + s.queuestate.random_order = self.queue.get_random_order(); + s.queuestate.current_track = self.queue.get_current_index(); + s.queuestate.track_progress = self.spotify.get_current_progress(); }); self.config.save_state(); s.quit(); diff --git a/src/config.rs b/src/config.rs index edb1baf..21ec248 100644 --- a/src/config.rs +++ b/src/config.rs @@ -60,12 +60,21 @@ pub struct SortingOrder { pub direction: SortDirection, } +#[derive(Serialize, Default, Deserialize, Debug, Clone)] +pub struct QueueState { + pub current_track: Option, + pub random_order: Option>, + pub track_progress: std::time::Duration, + pub queue: Vec, +} + #[derive(Serialize, Deserialize, Debug, Clone)] pub struct UserState { pub volume: u16, pub shuffle: bool, pub repeat: queue::RepeatSetting, - pub queue: Vec, + pub queuestate: QueueState, + #[serde(serialize_with = "toml::ser::tables_last")] pub playlist_orders: HashMap, } @@ -75,7 +84,7 @@ impl Default for UserState { volume: u16::max_value(), shuffle: false, repeat: queue::RepeatSetting::None, - queue: Vec::new(), + queuestate: QueueState::default(), playlist_orders: HashMap::new(), } } diff --git a/src/queue.rs b/src/queue.rs index 436daba..31b3ff5 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -31,14 +31,23 @@ pub struct Queue { impl Queue { pub fn new(spotify: Spotify, cfg: Arc) -> Queue { - let queue = cfg.state().queue.clone(); - Queue { - queue: Arc::new(RwLock::new(queue)), - spotify, - current_track: RwLock::new(None), - random_order: RwLock::new(None), + let state = cfg.state().queuestate.clone(); + let queue = Queue { + queue: Arc::new(RwLock::new(state.queue)), + spotify: spotify.clone(), + current_track: RwLock::new(state.current_track), + random_order: RwLock::new(state.random_order), cfg, + }; + + if let Some(playable) = queue.get_current() { + spotify.load(&playable, false, state.track_progress.as_millis() as u32); + spotify.update_track(); + spotify.pause(); + spotify.seek(state.track_progress.as_millis() as u32); } + + queue } pub fn next_index(&self) -> Option { @@ -245,7 +254,7 @@ impl Queue { } if let Some(track) = &self.queue.read().unwrap().get(index) { - self.spotify.load(&track); + self.spotify.load(&track, true, 0); let mut current = self.current_track.write().unwrap(); current.replace(index); self.spotify.update_track(); @@ -342,6 +351,10 @@ impl Queue { self.cfg.state().shuffle } + pub fn get_random_order(&self) -> Option> { + self.random_order.read().unwrap().clone() + } + fn generate_random_order(&self) { let q = self.queue.read().unwrap(); let mut order: Vec = Vec::with_capacity(q.len()); diff --git a/src/spotify.rs b/src/spotify.rs index e8ba477..78bef76 100644 --- a/src/spotify.rs +++ b/src/spotify.rs @@ -735,9 +735,13 @@ impl Spotify { self.api_with_retry(|api| api.current_user()) } - pub fn load(&self, track: &Playable) { + pub fn load(&self, track: &Playable, start_playing: bool, position_ms: u32) { info!("loading track: {:?}", track); - self.send_worker(WorkerCommand::Load(track.clone())); + self.send_worker(WorkerCommand::Load( + track.clone(), + start_playing, + position_ms, + )); } pub fn update_status(&self, new_status: PlayerEvent) { diff --git a/src/spotify_worker.rs b/src/spotify_worker.rs index ad34906..bf4e7c3 100644 --- a/src/spotify_worker.rs +++ b/src/spotify_worker.rs @@ -18,7 +18,7 @@ use std::pin::Pin; use std::time::Duration; pub(crate) enum WorkerCommand { - Load(Playable), + Load(Playable, bool, u32), Play, Pause, Stop, @@ -90,21 +90,23 @@ impl futures::Future for Worker { progress = true; debug!("message received!"); match cmd { - WorkerCommand::Load(playable) => match SpotifyId::from_uri(&playable.uri()) { - Ok(id) => { - info!("player loading track: {:?}", id); - if id.audio_type == SpotifyAudioType::NonPlayable { - warn!("track is not playable"); + WorkerCommand::Load(playable, start_playing, position_ms) => { + match SpotifyId::from_uri(&playable.uri()) { + Ok(id) => { + info!("player loading track: {:?}", id); + if id.audio_type == SpotifyAudioType::NonPlayable { + warn!("track is not playable"); + self.events.send(Event::Player(PlayerEvent::FinishedTrack)); + } else { + self.player.load(id, start_playing, position_ms); + } + } + Err(e) => { + error!("error parsing uri: {:?}", e); self.events.send(Event::Player(PlayerEvent::FinishedTrack)); - } else { - self.player.load(id, true, 0); } } - Err(e) => { - error!("error parsing uri: {:?}", e); - self.events.send(Event::Player(PlayerEvent::FinishedTrack)); - } - }, + } WorkerCommand::Play => { self.player.play(); }