Drop support for blank album names
This commit is contained in:
parent
4072e3b07d
commit
7be9f25cb3
6 changed files with 70 additions and 84 deletions
src
|
@ -140,21 +140,21 @@ impl Manager {
|
|||
.unwrap()
|
||||
}
|
||||
|
||||
pub async fn get_album(
|
||||
&self,
|
||||
artists: Vec<String>,
|
||||
name: Option<String>,
|
||||
) -> Result<Album, Error> {
|
||||
pub async fn get_album(&self, artists: Vec<String>, name: String) -> Result<Album, Error> {
|
||||
spawn_blocking({
|
||||
let index_manager = self.clone();
|
||||
move || {
|
||||
let index = index_manager.index.read().unwrap();
|
||||
let name = index
|
||||
.strings
|
||||
.get(&name)
|
||||
.ok_or_else(|| Error::AlbumNotFound)?;
|
||||
let album_key = AlbumKey {
|
||||
artists: artists
|
||||
.into_iter()
|
||||
.filter_map(|a| index.strings.get(a))
|
||||
.collect(),
|
||||
name: name.and_then(|n| index.strings.get(n)),
|
||||
name,
|
||||
};
|
||||
index
|
||||
.collection
|
||||
|
|
|
@ -38,7 +38,7 @@ pub struct Artist {
|
|||
|
||||
#[derive(Debug, Default, PartialEq, Eq)]
|
||||
pub struct Album {
|
||||
pub name: Option<String>,
|
||||
pub name: String,
|
||||
pub artwork: Option<PathBuf>,
|
||||
pub artists: Vec<String>,
|
||||
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)));
|
||||
|
||||
Album {
|
||||
name: a.name.map(|s| strings.resolve(&s).to_string()),
|
||||
name: strings.resolve(&a.name).to_string(),
|
||||
artwork: a
|
||||
.artwork
|
||||
.as_ref()
|
||||
|
@ -243,37 +243,45 @@ impl Builder {
|
|||
}
|
||||
|
||||
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();
|
||||
|
||||
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);
|
||||
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 {
|
||||
let artist = self.get_or_create_artist(*name);
|
||||
artist.albums_as_composer.insert(album_key.clone());
|
||||
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 {
|
||||
let artist = self.get_or_create_artist(*name);
|
||||
artist.albums_as_lyricist.insert(album_key.clone());
|
||||
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 {
|
||||
let artist = self.get_or_create_artist(*name);
|
||||
all_artists.push(*name);
|
||||
if song.album_artists.is_empty() {
|
||||
artist.albums_as_performer.insert(album_key.clone());
|
||||
} else if !song.album_artists.contains(name) {
|
||||
artist
|
||||
.albums_as_additional_performer
|
||||
.insert(album_key.clone());
|
||||
if let Some(album_key) = &album_key {
|
||||
let artist = self.get_or_create_artist(*name);
|
||||
if song.album_artists.is_empty() {
|
||||
artist.albums_as_performer.insert(album_key.clone());
|
||||
} else if !song.album_artists.contains(name) {
|
||||
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) {
|
||||
let album_key = song.album_key();
|
||||
let album = self.albums.entry(album_key).or_default().borrow_mut();
|
||||
let Some(album_key) = song.album_key() else {
|
||||
return;
|
||||
};
|
||||
|
||||
if album.name.is_none() {
|
||||
album.name = song.album;
|
||||
}
|
||||
let name = album_key.name;
|
||||
let album = self.albums.entry(album_key).or_default().borrow_mut();
|
||||
album.name = name;
|
||||
|
||||
if album.artwork.is_none() {
|
||||
album.artwork = song.artwork;
|
||||
|
@ -500,10 +509,7 @@ mod test {
|
|||
assert_eq!(albums.len(), 2);
|
||||
|
||||
assert_eq!(
|
||||
albums
|
||||
.into_iter()
|
||||
.map(|a| a.name.unwrap())
|
||||
.collect::<HashSet<_>>(),
|
||||
albums.into_iter().map(|a| a.name).collect::<HashSet<_>>(),
|
||||
HashSet::from_iter(["ISDN".to_owned(), "Lifeforms".to_owned()])
|
||||
);
|
||||
}
|
||||
|
@ -527,10 +533,7 @@ mod test {
|
|||
assert_eq!(albums.len(), 2);
|
||||
|
||||
assert_eq!(
|
||||
albums
|
||||
.into_iter()
|
||||
.map(|a| a.name.unwrap())
|
||||
.collect::<Vec<_>>(),
|
||||
albums.into_iter().map(|a| a.name).collect::<Vec<_>>(),
|
||||
vec!["ISDN".to_owned(), "Lifeforms".to_owned()]
|
||||
);
|
||||
}
|
||||
|
@ -617,11 +620,7 @@ mod test {
|
|||
};
|
||||
let artist = collection.get_artist(&strings, artist_key).unwrap();
|
||||
|
||||
let names = |a: &Vec<Album>| {
|
||||
a.iter()
|
||||
.map(|a| a.name.to_owned().unwrap())
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
let names = |a: &Vec<Album>| a.iter().map(|a| a.name.to_owned()).collect::<Vec<_>>();
|
||||
|
||||
if test.expect_performer {
|
||||
assert_eq!(names(&artist.albums_as_performer), vec![album_name]);
|
||||
|
@ -692,7 +691,7 @@ mod test {
|
|||
.unwrap()
|
||||
.albums_as_performer
|
||||
.into_iter()
|
||||
.map(|a| a.name.unwrap())
|
||||
.map(|a| a.name)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(
|
||||
|
@ -747,7 +746,7 @@ mod test {
|
|||
&strings,
|
||||
AlbumKey {
|
||||
artists: TinyVec::new(),
|
||||
name: strings.get("Lifeforms"),
|
||||
name: strings.get("Lifeforms").unwrap(),
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ pub struct Artist {
|
|||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct Album {
|
||||
pub name: Option<Spur>,
|
||||
pub name: Spur,
|
||||
pub artwork: Option<PathKey>,
|
||||
pub artists: TinyVec<[Spur; 1]>,
|
||||
pub year: Option<i64>,
|
||||
|
@ -70,7 +70,7 @@ pub struct ArtistKey {
|
|||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct AlbumKey {
|
||||
pub artists: TinyVec<[Spur; 4]>,
|
||||
pub name: Option<Spur>,
|
||||
pub name: Spur,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
|
@ -79,15 +79,18 @@ pub struct SongKey {
|
|||
}
|
||||
|
||||
impl Song {
|
||||
pub fn album_key(&self) -> AlbumKey {
|
||||
pub fn album_key(&self) -> Option<AlbumKey> {
|
||||
let album_artists = match self.album_artists.is_empty() {
|
||||
true => &self.artists,
|
||||
false => &self.album_artists,
|
||||
};
|
||||
|
||||
AlbumKey {
|
||||
artists: album_artists.iter().cloned().collect(),
|
||||
name: self.album.clone(),
|
||||
match self.album {
|
||||
None => None,
|
||||
Some(name) => Some(AlbumKey {
|
||||
artists: album_artists.iter().cloned().collect(),
|
||||
name,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,10 +122,15 @@ pub fn store_song(
|
|||
' ' | '_' | '-' | '\'' => false,
|
||||
_ => true,
|
||||
});
|
||||
minuscules
|
||||
.entry(cleaned.to_lowercase())
|
||||
.or_insert_with(|| strings.get_or_intern(s))
|
||||
.to_owned()
|
||||
match cleaned.is_empty() {
|
||||
true => None,
|
||||
false => Some(
|
||||
minuscules
|
||||
.entry(cleaned.to_lowercase())
|
||||
.or_insert_with(|| strings.get_or_intern(s))
|
||||
.to_owned(),
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
Some(Song {
|
||||
|
@ -130,47 +138,29 @@ pub fn store_song(
|
|||
virtual_path,
|
||||
track_number: song.track_number,
|
||||
disc_number: song.disc_number,
|
||||
title: song.title.as_ref().map(&mut canonicalize),
|
||||
artists: song
|
||||
.artists
|
||||
.iter()
|
||||
.filter(|s| s.len() > 0)
|
||||
.map(&mut canonicalize)
|
||||
.collect(),
|
||||
title: song.title.as_ref().and_then(&mut canonicalize),
|
||||
artists: song.artists.iter().filter_map(&mut canonicalize).collect(),
|
||||
album_artists: song
|
||||
.album_artists
|
||||
.iter()
|
||||
.filter(|s| s.len() > 0)
|
||||
.map(&mut canonicalize)
|
||||
.filter_map(&mut canonicalize)
|
||||
.collect(),
|
||||
year: song.year,
|
||||
album: song.album.as_ref().map(&mut canonicalize),
|
||||
album: song.album.as_ref().and_then(&mut canonicalize),
|
||||
artwork: artwork,
|
||||
duration: song.duration,
|
||||
lyricists: song
|
||||
.lyricists
|
||||
.iter()
|
||||
.filter(|s| s.len() > 0)
|
||||
.map(&mut canonicalize)
|
||||
.filter_map(&mut canonicalize)
|
||||
.collect(),
|
||||
composers: song
|
||||
.composers
|
||||
.iter()
|
||||
.filter(|s| s.len() > 0)
|
||||
.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)
|
||||
.filter_map(&mut canonicalize)
|
||||
.collect(),
|
||||
genres: song.genres.iter().filter_map(&mut canonicalize).collect(),
|
||||
labels: song.labels.iter().filter_map(&mut canonicalize).collect(),
|
||||
date_added: song.date_added,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -419,9 +419,7 @@ async fn get_album(
|
|||
.split(API_ARRAY_SEPARATOR)
|
||||
.map(str::to_owned)
|
||||
.collect::<Vec<_>>();
|
||||
Ok(Json(
|
||||
index_manager.get_album(artists, Some(name)).await?.into(),
|
||||
))
|
||||
Ok(Json(index_manager.get_album(artists, name).await?.into()))
|
||||
}
|
||||
|
||||
async fn get_songs(
|
||||
|
|
|
@ -363,7 +363,7 @@ impl From<index::Album> for Directory {
|
|||
false => Some(album.artists.join("")),
|
||||
},
|
||||
year: album.year,
|
||||
album: album.name,
|
||||
album: Some(album.name),
|
||||
artwork: album.artwork,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -368,8 +368,7 @@ impl From<index::Artist> for Artist {
|
|||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AlbumHeader {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub name: Option<String>,
|
||||
pub name: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub artwork: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
|
|
Loading…
Add table
Reference in a new issue