mirror of
https://github.com/Dummi26/musicdb.git
synced 2025-03-10 14:13:53 +01:00
queue: shuffle is now usable
This commit is contained in:
parent
30b466b2ff
commit
36da1ab189
@ -3,7 +3,7 @@ use std::collections::VecDeque;
|
|||||||
use musicdb_lib::{
|
use musicdb_lib::{
|
||||||
data::{
|
data::{
|
||||||
database::Database,
|
database::Database,
|
||||||
queue::{Queue, QueueContent},
|
queue::{Queue, QueueContent, ShuffleState},
|
||||||
song::Song,
|
song::Song,
|
||||||
AlbumId, ArtistId,
|
AlbumId, ArtistId,
|
||||||
},
|
},
|
||||||
@ -116,7 +116,7 @@ impl QueueViewer {
|
|||||||
GuiElemCfg::at(Rectangle::from_tuples((0.5, 0.5), (1.0, 1.0)))
|
GuiElemCfg::at(Rectangle::from_tuples((0.5, 0.5), (1.0, 1.0)))
|
||||||
.w_mouse(),
|
.w_mouse(),
|
||||||
vec![],
|
vec![],
|
||||||
QueueContent::Shuffle(0, vec![], vec![], 0).into(),
|
QueueContent::Shuffle { inner: Box::new(QueueContent::Folder(0, vec![], String::new()).into()), state: ShuffleState::NotShuffled }.into(),
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
.alwayscopy(),
|
.alwayscopy(),
|
||||||
@ -237,9 +237,9 @@ fn queue_gui(
|
|||||||
}
|
}
|
||||||
QueueContent::Loop(_, _, inner) => {
|
QueueContent::Loop(_, _, inner) => {
|
||||||
let mut p = path.clone();
|
let mut p = path.clone();
|
||||||
|
p.push(0);
|
||||||
let mut p1 = path.clone();
|
let mut p1 = path.clone();
|
||||||
let p2 = p1.pop().unwrap_or(0) + 1;
|
let p2 = p1.pop().unwrap_or(0) + 1;
|
||||||
p.push(0);
|
|
||||||
target.push((
|
target.push((
|
||||||
GuiElem::new(QueueLoop::new(cfg.clone(), path, queue.clone(), current)),
|
GuiElem::new(QueueLoop::new(cfg.clone(), path, queue.clone(), current)),
|
||||||
line_height * 0.8,
|
line_height * 0.8,
|
||||||
@ -262,7 +262,7 @@ fn queue_gui(
|
|||||||
}
|
}
|
||||||
QueueContent::Random(q) => {
|
QueueContent::Random(q) => {
|
||||||
target.push((
|
target.push((
|
||||||
GuiElem::new(QueueRandom::new(cfg, path.clone(), queue.clone(), current)),
|
GuiElem::new(QueueRandom::new(cfg.clone(), path.clone(), queue.clone(), current)),
|
||||||
line_height,
|
line_height,
|
||||||
));
|
));
|
||||||
for (i, inner) in q.iter().enumerate() {
|
for (i, inner) in q.iter().enumerate() {
|
||||||
@ -280,16 +280,20 @@ fn queue_gui(
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
let mut p1 = path.clone();
|
||||||
QueueContent::Shuffle(c, map, elems, _) => {
|
let p2 = p1.pop().unwrap_or(0) + 1;
|
||||||
target.push((
|
target.push((
|
||||||
GuiElem::new(QueueShuffle::new(cfg, path.clone(), queue.clone(), current)),
|
GuiElem::new(QueueIndentEnd::new(cfg, (p1, p2))),
|
||||||
|
line_height * 0.4,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
QueueContent::Shuffle { inner, state: _ } => {
|
||||||
|
target.push((
|
||||||
|
GuiElem::new(QueueShuffle::new(cfg.clone(), path.clone(), queue.clone(), current)),
|
||||||
line_height * 0.8,
|
line_height * 0.8,
|
||||||
));
|
));
|
||||||
for (i, inner) in map.iter().enumerate() {
|
|
||||||
if let Some(inner) = elems.get(*inner) {
|
|
||||||
let mut p = path.clone();
|
let mut p = path.clone();
|
||||||
p.push(i);
|
p.push(0);
|
||||||
queue_gui(
|
queue_gui(
|
||||||
inner,
|
inner,
|
||||||
db,
|
db,
|
||||||
@ -298,11 +302,15 @@ fn queue_gui(
|
|||||||
line_height,
|
line_height,
|
||||||
target,
|
target,
|
||||||
p,
|
p,
|
||||||
current && i == *c,
|
current,
|
||||||
false,
|
true,
|
||||||
);
|
);
|
||||||
}
|
let mut p1 = path.clone();
|
||||||
}
|
let p2 = p1.pop().unwrap_or(0) + 1;
|
||||||
|
target.push((
|
||||||
|
GuiElem::new(QueueIndentEnd::new(cfg, (p1, p2))),
|
||||||
|
line_height * 0.4,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1101,7 +1109,7 @@ impl QueueShuffle {
|
|||||||
children: vec![GuiElem::new(Label::new(
|
children: vec![GuiElem::new(Label::new(
|
||||||
GuiElemCfg::default(),
|
GuiElemCfg::default(),
|
||||||
match queue.content() {
|
match queue.content() {
|
||||||
QueueContent::Shuffle(..) => {
|
QueueContent::Shuffle { .. } => {
|
||||||
format!("shuffle")
|
format!("shuffle")
|
||||||
}
|
}
|
||||||
_ => "[???]".to_string(),
|
_ => "[???]".to_string(),
|
||||||
@ -1200,7 +1208,8 @@ impl GuiElemTrait for QueueShuffle {
|
|||||||
}
|
}
|
||||||
fn dragged(&mut self, dragged: Dragging) -> Vec<GuiAction> {
|
fn dragged(&mut self, dragged: Dragging) -> Vec<GuiAction> {
|
||||||
if !self.always_copy {
|
if !self.always_copy {
|
||||||
let p = self.path.clone();
|
let mut p = self.path.clone();
|
||||||
|
p.push(0);
|
||||||
dragged_add_to_queue(dragged, move |q| Command::QueueAdd(p, q))
|
dragged_add_to_queue(dragged, move |q| Command::QueueAdd(p, q))
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -12,7 +12,7 @@ use crate::{load::ToFromBytes, server::Command};
|
|||||||
use super::{
|
use super::{
|
||||||
album::Album,
|
album::Album,
|
||||||
artist::Artist,
|
artist::Artist,
|
||||||
queue::{Queue, QueueContent},
|
queue::{Queue, QueueContent, ShuffleState},
|
||||||
song::Song,
|
song::Song,
|
||||||
AlbumId, ArtistId, CoverId, DatabaseLocation, SongId,
|
AlbumId, ArtistId, CoverId, DatabaseLocation, SongId,
|
||||||
};
|
};
|
||||||
@ -250,43 +250,69 @@ impl Database {
|
|||||||
}
|
}
|
||||||
Command::SyncDatabase(a, b, c) => self.sync(a, b, c),
|
Command::SyncDatabase(a, b, c) => self.sync(a, b, c),
|
||||||
Command::QueueUpdate(index, new_data) => {
|
Command::QueueUpdate(index, new_data) => {
|
||||||
if let Some(v) = self.queue.get_item_at_index_mut(&index, 0) {
|
let mut actions = vec![];
|
||||||
|
if let Some(v) = self.queue.get_item_at_index_mut(&index, 0, &mut actions) {
|
||||||
*v = new_data;
|
*v = new_data;
|
||||||
}
|
}
|
||||||
|
Queue::handle_actions(self, actions);
|
||||||
}
|
}
|
||||||
Command::QueueAdd(mut index, new_data) => {
|
Command::QueueAdd(mut index, new_data) => {
|
||||||
if let Some(v) = self.queue.get_item_at_index_mut(&index, 0) {
|
let mut actions = vec![];
|
||||||
|
if let Some(v) = self.queue.get_item_at_index_mut(&index, 0, &mut actions) {
|
||||||
if let Some(i) = v.add_to_end(new_data) {
|
if let Some(i) = v.add_to_end(new_data) {
|
||||||
index.push(i);
|
index.push(i);
|
||||||
if let Some(q) = self.queue.get_item_at_index_mut(&index, 0) {
|
if let Some(q) = self.queue.get_item_at_index_mut(&index, 0, &mut actions) {
|
||||||
let mut actions = Vec::new();
|
let mut actions = Vec::new();
|
||||||
q.init(index, &mut actions);
|
q.init(index, &mut actions);
|
||||||
Queue::handle_actions(self, actions);
|
Queue::handle_actions(self, actions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Queue::handle_actions(self, actions);
|
||||||
}
|
}
|
||||||
Command::QueueInsert(mut index, pos, mut new_data) => {
|
Command::QueueInsert(mut index, pos, mut new_data) => {
|
||||||
if let Some(v) = self.queue.get_item_at_index_mut(&index, 0) {
|
let mut actions = vec![];
|
||||||
|
if let Some(v) = self.queue.get_item_at_index_mut(&index, 0, &mut actions) {
|
||||||
index.push(pos);
|
index.push(pos);
|
||||||
let mut actions = Vec::new();
|
let mut actions = Vec::new();
|
||||||
new_data.init(index, &mut actions);
|
new_data.init(index, &mut actions);
|
||||||
v.insert(new_data, pos);
|
v.insert(new_data, pos);
|
||||||
Queue::handle_actions(self, actions);
|
Queue::handle_actions(self, actions);
|
||||||
}
|
}
|
||||||
|
Queue::handle_actions(self, actions);
|
||||||
}
|
}
|
||||||
Command::QueueRemove(index) => {
|
Command::QueueRemove(index) => {
|
||||||
self.queue.remove_by_index(&index, 0);
|
self.queue.remove_by_index(&index, 0);
|
||||||
}
|
}
|
||||||
Command::QueueGoto(index) => Queue::set_index_db(self, &index),
|
Command::QueueGoto(index) => Queue::set_index_db(self, &index),
|
||||||
Command::QueueSetShuffle(path, map, next) => {
|
Command::QueueSetShuffle(path, order) => {
|
||||||
if let Some(elem) = self.queue.get_item_at_index_mut(&path, 0) {
|
let mut actions = vec![];
|
||||||
if let QueueContent::Shuffle(_, m, _, n) = elem.content_mut() {
|
if let Some(elem) = self.queue.get_item_at_index_mut(&path, 0, &mut actions) {
|
||||||
*m = map;
|
if let QueueContent::Shuffle { inner, state } = elem.content_mut() {
|
||||||
*n = next;
|
if let QueueContent::Folder(_, v, _) = inner.content_mut() {
|
||||||
|
let mut o = std::mem::replace(v, vec![])
|
||||||
|
.into_iter()
|
||||||
|
.map(|v| Some(v))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
for &i in order.iter() {
|
||||||
|
if let Some(a) = o.get_mut(i).and_then(Option::take) {
|
||||||
|
v.push(a);
|
||||||
|
} else {
|
||||||
|
eprintln!("[warn] Can't properly apply requested order to Queue/Shuffle: no element at index {i}. Index may be out of bounds or used twice. Len: {}, Order: {order:?}.", v.len());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*state = ShuffleState::Shuffled;
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"[warn] can't QueueSetShuffle - element at path {path:?} isn't Shuffle"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eprintln!("[warn] can't QueueSetShuffle - no element at path {path:?}");
|
||||||
|
}
|
||||||
|
Queue::handle_actions(self, actions);
|
||||||
|
}
|
||||||
Command::AddSong(song) => {
|
Command::AddSong(song) => {
|
||||||
self.add_song_new(song);
|
self.add_song_new(song);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use rand::{
|
use rand::seq::{IteratorRandom, SliceRandom};
|
||||||
seq::{IteratorRandom, SliceRandom},
|
|
||||||
Rng,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{load::ToFromBytes, server::Command};
|
use crate::{load::ToFromBytes, server::Command};
|
||||||
|
|
||||||
@ -20,12 +17,21 @@ pub enum QueueContent {
|
|||||||
Folder(usize, Vec<Queue>, String),
|
Folder(usize, Vec<Queue>, String),
|
||||||
Loop(usize, usize, Box<Queue>),
|
Loop(usize, usize, Box<Queue>),
|
||||||
Random(VecDeque<Queue>),
|
Random(VecDeque<Queue>),
|
||||||
Shuffle(usize, Vec<usize>, Vec<Queue>, usize),
|
Shuffle {
|
||||||
|
inner: Box<Queue>,
|
||||||
|
state: ShuffleState,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum ShuffleState {
|
||||||
|
NotShuffled,
|
||||||
|
Modified,
|
||||||
|
Shuffled,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum QueueAction {
|
pub enum QueueAction {
|
||||||
AddRandomSong(Vec<usize>),
|
AddRandomSong(Vec<usize>),
|
||||||
SetShuffle(Vec<usize>, Vec<usize>, usize),
|
SetShuffle(Vec<usize>, bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Queue {
|
impl Queue {
|
||||||
@ -51,11 +57,7 @@ impl Queue {
|
|||||||
q.push_back(v);
|
q.push_back(v);
|
||||||
Some(q.len() - 1)
|
Some(q.len() - 1)
|
||||||
}
|
}
|
||||||
QueueContent::Shuffle(_, map, elems, _) => {
|
QueueContent::Shuffle { .. } => None,
|
||||||
map.push(elems.len());
|
|
||||||
elems.push(v);
|
|
||||||
Some(map.len() - 1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn insert(&mut self, v: Self, index: usize) -> bool {
|
pub fn insert(&mut self, v: Self, index: usize) -> bool {
|
||||||
@ -72,17 +74,10 @@ impl Queue {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueueContent::Shuffle(_, map, elems, _) => {
|
QueueContent::Loop(..) | QueueContent::Random(..) | QueueContent::Shuffle { .. } => {
|
||||||
if index <= map.len() {
|
|
||||||
map.insert(index, elems.len());
|
|
||||||
elems.push(v);
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueueContent::Loop(..) | QueueContent::Random(..) => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
@ -100,7 +95,7 @@ impl Queue {
|
|||||||
*total * inner.len()
|
*total * inner.len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueueContent::Shuffle(_, _, v, _) => v.iter().map(|v| v.len()).sum(),
|
QueueContent::Shuffle { inner, state: _ } => inner.len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +113,7 @@ impl Queue {
|
|||||||
}
|
}
|
||||||
QueueContent::Loop(_, _, inner) => inner.get_current(),
|
QueueContent::Loop(_, _, inner) => inner.get_current(),
|
||||||
QueueContent::Random(v) => v.get(v.len().saturating_sub(2))?.get_current(),
|
QueueContent::Random(v) => v.get(v.len().saturating_sub(2))?.get_current(),
|
||||||
QueueContent::Shuffle(i, map, elems, _) => elems.get(*map.get(*i)?),
|
QueueContent::Shuffle { inner, state: _ } => inner.get_current(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get_current_song(&self) -> Option<&SongId> {
|
pub fn get_current_song(&self) -> Option<&SongId> {
|
||||||
@ -164,7 +159,7 @@ impl Queue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueueContent::Random(v) => v.get(v.len().saturating_sub(1))?.get_current(),
|
QueueContent::Random(v) => v.get(v.len().saturating_sub(1))?.get_current(),
|
||||||
QueueContent::Shuffle(i, map, elems, _) => elems.get(*map.get(*i + 1)?),
|
QueueContent::Shuffle { inner, state: _ } => inner.get_next(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get_first(&self) -> Option<&Self> {
|
pub fn get_first(&self) -> Option<&Self> {
|
||||||
@ -173,13 +168,7 @@ impl Queue {
|
|||||||
QueueContent::Folder(_, v, _) => v.first(),
|
QueueContent::Folder(_, v, _) => v.first(),
|
||||||
QueueContent::Loop(_, _, q) => q.get_first(),
|
QueueContent::Loop(_, _, q) => q.get_first(),
|
||||||
QueueContent::Random(q) => q.front(),
|
QueueContent::Random(q) => q.front(),
|
||||||
QueueContent::Shuffle(i, _, v, next) => {
|
QueueContent::Shuffle { inner, state: _ } => inner.get_first(),
|
||||||
if *i == 0 {
|
|
||||||
v.get(*i)
|
|
||||||
} else {
|
|
||||||
v.get(*next)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,12 +181,27 @@ impl Queue {
|
|||||||
pub fn init(&mut self, path: Vec<usize>, actions: &mut Vec<QueueAction>) {
|
pub fn init(&mut self, path: Vec<usize>, actions: &mut Vec<QueueAction>) {
|
||||||
match &mut self.content {
|
match &mut self.content {
|
||||||
QueueContent::Song(..) => {}
|
QueueContent::Song(..) => {}
|
||||||
QueueContent::Folder(_, v, _) => {
|
QueueContent::Folder(i, v, _) => {
|
||||||
|
*i = 0;
|
||||||
if let Some(v) = v.first_mut() {
|
if let Some(v) = v.first_mut() {
|
||||||
v.init(path, actions);
|
v.init(
|
||||||
|
{
|
||||||
|
let mut p = path.clone();
|
||||||
|
p.push(0);
|
||||||
|
p
|
||||||
|
},
|
||||||
|
actions,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueueContent::Loop(_, _, inner) => inner.init(path, actions),
|
QueueContent::Loop(_, _, inner) => inner.init(
|
||||||
|
{
|
||||||
|
let mut p = path.clone();
|
||||||
|
p.push(0);
|
||||||
|
p
|
||||||
|
},
|
||||||
|
actions,
|
||||||
|
),
|
||||||
QueueContent::Random(q) => {
|
QueueContent::Random(q) => {
|
||||||
if q.len() == 0 {
|
if q.len() == 0 {
|
||||||
actions.push(QueueAction::AddRandomSong(path.clone()));
|
actions.push(QueueAction::AddRandomSong(path.clone()));
|
||||||
@ -207,21 +211,17 @@ impl Queue {
|
|||||||
q.init(path, actions)
|
q.init(path, actions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueueContent::Shuffle(current, map, elems, next) => {
|
QueueContent::Shuffle { inner, state } => {
|
||||||
let mut new_map = (0..elems.len()).filter(|v| *v != *next).collect::<Vec<_>>();
|
let mut p = path.clone();
|
||||||
new_map.shuffle(&mut rand::thread_rng());
|
p.push(0);
|
||||||
if let Some(first) = new_map.first_mut() {
|
if matches!(state, ShuffleState::NotShuffled | ShuffleState::Modified) {
|
||||||
let was_first = std::mem::replace(first, *next);
|
actions.push(QueueAction::SetShuffle(
|
||||||
new_map.push(was_first);
|
path,
|
||||||
} else if *next < elems.len() {
|
matches!(state, ShuffleState::Modified),
|
||||||
new_map.push(*next);
|
));
|
||||||
|
*state = ShuffleState::Shuffled;
|
||||||
}
|
}
|
||||||
let new_next = if elems.is_empty() {
|
inner.init(p, actions);
|
||||||
0
|
|
||||||
} else {
|
|
||||||
rand::thread_rng().gen_range(0..elems.len())
|
|
||||||
};
|
|
||||||
actions.push(QueueAction::SetShuffle(path, new_map, new_next));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,15 +238,36 @@ impl Queue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueueAction::SetShuffle(path, shuf, next) => {
|
QueueAction::SetShuffle(path, partial) => {
|
||||||
if !db.is_client() {
|
if !db.is_client() {
|
||||||
db.apply_command(Command::QueueSetShuffle(path, shuf, next));
|
let mut actions = vec![];
|
||||||
|
if let Some(QueueContent::Shuffle { inner, state: _ }) = db
|
||||||
|
.queue
|
||||||
|
.get_item_at_index_mut(&path, 0, &mut actions)
|
||||||
|
.map(|v| v.content_mut())
|
||||||
|
{
|
||||||
|
if let QueueContent::Folder(i, v, _) = inner.content_mut() {
|
||||||
|
let mut order = (0..v.len()).collect::<Vec<usize>>();
|
||||||
|
if partial && *i + 1 < v.len() {
|
||||||
|
// shuffle only elements after the current one
|
||||||
|
order[*i + 1..].shuffle(&mut rand::thread_rng());
|
||||||
|
} else {
|
||||||
|
order.shuffle(&mut rand::thread_rng());
|
||||||
|
}
|
||||||
|
db.apply_command(Command::QueueSetShuffle(path, order));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Queue::handle_actions(db, actions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn advance_index_inner(&mut self, path: Vec<usize>, actions: &mut Vec<QueueAction>) -> bool {
|
fn advance_index_inner(
|
||||||
|
&mut self,
|
||||||
|
mut path: Vec<usize>,
|
||||||
|
actions: &mut Vec<QueueAction>,
|
||||||
|
) -> bool {
|
||||||
match &mut self.content {
|
match &mut self.content {
|
||||||
QueueContent::Song(_) => false,
|
QueueContent::Song(_) => false,
|
||||||
QueueContent::Folder(index, contents, _) => {
|
QueueContent::Folder(index, contents, _) => {
|
||||||
@ -278,9 +299,8 @@ impl Queue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueueContent::Loop(total, current, inner) => {
|
QueueContent::Loop(total, current, inner) => {
|
||||||
let mut p = path.clone();
|
path.push(0);
|
||||||
p.push(0);
|
if inner.advance_index_inner(path.clone(), actions) {
|
||||||
if inner.advance_index_inner(p, actions) {
|
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
*current += 1;
|
*current += 1;
|
||||||
@ -316,28 +336,15 @@ impl Queue {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueueContent::Shuffle(current, map, elems, _) => {
|
QueueContent::Shuffle { inner, state } => {
|
||||||
if map
|
|
||||||
.get(*current)
|
|
||||||
.and_then(|i| elems.get_mut(*i))
|
|
||||||
.is_some_and(|q| {
|
|
||||||
let mut p = path.clone();
|
let mut p = path.clone();
|
||||||
p.push(*current);
|
p.push(0);
|
||||||
q.advance_index_inner(p, actions)
|
if !inner.advance_index_inner(p, actions) {
|
||||||
})
|
*state = ShuffleState::Shuffled;
|
||||||
{
|
actions.push(QueueAction::SetShuffle(path, false));
|
||||||
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
|
false
|
||||||
}
|
} else {
|
||||||
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -345,6 +352,7 @@ impl Queue {
|
|||||||
|
|
||||||
pub fn set_index_db(db: &mut Database, index: &Vec<usize>) {
|
pub fn set_index_db(db: &mut Database, index: &Vec<usize>) {
|
||||||
let mut actions = vec![];
|
let mut actions = vec![];
|
||||||
|
db.queue.reset_index();
|
||||||
db.queue.set_index_inner(index, 0, vec![], &mut actions);
|
db.queue.set_index_inner(index, 0, vec![], &mut actions);
|
||||||
Self::handle_actions(db, actions);
|
Self::handle_actions(db, actions);
|
||||||
}
|
}
|
||||||
@ -377,15 +385,29 @@ impl Queue {
|
|||||||
inner.set_index_inner(index, depth + 1, build_index, actions)
|
inner.set_index_inner(index, depth + 1, build_index, actions)
|
||||||
}
|
}
|
||||||
QueueContent::Random(_) => {}
|
QueueContent::Random(_) => {}
|
||||||
QueueContent::Shuffle(current, map, elems, next) => {
|
QueueContent::Shuffle { inner, state: _ } => {
|
||||||
if i != *current {
|
inner.init(build_index.clone(), actions);
|
||||||
*current = i;
|
inner.set_index_inner(index, depth + 1, build_index, actions)
|
||||||
}
|
}
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn reset_index(&mut self) {
|
||||||
|
match self.content_mut() {
|
||||||
|
QueueContent::Song(_) => {}
|
||||||
|
QueueContent::Folder(i, v, _) => {
|
||||||
|
*i = 0;
|
||||||
|
for v in v {
|
||||||
|
v.reset_index();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QueueContent::Loop(_, done, i) => {
|
||||||
|
*done = 0;
|
||||||
|
i.reset_index();
|
||||||
|
}
|
||||||
|
QueueContent::Random(_) => {}
|
||||||
|
QueueContent::Shuffle { inner, state: _ } => {
|
||||||
|
inner.reset_index();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,34 +424,52 @@ impl Queue {
|
|||||||
}
|
}
|
||||||
QueueContent::Loop(_, _, inner) => inner.get_item_at_index(index, depth + 1),
|
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::Random(vec) => vec.get(*i)?.get_item_at_index(index, depth + 1),
|
||||||
QueueContent::Shuffle(_, map, elems, _) => map
|
QueueContent::Shuffle { inner, state: _ } => {
|
||||||
.get(*i)
|
inner.get_item_at_index(index, depth + 1)
|
||||||
.and_then(|i| elems.get(*i))
|
}
|
||||||
.and_then(|elem| elem.get_item_at_index(index, depth + 1)),
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Some(self)
|
Some(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get_item_at_index_mut(&mut self, index: &Vec<usize>, depth: usize) -> Option<&mut Self> {
|
pub fn get_item_at_index_mut(
|
||||||
|
&mut self,
|
||||||
|
index: &Vec<usize>,
|
||||||
|
depth: usize,
|
||||||
|
actions: &mut Vec<QueueAction>,
|
||||||
|
) -> Option<&mut Self> {
|
||||||
if let Some(i) = index.get(depth) {
|
if let Some(i) = index.get(depth) {
|
||||||
match &mut self.content {
|
match &mut self.content {
|
||||||
QueueContent::Song(_) => None,
|
QueueContent::Song(_) => None,
|
||||||
QueueContent::Folder(_, v, _) => {
|
QueueContent::Folder(_, v, _) => {
|
||||||
if let Some(v) = v.get_mut(*i) {
|
if let Some(v) = v.get_mut(*i) {
|
||||||
v.get_item_at_index_mut(index, depth + 1)
|
v.get_item_at_index_mut(index, depth + 1, actions)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueueContent::Loop(_, _, inner) => inner.get_item_at_index_mut(index, depth + 1),
|
QueueContent::Loop(_, _, inner) => {
|
||||||
QueueContent::Random(vec) => {
|
inner.get_item_at_index_mut(index, depth + 1, actions)
|
||||||
vec.get_mut(*i)?.get_item_at_index_mut(index, depth + 1)
|
}
|
||||||
|
QueueContent::Random(vec) => {
|
||||||
|
vec.get_mut(*i)?
|
||||||
|
.get_item_at_index_mut(index, depth + 1, actions)
|
||||||
|
}
|
||||||
|
QueueContent::Shuffle { inner, state } => {
|
||||||
|
// if getting a mutable reference to the Folder that holds our songs,
|
||||||
|
// it may have been modified
|
||||||
|
if depth + 1 == index.len() && matches!(state, ShuffleState::Shuffled) {
|
||||||
|
*state = ShuffleState::Modified;
|
||||||
|
}
|
||||||
|
if matches!(state, ShuffleState::NotShuffled | ShuffleState::Modified) {
|
||||||
|
actions.push(QueueAction::SetShuffle(
|
||||||
|
index[0..depth].to_vec(),
|
||||||
|
matches!(state, ShuffleState::Modified),
|
||||||
|
));
|
||||||
|
*state = ShuffleState::Shuffled;
|
||||||
|
}
|
||||||
|
inner.get_item_at_index_mut(index, depth + 1, actions)
|
||||||
}
|
}
|
||||||
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 {
|
} else {
|
||||||
Some(self)
|
Some(self)
|
||||||
@ -468,23 +508,8 @@ impl Queue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueueContent::Random(v) => v.remove(*i),
|
QueueContent::Random(v) => v.remove(*i),
|
||||||
QueueContent::Shuffle(current, map, elems, next) => {
|
QueueContent::Shuffle { inner, state: _ } => {
|
||||||
if *i < *current {
|
inner.remove_by_index(index, depth + 1)
|
||||||
*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 {
|
} else {
|
||||||
@ -550,12 +575,10 @@ impl ToFromBytes for QueueContent {
|
|||||||
s.write_all(&[0b00110000])?;
|
s.write_all(&[0b00110000])?;
|
||||||
q.to_bytes(s)?;
|
q.to_bytes(s)?;
|
||||||
}
|
}
|
||||||
Self::Shuffle(current, map, elems, next) => {
|
Self::Shuffle { inner, state } => {
|
||||||
s.write_all(&[0b00001100])?;
|
s.write_all(&[0b00001100])?;
|
||||||
current.to_bytes(s)?;
|
inner.to_bytes(s)?;
|
||||||
map.to_bytes(s)?;
|
state.to_bytes(s)?;
|
||||||
elems.to_bytes(s)?;
|
|
||||||
next.to_bytes(s)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -579,13 +602,42 @@ impl ToFromBytes for QueueContent {
|
|||||||
Box::new(ToFromBytes::from_bytes(s)?),
|
Box::new(ToFromBytes::from_bytes(s)?),
|
||||||
),
|
),
|
||||||
0b00110000 => Self::Random(ToFromBytes::from_bytes(s)?),
|
0b00110000 => Self::Random(ToFromBytes::from_bytes(s)?),
|
||||||
0b00001100 => Self::Shuffle(
|
0b00001100 => Self::Shuffle {
|
||||||
ToFromBytes::from_bytes(s)?,
|
inner: Box::new(ToFromBytes::from_bytes(s)?),
|
||||||
ToFromBytes::from_bytes(s)?,
|
state: ToFromBytes::from_bytes(s)?,
|
||||||
ToFromBytes::from_bytes(s)?,
|
},
|
||||||
ToFromBytes::from_bytes(s)?,
|
|
||||||
),
|
|
||||||
_ => Self::Folder(0, vec![], "<invalid byte received>".to_string()),
|
_ => Self::Folder(0, vec![], "<invalid byte received>".to_string()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl ToFromBytes for ShuffleState {
|
||||||
|
fn to_bytes<T>(&self, s: &mut T) -> Result<(), std::io::Error>
|
||||||
|
where
|
||||||
|
T: std::io::Write,
|
||||||
|
{
|
||||||
|
s.write_all(&[match self {
|
||||||
|
Self::NotShuffled => 1,
|
||||||
|
Self::Modified => 2,
|
||||||
|
Self::Shuffled => 4,
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
fn from_bytes<T>(s: &mut T) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
T: std::io::Read,
|
||||||
|
{
|
||||||
|
let mut b = [0];
|
||||||
|
s.read_exact(&mut b)?;
|
||||||
|
Ok(match b[0] {
|
||||||
|
1 => Self::NotShuffled,
|
||||||
|
2 => Self::Modified,
|
||||||
|
4 => Self::Shuffled,
|
||||||
|
_ => {
|
||||||
|
eprintln!(
|
||||||
|
"[warn] received {} as ShuffleState, which is invalid. defaulting to Shuffled.",
|
||||||
|
b[0]
|
||||||
|
);
|
||||||
|
Self::Shuffled
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
path::{Path, PathBuf},
|
path::PathBuf,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
thread::JoinHandle,
|
thread::JoinHandle,
|
||||||
};
|
};
|
||||||
|
@ -37,7 +37,7 @@ pub enum Command {
|
|||||||
QueueInsert(Vec<usize>, usize, Queue),
|
QueueInsert(Vec<usize>, usize, Queue),
|
||||||
QueueRemove(Vec<usize>),
|
QueueRemove(Vec<usize>),
|
||||||
QueueGoto(Vec<usize>),
|
QueueGoto(Vec<usize>),
|
||||||
QueueSetShuffle(Vec<usize>, Vec<usize>, usize),
|
QueueSetShuffle(Vec<usize>, Vec<usize>),
|
||||||
/// .id field is ignored!
|
/// .id field is ignored!
|
||||||
AddSong(Song),
|
AddSong(Song),
|
||||||
/// .id field is ignored!
|
/// .id field is ignored!
|
||||||
@ -232,11 +232,10 @@ impl ToFromBytes for Command {
|
|||||||
s.write_all(&[0b00011011])?;
|
s.write_all(&[0b00011011])?;
|
||||||
index.to_bytes(s)?;
|
index.to_bytes(s)?;
|
||||||
}
|
}
|
||||||
Self::QueueSetShuffle(path, map, next) => {
|
Self::QueueSetShuffle(path, map) => {
|
||||||
s.write_all(&[0b10011011])?;
|
s.write_all(&[0b10011011])?;
|
||||||
path.to_bytes(s)?;
|
path.to_bytes(s)?;
|
||||||
map.to_bytes(s)?;
|
map.to_bytes(s)?;
|
||||||
next.to_bytes(s)?;
|
|
||||||
}
|
}
|
||||||
Self::AddSong(song) => {
|
Self::AddSong(song) => {
|
||||||
s.write_all(&[0b01010000])?;
|
s.write_all(&[0b01010000])?;
|
||||||
@ -313,11 +312,9 @@ impl ToFromBytes for Command {
|
|||||||
),
|
),
|
||||||
0b00011001 => Self::QueueRemove(ToFromBytes::from_bytes(s)?),
|
0b00011001 => Self::QueueRemove(ToFromBytes::from_bytes(s)?),
|
||||||
0b00011011 => Self::QueueGoto(ToFromBytes::from_bytes(s)?),
|
0b00011011 => Self::QueueGoto(ToFromBytes::from_bytes(s)?),
|
||||||
0b10011011 => Self::QueueSetShuffle(
|
0b10011011 => {
|
||||||
ToFromBytes::from_bytes(s)?,
|
Self::QueueSetShuffle(ToFromBytes::from_bytes(s)?, ToFromBytes::from_bytes(s)?)
|
||||||
ToFromBytes::from_bytes(s)?,
|
}
|
||||||
ToFromBytes::from_bytes(s)?,
|
|
||||||
),
|
|
||||||
0b01010000 => Self::AddSong(ToFromBytes::from_bytes(s)?),
|
0b01010000 => Self::AddSong(ToFromBytes::from_bytes(s)?),
|
||||||
0b01010011 => Self::AddAlbum(ToFromBytes::from_bytes(s)?),
|
0b01010011 => Self::AddAlbum(ToFromBytes::from_bytes(s)?),
|
||||||
0b01011100 => Self::AddArtist(ToFromBytes::from_bytes(s)?),
|
0b01011100 => Self::AddArtist(ToFromBytes::from_bytes(s)?),
|
||||||
|
@ -663,7 +663,7 @@ fn build_queue_content_build(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueueContent::Shuffle(cur, map, content, _) => {
|
QueueContent::Shuffle { inner, state: _ } => {
|
||||||
for v in if current {
|
for v in if current {
|
||||||
&state.html.queue_shuffle_current
|
&state.html.queue_shuffle_current
|
||||||
} else {
|
} else {
|
||||||
@ -674,19 +674,16 @@ fn build_queue_content_build(
|
|||||||
HtmlPart::Insert(key) => match key.as_str() {
|
HtmlPart::Insert(key) => match key.as_str() {
|
||||||
"path" => html.push_str(&path),
|
"path" => html.push_str(&path),
|
||||||
"content" => {
|
"content" => {
|
||||||
for (i, v) in map.iter().filter_map(|i| content.get(*i)).enumerate()
|
|
||||||
{
|
|
||||||
build_queue_content_build(
|
build_queue_content_build(
|
||||||
db,
|
db,
|
||||||
state,
|
state,
|
||||||
html,
|
html,
|
||||||
&v,
|
&inner,
|
||||||
format!("{path}-0"),
|
format!("{path}-0"),
|
||||||
current && i == *cur,
|
current,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user