@@ -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();
|
||||||
|
|||||||
@@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
src/queue.rs
27
src/queue.rs
@@ -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());
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user