diff --git a/musicdb-client/src/gui_edit.rs b/musicdb-client/src/gui_edit.rs index 3b6aac0..dc50881 100755 --- a/musicdb-client/src/gui_edit.rs +++ b/musicdb-client/src/gui_edit.rs @@ -46,11 +46,8 @@ pub enum Editing { #[derive(Clone)] pub enum ArtistChange { SetName(String), - SetCover(Option), - RemoveAlbum(AlbumId), + SetCover(Option), AddAlbum(AlbumId), - RemoveSong(SongId), - AddSong(SongId), } #[derive(Clone)] pub enum AlbumChange { @@ -163,39 +160,59 @@ impl GuiElemTrait for GuiEdit { } if self.send { self.send = false; - match &self.editing { + self.rebuild_main = true; + self.rebuild_changes = true; + self.config.redraw = true; + match &mut self.editing { Editing::NotLoaded => {} Editing::Artist(v, changes) => { - for v in v { - let mut v = v.clone(); - for change in changes.iter() { - match change { - ArtistChange::SetName(n) => v.name = n.clone(), - ArtistChange::SetCover(c) => v.cover = c.clone(), - ArtistChange::RemoveAlbum(id) => { - if let Some(i) = v.albums.iter().position(|id| id == id) { - v.albums.remove(i); - } + for change in changes.iter() { + match change { + ArtistChange::SetName(n) => { + for artist in v.iter_mut() { + artist.name = n.clone(); + info.actions.push(GuiAction::SendToServer( + Command::ModifyArtist(artist.clone()), + )); } - ArtistChange::AddAlbum(id) => { - if !v.albums.contains(id) { - v.albums.push(*id); - } + } + ArtistChange::SetCover(c) => { + for artist in v.iter_mut() { + artist.cover = c.clone(); + info.actions.push(GuiAction::SendToServer( + Command::ModifyArtist(artist.clone()), + )); } - ArtistChange::RemoveSong(id) => { - if let Some(i) = v.singles.iter().position(|id| id == id) { - v.singles.remove(i); + } + ArtistChange::AddAlbum(id) => { + // use the first artist for the artist fields + let mut editing = v.first().unwrap().clone(); + if let Some(album) = info.database.albums().get(id) { + let mut album = album.clone(); + // find the previous artist for this album and remove them + if let Some(prev) = info.database.artists().get(&album.artist) { + let mut prev = prev.clone(); + if let Some(i) = prev.albums.iter().position(|v| v == id) { + prev.albums.remove(i); + info.actions.push(GuiAction::SendToServer( + Command::ModifyArtist(prev), + )); + } } - } - ArtistChange::AddSong(id) => { - if !v.singles.contains(id) { - v.singles.push(*id); + // update the artist field on the album so it points to the new artist + album.artist = editing.id; + info.actions + .push(GuiAction::SendToServer(Command::ModifyAlbum(album))); + // add the album to the artist we are editing + if !editing.albums.contains(id) { + editing.albums.push(*id); + info.actions.push(GuiAction::SendToServer( + Command::ModifyArtist(editing), + )); } } } } - info.actions - .push(GuiAction::SendToServer(Command::ModifyArtist(v))); } } Editing::Album(v, changes) => { @@ -487,18 +504,19 @@ impl GuiEdit { let add_button = { let apply_change = self.apply_change.clone(); GuiElem::new(Button::new( - GuiElemCfg::at(Rectangle::from_tuples((0.8, 0.0), (0.9, 1.0))), + GuiElemCfg::at(Rectangle::from_tuples((0.9, 0.0), (1.0, 1.0))), move |_| { _ = apply_change.send(Box::new(move |s| { if let Some(album_id) = get_id(s) { - if let Editing::Artist(_, c) = &mut s.editing { - if let Some(i) = c.iter().position(|c| { - matches!(c, ArtistChange::AddAlbum(id) if *id == album_id) - }) { - c.remove(i); + if let Editing::Artist(_, c) = &mut s.editing { + if let Some(i) = c.iter().position(|c| { + matches!(c, ArtistChange::AddAlbum(id) if *id == album_id) + }) { + c.remove(i); + } + c.push(ArtistChange::AddAlbum(album_id)); + s.rebuild_changes = true; } - c.push(ArtistChange::AddAlbum(album_id)); - s.rebuild_changes = true;} } })); vec![] @@ -512,111 +530,21 @@ impl GuiEdit { ))], )) }; - let remove_button = { - let apply_change = self.apply_change.clone(); - GuiElem::new(Button::new( - GuiElemCfg::at(Rectangle::from_tuples((0.9, 0.0), (1.0, 1.0))), - move |_| { - _ = apply_change.send(Box::new(move |s| { - if let Some(album_id) = get_id(s) { - if let Editing::Artist(_, c) = &mut s.editing { - if let Some(i) = c.iter().position(|c| { - matches!(c, ArtistChange::RemoveAlbum(id) if *id == album_id) - }) { - c.remove(i); - } - c.push(ArtistChange::RemoveAlbum(album_id)); - s.rebuild_changes = true;} - } - })); - vec![] - }, - vec![GuiElem::new(Label::new( - GuiElemCfg::default(), - format!("remove"), - Color::RED, - None, - Vec2::new(0.5, 0.5), - ))], - )) - }; let name = GuiElem::new(TextField::new( - GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.8, 1.0))), - "add or remove album by id".to_string(), + GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.9, 1.0))), + "add album by id".to_string(), Color::LIGHT_GRAY, Color::WHITE, )); sb.children.push(( - GuiElem::new(Panel::new( - GuiElemCfg::default(), - vec![name, add_button, remove_button], - )), + GuiElem::new(Panel::new(GuiElemCfg::default(), vec![name, add_button])), info.line_height * 2.0, )); } for (album_id, count) in albums { let album = info.database.albums().get(&album_id); - let add_button = if count == v.len() { - None - } else { - let apply_change = self.apply_change.clone(); - Some(GuiElem::new(Button::new( - GuiElemCfg::at(Rectangle::from_tuples((0.8, 0.0), (0.9, 1.0))), - move |_| { - _ = apply_change.send(Box::new(move |s| { - if let Editing::Artist(_, c) = &mut s.editing { - if let Some(i) = c.iter().position(|c| { - matches!(c, ArtistChange::AddAlbum(id) if *id == album_id) - }) { - c.remove(i); - } - c.push(ArtistChange::AddAlbum(album_id)); - s.rebuild_changes = true; - } - })); - vec![] - }, - vec![GuiElem::new(Label::new( - GuiElemCfg::default(), - format!("add"), - Color::GREEN, - None, - Vec2::new(0.5, 0.5), - ))], - ))) - }; - let remove_button = { - let apply_change = self.apply_change.clone(); - GuiElem::new(Button::new( - GuiElemCfg::at(Rectangle::from_tuples((0.9, 0.0), (1.0, 1.0))), - move |_| { - _ = apply_change.send(Box::new(move |s| { - if let Editing::Artist(_, c) = &mut s.editing { - if let Some(i) = c.iter().position(|c| { - matches!(c, ArtistChange::RemoveAlbum(id) if *id == album_id) - }) { - c.remove(i); - } - c.push(ArtistChange::RemoveAlbum(album_id)); - s.rebuild_changes = true; - } - })); - vec![] - }, - vec![GuiElem::new(Label::new( - GuiElemCfg::default(), - format!("remove"), - Color::RED, - None, - Vec2::new(0.5, 0.5), - ))], - )) - }; let name = GuiElem::new(Button::new( - GuiElemCfg::at(Rectangle::from_tuples( - (0.0, 0.0), - (if add_button.is_some() { 0.8 } else { 0.9 }, 1.0), - )), + GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (1.0, 1.0))), move |_| { vec![GuiAction::OpenEditPanel(GuiElem::new(GuiEdit::new( GuiElemCfg::default(), @@ -636,14 +564,7 @@ impl GuiEdit { ))], )); sb.children.push(( - GuiElem::new(Panel::new( - GuiElemCfg::default(), - if let Some(add_button) = add_button { - vec![name, add_button, remove_button] - } else { - vec![name, remove_button] - }, - )), + GuiElem::new(Panel::new(GuiElemCfg::default(), vec![name])), info.line_height, )); } @@ -670,10 +591,7 @@ impl GuiEdit { "remove cover".to_string() } } - ArtistChange::RemoveAlbum(v) => format!("remove album {v}"), ArtistChange::AddAlbum(v) => format!("add album {v}"), - ArtistChange::RemoveSong(v) => format!("remove song {v}"), - ArtistChange::AddSong(v) => format!("add song {v}"), }; let s = self.apply_change.clone(); sb.children.push(( diff --git a/musicdb-client/src/gui_playback.rs b/musicdb-client/src/gui_playback.rs index 0e32ec2..cba5491 100755 --- a/musicdb-client/src/gui_playback.rs +++ b/musicdb-client/src/gui_playback.rs @@ -130,11 +130,7 @@ impl GuiElemTrait for CurrentSong { (None, None) => String::new(), (Some(artist), None) => format!("by {}", artist.name), (None, Some(album)) => { - if let Some(artist) = album - .artist - .as_ref() - .and_then(|id| info.database.artists().get(id)) - { + if let Some(artist) = info.database.artists().get(&album.artist) { format!("on {} by {}", album.name, artist.name) } else { format!("on {}", album.name) diff --git a/musicdb-client/src/gui_queue.rs b/musicdb-client/src/gui_queue.rs index 5de511f..fe47bf4 100755 --- a/musicdb-client/src/gui_queue.rs +++ b/musicdb-client/src/gui_queue.rs @@ -404,9 +404,7 @@ impl QueueSong { (None, None) => String::new(), (Some(artist), None) => format!("by {}", artist.name), (None, Some(album)) => { - if let Some(artist) = - album.artist.as_ref().and_then(|id| db.artists().get(id)) - { + if let Some(artist) = db.artists().get(&album.artist) { format!("on {} by {}", album.name, artist.name) } else { format!("on {}", album.name) diff --git a/musicdb-filldb/src/main.rs b/musicdb-filldb/src/main.rs index 7ddd822..e0bb479 100755 --- a/musicdb-filldb/src/main.rs +++ b/musicdb-filldb/src/main.rs @@ -47,65 +47,83 @@ fn main() { } eprintln!("\nloaded metadata of {} files.", songs.len()); let mut database = Database::new_empty(PathBuf::from("dbfile"), PathBuf::from(&lib_dir)); + let unknown_artist = database.add_artist_new(Artist { + id: 0, + name: format!(""), + cover: None, + albums: vec![], + singles: vec![], + general: GeneralData::default(), + }); eprintln!("searching for artists..."); let mut artists = HashMap::new(); for song in songs { - let (artist_id, album_id) = - if let Some(artist) = song.1.album_artist().or_else(|| song.1.artist()) { - let artist_id = if !artists.contains_key(artist) { - let artist_id = database.add_artist_new(Artist { + let (artist_id, album_id) = if let Some(artist) = song + .1 + .album_artist() + .or_else(|| song.1.artist()) + .filter(|v| !v.trim().is_empty()) + { + let artist_id = if !artists.contains_key(artist) { + let artist_id = database.add_artist_new(Artist { + id: 0, + name: artist.to_string(), + cover: None, + albums: vec![], + singles: vec![], + general: GeneralData::default(), + }); + artists.insert(artist.to_string(), (artist_id, HashMap::new())); + artist_id + } else { + artists.get(artist).unwrap().0 + }; + if let Some(album) = song.1.album() { + let (_, albums) = artists.get_mut(artist).unwrap(); + let album_id = if !albums.contains_key(album) { + let album_id = database.add_album_new(Album { id: 0, - name: artist.to_string(), + artist: artist_id, + name: album.to_string(), cover: None, - albums: vec![], - singles: vec![], + songs: vec![], general: GeneralData::default(), }); - artists.insert(artist.to_string(), (artist_id, HashMap::new())); - artist_id + albums.insert( + album.to_string(), + (album_id, song.0.parent().map(|dir| dir.to_path_buf())), + ); + album_id } else { - artists.get(artist).unwrap().0 + let album = albums.get_mut(album).unwrap(); + if album + .1 + .as_ref() + .is_some_and(|dir| Some(dir.as_path()) != song.0.parent()) + { + // album directory is inconsistent + album.1 = None; + } + album.0 }; - if let Some(album) = song.1.album() { - let (_, albums) = artists.get_mut(artist).unwrap(); - let album_id = if !albums.contains_key(album) { - let album_id = database.add_album_new(Album { - id: 0, - artist: Some(artist_id), - name: album.to_string(), - cover: None, - songs: vec![], - general: GeneralData::default(), - }); - albums.insert( - album.to_string(), - (album_id, song.0.parent().map(|dir| dir.to_path_buf())), - ); - album_id - } else { - let album = albums.get_mut(album).unwrap(); - if album - .1 - .as_ref() - .is_some_and(|dir| Some(dir.as_path()) != song.0.parent()) - { - // album directory is inconsistent - album.1 = None; - } - album.0 - }; - (Some(artist_id), Some(album_id)) - } else { - (Some(artist_id), None) - } + (artist_id, Some(album_id)) } else { - (None, None) - }; + (artist_id, None) + } + } else { + (unknown_artist, None) + }; let path = song.0.strip_prefix(&lib_dir).unwrap(); let title = song .1 .title() - .map(|title| title.to_string()) + .map_or(None, |title| { + if title.trim().is_empty() { + None + } else { + Some(title.to_string()) + } + }) .unwrap_or_else(|| song.0.file_stem().unwrap().to_string_lossy().into_owned()); database.add_song_new(Song { id: 0, @@ -152,7 +170,15 @@ fn main() { } } } - eprintln!("\nsaving dbfile..."); + eprintln!(); + if let Some(uka) = database.artists().get(&unknown_artist) { + if uka.albums.is_empty() && uka.singles.is_empty() { + database.artists_mut().remove(&unknown_artist); + } else { + eprintln!("Added the artist as a fallback!"); + } + } + eprintln!("saving dbfile..."); database.save_database(None).unwrap(); eprintln!("done!"); } diff --git a/musicdb-lib/src/data/album.rs b/musicdb-lib/src/data/album.rs index 94df956..5cb7fe6 100755 --- a/musicdb-lib/src/data/album.rs +++ b/musicdb-lib/src/data/album.rs @@ -8,7 +8,7 @@ use super::{AlbumId, ArtistId, CoverId, GeneralData, SongId}; pub struct Album { pub id: AlbumId, pub name: String, - pub artist: Option, + pub artist: ArtistId, pub cover: Option, pub songs: Vec, pub general: GeneralData, diff --git a/musicdb-lib/src/data/database.rs b/musicdb-lib/src/data/database.rs index eac3704..c07c5a1 100755 --- a/musicdb-lib/src/data/database.rs +++ b/musicdb-lib/src/data/database.rs @@ -121,7 +121,7 @@ impl Database { pub fn add_album_new(&mut self, album: Album) -> AlbumId { let artist = album.artist.clone(); let id = self.add_album_new_nomagic(album); - if let Some(Some(artist)) = artist.map(|v| self.artists.get_mut(&v)) { + if let Some(artist) = self.artists.get_mut(&artist) { artist.albums.push(id); } id