Semantic indexing for composer/lyricist

This commit is contained in:
Antoine Gersant 2024-08-09 13:02:49 -07:00
parent 0841c15f48
commit a2232aa9f2
3 changed files with 75 additions and 23 deletions

View file

@ -4,7 +4,7 @@ use std::{
path::PathBuf, path::PathBuf,
}; };
use lasso2::{RodeoReader, Rodeo}; use lasso2::{Rodeo, RodeoReader};
use rand::{rngs::ThreadRng, seq::IteratorRandom}; use rand::{rngs::ThreadRng, seq::IteratorRandom};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -17,7 +17,9 @@ use super::storage::fetch_song;
pub struct Artist { pub struct Artist {
pub name: Option<String>, pub name: Option<String>,
pub albums: Vec<Album>, pub albums: Vec<Album>,
pub album_appearances: Vec<Album>, pub song_credits: Vec<Album>, // Albums where this artist shows up as `artist` without being `album_artist`
pub composer_credits: Vec<Album>, // Albums where this artist shows up as `composer` without being `artist` or `album_artist`
pub lyricist_credits: Vec<Album>, // Albums where this artist shows up as `lyricist` without being `artist` or `album_artist`
} }
#[derive(Debug, Default, PartialEq, Eq)] #[derive(Debug, Default, PartialEq, Eq)]
@ -72,24 +74,48 @@ impl Collection {
albums albums
}; };
let album_appearances = { let sort_albums = |a: &Album, b: &Album| {
let mut album_appearances = a (&a.artists, a.year, &a.name)
.album_appearances .partial_cmp(&(&b.artists, b.year, &b.name))
.unwrap()
};
let song_credits = {
let mut albums = a
.song_credits
.iter() .iter()
.filter_map(|key| self.get_album(strings, key.clone())) .filter_map(|key| self.get_album(strings, key.clone()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
album_appearances.sort_by(|a, b| { albums.sort_by(&sort_albums);
(&a.artists, a.year, &a.name) albums
.partial_cmp(&(&b.artists, b.year, &b.name)) };
.unwrap()
}); let composer_credits = {
album_appearances let mut albums = a
.composer_credits
.iter()
.filter_map(|key| self.get_album(strings, key.clone()))
.collect::<Vec<_>>();
albums.sort_by(&sort_albums);
albums
};
let lyricist_credits = {
let mut albums = a
.lyricist_credits
.iter()
.filter_map(|key| self.get_album(strings, key.clone()))
.collect::<Vec<_>>();
albums.sort_by(&sort_albums);
albums
}; };
Artist { Artist {
name: a.name.map(|s| strings.resolve(&s).to_string()), name: a.name.map(|s| strings.resolve(&s).to_string()),
albums, albums,
album_appearances, song_credits,
composer_credits,
lyricist_credits,
} }
}) })
} }
@ -196,17 +222,35 @@ impl Builder {
fn add_album_to_artists(&mut self, song: &storage::Song) { fn add_album_to_artists(&mut self, song: &storage::Song) {
let album_key: AlbumKey = song.album_key(); let album_key: AlbumKey = song.album_key();
for artist_name in &song.album_artists { for name in &song.album_artists {
let artist = self.get_or_create_artist(*artist_name); let artist = self.get_or_create_artist(*name);
artist.albums.insert(album_key.clone()); artist.albums.insert(album_key.clone());
} }
for artist_name in &song.artists { for name in &song.artists {
let artist = self.get_or_create_artist(*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.insert(album_key.clone());
} else if !song.album_artists.contains(artist_name) { } else if !song.album_artists.contains(name) {
artist.album_appearances.insert(album_key.clone()); artist.song_credits.insert(album_key.clone());
}
}
for name in &song.composers {
let is_also_artist = song.artists.contains(name);
let is_also_album_artist = song.artists.contains(name);
if !is_also_artist && !is_also_album_artist {
let artist = self.get_or_create_artist(*name);
artist.composer_credits.insert(album_key.clone());
}
}
for name in &song.lyricists {
let is_also_artist = song.artists.contains(name);
let is_also_album_artist = song.artists.contains(name);
if !is_also_artist && !is_also_album_artist {
let artist = self.get_or_create_artist(*name);
artist.lyricist_credits.insert(album_key.clone());
} }
} }
} }
@ -218,7 +262,9 @@ impl Builder {
.or_insert_with(|| storage::Artist { .or_insert_with(|| storage::Artist {
name: Some(name), name: Some(name),
albums: HashSet::new(), albums: HashSet::new(),
album_appearances: HashSet::new(), song_credits: HashSet::new(),
composer_credits: HashSet::new(),
lyricist_credits: HashSet::new(),
}) })
.borrow_mut() .borrow_mut()
} }

View file

@ -3,7 +3,7 @@ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use lasso2::{RodeoReader, Rodeo}; use lasso2::{Rodeo, RodeoReader};
use log::error; use log::error;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tinyvec::TinyVec; use tinyvec::TinyVec;
@ -20,7 +20,9 @@ pub enum File {
pub struct Artist { pub struct Artist {
pub name: Option<lasso2::Spur>, pub name: Option<lasso2::Spur>,
pub albums: HashSet<AlbumKey>, pub albums: HashSet<AlbumKey>,
pub album_appearances: HashSet<AlbumKey>, pub song_credits: HashSet<AlbumKey>,
pub composer_credits: HashSet<AlbumKey>,
pub lyricist_credits: HashSet<AlbumKey>,
} }
#[derive(Clone, Default, Serialize, Deserialize)] #[derive(Clone, Default, Serialize, Deserialize)]

View file

@ -310,7 +310,9 @@ impl From<index::File> for BrowserEntry {
pub struct Artist { pub struct Artist {
pub name: Option<String>, pub name: Option<String>,
pub albums: Vec<AlbumHeader>, pub albums: Vec<AlbumHeader>,
pub album_appearances: Vec<AlbumHeader>, pub song_credits: Vec<AlbumHeader>,
pub composer_credits: Vec<AlbumHeader>,
pub lyricist_credits: Vec<AlbumHeader>,
} }
impl From<index::Artist> for Artist { impl From<index::Artist> for Artist {
@ -318,7 +320,9 @@ impl From<index::Artist> for Artist {
Self { Self {
name: a.name, name: a.name,
albums: a.albums.into_iter().map(|a| a.into()).collect(), albums: a.albums.into_iter().map(|a| a.into()).collect(),
album_appearances: a.album_appearances.into_iter().map(|a| a.into()).collect(), song_credits: a.song_credits.into_iter().map(|a| a.into()).collect(),
composer_credits: a.composer_credits.into_iter().map(|a| a.into()).collect(),
lyricist_credits: a.lyricist_credits.into_iter().map(|a| a.into()).collect(),
} }
} }
} }