Drop support for blank album names

This commit is contained in:
Antoine Gersant 2024-09-07 16:22:39 -07:00
parent 4072e3b07d
commit 7be9f25cb3
6 changed files with 70 additions and 84 deletions

View file

@ -140,21 +140,21 @@ impl Manager {
.unwrap() .unwrap()
} }
pub async fn get_album( pub async fn get_album(&self, artists: Vec<String>, name: String) -> Result<Album, Error> {
&self,
artists: Vec<String>,
name: Option<String>,
) -> Result<Album, Error> {
spawn_blocking({ spawn_blocking({
let index_manager = self.clone(); let index_manager = self.clone();
move || { move || {
let index = index_manager.index.read().unwrap(); let index = index_manager.index.read().unwrap();
let name = index
.strings
.get(&name)
.ok_or_else(|| Error::AlbumNotFound)?;
let album_key = AlbumKey { let album_key = AlbumKey {
artists: artists artists: artists
.into_iter() .into_iter()
.filter_map(|a| index.strings.get(a)) .filter_map(|a| index.strings.get(a))
.collect(), .collect(),
name: name.and_then(|n| index.strings.get(n)), name,
}; };
index index
.collection .collection

View file

@ -38,7 +38,7 @@ pub struct Artist {
#[derive(Debug, Default, PartialEq, Eq)] #[derive(Debug, Default, PartialEq, Eq)]
pub struct Album { pub struct Album {
pub name: Option<String>, pub name: String,
pub artwork: Option<PathBuf>, pub artwork: Option<PathBuf>,
pub artists: Vec<String>, pub artists: Vec<String>,
pub year: Option<i64>, pub year: Option<i64>,
@ -140,7 +140,7 @@ impl Collection {
songs.sort_by_key(|s| (s.disc_number.unwrap_or(-1), s.track_number.unwrap_or(-1))); songs.sort_by_key(|s| (s.disc_number.unwrap_or(-1), s.track_number.unwrap_or(-1)));
Album { Album {
name: a.name.map(|s| strings.resolve(&s).to_string()), name: strings.resolve(&a.name).to_string(),
artwork: a artwork: a
.artwork .artwork
.as_ref() .as_ref()
@ -243,37 +243,45 @@ impl Builder {
} }
fn add_song_to_artists(&mut self, song: &storage::Song) { fn add_song_to_artists(&mut self, song: &storage::Song) {
let album_key: AlbumKey = song.album_key(); let album_key = song.album_key();
let mut all_artists = TinyVec::<[Spur; 8]>::new(); let mut all_artists = TinyVec::<[Spur; 8]>::new();
for name in &song.album_artists { for name in &song.album_artists {
let artist = self.get_or_create_artist(*name);
artist.albums_as_performer.insert(album_key.clone());
all_artists.push(*name); all_artists.push(*name);
if let Some(album_key) = &album_key {
let artist = self.get_or_create_artist(*name);
artist.albums_as_performer.insert(album_key.clone());
}
} }
for name in &song.composers { for name in &song.composers {
let artist = self.get_or_create_artist(*name);
artist.albums_as_composer.insert(album_key.clone());
all_artists.push(*name); all_artists.push(*name);
if let Some(album_key) = &album_key {
let artist = self.get_or_create_artist(*name);
artist.albums_as_composer.insert(album_key.clone());
}
} }
for name in &song.lyricists { for name in &song.lyricists {
let artist = self.get_or_create_artist(*name);
artist.albums_as_lyricist.insert(album_key.clone());
all_artists.push(*name); all_artists.push(*name);
if let Some(album_key) = &album_key {
let artist = self.get_or_create_artist(*name);
artist.albums_as_lyricist.insert(album_key.clone());
}
} }
for name in &song.artists { for name in &song.artists {
let artist = self.get_or_create_artist(*name);
all_artists.push(*name); all_artists.push(*name);
if song.album_artists.is_empty() { if let Some(album_key) = &album_key {
artist.albums_as_performer.insert(album_key.clone()); let artist = self.get_or_create_artist(*name);
} else if !song.album_artists.contains(name) { if song.album_artists.is_empty() {
artist artist.albums_as_performer.insert(album_key.clone());
.albums_as_additional_performer } else if !song.album_artists.contains(name) {
.insert(album_key.clone()); artist
.albums_as_additional_performer
.insert(album_key.clone());
}
} }
} }
@ -307,12 +315,13 @@ impl Builder {
} }
fn add_song_to_album(&mut self, song: &storage::Song) { fn add_song_to_album(&mut self, song: &storage::Song) {
let album_key = song.album_key(); let Some(album_key) = song.album_key() else {
let album = self.albums.entry(album_key).or_default().borrow_mut(); return;
};
if album.name.is_none() { let name = album_key.name;
album.name = song.album; let album = self.albums.entry(album_key).or_default().borrow_mut();
} album.name = name;
if album.artwork.is_none() { if album.artwork.is_none() {
album.artwork = song.artwork; album.artwork = song.artwork;
@ -500,10 +509,7 @@ mod test {
assert_eq!(albums.len(), 2); assert_eq!(albums.len(), 2);
assert_eq!( assert_eq!(
albums albums.into_iter().map(|a| a.name).collect::<HashSet<_>>(),
.into_iter()
.map(|a| a.name.unwrap())
.collect::<HashSet<_>>(),
HashSet::from_iter(["ISDN".to_owned(), "Lifeforms".to_owned()]) HashSet::from_iter(["ISDN".to_owned(), "Lifeforms".to_owned()])
); );
} }
@ -527,10 +533,7 @@ mod test {
assert_eq!(albums.len(), 2); assert_eq!(albums.len(), 2);
assert_eq!( assert_eq!(
albums albums.into_iter().map(|a| a.name).collect::<Vec<_>>(),
.into_iter()
.map(|a| a.name.unwrap())
.collect::<Vec<_>>(),
vec!["ISDN".to_owned(), "Lifeforms".to_owned()] vec!["ISDN".to_owned(), "Lifeforms".to_owned()]
); );
} }
@ -617,11 +620,7 @@ mod test {
}; };
let artist = collection.get_artist(&strings, artist_key).unwrap(); let artist = collection.get_artist(&strings, artist_key).unwrap();
let names = |a: &Vec<Album>| { let names = |a: &Vec<Album>| a.iter().map(|a| a.name.to_owned()).collect::<Vec<_>>();
a.iter()
.map(|a| a.name.to_owned().unwrap())
.collect::<Vec<_>>()
};
if test.expect_performer { if test.expect_performer {
assert_eq!(names(&artist.albums_as_performer), vec![album_name]); assert_eq!(names(&artist.albums_as_performer), vec![album_name]);
@ -692,7 +691,7 @@ mod test {
.unwrap() .unwrap()
.albums_as_performer .albums_as_performer
.into_iter() .into_iter()
.map(|a| a.name.unwrap()) .map(|a| a.name)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
assert_eq!( assert_eq!(
@ -747,7 +746,7 @@ mod test {
&strings, &strings,
AlbumKey { AlbumKey {
artists: TinyVec::new(), artists: TinyVec::new(),
name: strings.get("Lifeforms"), name: strings.get("Lifeforms").unwrap(),
}, },
); );

View file

@ -29,7 +29,7 @@ pub struct Artist {
#[derive(Clone, Debug, Default, Serialize, Deserialize)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Album { pub struct Album {
pub name: Option<Spur>, pub name: Spur,
pub artwork: Option<PathKey>, pub artwork: Option<PathKey>,
pub artists: TinyVec<[Spur; 1]>, pub artists: TinyVec<[Spur; 1]>,
pub year: Option<i64>, pub year: Option<i64>,
@ -70,7 +70,7 @@ pub struct ArtistKey {
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct AlbumKey { pub struct AlbumKey {
pub artists: TinyVec<[Spur; 4]>, pub artists: TinyVec<[Spur; 4]>,
pub name: Option<Spur>, pub name: Spur,
} }
#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
@ -79,15 +79,18 @@ pub struct SongKey {
} }
impl Song { impl Song {
pub fn album_key(&self) -> AlbumKey { pub fn album_key(&self) -> Option<AlbumKey> {
let album_artists = match self.album_artists.is_empty() { let album_artists = match self.album_artists.is_empty() {
true => &self.artists, true => &self.artists,
false => &self.album_artists, false => &self.album_artists,
}; };
AlbumKey { match self.album {
artists: album_artists.iter().cloned().collect(), None => None,
name: self.album.clone(), Some(name) => Some(AlbumKey {
artists: album_artists.iter().cloned().collect(),
name,
}),
} }
} }
} }
@ -119,10 +122,15 @@ pub fn store_song(
' ' | '_' | '-' | '\'' => false, ' ' | '_' | '-' | '\'' => false,
_ => true, _ => true,
}); });
minuscules match cleaned.is_empty() {
.entry(cleaned.to_lowercase()) true => None,
.or_insert_with(|| strings.get_or_intern(s)) false => Some(
.to_owned() minuscules
.entry(cleaned.to_lowercase())
.or_insert_with(|| strings.get_or_intern(s))
.to_owned(),
),
}
}; };
Some(Song { Some(Song {
@ -130,47 +138,29 @@ pub fn store_song(
virtual_path, virtual_path,
track_number: song.track_number, track_number: song.track_number,
disc_number: song.disc_number, disc_number: song.disc_number,
title: song.title.as_ref().map(&mut canonicalize), title: song.title.as_ref().and_then(&mut canonicalize),
artists: song artists: song.artists.iter().filter_map(&mut canonicalize).collect(),
.artists
.iter()
.filter(|s| s.len() > 0)
.map(&mut canonicalize)
.collect(),
album_artists: song album_artists: song
.album_artists .album_artists
.iter() .iter()
.filter(|s| s.len() > 0) .filter_map(&mut canonicalize)
.map(&mut canonicalize)
.collect(), .collect(),
year: song.year, year: song.year,
album: song.album.as_ref().map(&mut canonicalize), album: song.album.as_ref().and_then(&mut canonicalize),
artwork: artwork, artwork: artwork,
duration: song.duration, duration: song.duration,
lyricists: song lyricists: song
.lyricists .lyricists
.iter() .iter()
.filter(|s| s.len() > 0) .filter_map(&mut canonicalize)
.map(&mut canonicalize)
.collect(), .collect(),
composers: song composers: song
.composers .composers
.iter() .iter()
.filter(|s| s.len() > 0) .filter_map(&mut canonicalize)
.map(&mut canonicalize)
.collect(),
genres: song
.genres
.iter()
.filter(|s| s.len() > 0)
.map(&mut canonicalize)
.collect(),
labels: song
.labels
.iter()
.filter(|s| s.len() > 0)
.map(&mut canonicalize)
.collect(), .collect(),
genres: song.genres.iter().filter_map(&mut canonicalize).collect(),
labels: song.labels.iter().filter_map(&mut canonicalize).collect(),
date_added: song.date_added, date_added: song.date_added,
}) })
} }

View file

@ -419,9 +419,7 @@ async fn get_album(
.split(API_ARRAY_SEPARATOR) .split(API_ARRAY_SEPARATOR)
.map(str::to_owned) .map(str::to_owned)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
Ok(Json( Ok(Json(index_manager.get_album(artists, name).await?.into()))
index_manager.get_album(artists, Some(name)).await?.into(),
))
} }
async fn get_songs( async fn get_songs(

View file

@ -363,7 +363,7 @@ impl From<index::Album> for Directory {
false => Some(album.artists.join("")), false => Some(album.artists.join("")),
}, },
year: album.year, year: album.year,
album: album.name, album: Some(album.name),
artwork: album.artwork, artwork: album.artwork,
} }
} }

View file

@ -368,8 +368,7 @@ impl From<index::Artist> for Artist {
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AlbumHeader { pub struct AlbumHeader {
#[serde(default, skip_serializing_if = "Option::is_none")] pub name: String,
pub name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")] #[serde(default, skip_serializing_if = "Option::is_none")]
pub artwork: Option<String>, pub artwork: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")] #[serde(default, skip_serializing_if = "Vec::is_empty")]