(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 => {
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();

View File

@@ -60,12 +60,21 @@ pub struct SortingOrder {
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)]
pub struct UserState {
pub volume: u16,
pub shuffle: bool,
pub repeat: queue::RepeatSetting,
pub queue: Vec<Playable>,
pub queuestate: QueueState,
#[serde(serialize_with = "toml::ser::tables_last")]
pub playlist_orders: HashMap<String, SortingOrder>,
}
@@ -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(),
}
}

View File

@@ -31,14 +31,23 @@ pub struct Queue {
impl Queue {
pub fn new(spotify: Spotify, cfg: Arc<Config>) -> 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<usize> {
@@ -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<Vec<usize>> {
self.random_order.read().unwrap().clone()
}
fn generate_random_order(&self) {
let q = self.queue.read().unwrap();
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())
}
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) {

View File

@@ -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();
}