Artist indexing

This commit is contained in:
Antoine Gersant 2024-09-05 23:08:40 -07:00
parent ad37a14cfa
commit 0c12729983
3 changed files with 70 additions and 40 deletions

View file

@ -17,15 +17,19 @@ use super::storage::fetch_song;
#[derive(Debug, Default, PartialEq, Eq)] #[derive(Debug, Default, PartialEq, Eq)]
pub struct ArtistHeader { pub struct ArtistHeader {
pub name: UniCase<String>, pub name: UniCase<String>,
pub num_own_albums: u32, pub num_albums_as_performer: u32,
pub num_appearances: u32, pub num_albums_as_additional_performer: u32,
pub num_albums_as_composer: u32,
pub num_albums_as_lyricist: u32,
} }
#[derive(Debug, Default, PartialEq, Eq)] #[derive(Debug, Default, PartialEq, Eq)]
pub struct Artist { pub struct Artist {
pub header: ArtistHeader, pub header: ArtistHeader,
pub albums: Vec<Album>, pub albums_as_performer: Vec<Album>,
pub featured_on: Vec<Album>, // Albums where this artist shows up as `artist` without being `album_artist` pub albums_as_additional_performer: Vec<Album>, // Albums where this artist shows up as `artist` without being `album_artist`
pub albums_as_composer: Vec<Album>,
pub albums_as_lyricist: Vec<Album>,
} }
#[derive(Debug, Default, PartialEq, Eq)] #[derive(Debug, Default, PartialEq, Eq)]
@ -83,9 +87,8 @@ impl Collection {
self.artists.get(&artist_key).map(|a| { self.artists.get(&artist_key).map(|a| {
let sort_albums = |a: &Album, b: &Album| (&a.year, &a.name).cmp(&(&b.year, &b.name)); let sort_albums = |a: &Album, b: &Album| (&a.year, &a.name).cmp(&(&b.year, &b.name));
let albums = { let list_albums = |keys: &HashSet<AlbumKey>| {
let mut albums = a let mut albums = keys
.albums
.iter() .iter()
.filter_map(|key| self.get_album(strings, key.clone())) .filter_map(|key| self.get_album(strings, key.clone()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -93,20 +96,17 @@ impl Collection {
albums albums
}; };
let featured_on = { let albums_as_performer = list_albums(&a.albums_as_performer);
let mut albums = a let albums_as_additional_performer = list_albums(&a.albums_as_additional_performer);
.featured_on let albums_as_composer = list_albums(&a.albums_as_composer);
.iter() let albums_as_lyricist = list_albums(&a.albums_as_lyricist);
.filter_map(|key| self.get_album(strings, key.clone()))
.collect::<Vec<_>>();
albums.sort_by(&sort_albums);
albums
};
Artist { Artist {
header: make_artist_header(a, strings), header: make_artist_header(a, strings),
albums, albums_as_performer,
featured_on, albums_as_additional_performer,
albums_as_composer,
albums_as_lyricist,
} }
}) })
} }
@ -172,8 +172,10 @@ impl Collection {
fn make_artist_header(artist: &storage::Artist, strings: &RodeoReader) -> ArtistHeader { fn make_artist_header(artist: &storage::Artist, strings: &RodeoReader) -> ArtistHeader {
ArtistHeader { ArtistHeader {
name: UniCase::new(strings.resolve(&artist.name).to_owned()), name: UniCase::new(strings.resolve(&artist.name).to_owned()),
num_own_albums: artist.albums.len() as u32, num_albums_as_performer: artist.albums_as_performer.len() as u32,
num_appearances: artist.featured_on.len() as u32, num_albums_as_additional_performer: artist.albums_as_additional_performer.len() as u32,
num_albums_as_composer: artist.albums_as_composer.len() as u32,
num_albums_as_lyricist: artist.albums_as_lyricist.len() as u32,
} }
} }
@ -228,15 +230,27 @@ impl Builder {
for name in &song.album_artists { for name in &song.album_artists {
let artist = self.get_or_create_artist(*name); let artist = self.get_or_create_artist(*name);
artist.albums.insert(album_key.clone()); artist.albums_as_performer.insert(album_key.clone());
}
for name in &song.composers {
let artist = self.get_or_create_artist(*name);
artist.albums_as_composer.insert(album_key.clone());
}
for name in &song.lyricists {
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); let artist = self.get_or_create_artist(*name);
if song.album_artists.is_empty() { if song.album_artists.is_empty() {
artist.albums.insert(album_key.clone()); artist.albums_as_performer.insert(album_key.clone());
} else if !song.album_artists.contains(name) { } else if !song.album_artists.contains(name) {
artist.featured_on.insert(album_key.clone()); artist
.albums_as_additional_performer
.insert(album_key.clone());
} }
} }
} }
@ -247,8 +261,10 @@ impl Builder {
.entry(artist_key) .entry(artist_key)
.or_insert_with(|| storage::Artist { .or_insert_with(|| storage::Artist {
name, name,
albums: HashSet::new(), albums_as_performer: HashSet::new(),
featured_on: HashSet::new(), albums_as_additional_performer: HashSet::new(),
albums_as_composer: HashSet::new(),
albums_as_lyricist: HashSet::new(),
}) })
.borrow_mut() .borrow_mut()
} }
@ -576,15 +592,18 @@ mod test {
}; };
if test.expect_albums { if test.expect_albums {
assert_eq!(names(&artist.albums), vec![album_name]); assert_eq!(names(&artist.albums_as_performer), vec![album_name]);
} else { } else {
assert!(names(&artist.albums).is_empty()); assert!(names(&artist.albums_as_performer).is_empty());
} }
if test.expect_featured_on { if test.expect_featured_on {
assert_eq!(names(&artist.featured_on), vec![album_name]); assert_eq!(
names(&artist.albums_as_additional_performer),
vec![album_name]
);
} else { } else {
assert!(names(&artist.featured_on).is_empty()); assert!(names(&artist.albums_as_additional_performer).is_empty());
} }
} }
} }
@ -627,7 +646,7 @@ mod test {
let names = artist let names = artist
.unwrap() .unwrap()
.albums .albums_as_performer
.into_iter() .into_iter()
.map(|a| a.name.unwrap()) .map(|a| a.name.unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();

View file

@ -19,8 +19,10 @@ pub enum File {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Artist { pub struct Artist {
pub name: lasso2::Spur, pub name: lasso2::Spur,
pub albums: HashSet<AlbumKey>, pub albums_as_performer: HashSet<AlbumKey>,
pub featured_on: HashSet<AlbumKey>, pub albums_as_additional_performer: HashSet<AlbumKey>,
pub albums_as_composer: HashSet<AlbumKey>,
pub albums_as_lyricist: HashSet<AlbumKey>,
} }
#[derive(Clone, Debug, Default, Serialize, Deserialize)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]

View file

@ -320,16 +320,20 @@ impl From<index::File> for BrowserEntry {
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ArtistHeader { pub struct ArtistHeader {
pub name: String, pub name: String,
pub num_own_albums: u32, pub num_albums_as_performer: u32,
pub num_appearances: u32, pub num_albums_as_additional_performer: u32,
pub num_albums_as_composer: u32,
pub num_albums_as_lyricist: u32,
} }
impl From<index::ArtistHeader> for ArtistHeader { impl From<index::ArtistHeader> for ArtistHeader {
fn from(a: index::ArtistHeader) -> Self { fn from(a: index::ArtistHeader) -> Self {
Self { Self {
name: a.name.to_string(), name: a.name.to_string(),
num_own_albums: a.num_own_albums, num_albums_as_performer: a.num_albums_as_performer,
num_appearances: a.num_appearances, num_albums_as_additional_performer: a.num_albums_as_additional_performer,
num_albums_as_composer: a.num_albums_as_composer,
num_albums_as_lyricist: a.num_albums_as_lyricist,
} }
} }
} }
@ -338,16 +342,21 @@ impl From<index::ArtistHeader> for ArtistHeader {
pub struct Artist { pub struct Artist {
#[serde(flatten)] #[serde(flatten)]
pub header: ArtistHeader, pub header: ArtistHeader,
pub albums: Vec<AlbumHeader>, pub albums_as_performer: Vec<AlbumHeader>,
pub featured_on: Vec<AlbumHeader>, pub albums_as_additional_performer: Vec<AlbumHeader>,
pub albums_as_composer: Vec<AlbumHeader>,
pub albums_as_lyricist: Vec<AlbumHeader>,
} }
impl From<index::Artist> for Artist { impl From<index::Artist> for Artist {
fn from(a: index::Artist) -> Self { fn from(a: index::Artist) -> Self {
let convert_albums = |a: Vec<index::Album>| a.into_iter().map(|a| a.into()).collect();
Self { Self {
header: a.header.into(), header: a.header.into(),
albums: a.albums.into_iter().map(|a| a.into()).collect(), albums_as_performer: convert_albums(a.albums_as_performer),
featured_on: a.featured_on.into_iter().map(|a| a.into()).collect(), albums_as_additional_performer: convert_albums(a.albums_as_additional_performer),
albums_as_composer: convert_albums(a.albums_as_composer),
albums_as_lyricist: convert_albums(a.albums_as_lyricist),
} }
} }
} }