(Re)store currently playing track + shuffle state

Solves #448
This commit is contained in:
Henrik Friedrichsen
2021-04-09 19:10:34 +02:00
parent d0db141c2d
commit cea5228245
5 changed files with 61 additions and 25 deletions

View File

@@ -108,7 +108,15 @@ impl CommandManager {
Command::Quit => { Command::Quit => {
let queue = self.queue.queue.read().expect("can't readlock queue"); let queue = self.queue.queue.read().expect("can't readlock queue");
self.config.with_state_mut(move |mut s| { 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(); self.config.save_state();
s.quit(); s.quit();

View File

@@ -60,12 +60,21 @@ pub struct SortingOrder {
pub direction: SortDirection, pub direction: SortDirection,
} }
#[derive(Serialize, Default, Deserialize, Debug, Clone)]
pub struct QueueState {
pub current_track: Option<usize>,
pub random_order: Option<Vec<usize>>,
pub track_progress: std::time::Duration,
pub queue: Vec<Playable>,
}
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UserState { pub struct UserState {
pub volume: u16, pub volume: u16,
pub shuffle: bool, pub shuffle: bool,
pub repeat: queue::RepeatSetting, pub repeat: queue::RepeatSetting,
pub queue: Vec<Playable>, pub queuestate: QueueState,
#[serde(serialize_with = "toml::ser::tables_last")]
pub playlist_orders: HashMap<String, SortingOrder>, pub playlist_orders: HashMap<String, SortingOrder>,
} }
@@ -75,7 +84,7 @@ impl Default for UserState {
volume: u16::max_value(), volume: u16::max_value(),
shuffle: false, shuffle: false,
repeat: queue::RepeatSetting::None, repeat: queue::RepeatSetting::None,
queue: Vec::new(), queuestate: QueueState::default(),
playlist_orders: HashMap::new(), playlist_orders: HashMap::new(),
} }
} }

View File

@@ -31,14 +31,23 @@ pub struct Queue {
impl Queue { impl Queue {
pub fn new(spotify: Spotify, cfg: Arc<Config>) -> Queue { pub fn new(spotify: Spotify, cfg: Arc<Config>) -> Queue {
let queue = cfg.state().queue.clone(); let state = cfg.state().queuestate.clone();
Queue { let queue = Queue {
queue: Arc::new(RwLock::new(queue)), queue: Arc::new(RwLock::new(state.queue)),
spotify, spotify: spotify.clone(),
current_track: RwLock::new(None), current_track: RwLock::new(state.current_track),
random_order: RwLock::new(None), random_order: RwLock::new(state.random_order),
cfg, 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<usize> { pub fn next_index(&self) -> Option<usize> {
@@ -245,7 +254,7 @@ impl Queue {
} }
if let Some(track) = &self.queue.read().unwrap().get(index) { 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(); let mut current = self.current_track.write().unwrap();
current.replace(index); current.replace(index);
self.spotify.update_track(); self.spotify.update_track();
@@ -342,6 +351,10 @@ impl Queue {
self.cfg.state().shuffle self.cfg.state().shuffle
} }
pub fn get_random_order(&self) -> Option<Vec<usize>> {
self.random_order.read().unwrap().clone()
}
fn generate_random_order(&self) { fn generate_random_order(&self) {
let q = self.queue.read().unwrap(); let q = self.queue.read().unwrap();
let mut order: Vec<usize> = Vec::with_capacity(q.len()); let mut order: Vec<usize> = Vec::with_capacity(q.len());

View File

@@ -735,9 +735,13 @@ impl Spotify {
self.api_with_retry(|api| api.current_user()) 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); 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) { pub fn update_status(&self, new_status: PlayerEvent) {

View File

@@ -18,7 +18,7 @@ use std::pin::Pin;
use std::time::Duration; use std::time::Duration;
pub(crate) enum WorkerCommand { pub(crate) enum WorkerCommand {
Load(Playable), Load(Playable, bool, u32),
Play, Play,
Pause, Pause,
Stop, Stop,
@@ -90,21 +90,23 @@ impl futures::Future for Worker {
progress = true; progress = true;
debug!("message received!"); debug!("message received!");
match cmd { match cmd {
WorkerCommand::Load(playable) => match SpotifyId::from_uri(&playable.uri()) { WorkerCommand::Load(playable, start_playing, position_ms) => {
Ok(id) => { match SpotifyId::from_uri(&playable.uri()) {
info!("player loading track: {:?}", id); Ok(id) => {
if id.audio_type == SpotifyAudioType::NonPlayable { info!("player loading track: {:?}", id);
warn!("track is not playable"); 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)); 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 => { WorkerCommand::Play => {
self.player.play(); self.player.play();
} }