mirror of
https://github.com/Dummi26/musicdb.git
synced 2025-12-20 22:36:30 +01:00
small improvements idk i forgot i had a git repo for this project
This commit is contained in:
@@ -3,8 +3,8 @@ use std::{
|
||||
fs::{self, File},
|
||||
io::{BufReader, Write},
|
||||
path::PathBuf,
|
||||
sync::{mpsc, Arc},
|
||||
time::Instant,
|
||||
sync::{mpsc, Arc, Mutex},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use crate::{load::ToFromBytes, server::Command};
|
||||
@@ -18,16 +18,14 @@ use super::{
|
||||
};
|
||||
|
||||
pub struct Database {
|
||||
/// the path to the file used to save/load the data
|
||||
db_file: PathBuf,
|
||||
/// the path to the file used to save/load the data. empty if database is in client mode.
|
||||
pub db_file: PathBuf,
|
||||
/// the path to the directory containing the actual music and cover image files
|
||||
pub lib_directory: PathBuf,
|
||||
artists: HashMap<ArtistId, Artist>,
|
||||
albums: HashMap<AlbumId, Album>,
|
||||
songs: HashMap<SongId, Song>,
|
||||
covers: HashMap<CoverId, DatabaseLocation>,
|
||||
// TODO! make sure this works out for the server AND clients
|
||||
// cover_cache: HashMap<CoverId, Vec<u8>>,
|
||||
covers: HashMap<CoverId, Cover>,
|
||||
// These will be used for autosave once that gets implemented
|
||||
db_data_file_change_first: Option<Instant>,
|
||||
db_data_file_change_last: Option<Instant>,
|
||||
@@ -132,6 +130,21 @@ impl Database {
|
||||
}
|
||||
self.panic("database.artists all keys used - no more capacity for new artists!");
|
||||
}
|
||||
/// adds a cover to the database.
|
||||
/// assigns a new id, which it then returns.
|
||||
pub fn add_cover_new(&mut self, cover: Cover) -> AlbumId {
|
||||
self.add_cover_new_nomagic(cover)
|
||||
}
|
||||
/// used internally
|
||||
fn add_cover_new_nomagic(&mut self, cover: Cover) -> AlbumId {
|
||||
for key in 0.. {
|
||||
if !self.covers.contains_key(&key) {
|
||||
self.covers.insert(key, cover);
|
||||
return key;
|
||||
}
|
||||
}
|
||||
self.panic("database.artists all keys used - no more capacity for new artists!");
|
||||
}
|
||||
/// updates an existing song in the database with the new value.
|
||||
/// uses song.id to find the correct song.
|
||||
/// if the id doesn't exist in the db, Err(()) is returned.
|
||||
@@ -193,7 +206,13 @@ impl Database {
|
||||
Command::Pause => self.playing = false,
|
||||
Command::Stop => self.playing = false,
|
||||
Command::NextSong => {
|
||||
self.queue.advance_index();
|
||||
if !Queue::advance_index_db(self) {
|
||||
// end of queue
|
||||
self.apply_command(Command::Pause);
|
||||
let mut actions = Vec::new();
|
||||
self.queue.init(vec![], &mut actions);
|
||||
Queue::handle_actions(self, actions);
|
||||
}
|
||||
}
|
||||
Command::Save => {
|
||||
if let Err(e) = self.save_database(None) {
|
||||
@@ -208,18 +227,37 @@ impl Database {
|
||||
}
|
||||
Command::QueueAdd(mut index, new_data) => {
|
||||
if let Some(v) = self.queue.get_item_at_index_mut(&index, 0) {
|
||||
v.add_to_end(new_data);
|
||||
if let Some(i) = v.add_to_end(new_data) {
|
||||
index.push(i);
|
||||
if let Some(q) = self.queue.get_item_at_index_mut(&index, 0) {
|
||||
let mut actions = Vec::new();
|
||||
q.init(index, &mut actions);
|
||||
Queue::handle_actions(self, actions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Command::QueueInsert(mut index, pos, new_data) => {
|
||||
Command::QueueInsert(mut index, pos, mut new_data) => {
|
||||
if let Some(v) = self.queue.get_item_at_index_mut(&index, 0) {
|
||||
index.push(pos);
|
||||
let mut actions = Vec::new();
|
||||
new_data.init(index, &mut actions);
|
||||
v.insert(new_data, pos);
|
||||
Queue::handle_actions(self, actions);
|
||||
}
|
||||
}
|
||||
Command::QueueRemove(index) => {
|
||||
self.queue.remove_by_index(&index, 0);
|
||||
}
|
||||
Command::QueueGoto(index) => self.queue.set_index(&index, 0),
|
||||
Command::QueueGoto(index) => Queue::set_index_db(self, &index),
|
||||
Command::QueueSetShuffle(path, map, next) => {
|
||||
if let Some(elem) = self.queue.get_item_at_index_mut(&path, 0) {
|
||||
if let QueueContent::Shuffle(_, m, _, n) = elem.content_mut() {
|
||||
*m = map;
|
||||
*n = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
Command::AddSong(song) => {
|
||||
self.add_song_new(song);
|
||||
}
|
||||
@@ -229,6 +267,7 @@ impl Database {
|
||||
Command::AddArtist(artist) => {
|
||||
self.add_artist_new(artist);
|
||||
}
|
||||
Command::AddCover(cover) => _ = self.add_cover_new(cover),
|
||||
Command::ModifySong(song) => {
|
||||
_ = self.update_song(song);
|
||||
}
|
||||
@@ -302,6 +341,7 @@ impl Database {
|
||||
command_sender: None,
|
||||
})
|
||||
}
|
||||
/// saves the database's contents. save path can be overridden
|
||||
pub fn save_database(&self, path: Option<PathBuf>) -> Result<PathBuf, std::io::Error> {
|
||||
let path = if let Some(p) = path {
|
||||
p
|
||||
@@ -386,4 +426,75 @@ impl Database {
|
||||
pub fn artists(&self) -> &HashMap<ArtistId, Artist> {
|
||||
&self.artists
|
||||
}
|
||||
pub fn covers(&self) -> &HashMap<CoverId, Cover> {
|
||||
&self.covers
|
||||
}
|
||||
/// you should probably use a Command to do this...
|
||||
pub fn songs_mut(&mut self) -> &mut HashMap<SongId, Song> {
|
||||
&mut self.songs
|
||||
}
|
||||
/// you should probably use a Command to do this...
|
||||
pub fn albums_mut(&mut self) -> &mut HashMap<AlbumId, Album> {
|
||||
&mut self.albums
|
||||
}
|
||||
/// you should probably use a Command to do this...
|
||||
pub fn artists_mut(&mut self) -> &mut HashMap<ArtistId, Artist> {
|
||||
&mut self.artists
|
||||
}
|
||||
/// you should probably use a Command to do this...
|
||||
pub fn covers_mut(&mut self) -> &mut HashMap<CoverId, Cover> {
|
||||
&mut self.covers
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Cover {
|
||||
pub location: DatabaseLocation,
|
||||
pub data: Arc<Mutex<(bool, Option<(Instant, Vec<u8>)>)>>,
|
||||
}
|
||||
impl Cover {
|
||||
pub fn get_bytes<O>(
|
||||
&self,
|
||||
path: impl FnOnce(&DatabaseLocation) -> PathBuf,
|
||||
conv: impl FnOnce(&Vec<u8>) -> O,
|
||||
) -> Option<O> {
|
||||
let mut data = loop {
|
||||
let data = self.data.lock().unwrap();
|
||||
if data.0 {
|
||||
drop(data);
|
||||
std::thread::sleep(Duration::from_secs(1));
|
||||
} else {
|
||||
break data;
|
||||
}
|
||||
};
|
||||
if let Some((accessed, data)) = &mut data.1 {
|
||||
*accessed = Instant::now();
|
||||
Some(conv(&data))
|
||||
} else {
|
||||
match std::fs::read(path(&self.location)) {
|
||||
Ok(bytes) => {
|
||||
data.1 = Some((Instant::now(), bytes));
|
||||
Some(conv(&data.1.as_ref().unwrap().1))
|
||||
}
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ToFromBytes for Cover {
|
||||
fn to_bytes<T>(&self, s: &mut T) -> Result<(), std::io::Error>
|
||||
where
|
||||
T: Write,
|
||||
{
|
||||
self.location.to_bytes(s)
|
||||
}
|
||||
fn from_bytes<T>(s: &mut T) -> Result<Self, std::io::Error>
|
||||
where
|
||||
T: std::io::Read,
|
||||
{
|
||||
Ok(Self {
|
||||
location: ToFromBytes::from_bytes(s)?,
|
||||
data: Arc::new(Mutex::new((false, None))),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
use crate::load::ToFromBytes;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use super::SongId;
|
||||
use rand::{
|
||||
seq::{IteratorRandom, SliceRandom},
|
||||
Rng,
|
||||
};
|
||||
|
||||
use crate::{load::ToFromBytes, server::Command};
|
||||
|
||||
use super::{database::Database, SongId};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Queue {
|
||||
@@ -11,6 +18,14 @@ pub struct Queue {
|
||||
pub enum QueueContent {
|
||||
Song(SongId),
|
||||
Folder(usize, Vec<Queue>, String),
|
||||
Loop(usize, usize, Box<Queue>),
|
||||
Random(VecDeque<Queue>),
|
||||
Shuffle(usize, Vec<usize>, Vec<Queue>, usize),
|
||||
}
|
||||
|
||||
pub enum QueueAction {
|
||||
AddRandomSong(Vec<usize>),
|
||||
SetShuffle(Vec<usize>, Vec<usize>, usize),
|
||||
}
|
||||
|
||||
impl Queue {
|
||||
@@ -20,27 +35,53 @@ impl Queue {
|
||||
pub fn content(&self) -> &QueueContent {
|
||||
&self.content
|
||||
}
|
||||
pub fn content_mut(&mut self) -> &mut QueueContent {
|
||||
&mut self.content
|
||||
}
|
||||
|
||||
pub fn add_to_end(&mut self, v: Self) -> bool {
|
||||
pub fn add_to_end(&mut self, v: Self) -> Option<usize> {
|
||||
match &mut self.content {
|
||||
QueueContent::Song(_) => false,
|
||||
QueueContent::Song(_) => None,
|
||||
QueueContent::Folder(_, vec, _) => {
|
||||
vec.push(v);
|
||||
true
|
||||
Some(vec.len() - 1)
|
||||
}
|
||||
QueueContent::Loop(..) => None,
|
||||
QueueContent::Random(q) => {
|
||||
q.push_back(v);
|
||||
Some(q.len() - 1)
|
||||
}
|
||||
QueueContent::Shuffle(_, map, elems, _) => {
|
||||
map.push(elems.len());
|
||||
elems.push(v);
|
||||
Some(map.len() - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn insert(&mut self, v: Self, index: usize) -> bool {
|
||||
match &mut self.content {
|
||||
QueueContent::Song(_) => false,
|
||||
QueueContent::Folder(_, vec, _) => {
|
||||
QueueContent::Folder(current, vec, _) => {
|
||||
if index <= vec.len() {
|
||||
if *current >= index {
|
||||
*current += 1;
|
||||
}
|
||||
vec.insert(index, v);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
QueueContent::Shuffle(_, map, elems, _) => {
|
||||
if index <= map.len() {
|
||||
map.insert(index, elems.len());
|
||||
elems.push(v);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
QueueContent::Loop(..) | QueueContent::Random(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,12 +92,22 @@ impl Queue {
|
||||
match &self.content {
|
||||
QueueContent::Song(_) => 1,
|
||||
QueueContent::Folder(_, v, _) => v.iter().map(|v| v.len()).sum(),
|
||||
QueueContent::Random(v) => v.iter().map(|v| v.len()).sum(),
|
||||
QueueContent::Loop(total, _done, inner) => {
|
||||
if *total == 0 {
|
||||
inner.len()
|
||||
} else {
|
||||
*total * inner.len()
|
||||
}
|
||||
}
|
||||
QueueContent::Shuffle(_, _, v, _) => v.iter().map(|v| v.len()).sum(),
|
||||
}
|
||||
}
|
||||
|
||||
/// recursively descends the queue until the current active element is found, then returns it.
|
||||
pub fn get_current(&self) -> Option<&Self> {
|
||||
match &self.content {
|
||||
QueueContent::Song(_) => Some(self),
|
||||
QueueContent::Folder(i, v, _) => {
|
||||
let i = *i;
|
||||
if let Some(v) = v.get(i) {
|
||||
@@ -65,7 +116,9 @@ impl Queue {
|
||||
None
|
||||
}
|
||||
}
|
||||
QueueContent::Song(_) => Some(self),
|
||||
QueueContent::Loop(_, _, inner) => inner.get_current(),
|
||||
QueueContent::Random(v) => v.get(v.len().saturating_sub(2))?.get_current(),
|
||||
QueueContent::Shuffle(i, map, elems, _) => elems.get(*map.get(*i)?),
|
||||
}
|
||||
}
|
||||
pub fn get_current_song(&self) -> Option<&SongId> {
|
||||
@@ -84,6 +137,7 @@ impl Queue {
|
||||
}
|
||||
pub fn get_next(&self) -> Option<&Self> {
|
||||
match &self.content {
|
||||
QueueContent::Song(_) => None,
|
||||
QueueContent::Folder(i, vec, _) => {
|
||||
let i = *i;
|
||||
if let Some(v) = vec.get(i) {
|
||||
@@ -100,17 +154,107 @@ impl Queue {
|
||||
None
|
||||
}
|
||||
}
|
||||
QueueContent::Song(_) => None,
|
||||
QueueContent::Loop(total, current, inner) => {
|
||||
if let Some(v) = inner.get_next() {
|
||||
Some(v)
|
||||
} else if *total == 0 || current < total {
|
||||
inner.get_first()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
QueueContent::Random(v) => v.get(v.len().saturating_sub(1))?.get_current(),
|
||||
QueueContent::Shuffle(i, map, elems, _) => elems.get(*map.get(*i + 1)?),
|
||||
}
|
||||
}
|
||||
pub fn get_first(&self) -> Option<&Self> {
|
||||
match &self.content {
|
||||
QueueContent::Song(..) => Some(self),
|
||||
QueueContent::Folder(_, v, _) => v.first(),
|
||||
QueueContent::Loop(_, _, q) => q.get_first(),
|
||||
QueueContent::Random(q) => q.front(),
|
||||
QueueContent::Shuffle(i, _, v, next) => {
|
||||
if *i == 0 {
|
||||
v.get(*i)
|
||||
} else {
|
||||
v.get(*next)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn advance_index(&mut self) -> bool {
|
||||
pub fn advance_index_db(db: &mut Database) -> bool {
|
||||
let mut actions = vec![];
|
||||
let o = db.queue.advance_index_inner(vec![], &mut actions);
|
||||
Self::handle_actions(db, actions);
|
||||
o
|
||||
}
|
||||
pub fn init(&mut self, path: Vec<usize>, actions: &mut Vec<QueueAction>) {
|
||||
match &mut self.content {
|
||||
QueueContent::Song(..) => {}
|
||||
QueueContent::Folder(_, v, _) => {
|
||||
if let Some(v) = v.first_mut() {
|
||||
v.init(path, actions);
|
||||
}
|
||||
}
|
||||
QueueContent::Loop(_, _, inner) => inner.init(path, actions),
|
||||
QueueContent::Random(q) => {
|
||||
if q.len() == 0 {
|
||||
actions.push(QueueAction::AddRandomSong(path.clone()));
|
||||
actions.push(QueueAction::AddRandomSong(path.clone()));
|
||||
}
|
||||
if let Some(q) = q.get_mut(q.len().saturating_sub(2)) {
|
||||
q.init(path, actions)
|
||||
}
|
||||
}
|
||||
QueueContent::Shuffle(current, map, elems, next) => {
|
||||
let mut new_map = (0..elems.len()).filter(|v| *v != *next).collect::<Vec<_>>();
|
||||
new_map.shuffle(&mut rand::thread_rng());
|
||||
if let Some(first) = new_map.first_mut() {
|
||||
let was_first = std::mem::replace(first, *next);
|
||||
new_map.push(was_first);
|
||||
} else if *next < elems.len() {
|
||||
new_map.push(*next);
|
||||
}
|
||||
let new_next = if elems.is_empty() {
|
||||
0
|
||||
} else {
|
||||
rand::thread_rng().gen_range(0..elems.len())
|
||||
};
|
||||
actions.push(QueueAction::SetShuffle(path, new_map, new_next));
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn handle_actions(db: &mut Database, actions: Vec<QueueAction>) {
|
||||
for action in actions {
|
||||
match action {
|
||||
QueueAction::AddRandomSong(path) => {
|
||||
if !db.db_file.as_os_str().is_empty() {
|
||||
if let Some(song) = db.songs().keys().choose(&mut rand::thread_rng()) {
|
||||
db.apply_command(Command::QueueAdd(
|
||||
path,
|
||||
QueueContent::Song(*song).into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
QueueAction::SetShuffle(path, shuf, next) => {
|
||||
if !db.db_file.as_os_str().is_empty() {
|
||||
db.apply_command(Command::QueueSetShuffle(path, shuf, next));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn advance_index_inner(&mut self, path: Vec<usize>, actions: &mut Vec<QueueAction>) -> bool {
|
||||
match &mut self.content {
|
||||
QueueContent::Song(_) => false,
|
||||
QueueContent::Folder(index, contents, _) => {
|
||||
if let Some(c) = contents.get_mut(*index) {
|
||||
// inner value could advance index, do nothing.
|
||||
if c.advance_index() {
|
||||
let mut p = path.clone();
|
||||
p.push(*index);
|
||||
if c.advance_index_inner(p, actions) {
|
||||
// inner value could advance index, do nothing.
|
||||
true
|
||||
} else {
|
||||
loop {
|
||||
@@ -118,6 +262,7 @@ impl Queue {
|
||||
// can advance
|
||||
*index += 1;
|
||||
if contents[*index].enabled {
|
||||
contents[*index].init(path, actions);
|
||||
break true;
|
||||
}
|
||||
} else {
|
||||
@@ -132,22 +277,113 @@ impl Queue {
|
||||
false
|
||||
}
|
||||
}
|
||||
QueueContent::Loop(total, current, inner) => {
|
||||
let mut p = path.clone();
|
||||
p.push(0);
|
||||
if inner.advance_index_inner(p, actions) {
|
||||
true
|
||||
} else {
|
||||
*current += 1;
|
||||
if *total == 0 || *current < *total {
|
||||
inner.init(path, actions);
|
||||
true
|
||||
} else {
|
||||
*current = 0;
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
QueueContent::Random(q) => {
|
||||
let i = q.len().saturating_sub(2);
|
||||
let mut p = path.clone();
|
||||
p.push(i);
|
||||
if q.get_mut(i)
|
||||
.is_some_and(|inner| inner.advance_index_inner(p, actions))
|
||||
{
|
||||
true
|
||||
} else {
|
||||
if q.len() >= 2 {
|
||||
q.pop_front();
|
||||
}
|
||||
// only sub 1 here because this is before the next random song is added
|
||||
let i2 = q.len().saturating_sub(1);
|
||||
if let Some(q) = q.get_mut(i2) {
|
||||
let mut p = path.clone();
|
||||
p.push(i2);
|
||||
q.init(p, actions);
|
||||
}
|
||||
actions.push(QueueAction::AddRandomSong(path));
|
||||
false
|
||||
}
|
||||
}
|
||||
QueueContent::Shuffle(current, map, elems, _) => {
|
||||
if map
|
||||
.get(*current)
|
||||
.and_then(|i| elems.get_mut(*i))
|
||||
.is_some_and(|q| {
|
||||
let mut p = path.clone();
|
||||
p.push(*current);
|
||||
q.advance_index_inner(p, actions)
|
||||
})
|
||||
{
|
||||
true
|
||||
} else {
|
||||
*current += 1;
|
||||
if *current < map.len() {
|
||||
if let Some(elem) = map.get(*current).and_then(|i| elems.get_mut(*i)) {
|
||||
elem.init(path, actions);
|
||||
}
|
||||
true
|
||||
} else {
|
||||
*current = 0;
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_index(&mut self, index: &Vec<usize>, depth: usize) {
|
||||
let i = index.get(depth).map(|v| *v).unwrap_or(0);
|
||||
pub fn set_index_db(db: &mut Database, index: &Vec<usize>) {
|
||||
let mut actions = vec![];
|
||||
db.queue.set_index_inner(index, 0, vec![], &mut actions);
|
||||
Self::handle_actions(db, actions);
|
||||
}
|
||||
pub fn set_index_inner(
|
||||
&mut self,
|
||||
index: &Vec<usize>,
|
||||
depth: usize,
|
||||
mut build_index: Vec<usize>,
|
||||
actions: &mut Vec<QueueAction>,
|
||||
) {
|
||||
let i = if let Some(i) = index.get(depth) {
|
||||
*i
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
build_index.push(i);
|
||||
match &mut self.content {
|
||||
QueueContent::Song(_) => {}
|
||||
QueueContent::Folder(idx, contents, _) => {
|
||||
*idx = i;
|
||||
for (i2, c) in contents.iter_mut().enumerate() {
|
||||
if i2 != i {
|
||||
c.set_index(&vec![], 0)
|
||||
}
|
||||
if i != *idx {
|
||||
*idx = i;
|
||||
}
|
||||
if let Some(c) = contents.get_mut(i) {
|
||||
c.set_index(index, depth + 1);
|
||||
c.init(build_index.clone(), actions);
|
||||
c.set_index_inner(index, depth + 1, build_index, actions);
|
||||
}
|
||||
}
|
||||
QueueContent::Loop(_, _, inner) => {
|
||||
inner.init(build_index.clone(), actions);
|
||||
inner.set_index_inner(index, depth + 1, build_index, actions)
|
||||
}
|
||||
QueueContent::Random(_) => {}
|
||||
QueueContent::Shuffle(current, map, elems, next) => {
|
||||
if i != *current {
|
||||
*current = i;
|
||||
}
|
||||
if let Some(c) = map.get(i).and_then(|i| elems.get_mut(*i)) {
|
||||
c.init(build_index.clone(), actions);
|
||||
c.set_index_inner(index, depth + 1, build_index, actions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,6 +400,12 @@ impl Queue {
|
||||
None
|
||||
}
|
||||
}
|
||||
QueueContent::Loop(_, _, inner) => inner.get_item_at_index(index, depth + 1),
|
||||
QueueContent::Random(vec) => vec.get(*i)?.get_item_at_index(index, depth + 1),
|
||||
QueueContent::Shuffle(_, map, elems, _) => map
|
||||
.get(*i)
|
||||
.and_then(|i| elems.get(*i))
|
||||
.and_then(|elem| elem.get_item_at_index(index, depth + 1)),
|
||||
}
|
||||
} else {
|
||||
Some(self)
|
||||
@@ -180,6 +422,14 @@ impl Queue {
|
||||
None
|
||||
}
|
||||
}
|
||||
QueueContent::Loop(_, _, inner) => inner.get_item_at_index_mut(index, depth + 1),
|
||||
QueueContent::Random(vec) => {
|
||||
vec.get_mut(*i)?.get_item_at_index_mut(index, depth + 1)
|
||||
}
|
||||
QueueContent::Shuffle(_, map, elems, _) => map
|
||||
.get(*i)
|
||||
.and_then(|i| elems.get_mut(*i))
|
||||
.and_then(|elem| elem.get_item_at_index_mut(index, depth + 1)),
|
||||
}
|
||||
} else {
|
||||
Some(self)
|
||||
@@ -210,6 +460,32 @@ impl Queue {
|
||||
}
|
||||
}
|
||||
}
|
||||
QueueContent::Loop(_, _, inner) => {
|
||||
if depth + 1 < index.len() {
|
||||
inner.remove_by_index(index, depth + 1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
QueueContent::Random(v) => v.remove(*i),
|
||||
QueueContent::Shuffle(current, map, elems, next) => {
|
||||
if *i < *current {
|
||||
*current -= 1;
|
||||
}
|
||||
if *i < *next {
|
||||
*next -= 1;
|
||||
}
|
||||
if *i < map.len() {
|
||||
let elem = map.remove(*i);
|
||||
if elem < elems.len() {
|
||||
Some(elems.remove(elem))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
@@ -264,6 +540,23 @@ impl ToFromBytes for QueueContent {
|
||||
contents.to_bytes(s)?;
|
||||
name.to_bytes(s)?;
|
||||
}
|
||||
Self::Loop(total, current, inner) => {
|
||||
s.write_all(&[0b11000000])?;
|
||||
total.to_bytes(s)?;
|
||||
current.to_bytes(s)?;
|
||||
inner.to_bytes(s)?;
|
||||
}
|
||||
Self::Random(q) => {
|
||||
s.write_all(&[0b00110000])?;
|
||||
q.to_bytes(s)?;
|
||||
}
|
||||
Self::Shuffle(current, map, elems, next) => {
|
||||
s.write_all(&[0b00001100])?;
|
||||
current.to_bytes(s)?;
|
||||
map.to_bytes(s)?;
|
||||
elems.to_bytes(s)?;
|
||||
next.to_bytes(s)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -273,14 +566,26 @@ impl ToFromBytes for QueueContent {
|
||||
{
|
||||
let mut switch_on = [0];
|
||||
s.read_exact(&mut switch_on)?;
|
||||
Ok(if switch_on[0].count_ones() > 4 {
|
||||
Self::Song(ToFromBytes::from_bytes(s)?)
|
||||
} else {
|
||||
Self::Folder(
|
||||
Ok(match switch_on[0] {
|
||||
0b11111111 => Self::Song(ToFromBytes::from_bytes(s)?),
|
||||
0b00000000 => Self::Folder(
|
||||
ToFromBytes::from_bytes(s)?,
|
||||
ToFromBytes::from_bytes(s)?,
|
||||
ToFromBytes::from_bytes(s)?,
|
||||
)
|
||||
),
|
||||
0b11000000 => Self::Loop(
|
||||
ToFromBytes::from_bytes(s)?,
|
||||
ToFromBytes::from_bytes(s)?,
|
||||
Box::new(ToFromBytes::from_bytes(s)?),
|
||||
),
|
||||
0b00110000 => Self::Random(ToFromBytes::from_bytes(s)?),
|
||||
0b00001100 => Self::Shuffle(
|
||||
ToFromBytes::from_bytes(s)?,
|
||||
ToFromBytes::from_bytes(s)?,
|
||||
ToFromBytes::from_bytes(s)?,
|
||||
ToFromBytes::from_bytes(s)?,
|
||||
),
|
||||
_ => Self::Folder(0, vec![], "<invalid byte received>".to_string()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user