albums must have an artist + some client gui_edit changes

This commit is contained in:
Mark 2023-09-11 18:50:22 +02:00
parent c93b933037
commit a465f2be79
6 changed files with 135 additions and 197 deletions

View File

@ -46,11 +46,8 @@ pub enum Editing {
#[derive(Clone)] #[derive(Clone)]
pub enum ArtistChange { pub enum ArtistChange {
SetName(String), SetName(String),
SetCover(Option<ArtistId>), SetCover(Option<CoverId>),
RemoveAlbum(AlbumId),
AddAlbum(AlbumId), AddAlbum(AlbumId),
RemoveSong(SongId),
AddSong(SongId),
} }
#[derive(Clone)] #[derive(Clone)]
pub enum AlbumChange { pub enum AlbumChange {
@ -163,39 +160,59 @@ impl GuiElemTrait for GuiEdit {
} }
if self.send { if self.send {
self.send = false; 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::NotLoaded => {}
Editing::Artist(v, changes) => { Editing::Artist(v, changes) => {
for v in v {
let mut v = v.clone();
for change in changes.iter() { for change in changes.iter() {
match change { match change {
ArtistChange::SetName(n) => v.name = n.clone(), ArtistChange::SetName(n) => {
ArtistChange::SetCover(c) => v.cover = c.clone(), for artist in v.iter_mut() {
ArtistChange::RemoveAlbum(id) => { artist.name = n.clone();
if let Some(i) = v.albums.iter().position(|id| id == id) { info.actions.push(GuiAction::SendToServer(
v.albums.remove(i); Command::ModifyArtist(artist.clone()),
));
}
}
ArtistChange::SetCover(c) => {
for artist in v.iter_mut() {
artist.cover = c.clone();
info.actions.push(GuiAction::SendToServer(
Command::ModifyArtist(artist.clone()),
));
} }
} }
ArtistChange::AddAlbum(id) => { ArtistChange::AddAlbum(id) => {
if !v.albums.contains(id) { // use the first artist for the artist fields
v.albums.push(*id); let mut editing = v.first().unwrap().clone();
} if let Some(album) = info.database.albums().get(id) {
} let mut album = album.clone();
ArtistChange::RemoveSong(id) => { // find the previous artist for this album and remove them
if let Some(i) = v.singles.iter().position(|id| id == id) { if let Some(prev) = info.database.artists().get(&album.artist) {
v.singles.remove(i); let mut prev = prev.clone();
} if let Some(i) = prev.albums.iter().position(|v| v == id) {
} prev.albums.remove(i);
ArtistChange::AddSong(id) => { info.actions.push(GuiAction::SendToServer(
if !v.singles.contains(id) { Command::ModifyArtist(prev),
v.singles.push(*id); ));
}
}
} }
} }
// update the artist field on the album so it points to the new artist
album.artist = editing.id;
info.actions info.actions
.push(GuiAction::SendToServer(Command::ModifyArtist(v))); .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),
));
}
}
}
}
} }
} }
Editing::Album(v, changes) => { Editing::Album(v, changes) => {
@ -487,7 +504,7 @@ impl GuiEdit {
let add_button = { let add_button = {
let apply_change = self.apply_change.clone(); let apply_change = self.apply_change.clone();
GuiElem::new(Button::new( 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 |_| { move |_| {
_ = apply_change.send(Box::new(move |s| { _ = apply_change.send(Box::new(move |s| {
if let Some(album_id) = get_id(s) { if let Some(album_id) = get_id(s) {
@ -498,7 +515,8 @@ impl GuiEdit {
c.remove(i); c.remove(i);
} }
c.push(ArtistChange::AddAlbum(album_id)); c.push(ArtistChange::AddAlbum(album_id));
s.rebuild_changes = true;} s.rebuild_changes = true;
}
} }
})); }));
vec![] 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( let name = GuiElem::new(TextField::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.8, 1.0))), GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.9, 1.0))),
"add or remove album by id".to_string(), "add album by id".to_string(),
Color::LIGHT_GRAY, Color::LIGHT_GRAY,
Color::WHITE, Color::WHITE,
)); ));
sb.children.push(( sb.children.push((
GuiElem::new(Panel::new( GuiElem::new(Panel::new(GuiElemCfg::default(), vec![name, add_button])),
GuiElemCfg::default(),
vec![name, add_button, remove_button],
)),
info.line_height * 2.0, info.line_height * 2.0,
)); ));
} }
for (album_id, count) in albums { for (album_id, count) in albums {
let album = info.database.albums().get(&album_id); 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( let name = GuiElem::new(Button::new(
GuiElemCfg::at(Rectangle::from_tuples( GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (1.0, 1.0))),
(0.0, 0.0),
(if add_button.is_some() { 0.8 } else { 0.9 }, 1.0),
)),
move |_| { move |_| {
vec![GuiAction::OpenEditPanel(GuiElem::new(GuiEdit::new( vec![GuiAction::OpenEditPanel(GuiElem::new(GuiEdit::new(
GuiElemCfg::default(), GuiElemCfg::default(),
@ -636,14 +564,7 @@ impl GuiEdit {
))], ))],
)); ));
sb.children.push(( sb.children.push((
GuiElem::new(Panel::new( GuiElem::new(Panel::new(GuiElemCfg::default(), vec![name])),
GuiElemCfg::default(),
if let Some(add_button) = add_button {
vec![name, add_button, remove_button]
} else {
vec![name, remove_button]
},
)),
info.line_height, info.line_height,
)); ));
} }
@ -670,10 +591,7 @@ impl GuiEdit {
"remove cover".to_string() "remove cover".to_string()
} }
} }
ArtistChange::RemoveAlbum(v) => format!("remove album {v}"),
ArtistChange::AddAlbum(v) => format!("add 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(); let s = self.apply_change.clone();
sb.children.push(( sb.children.push((

View File

@ -130,11 +130,7 @@ impl GuiElemTrait for CurrentSong {
(None, None) => String::new(), (None, None) => String::new(),
(Some(artist), None) => format!("by {}", artist.name), (Some(artist), None) => format!("by {}", artist.name),
(None, Some(album)) => { (None, Some(album)) => {
if let Some(artist) = album if let Some(artist) = info.database.artists().get(&album.artist) {
.artist
.as_ref()
.and_then(|id| info.database.artists().get(id))
{
format!("on {} by {}", album.name, artist.name) format!("on {} by {}", album.name, artist.name)
} else { } else {
format!("on {}", album.name) format!("on {}", album.name)

View File

@ -404,9 +404,7 @@ impl QueueSong {
(None, None) => String::new(), (None, None) => String::new(),
(Some(artist), None) => format!("by {}", artist.name), (Some(artist), None) => format!("by {}", artist.name),
(None, Some(album)) => { (None, Some(album)) => {
if let Some(artist) = if let Some(artist) = db.artists().get(&album.artist) {
album.artist.as_ref().and_then(|id| db.artists().get(id))
{
format!("on {} by {}", album.name, artist.name) format!("on {} by {}", album.name, artist.name)
} else { } else {
format!("on {}", album.name) format!("on {}", album.name)

View File

@ -47,11 +47,23 @@ fn main() {
} }
eprintln!("\nloaded metadata of {} files.", songs.len()); eprintln!("\nloaded metadata of {} files.", songs.len());
let mut database = Database::new_empty(PathBuf::from("dbfile"), PathBuf::from(&lib_dir)); 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!("<unknown>"),
cover: None,
albums: vec![],
singles: vec![],
general: GeneralData::default(),
});
eprintln!("searching for artists..."); eprintln!("searching for artists...");
let mut artists = HashMap::new(); let mut artists = HashMap::new();
for song in songs { for song in songs {
let (artist_id, album_id) = let (artist_id, album_id) = if let Some(artist) = song
if let Some(artist) = song.1.album_artist().or_else(|| song.1.artist()) { .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 = if !artists.contains_key(artist) {
let artist_id = database.add_artist_new(Artist { let artist_id = database.add_artist_new(Artist {
id: 0, id: 0,
@ -71,7 +83,7 @@ fn main() {
let album_id = if !albums.contains_key(album) { let album_id = if !albums.contains_key(album) {
let album_id = database.add_album_new(Album { let album_id = database.add_album_new(Album {
id: 0, id: 0,
artist: Some(artist_id), artist: artist_id,
name: album.to_string(), name: album.to_string(),
cover: None, cover: None,
songs: vec![], songs: vec![],
@ -94,18 +106,24 @@ fn main() {
} }
album.0 album.0
}; };
(Some(artist_id), Some(album_id)) (artist_id, Some(album_id))
} else { } else {
(Some(artist_id), None) (artist_id, None)
} }
} else { } else {
(None, None) (unknown_artist, None)
}; };
let path = song.0.strip_prefix(&lib_dir).unwrap(); let path = song.0.strip_prefix(&lib_dir).unwrap();
let title = song let title = song
.1 .1
.title() .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()); .unwrap_or_else(|| song.0.file_stem().unwrap().to_string_lossy().into_owned());
database.add_song_new(Song { database.add_song_new(Song {
id: 0, 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 <unknown> artist as a fallback!");
}
}
eprintln!("saving dbfile...");
database.save_database(None).unwrap(); database.save_database(None).unwrap();
eprintln!("done!"); eprintln!("done!");
} }

View File

@ -8,7 +8,7 @@ use super::{AlbumId, ArtistId, CoverId, GeneralData, SongId};
pub struct Album { pub struct Album {
pub id: AlbumId, pub id: AlbumId,
pub name: String, pub name: String,
pub artist: Option<ArtistId>, pub artist: ArtistId,
pub cover: Option<CoverId>, pub cover: Option<CoverId>,
pub songs: Vec<SongId>, pub songs: Vec<SongId>,
pub general: GeneralData, pub general: GeneralData,

View File

@ -121,7 +121,7 @@ impl Database {
pub fn add_album_new(&mut self, album: Album) -> AlbumId { pub fn add_album_new(&mut self, album: Album) -> AlbumId {
let artist = album.artist.clone(); let artist = album.artist.clone();
let id = self.add_album_new_nomagic(album); 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); artist.albums.push(id);
} }
id id