mirror of
https://github.com/Dummi26/musicdb.git
synced 2025-03-10 14:13:53 +01:00
fix shuffle not shuffling away first element
and fix dragging selected song not dragging all selected elements but rather only those that pass current filter/search, which was not intended.
This commit is contained in:
parent
7f33d2daf8
commit
8a9ee5c9cf
@ -1106,6 +1106,8 @@ impl Gui {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
GuiAction::SendToServer(cmd) => {
|
GuiAction::SendToServer(cmd) => {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
eprintln!("[DEBUG] Sending command to server: {cmd:?}");
|
||||||
if let Err(e) = cmd.to_bytes(&mut self.connection) {
|
if let Err(e) = cmd.to_bytes(&mut self.connection) {
|
||||||
eprintln!("Error sending command to server: {e}");
|
eprintln!("Error sending command to server: {e}");
|
||||||
}
|
}
|
||||||
|
@ -2157,7 +2157,7 @@ mod selected {
|
|||||||
let lock = self.0.lock().unwrap();
|
let lock = self.0.lock().unwrap();
|
||||||
let (sel_artists, sel_albums, sel_songs) = &*lock;
|
let (sel_artists, sel_albums, sel_songs) = &*lock;
|
||||||
let mut out = vec![];
|
let mut out = vec![];
|
||||||
for (artist, singles, albums, _) in &lb.library_filtered {
|
for (artist, singles, albums) in &lb.library_sorted {
|
||||||
let artist_selected = sel_artists.contains(artist);
|
let artist_selected = sel_artists.contains(artist);
|
||||||
let mut local_artist_owned = vec![];
|
let mut local_artist_owned = vec![];
|
||||||
let mut local_artist = if artist_selected {
|
let mut local_artist = if artist_selected {
|
||||||
@ -2165,13 +2165,13 @@ mod selected {
|
|||||||
} else {
|
} else {
|
||||||
&mut out
|
&mut out
|
||||||
};
|
};
|
||||||
for (song, _) in singles {
|
for song in singles {
|
||||||
let song_selected = sel_songs.contains(song);
|
let song_selected = sel_songs.contains(song);
|
||||||
if song_selected {
|
if song_selected {
|
||||||
local_artist.push(QueueContent::Song(*song).into());
|
local_artist.push(QueueContent::Song(*song).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (album, songs, _) in albums {
|
for (album, songs) in albums {
|
||||||
let album_selected = sel_albums.contains(album);
|
let album_selected = sel_albums.contains(album);
|
||||||
let mut local_album_owned = vec![];
|
let mut local_album_owned = vec![];
|
||||||
let local_album = if album_selected {
|
let local_album = if album_selected {
|
||||||
@ -2179,7 +2179,7 @@ mod selected {
|
|||||||
} else {
|
} else {
|
||||||
&mut local_artist
|
&mut local_artist
|
||||||
};
|
};
|
||||||
for (song, _) in songs {
|
for song in songs {
|
||||||
let song_selected = sel_songs.contains(song);
|
let song_selected = sel_songs.contains(song);
|
||||||
if song_selected {
|
if song_selected {
|
||||||
local_album.push(QueueContent::Song(*song).into());
|
local_album.push(QueueContent::Song(*song).into());
|
||||||
|
@ -408,7 +408,7 @@ impl GuiElem for QueueEmptySpaceDragHandler {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
fn dragged(&mut self, dragged: Dragging) -> Vec<GuiAction> {
|
fn dragged(&mut self, dragged: Dragging) -> Vec<GuiAction> {
|
||||||
dragged_add_to_queue(dragged, |q, _| Command::QueueAdd(vec![], q))
|
dragged_add_to_queue(dragged, |q| Command::QueueAdd(vec![], q))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -623,9 +623,9 @@ impl GuiElem for QueueSong {
|
|||||||
if !self.always_copy {
|
if !self.always_copy {
|
||||||
let mut p = self.path.clone();
|
let mut p = self.path.clone();
|
||||||
let insert_below = self.insert_below;
|
let insert_below = self.insert_below;
|
||||||
dragged_add_to_queue(dragged, move |q, i| {
|
dragged_add_to_queue(dragged, move |q| {
|
||||||
if let Some(j) = p.pop() {
|
if let Some(j) = p.pop() {
|
||||||
Command::QueueInsert(p.clone(), if insert_below { j + 1 } else { j } + i, q)
|
Command::QueueInsert(p.clone(), if insert_below { j + 1 } else { j }, q)
|
||||||
} else {
|
} else {
|
||||||
Command::QueueAdd(p.clone(), q)
|
Command::QueueAdd(p.clone(), q)
|
||||||
}
|
}
|
||||||
@ -782,13 +782,11 @@ impl GuiElem for QueueFolder {
|
|||||||
if !self.always_copy {
|
if !self.always_copy {
|
||||||
if self.insert_into {
|
if self.insert_into {
|
||||||
let p = self.path.clone();
|
let p = self.path.clone();
|
||||||
dragged_add_to_queue(dragged, move |q, _| Command::QueueAdd(p.clone(), q))
|
dragged_add_to_queue(dragged, move |q| Command::QueueAdd(p.clone(), q))
|
||||||
} else {
|
} else {
|
||||||
let mut p = self.path.clone();
|
let mut p = self.path.clone();
|
||||||
let j = p.pop().unwrap_or(0);
|
let j = p.pop().unwrap_or(0);
|
||||||
dragged_add_to_queue(dragged, move |q, i| {
|
dragged_add_to_queue(dragged, move |q| Command::QueueInsert(p.clone(), j, q))
|
||||||
Command::QueueInsert(p.clone(), j + i, q)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
@ -850,9 +848,7 @@ impl GuiElem for QueueIndentEnd {
|
|||||||
}
|
}
|
||||||
fn dragged(&mut self, dragged: Dragging) -> Vec<GuiAction> {
|
fn dragged(&mut self, dragged: Dragging) -> Vec<GuiAction> {
|
||||||
let (p, j) = self.path_insert.clone();
|
let (p, j) = self.path_insert.clone();
|
||||||
dragged_add_to_queue(dragged, move |q, i| {
|
dragged_add_to_queue(dragged, move |q| Command::QueueInsert(p.clone(), j, q))
|
||||||
Command::QueueInsert(p.clone(), j + i, q)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1004,7 +1000,7 @@ impl GuiElem for QueueLoop {
|
|||||||
if !self.always_copy {
|
if !self.always_copy {
|
||||||
let mut p = self.path.clone();
|
let mut p = self.path.clone();
|
||||||
p.push(0);
|
p.push(0);
|
||||||
dragged_add_to_queue(dragged, move |q, _| Command::QueueAdd(p.clone(), q))
|
dragged_add_to_queue(dragged, move |q| Command::QueueAdd(p.clone(), q))
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
@ -1130,7 +1126,7 @@ impl GuiElem for QueueRandom {
|
|||||||
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 p = self.path.clone();
|
||||||
dragged_add_to_queue(dragged, move |q, _| Command::QueueAdd(p.clone(), q))
|
dragged_add_to_queue(dragged, move |q| Command::QueueAdd(p.clone(), q))
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
@ -1257,22 +1253,22 @@ impl GuiElem for QueueShuffle {
|
|||||||
if !self.always_copy {
|
if !self.always_copy {
|
||||||
let mut p = self.path.clone();
|
let mut p = self.path.clone();
|
||||||
p.push(0);
|
p.push(0);
|
||||||
dragged_add_to_queue(dragged, move |q, _| Command::QueueAdd(p.clone(), q))
|
dragged_add_to_queue(dragged, move |q| Command::QueueAdd(p.clone(), q))
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dragged_add_to_queue<F: FnMut(Queue, usize) -> Command + 'static>(
|
fn dragged_add_to_queue<F: FnOnce(Vec<Queue>) -> Command + 'static>(
|
||||||
dragged: Dragging,
|
dragged: Dragging,
|
||||||
mut f: F,
|
f: F,
|
||||||
) -> Vec<GuiAction> {
|
) -> Vec<GuiAction> {
|
||||||
match dragged {
|
match dragged {
|
||||||
Dragging::Artist(id) => {
|
Dragging::Artist(id) => {
|
||||||
vec![GuiAction::Build(Box::new(move |db| {
|
vec![GuiAction::Build(Box::new(move |db| {
|
||||||
if let Some(q) = add_to_queue_artist_by_id(id, db) {
|
if let Some(q) = add_to_queue_artist_by_id(id, db) {
|
||||||
vec![GuiAction::SendToServer(f(q, 0))]
|
vec![GuiAction::SendToServer(f(vec![q]))]
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
@ -1281,7 +1277,7 @@ fn dragged_add_to_queue<F: FnMut(Queue, usize) -> Command + 'static>(
|
|||||||
Dragging::Album(id) => {
|
Dragging::Album(id) => {
|
||||||
vec![GuiAction::Build(Box::new(move |db| {
|
vec![GuiAction::Build(Box::new(move |db| {
|
||||||
if let Some(q) = add_to_queue_album_by_id(id, db) {
|
if let Some(q) = add_to_queue_album_by_id(id, db) {
|
||||||
vec![GuiAction::SendToServer(f(q, 0))]
|
vec![GuiAction::SendToServer(f(vec![q]))]
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
@ -1289,16 +1285,12 @@ fn dragged_add_to_queue<F: FnMut(Queue, usize) -> Command + 'static>(
|
|||||||
}
|
}
|
||||||
Dragging::Song(id) => {
|
Dragging::Song(id) => {
|
||||||
let q = QueueContent::Song(id).into();
|
let q = QueueContent::Song(id).into();
|
||||||
vec![GuiAction::SendToServer(f(q, 0))]
|
vec![GuiAction::SendToServer(f(vec![q]))]
|
||||||
}
|
}
|
||||||
Dragging::Queue(q) => {
|
Dragging::Queue(q) => {
|
||||||
vec![GuiAction::SendToServer(f(q, 0))]
|
vec![GuiAction::SendToServer(f(vec![q]))]
|
||||||
}
|
}
|
||||||
Dragging::Queues(q) => q
|
Dragging::Queues(q) => vec![GuiAction::SendToServer(f(q))],
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(i, q)| GuiAction::SendToServer(f(q, i)))
|
|
||||||
.collect(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
awedio = { version = "0.2.0", optional = true }
|
awedio = { version = "0.2.0", optional = true }
|
||||||
base64 = "0.21.2"
|
base64 = "0.21.2"
|
||||||
|
colorize = "0.1.0"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
rc-u8-reader = "2.0.16"
|
rc-u8-reader = "2.0.16"
|
||||||
tokio = { version = "1.29.1", features = ["sync"] }
|
tokio = { version = "1.29.1", features = ["sync"] }
|
||||||
|
@ -7,6 +7,8 @@ use std::{
|
|||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use colorize::AnsiColor;
|
||||||
|
|
||||||
use crate::{load::ToFromBytes, server::Command};
|
use crate::{load::ToFromBytes, server::Command};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@ -263,7 +265,7 @@ impl Database {
|
|||||||
}
|
}
|
||||||
Command::Save => {
|
Command::Save => {
|
||||||
if let Err(e) = self.save_database(None) {
|
if let Err(e) = self.save_database(None) {
|
||||||
eprintln!("Couldn't save: {e}");
|
eprintln!("[{}] Couldn't save: {e}", "ERR!".red());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Command::SyncDatabase(a, b, c) => self.sync(a, b, c),
|
Command::SyncDatabase(a, b, c) => self.sync(a, b, c),
|
||||||
@ -274,28 +276,17 @@ impl Database {
|
|||||||
}
|
}
|
||||||
Queue::handle_actions(self, actions);
|
Queue::handle_actions(self, actions);
|
||||||
}
|
}
|
||||||
Command::QueueAdd(mut index, new_data) => {
|
Command::QueueAdd(index, new_data) => {
|
||||||
let mut actions = vec![];
|
let mut actions = vec![];
|
||||||
if let Some(v) = self.queue.get_item_at_index_mut(&index, 0, &mut actions) {
|
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) {
|
v.add_to_end(new_data, index, &mut actions);
|
||||||
index.push(i);
|
|
||||||
if let Some(q) = self.queue.get_item_at_index_mut(&index, 0, &mut actions) {
|
|
||||||
let mut actions = Vec::new();
|
|
||||||
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(index, pos, new_data) => {
|
||||||
let mut actions = vec![];
|
let mut actions = vec![];
|
||||||
if let Some(v) = self.queue.get_item_at_index_mut(&index, 0, &mut actions) {
|
if let Some(v) = self.queue.get_item_at_index_mut(&index, 0, &mut actions) {
|
||||||
index.push(pos);
|
v.insert(new_data, pos, index, &mut actions);
|
||||||
let mut actions = Vec::new();
|
|
||||||
new_data.init(index, &mut actions);
|
|
||||||
v.insert(new_data, pos);
|
|
||||||
Queue::handle_actions(self, actions);
|
|
||||||
}
|
}
|
||||||
Queue::handle_actions(self, actions);
|
Queue::handle_actions(self, actions);
|
||||||
}
|
}
|
||||||
@ -316,7 +307,7 @@ impl Database {
|
|||||||
if let Some(a) = o.get_mut(i).and_then(Option::take) {
|
if let Some(a) = o.get_mut(i).and_then(Option::take) {
|
||||||
v.push(a);
|
v.push(a);
|
||||||
} else {
|
} 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());
|
eprintln!("[{}] 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:?}.", "WARN".yellow(), v.len());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -327,7 +318,10 @@ impl Database {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
eprintln!("[warn] can't QueueSetShuffle - no element at path {path:?}");
|
eprintln!(
|
||||||
|
"[{}] can't QueueSetShuffle - no element at path {path:?}",
|
||||||
|
"WARN".yellow()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Queue::handle_actions(self, actions);
|
Queue::handle_actions(self, actions);
|
||||||
}
|
}
|
||||||
@ -365,42 +359,42 @@ impl Database {
|
|||||||
v.general.tags.push(tag);
|
v.general.tags.push(tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Command::TagSongFlagUnset(id, tag) => {
|
Command::TagSongFlagUnset(id, tag) => {
|
||||||
if let Some(v) = self.get_song_mut(&id) {
|
if let Some(v) = self.get_song_mut(&id) {
|
||||||
if let Some(i) = v.general.tags.iter().position(|v| v == &tag) {
|
if let Some(i) = v.general.tags.iter().position(|v| v == &tag) {
|
||||||
v.general.tags.remove(i);
|
v.general.tags.remove(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Command::TagAlbumFlagSet(id, tag) => {
|
Command::TagAlbumFlagSet(id, tag) => {
|
||||||
if let Some(v) = self.albums.get_mut(&id) {
|
if let Some(v) = self.albums.get_mut(&id) {
|
||||||
if !v.general.tags.contains(&tag) {
|
if !v.general.tags.contains(&tag) {
|
||||||
v.general.tags.push(tag);
|
v.general.tags.push(tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Command::TagAlbumFlagUnset(id, tag) => {
|
Command::TagAlbumFlagUnset(id, tag) => {
|
||||||
if let Some(v) = self.albums.get_mut(&id) {
|
if let Some(v) = self.albums.get_mut(&id) {
|
||||||
if let Some(i) = v.general.tags.iter().position(|v| v == &tag) {
|
if let Some(i) = v.general.tags.iter().position(|v| v == &tag) {
|
||||||
v.general.tags.remove(i);
|
v.general.tags.remove(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Command::TagArtistFlagSet(id, tag) => {
|
Command::TagArtistFlagSet(id, tag) => {
|
||||||
if let Some(v) = self.artists.get_mut(&id) {
|
if let Some(v) = self.artists.get_mut(&id) {
|
||||||
if !v.general.tags.contains(&tag) {
|
if !v.general.tags.contains(&tag) {
|
||||||
v.general.tags.push(tag);
|
v.general.tags.push(tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Command::TagArtistFlagUnset(id, tag) => {
|
Command::TagArtistFlagUnset(id, tag) => {
|
||||||
if let Some(v) = self.artists.get_mut(&id) {
|
if let Some(v) = self.artists.get_mut(&id) {
|
||||||
if let Some(i) = v.general.tags.iter().position(|v| v == &tag) {
|
if let Some(i) = v.general.tags.iter().position(|v| v == &tag) {
|
||||||
v.general.tags.remove(i);
|
v.general.tags.remove(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Command::TagSongPropertySet(id, key, val) => {
|
Command::TagSongPropertySet(id, key, val) => {
|
||||||
if let Some(v) = self.get_song_mut(&id) {
|
if let Some(v) = self.get_song_mut(&id) {
|
||||||
let new = format!("{key}{val}");
|
let new = format!("{key}{val}");
|
||||||
@ -507,8 +501,8 @@ impl Database {
|
|||||||
}
|
}
|
||||||
pub fn load_database(path: PathBuf, lib_directory: PathBuf) -> Result<Self, std::io::Error> {
|
pub fn load_database(path: PathBuf, lib_directory: PathBuf) -> Result<Self, std::io::Error> {
|
||||||
let mut file = BufReader::new(File::open(&path)?);
|
let mut file = BufReader::new(File::open(&path)?);
|
||||||
eprintln!("[info] loading library from {file:?}");
|
eprintln!("[{}] loading library from {file:?}", "INFO".cyan());
|
||||||
Ok(Self {
|
let s = Self {
|
||||||
db_file: path,
|
db_file: path,
|
||||||
lib_directory,
|
lib_directory,
|
||||||
artists: ToFromBytes::from_bytes(&mut file)?,
|
artists: ToFromBytes::from_bytes(&mut file)?,
|
||||||
@ -524,7 +518,9 @@ impl Database {
|
|||||||
command_sender: None,
|
command_sender: None,
|
||||||
remote_server_as_song_file_source: None,
|
remote_server_as_song_file_source: None,
|
||||||
client_is_init: false,
|
client_is_init: false,
|
||||||
})
|
};
|
||||||
|
eprintln!("[{}] loaded library", "INFO".green());
|
||||||
|
Ok(s)
|
||||||
}
|
}
|
||||||
/// saves the database's contents. save path can be overridden
|
/// saves the database's contents. save path can be overridden
|
||||||
pub fn save_database(&self, path: Option<PathBuf>) -> Result<PathBuf, std::io::Error> {
|
pub fn save_database(&self, path: Option<PathBuf>) -> Result<PathBuf, std::io::Error> {
|
||||||
@ -537,7 +533,7 @@ impl Database {
|
|||||||
if path.as_os_str().is_empty() {
|
if path.as_os_str().is_empty() {
|
||||||
return Ok(path);
|
return Ok(path);
|
||||||
}
|
}
|
||||||
eprintln!("[info] saving db to {path:?}.");
|
eprintln!("[{}] saving db to {path:?}", "INFO".cyan());
|
||||||
let mut file = fs::OpenOptions::new()
|
let mut file = fs::OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.truncate(true)
|
.truncate(true)
|
||||||
@ -547,6 +543,7 @@ impl Database {
|
|||||||
self.albums.to_bytes(&mut file)?;
|
self.albums.to_bytes(&mut file)?;
|
||||||
self.songs.to_bytes(&mut file)?;
|
self.songs.to_bytes(&mut file)?;
|
||||||
self.covers.to_bytes(&mut file)?;
|
self.covers.to_bytes(&mut file)?;
|
||||||
|
eprintln!("[{}] saved db", "INFO".green());
|
||||||
Ok(path)
|
Ok(path)
|
||||||
}
|
}
|
||||||
pub fn broadcast_update(&mut self, update: &Command) {
|
pub fn broadcast_update(&mut self, update: &Command) {
|
||||||
|
@ -31,6 +31,7 @@ pub enum ShuffleState {
|
|||||||
|
|
||||||
pub enum QueueAction {
|
pub enum QueueAction {
|
||||||
AddRandomSong(Vec<usize>),
|
AddRandomSong(Vec<usize>),
|
||||||
|
/// `partial: bool`, if true, indicates that we only shuffle what is beyond the current index
|
||||||
SetShuffle(Vec<usize>, bool),
|
SetShuffle(Vec<usize>, bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,30 +46,64 @@ impl Queue {
|
|||||||
&mut self.content
|
&mut self.content
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_to_end(&mut self, v: Self) -> Option<usize> {
|
pub fn add_to_end(
|
||||||
|
&mut self,
|
||||||
|
v: Vec<Self>,
|
||||||
|
mut path: Vec<usize>,
|
||||||
|
actions: &mut Vec<QueueAction>,
|
||||||
|
) -> Option<usize> {
|
||||||
match &mut self.content {
|
match &mut self.content {
|
||||||
QueueContent::Song(_) => None,
|
QueueContent::Song(_) => None,
|
||||||
QueueContent::Folder(_, vec, _) => {
|
QueueContent::Folder(_, vec, _) => {
|
||||||
vec.push(v);
|
let len = vec.len();
|
||||||
Some(vec.len() - 1)
|
for (i, mut v) in v.into_iter().enumerate() {
|
||||||
|
path.push(len + i);
|
||||||
|
v.init(path.clone(), actions);
|
||||||
|
vec.push(v);
|
||||||
|
path.pop();
|
||||||
|
}
|
||||||
|
Some(len)
|
||||||
}
|
}
|
||||||
QueueContent::Loop(..) => None,
|
QueueContent::Loop(..) => None,
|
||||||
QueueContent::Random(q) => {
|
QueueContent::Random(q) => {
|
||||||
q.push_back(v);
|
// insert new elements
|
||||||
Some(q.len() - 1)
|
let len = q.len();
|
||||||
|
for (i, mut v) in v.into_iter().enumerate() {
|
||||||
|
path.push(len + i);
|
||||||
|
v.init(path.clone(), actions);
|
||||||
|
q.push_back(v);
|
||||||
|
path.pop();
|
||||||
|
}
|
||||||
|
Some(len)
|
||||||
}
|
}
|
||||||
QueueContent::Shuffle { .. } => None,
|
QueueContent::Shuffle { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn insert(&mut self, v: Self, index: usize) -> bool {
|
pub fn insert(
|
||||||
|
&mut self,
|
||||||
|
v: Vec<Self>,
|
||||||
|
index: usize,
|
||||||
|
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(current, vec, _) => {
|
QueueContent::Folder(current, vec, _) => {
|
||||||
if index <= vec.len() {
|
if index <= vec.len() {
|
||||||
if *current >= index {
|
if *current >= index {
|
||||||
*current += 1;
|
*current += v.len();
|
||||||
}
|
}
|
||||||
vec.insert(index, v);
|
// remove the elements starting at the insertion point
|
||||||
|
let end = vec.split_off(index);
|
||||||
|
// insert new elements
|
||||||
|
for (i, mut v) in v.into_iter().enumerate() {
|
||||||
|
path.push(index + i);
|
||||||
|
v.init(path.clone(), actions);
|
||||||
|
vec.push(v);
|
||||||
|
path.pop();
|
||||||
|
}
|
||||||
|
// re-add previously removed elements
|
||||||
|
vec.extend(end);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@ -268,7 +303,9 @@ impl Queue {
|
|||||||
QueueContent::Shuffle { inner, state } => {
|
QueueContent::Shuffle { inner, state } => {
|
||||||
let mut p = path.clone();
|
let mut p = path.clone();
|
||||||
p.push(0);
|
p.push(0);
|
||||||
if matches!(state, ShuffleState::NotShuffled | ShuffleState::Modified) {
|
if inner.len() == 0 {
|
||||||
|
*state = ShuffleState::NotShuffled;
|
||||||
|
} else if matches!(state, ShuffleState::NotShuffled | ShuffleState::Modified) {
|
||||||
actions.push(QueueAction::SetShuffle(
|
actions.push(QueueAction::SetShuffle(
|
||||||
path,
|
path,
|
||||||
matches!(state, ShuffleState::Modified),
|
matches!(state, ShuffleState::Modified),
|
||||||
@ -287,7 +324,7 @@ impl Queue {
|
|||||||
if let Some(song) = db.songs().keys().choose(&mut rand::thread_rng()) {
|
if let Some(song) = db.songs().keys().choose(&mut rand::thread_rng()) {
|
||||||
db.apply_command(Command::QueueAdd(
|
db.apply_command(Command::QueueAdd(
|
||||||
path,
|
path,
|
||||||
QueueContent::Song(*song).into(),
|
vec![QueueContent::Song(*song).into()],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -394,6 +431,7 @@ impl Queue {
|
|||||||
let mut p = path.clone();
|
let mut p = path.clone();
|
||||||
p.push(0);
|
p.push(0);
|
||||||
if !inner.advance_index_inner(p, actions) {
|
if !inner.advance_index_inner(p, actions) {
|
||||||
|
// end of inner Folder element, reshuffle for next time
|
||||||
*state = ShuffleState::Shuffled;
|
*state = ShuffleState::Shuffled;
|
||||||
actions.push(QueueAction::SetShuffle(path, false));
|
actions.push(QueueAction::SetShuffle(path, false));
|
||||||
false
|
false
|
||||||
|
@ -6,6 +6,8 @@ use std::{
|
|||||||
thread::JoinHandle,
|
thread::JoinHandle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use colorize::AnsiColor;
|
||||||
|
|
||||||
use crate::load::ToFromBytes;
|
use crate::load::ToFromBytes;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@ -139,20 +141,20 @@ impl Song {
|
|||||||
) -> Option<Vec<u8>> {
|
) -> Option<Vec<u8>> {
|
||||||
match src {
|
match src {
|
||||||
Ok(path) => {
|
Ok(path) => {
|
||||||
eprintln!("[info] loading song from {:?}", path);
|
eprintln!("[{}] loading song from {:?}", "INFO".cyan(), path);
|
||||||
match std::fs::read(&path) {
|
match std::fs::read(&path) {
|
||||||
Ok(v) => {
|
Ok(v) => {
|
||||||
eprintln!("[info] loaded song from {:?}", path);
|
eprintln!("[{}] loaded song from {:?}", "INFO".green(), path);
|
||||||
Some(v)
|
Some(v)
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("[info] error loading {:?}: {e:?}", path);
|
eprintln!("[{}] error loading {:?}: {e:?}", "ERR!".red(), path);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err((id, dlcon)) => {
|
Err((id, dlcon)) => {
|
||||||
eprintln!("[info] loading song {id}");
|
eprintln!("[{}] loading song {id}", "INFO".cyan());
|
||||||
match dlcon
|
match dlcon
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -161,7 +163,7 @@ impl Song {
|
|||||||
{
|
{
|
||||||
Ok(data) => Some(data),
|
Ok(data) => Some(data),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("[WARN] error loading song {id}: {e}");
|
eprintln!("[{}] error loading song {id}: {e}", "ERR!".red());
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ use awedio::{
|
|||||||
sounds::wrappers::{AsyncCompletionNotifier, Controller, Pausable},
|
sounds::wrappers::{AsyncCompletionNotifier, Controller, Pausable},
|
||||||
Sound,
|
Sound,
|
||||||
};
|
};
|
||||||
|
use colorize::AnsiColor;
|
||||||
use rc_u8_reader::ArcU8Reader;
|
use rc_u8_reader::ArcU8Reader;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -148,7 +149,10 @@ impl Player {
|
|||||||
self.manager.play(Box::new(sound));
|
self.manager.play(Box::new(sound));
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("[player] Can't play, skipping! {e}");
|
eprintln!(
|
||||||
|
"[{}] [player] Can't play, skipping! {e}",
|
||||||
|
"INFO".blue()
|
||||||
|
);
|
||||||
apply_command!(Command::NextSong);
|
apply_command!(Command::NextSong);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ use std::{
|
|||||||
sync::{mpsc, Arc, Mutex},
|
sync::{mpsc, Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use colorize::AnsiColor;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{
|
data::{
|
||||||
album::Album,
|
album::Album,
|
||||||
@ -34,8 +36,8 @@ pub enum Command {
|
|||||||
NextSong,
|
NextSong,
|
||||||
SyncDatabase(Vec<Artist>, Vec<Album>, Vec<Song>),
|
SyncDatabase(Vec<Artist>, Vec<Album>, Vec<Song>),
|
||||||
QueueUpdate(Vec<usize>, Queue),
|
QueueUpdate(Vec<usize>, Queue),
|
||||||
QueueAdd(Vec<usize>, Queue),
|
QueueAdd(Vec<usize>, Vec<Queue>),
|
||||||
QueueInsert(Vec<usize>, usize, Queue),
|
QueueInsert(Vec<usize>, usize, Vec<Queue>),
|
||||||
QueueRemove(Vec<usize>),
|
QueueRemove(Vec<usize>),
|
||||||
QueueGoto(Vec<usize>),
|
QueueGoto(Vec<usize>),
|
||||||
QueueSetShuffle(Vec<usize>, Vec<usize>),
|
QueueSetShuffle(Vec<usize>, Vec<usize>),
|
||||||
@ -165,7 +167,7 @@ pub fn run_server(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("[WARN] Couldn't start TCP listener: {e}");
|
eprintln!("[{}] Couldn't start TCP listener: {e}", "ERR!".red());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -242,7 +244,7 @@ const BYTE_TAG_SONG_FLAG_SET: u8 = 0b11100000;
|
|||||||
const BYTE_TAG_SONG_FLAG_UNSET: u8 = 0b11100001;
|
const BYTE_TAG_SONG_FLAG_UNSET: u8 = 0b11100001;
|
||||||
const BYTE_TAG_ALBUM_FLAG_SET: u8 = 0b11100010;
|
const BYTE_TAG_ALBUM_FLAG_SET: u8 = 0b11100010;
|
||||||
const BYTE_TAG_ALBUM_FLAG_UNSET: u8 = 0b11100011;
|
const BYTE_TAG_ALBUM_FLAG_UNSET: u8 = 0b11100011;
|
||||||
const BYTE_TAG_ARTIST_FLAG_SET: u8 = 0b11100110;
|
const BYTE_TAG_ARTIST_FLAG_SET: u8 = 0b11100110;
|
||||||
const BYTE_TAG_ARTIST_FLAG_UNSET: u8 = 0b11100111;
|
const BYTE_TAG_ARTIST_FLAG_UNSET: u8 = 0b11100111;
|
||||||
const BYTE_TAG_SONG_PROPERTY_SET: u8 = 0b11101001;
|
const BYTE_TAG_SONG_PROPERTY_SET: u8 = 0b11101001;
|
||||||
const BYTE_TAG_SONG_PROPERTY_UNSET: u8 = 0b11101010;
|
const BYTE_TAG_SONG_PROPERTY_UNSET: u8 = 0b11101010;
|
||||||
@ -484,7 +486,10 @@ impl ToFromBytes for Command {
|
|||||||
BYTE_SAVE => Self::Save,
|
BYTE_SAVE => Self::Save,
|
||||||
BYTE_ERRORINFO => Self::ErrorInfo(from_bytes!(), from_bytes!()),
|
BYTE_ERRORINFO => Self::ErrorInfo(from_bytes!(), from_bytes!()),
|
||||||
_ => {
|
_ => {
|
||||||
eprintln!("unexpected byte when reading command; stopping playback.");
|
eprintln!(
|
||||||
|
"[{}] unexpected byte when reading command; stopping playback.",
|
||||||
|
"WARN".yellow()
|
||||||
|
);
|
||||||
Self::Stop
|
Self::Stop
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -287,7 +287,7 @@ pub async fn main(db: Arc<Mutex<Database>>, sender: mpsc::Sender<Command>, addr:
|
|||||||
post(move |Path(song_id)| async move {
|
post(move |Path(song_id)| async move {
|
||||||
_ = s6.send(Command::QueueAdd(
|
_ = s6.send(Command::QueueAdd(
|
||||||
vec![],
|
vec![],
|
||||||
QueueContent::Song(song_id).into(),
|
vec![QueueContent::Song(song_id).into()],
|
||||||
));
|
));
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@ -297,7 +297,7 @@ pub async fn main(db: Arc<Mutex<Database>>, sender: mpsc::Sender<Command>, addr:
|
|||||||
if let Some(album) = db1.lock().unwrap().albums().get(&album_id) {
|
if let Some(album) = db1.lock().unwrap().albums().get(&album_id) {
|
||||||
_ = s7.send(Command::QueueAdd(
|
_ = s7.send(Command::QueueAdd(
|
||||||
vec![],
|
vec![],
|
||||||
QueueContent::Folder(
|
vec![QueueContent::Folder(
|
||||||
0,
|
0,
|
||||||
album
|
album
|
||||||
.songs
|
.songs
|
||||||
@ -306,7 +306,7 @@ pub async fn main(db: Arc<Mutex<Database>>, sender: mpsc::Sender<Command>, addr:
|
|||||||
.collect(),
|
.collect(),
|
||||||
album.name.clone(),
|
album.name.clone(),
|
||||||
)
|
)
|
||||||
.into(),
|
.into()],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
Loading…
Reference in New Issue
Block a user