mirror of
				https://github.com/Dummi26/musicdb.git
				synced 2025-10-29 19:19:20 +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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Mark
						Mark