aboutsummaryrefslogtreecommitdiffstats
path: root/src/queue.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/queue.rs')
-rw-r--r--src/queue.rs56
1 files changed, 54 insertions, 2 deletions
diff --git a/src/queue.rs b/src/queue.rs
index 17f2143..c985755 100644
--- a/src/queue.rs
+++ b/src/queue.rs
@@ -8,9 +8,11 @@
8use rand::SeedableRng; 8use rand::SeedableRng;
9use rand::rngs::StdRng; 9use rand::rngs::StdRng;
10use rand::seq::SliceRandom; 10use rand::seq::SliceRandom;
11use serde::{Deserialize, Serialize};
11use std::path::{Path, PathBuf}; 12use std::path::{Path, PathBuf};
12 13
13#[derive(Debug, Clone, PartialEq)] 14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
15#[serde(rename_all = "lowercase")]
14pub enum ShuffleMode { 16pub enum ShuffleMode {
15 None, 17 None,
16 All, 18 All,
@@ -94,7 +96,7 @@ pub fn extract_metadata(path: &Path) -> Option<AudioMetadata> {
94 } 96 }
95} 97}
96 98
97#[derive(Debug, Clone)] 99#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct Track { 100pub struct Track {
99 pub path: PathBuf, 101 pub path: PathBuf,
100 pub title: Option<String>, 102 pub title: Option<String>,
@@ -199,6 +201,18 @@ impl Track {
199 } 201 }
200} 202}
201 203
204/// A queue captured for persistence.
205///
206/// `shuffled_indices` carries the current play order, so restoring a shuffled
207/// queue keeps the order it was played in instead of reshuffling the tail.
208#[derive(Debug, Clone, Serialize, Deserialize)]
209pub struct QueueSnapshot {
210 pub tracks: Vec<Track>,
211 pub position: usize,
212 pub shuffle: ShuffleMode,
213 pub shuffled_indices: Vec<usize>,
214}
215
202pub struct Queue { 216pub struct Queue {
203 tracks: Vec<Track>, 217 tracks: Vec<Track>,
204 position: usize, 218 position: usize,
@@ -591,4 +605,42 @@ impl Queue {
591 self.position = 0; 605 self.position = 0;
592 self.shuffled_indices.clear(); 606 self.shuffled_indices.clear();
593 } 607 }
608
609 /// Everything needed to rebuild this queue exactly.
610 pub fn snapshot(&self) -> QueueSnapshot {
611 QueueSnapshot {
612 tracks: self.tracks.clone(),
613 position: self.position,
614 shuffle: self.shuffle,
615 shuffled_indices: self.shuffled_indices.clone(),
616 }
617 }
618
619 pub fn from_snapshot(snapshot: QueueSnapshot) -> Self {
620 let mut queue = Queue::new();
621 queue.tracks = snapshot.tracks;
622 queue.shuffle = snapshot.shuffle;
623 queue.position = if queue.tracks.is_empty() {
624 0
625 } else {
626 snapshot.position.min(queue.tracks.len() - 1)
627 };
628 // Trust the saved play order only when it still describes this queue;
629 // otherwise derive a new one instead of playing stale indices.
630 if queue.shuffle != ShuffleMode::None
631 && snapshot.shuffled_indices.len() == queue.tracks.len()
632 && Self::is_permutation(&snapshot.shuffled_indices)
633 {
634 queue.shuffled_indices = snapshot.shuffled_indices;
635 } else {
636 queue.update_shuffle_indices();
637 }
638 queue
639 }
640
641 fn is_permutation(indices: &[usize]) -> bool {
642 let mut sorted = indices.to_vec();
643 sorted.sort_unstable();
644 sorted.iter().enumerate().all(|(i, &idx)| i == idx)
645 }
594} 646}