diff options
Diffstat (limited to 'src/queue.rs')
| -rw-r--r-- | src/queue.rs | 130 |
1 files changed, 107 insertions, 23 deletions
diff --git a/src/queue.rs b/src/queue.rs index b0acf5f..9d09fec 100644 --- a/src/queue.rs +++ b/src/queue.rs | |||
| @@ -6,6 +6,7 @@ pub enum ShuffleMode { | |||
| 6 | None, | 6 | None, |
| 7 | All, | 7 | All, |
| 8 | Album, | 8 | Album, |
| 9 | Albums, | ||
| 9 | } | 10 | } |
| 10 | 11 | ||
| 11 | #[derive(Debug, Default, Clone)] | 12 | #[derive(Debug, Default, Clone)] |
| @@ -46,28 +47,8 @@ pub fn extract_metadata(path: &Path) -> Option<AudioMetadata> { | |||
| 46 | }; | 47 | }; |
| 47 | 48 | ||
| 48 | { | 49 | { |
| 49 | let meta = probed.metadata(); | 50 | let mut meta = probed.metadata(); |
| 50 | if let Some(rev) = meta.current() { | 51 | if let Some(rev) = meta.skip_to_latest() { |
| 51 | for tag in &rev.media.tags { | ||
| 52 | match &tag.std { | ||
| 53 | Some(StandardTag::TrackTitle(value)) => { | ||
| 54 | metadata.title = Some(value.to_string()); | ||
| 55 | } | ||
| 56 | Some(StandardTag::Artist(value)) => { | ||
| 57 | metadata.artist = Some(value.to_string()); | ||
| 58 | } | ||
| 59 | Some(StandardTag::Album(value)) => { | ||
| 60 | metadata.album = Some(value.to_string()); | ||
| 61 | } | ||
| 62 | _ => {} | ||
| 63 | } | ||
| 64 | } | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | if metadata.title.is_none() && metadata.artist.is_none() && metadata.album.is_none() { | ||
| 69 | let meta = probed.metadata(); | ||
| 70 | if let Some(rev) = meta.current() { | ||
| 71 | for tag in &rev.media.tags { | 52 | for tag in &rev.media.tags { |
| 72 | match &tag.std { | 53 | match &tag.std { |
| 73 | Some(StandardTag::TrackTitle(value)) => { | 54 | Some(StandardTag::TrackTitle(value)) => { |
| @@ -183,6 +164,12 @@ impl Queue { | |||
| 183 | self.update_shuffle_indices(); | 164 | self.update_shuffle_indices(); |
| 184 | } | 165 | } |
| 185 | 166 | ||
| 167 | #[allow(dead_code)] | ||
| 168 | pub fn push_track(&mut self, track: Track) { | ||
| 169 | self.tracks.push(track); | ||
| 170 | self.update_shuffle_indices(); | ||
| 171 | } | ||
| 172 | |||
| 186 | pub fn insert_after_current(&mut self, path: PathBuf) { | 173 | pub fn insert_after_current(&mut self, path: PathBuf) { |
| 187 | if self.tracks.is_empty() { | 174 | if self.tracks.is_empty() { |
| 188 | self.tracks.push(Track::from_path(path)); | 175 | self.tracks.push(Track::from_path(path)); |
| @@ -213,6 +200,11 @@ impl Queue { | |||
| 213 | self.shuffle = ShuffleMode::Album; | 200 | self.shuffle = ShuffleMode::Album; |
| 214 | self.update_shuffle_indices_album(); | 201 | self.update_shuffle_indices_album(); |
| 215 | } | 202 | } |
| 203 | ShuffleMode::Albums => { | ||
| 204 | self.original_tracks = self.tracks.clone(); | ||
| 205 | self.shuffle = ShuffleMode::Albums; | ||
| 206 | self.update_shuffle_indices_albums(); | ||
| 207 | } | ||
| 216 | } | 208 | } |
| 217 | } | 209 | } |
| 218 | 210 | ||
| @@ -268,6 +260,9 @@ impl Queue { | |||
| 268 | ShuffleMode::Album => { | 260 | ShuffleMode::Album => { |
| 269 | self.update_shuffle_indices_album(); | 261 | self.update_shuffle_indices_album(); |
| 270 | } | 262 | } |
| 263 | ShuffleMode::Albums => { | ||
| 264 | self.update_shuffle_indices_albums(); | ||
| 265 | } | ||
| 271 | ShuffleMode::None => {} | 266 | ShuffleMode::None => {} |
| 272 | } | 267 | } |
| 273 | } | 268 | } |
| @@ -285,6 +280,62 @@ impl Queue { | |||
| 285 | } | 280 | } |
| 286 | } | 281 | } |
| 287 | 282 | ||
| 283 | fn update_shuffle_indices_albums(&mut self) { | ||
| 284 | let len = self.tracks.len(); | ||
| 285 | self.shuffled_indices = (0..len).collect(); | ||
| 286 | |||
| 287 | if len <= 1 { | ||
| 288 | return; | ||
| 289 | } | ||
| 290 | |||
| 291 | let pos = self.position.min(len.saturating_sub(1)); | ||
| 292 | if pos + 1 >= len { | ||
| 293 | return; | ||
| 294 | } | ||
| 295 | |||
| 296 | let range_start = pos + 1; | ||
| 297 | let mut rng = rand::rng(); | ||
| 298 | |||
| 299 | // Build album groups within the range, shuffling tracks within each group | ||
| 300 | let mut groups: Vec<Vec<usize>> = Vec::new(); | ||
| 301 | let mut current_group: Vec<usize> = Vec::new(); | ||
| 302 | let mut current_album: Option<&str> = None; | ||
| 303 | |||
| 304 | for i in range_start..len { | ||
| 305 | let album = self.tracks.get(i).and_then(|t| t.album.as_deref()); | ||
| 306 | |||
| 307 | if current_group.is_empty() { | ||
| 308 | current_group.push(i); | ||
| 309 | current_album = album; | ||
| 310 | } else if album != current_album { | ||
| 311 | // Shuffle tracks within this album group before adding it | ||
| 312 | if current_group.len() > 1 { | ||
| 313 | current_group.shuffle(&mut rng); | ||
| 314 | } | ||
| 315 | groups.push(std::mem::take(&mut current_group)); | ||
| 316 | current_group.push(i); | ||
| 317 | current_album = album; | ||
| 318 | } else { | ||
| 319 | current_group.push(i); | ||
| 320 | } | ||
| 321 | } | ||
| 322 | if !current_group.is_empty() { | ||
| 323 | if current_group.len() > 1 { | ||
| 324 | current_group.shuffle(&mut rng); | ||
| 325 | } | ||
| 326 | groups.push(current_group); | ||
| 327 | } | ||
| 328 | |||
| 329 | // Shuffle the album group order | ||
| 330 | groups.shuffle(&mut rng); | ||
| 331 | |||
| 332 | let mut new_indices: Vec<usize> = self.shuffled_indices[..=pos].to_vec(); | ||
| 333 | for group in &groups { | ||
| 334 | new_indices.extend(group); | ||
| 335 | } | ||
| 336 | self.shuffled_indices = new_indices; | ||
| 337 | } | ||
| 338 | |||
| 288 | fn shuffle_album_range(&mut self, range: std::ops::Range<usize>, rng: &mut impl rand::Rng) { | 339 | fn shuffle_album_range(&mut self, range: std::ops::Range<usize>, rng: &mut impl rand::Rng) { |
| 289 | if range.start >= range.end { | 340 | if range.start >= range.end { |
| 290 | return; | 341 | return; |
| @@ -327,7 +378,7 @@ impl Queue { | |||
| 327 | self.shuffled_indices | 378 | self.shuffled_indices |
| 328 | .get(self.position) | 379 | .get(self.position) |
| 329 | .and_then(|&idx| self.tracks.get(idx)) | 380 | .and_then(|&idx| self.tracks.get(idx)) |
| 330 | } else if self.shuffle == ShuffleMode::Album { | 381 | } else if self.shuffle == ShuffleMode::Album || self.shuffle == ShuffleMode::Albums { |
| 331 | self.shuffled_indices | 382 | self.shuffled_indices |
| 332 | .get(self.position) | 383 | .get(self.position) |
| 333 | .and_then(|&idx| self.tracks.get(idx)) | 384 | .and_then(|&idx| self.tracks.get(idx)) |
| @@ -397,6 +448,39 @@ impl Queue { | |||
| 397 | ShuffleMode::Album => { | 448 | ShuffleMode::Album => { |
| 398 | self.shuffle_album_range(0..self.tracks.len(), &mut rng); | 449 | self.shuffle_album_range(0..self.tracks.len(), &mut rng); |
| 399 | } | 450 | } |
| 451 | ShuffleMode::Albums => { | ||
| 452 | let mut groups: Vec<Vec<usize>> = Vec::new(); | ||
| 453 | let mut current_group: Vec<usize> = Vec::new(); | ||
| 454 | let mut current_album: Option<&str> = None; | ||
| 455 | |||
| 456 | for i in 0..self.tracks.len() { | ||
| 457 | let album = self.tracks.get(i).and_then(|t| t.album.as_deref()); | ||
| 458 | |||
| 459 | if current_group.is_empty() { | ||
| 460 | current_group.push(i); | ||
| 461 | current_album = album; | ||
| 462 | } else if album != current_album { | ||
| 463 | if current_group.len() > 1 { | ||
| 464 | current_group.shuffle(&mut rng); | ||
| 465 | } | ||
| 466 | groups.push(std::mem::take(&mut current_group)); | ||
| 467 | current_group.push(i); | ||
| 468 | current_album = album; | ||
| 469 | } else { | ||
| 470 | current_group.push(i); | ||
| 471 | } | ||
| 472 | } | ||
| 473 | if !current_group.is_empty() { | ||
| 474 | if current_group.len() > 1 { | ||
| 475 | current_group.shuffle(&mut rng); | ||
| 476 | } | ||
| 477 | groups.push(current_group); | ||
| 478 | } | ||
| 479 | |||
| 480 | groups.shuffle(&mut rng); | ||
| 481 | |||
| 482 | self.shuffled_indices = groups.concat(); | ||
| 483 | } | ||
| 400 | ShuffleMode::None => {} | 484 | ShuffleMode::None => {} |
| 401 | } | 485 | } |
| 402 | } | 486 | } |
