Implement cannot have MBID in core #220
@ -5,7 +5,7 @@ use std::{
|
||||
|
||||
use crate::core::collection::{
|
||||
merge::{Merge, MergeSorted, WithId},
|
||||
musicbrainz::MbAlbumRef,
|
||||
musicbrainz::{MbAlbumRef, MbRefOption},
|
||||
track::{Track, TrackFormat},
|
||||
};
|
||||
|
||||
@ -22,7 +22,7 @@ pub struct AlbumMeta {
|
||||
pub id: AlbumId,
|
||||
pub date: AlbumDate,
|
||||
pub seq: AlbumSeq,
|
||||
pub musicbrainz: Option<MbAlbumRef>,
|
||||
pub musicbrainz: MbRefOption<MbAlbumRef>,
|
||||
pub primary_type: Option<AlbumPrimaryType>,
|
||||
pub secondary_types: Vec<AlbumSecondaryType>,
|
||||
}
|
||||
@ -186,7 +186,7 @@ impl AlbumMeta {
|
||||
id: id.into(),
|
||||
date: date.into(),
|
||||
seq: AlbumSeq::default(),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type,
|
||||
secondary_types,
|
||||
}
|
||||
@ -364,7 +364,7 @@ mod tests {
|
||||
|
||||
let mut album = Album::new(AlbumId::new("an album"), AlbumDate::default(), None, vec![]);
|
||||
|
||||
let mut expected: Option<MbAlbumRef> = None;
|
||||
let mut expected: MbRefOption<MbAlbumRef> = MbRefOption::None;
|
||||
assert_eq!(album.meta.musicbrainz, expected);
|
||||
|
||||
// Setting a URL on an album.
|
||||
|
@ -7,7 +7,7 @@ use std::{
|
||||
use crate::core::collection::{
|
||||
album::Album,
|
||||
merge::{Merge, MergeCollections, WithId},
|
||||
musicbrainz::MbArtistRef,
|
||||
musicbrainz::{MbArtistRef, MbRefOption},
|
||||
};
|
||||
|
||||
/// An artist.
|
||||
@ -22,7 +22,7 @@ pub struct Artist {
|
||||
pub struct ArtistMeta {
|
||||
pub id: ArtistId,
|
||||
pub sort: Option<ArtistId>,
|
||||
pub musicbrainz: Option<MbArtistRef>,
|
||||
pub musicbrainz: MbRefOption<MbArtistRef>,
|
||||
pub properties: HashMap<String, Vec<String>>,
|
||||
}
|
||||
|
||||
@ -75,7 +75,7 @@ impl ArtistMeta {
|
||||
ArtistMeta {
|
||||
id: id.into(),
|
||||
sort: None,
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
properties: HashMap::new(),
|
||||
}
|
||||
}
|
||||
@ -255,7 +255,7 @@ mod tests {
|
||||
fn set_clear_musicbrainz_url() {
|
||||
let mut artist = Artist::new(ArtistId::new("an artist"));
|
||||
|
||||
let mut expected: Option<MbArtistRef> = None;
|
||||
let mut expected: MbRefOption<MbArtistRef> = MbRefOption::None;
|
||||
assert_eq!(artist.meta.musicbrainz, expected);
|
||||
|
||||
// Setting a URL on an artist.
|
||||
@ -417,7 +417,7 @@ mod tests {
|
||||
let left = FULL_COLLECTION[0].to_owned();
|
||||
let mut right = FULL_COLLECTION[1].to_owned();
|
||||
right.meta.id = left.meta.id.clone();
|
||||
right.meta.musicbrainz = None;
|
||||
right.meta.musicbrainz = MbRefOption::None;
|
||||
right.meta.properties = HashMap::new();
|
||||
|
||||
let mut expected = left.clone();
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::{fmt, mem};
|
||||
|
||||
use url::Url;
|
||||
use uuid::Uuid;
|
||||
@ -38,6 +38,30 @@ try_from_impl_for_mbid!(&str);
|
||||
try_from_impl_for_mbid!(&String);
|
||||
try_from_impl_for_mbid!(String);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum MbRefOption<T> {
|
||||
Some(T),
|
||||
CannotHaveMbid,
|
||||
None,
|
||||
}
|
||||
|
||||
impl<T> MbRefOption<T> {
|
||||
pub fn or(self, optb: MbRefOption<T>) -> MbRefOption<T> {
|
||||
match self {
|
||||
x @ MbRefOption::Some(_) => x,
|
||||
MbRefOption::CannotHaveMbid | MbRefOption::None => optb,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn replace(&mut self, value: T) -> MbRefOption<T> {
|
||||
mem::replace(self, MbRefOption::Some(value))
|
||||
}
|
||||
|
||||
pub fn take(&mut self) -> MbRefOption<T> {
|
||||
mem::replace(self, MbRefOption::None)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
struct MusicBrainzRef {
|
||||
mbid: Mbid,
|
||||
@ -142,7 +166,7 @@ impl MusicBrainzRef {
|
||||
MusicBrainzRef { mbid, url }
|
||||
}
|
||||
|
||||
fn invalid_url_error<U: Display>(url: U, entity: &'static str) -> Error {
|
||||
fn invalid_url_error<U: fmt::Display>(url: U, entity: &'static str) -> Error {
|
||||
Error::UrlError(format!("invalid {entity} MusicBrainz URL: {url}"))
|
||||
}
|
||||
}
|
||||
|
@ -297,11 +297,14 @@ impl<Database: IDatabase, Library> MusicHoard<Database, Library> {
|
||||
mod tests {
|
||||
use mockall::{predicate, Sequence};
|
||||
|
||||
use crate::core::{
|
||||
use crate::{
|
||||
collection::musicbrainz::MbRefOption,
|
||||
core::{
|
||||
collection::{album::AlbumDate, artist::ArtistId},
|
||||
interface::database::{self, MockIDatabase},
|
||||
musichoard::{base::IMusicHoardBase, NoLibrary},
|
||||
testmod::FULL_COLLECTION,
|
||||
},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
@ -441,7 +444,7 @@ mod tests {
|
||||
|
||||
assert!(music_hoard.add_artist(artist_id.clone()).is_ok());
|
||||
|
||||
let mut expected: Option<MbArtistRef> = None;
|
||||
let mut expected: MbRefOption<MbArtistRef> = MbRefOption::None;
|
||||
assert_eq!(music_hoard.collection[0].meta.musicbrainz, expected);
|
||||
|
||||
// Setting a URL on an artist not in the collection is an error.
|
||||
|
@ -4,7 +4,7 @@ use std::collections::HashMap;
|
||||
use crate::core::collection::{
|
||||
album::{Album, AlbumId, AlbumMeta, AlbumPrimaryType, AlbumSeq},
|
||||
artist::{Artist, ArtistId, ArtistMeta},
|
||||
musicbrainz::{MbAlbumRef, MbArtistRef},
|
||||
musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption},
|
||||
track::{Track, TrackFormat, TrackId, TrackNum, TrackQuality},
|
||||
};
|
||||
use crate::testmod::*;
|
||||
|
30
src/external/database/json/testmod.rs
vendored
30
src/external/database/json/testmod.rs
vendored
@ -1,10 +1,10 @@
|
||||
pub static DATABASE_JSON: &str = "{\
|
||||
\"V20240828\":\
|
||||
\"V20240924\":\
|
||||
[\
|
||||
{\
|
||||
\"name\":\"Album_Artist ‘A’\",\
|
||||
\"sort\":null,\
|
||||
\"musicbrainz\":\"00000000-0000-0000-0000-000000000000\",\
|
||||
\"musicbrainz\":{\"Some\":\"00000000-0000-0000-0000-000000000000\"},\
|
||||
\"properties\":{\
|
||||
\"MusicButler\":[\"https://www.musicbutler.io/artist-page/000000000\"],\
|
||||
\"Qobuz\":[\"https://www.qobuz.com/nl-nl/interpreter/artist-a/download-streaming-albums\"]\
|
||||
@ -12,11 +12,11 @@ pub static DATABASE_JSON: &str = "{\
|
||||
\"albums\":[\
|
||||
{\
|
||||
\"title\":\"album_title a.a\",\"seq\":1,\
|
||||
\"musicbrainz\":\"00000000-0000-0000-0000-000000000000\",\
|
||||
\"musicbrainz\":{\"Some\":\"00000000-0000-0000-0000-000000000000\"},\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
},\
|
||||
{\
|
||||
\"title\":\"album_title a.b\",\"seq\":1,\"musicbrainz\":null,\
|
||||
\"title\":\"album_title a.b\",\"seq\":1,\"musicbrainz\":\"None\",\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
}\
|
||||
]\
|
||||
@ -24,7 +24,7 @@ pub static DATABASE_JSON: &str = "{\
|
||||
{\
|
||||
\"name\":\"Album_Artist ‘B’\",\
|
||||
\"sort\":null,\
|
||||
\"musicbrainz\":\"11111111-1111-1111-1111-111111111111\",\
|
||||
\"musicbrainz\":{\"Some\":\"11111111-1111-1111-1111-111111111111\"},\
|
||||
\"properties\":{\
|
||||
\"Bandcamp\":[\"https://artist-b.bandcamp.com/\"],\
|
||||
\"MusicButler\":[\
|
||||
@ -35,21 +35,21 @@ pub static DATABASE_JSON: &str = "{\
|
||||
},\
|
||||
\"albums\":[\
|
||||
{\
|
||||
\"title\":\"album_title b.a\",\"seq\":1,\"musicbrainz\":null,\
|
||||
\"title\":\"album_title b.a\",\"seq\":1,\"musicbrainz\":\"None\",\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
},\
|
||||
{\
|
||||
\"title\":\"album_title b.b\",\"seq\":3,\
|
||||
\"musicbrainz\":\"11111111-1111-1111-1111-111111111111\",\
|
||||
\"musicbrainz\":{\"Some\":\"11111111-1111-1111-1111-111111111111\"},\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
},\
|
||||
{\
|
||||
\"title\":\"album_title b.c\",\"seq\":2,\
|
||||
\"musicbrainz\":\"11111111-1111-1111-1111-111111111112\",\
|
||||
\"musicbrainz\":{\"Some\":\"11111111-1111-1111-1111-111111111112\"},\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
},\
|
||||
{\
|
||||
\"title\":\"album_title b.d\",\"seq\":4,\"musicbrainz\":null,\
|
||||
\"title\":\"album_title b.d\",\"seq\":4,\"musicbrainz\":\"None\",\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
}\
|
||||
]\
|
||||
@ -57,15 +57,15 @@ pub static DATABASE_JSON: &str = "{\
|
||||
{\
|
||||
\"name\":\"The Album_Artist ‘C’\",\
|
||||
\"sort\":\"Album_Artist ‘C’, The\",\
|
||||
\"musicbrainz\":\"11111111-1111-1111-1111-111111111111\",\
|
||||
\"musicbrainz\":\"CannotHaveMbid\",\
|
||||
\"properties\":{},\
|
||||
\"albums\":[\
|
||||
{\
|
||||
\"title\":\"album_title c.a\",\"seq\":0,\"musicbrainz\":null,\
|
||||
\"title\":\"album_title c.a\",\"seq\":0,\"musicbrainz\":\"None\",\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
},\
|
||||
{\
|
||||
\"title\":\"album_title c.b\",\"seq\":0,\"musicbrainz\":null,\
|
||||
\"title\":\"album_title c.b\",\"seq\":0,\"musicbrainz\":\"None\",\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
}\
|
||||
]\
|
||||
@ -73,15 +73,15 @@ pub static DATABASE_JSON: &str = "{\
|
||||
{\
|
||||
\"name\":\"Album_Artist ‘D’\",\
|
||||
\"sort\":null,\
|
||||
\"musicbrainz\":null,\
|
||||
\"musicbrainz\":\"None\",\
|
||||
\"properties\":{},\
|
||||
\"albums\":[\
|
||||
{\
|
||||
\"title\":\"album_title d.a\",\"seq\":0,\"musicbrainz\":null,\
|
||||
\"title\":\"album_title d.a\",\"seq\":0,\"musicbrainz\":\"None\",\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
},\
|
||||
{\
|
||||
\"title\":\"album_title d.b\",\"seq\":0,\"musicbrainz\":null,\
|
||||
\"title\":\"album_title d.b\",\"seq\":0,\"musicbrainz\":\"None\",\
|
||||
\"primary_type\":\"Album\",\"secondary_types\":[]\
|
||||
}\
|
||||
]\
|
||||
|
13
src/external/database/serde/common.rs
vendored
13
src/external/database/serde/common.rs
vendored
@ -1,6 +1,17 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::core::collection::album::{AlbumPrimaryType, AlbumSecondaryType};
|
||||
use crate::{
|
||||
collection::musicbrainz::MbRefOption,
|
||||
core::collection::album::{AlbumPrimaryType, AlbumSecondaryType},
|
||||
};
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[serde(remote = "MbRefOption")]
|
||||
pub enum MbRefOptionDef<T> {
|
||||
Some(T),
|
||||
CannotHaveMbid,
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[serde(remote = "AlbumPrimaryType")]
|
||||
|
40
src/external/database/serde/deserialize.rs
vendored
40
src/external/database/serde/deserialize.rs
vendored
@ -3,7 +3,11 @@ use std::{collections::HashMap, fmt};
|
||||
use serde::{de::Visitor, Deserialize, Deserializer};
|
||||
|
||||
use crate::{
|
||||
collection::{album::AlbumMeta, artist::ArtistMeta, musicbrainz::Mbid},
|
||||
collection::{
|
||||
album::AlbumMeta,
|
||||
artist::ArtistMeta,
|
||||
musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption, Mbid},
|
||||
},
|
||||
core::collection::{
|
||||
album::{Album, AlbumDate, AlbumId, AlbumSeq},
|
||||
artist::{Artist, ArtistId},
|
||||
@ -12,15 +16,17 @@ use crate::{
|
||||
external::database::serde::common::{SerdeAlbumPrimaryType, SerdeAlbumSecondaryType},
|
||||
};
|
||||
|
||||
use super::common::MbRefOptionDef;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub enum DeserializeDatabase {
|
||||
V20240828(Vec<DeserializeArtist>),
|
||||
V20240924(Vec<DeserializeArtist>),
|
||||
}
|
||||
|
||||
impl From<DeserializeDatabase> for Collection {
|
||||
fn from(database: DeserializeDatabase) -> Self {
|
||||
match database {
|
||||
DeserializeDatabase::V20240828(collection) => {
|
||||
DeserializeDatabase::V20240924(collection) => {
|
||||
collection.into_iter().map(Into::into).collect()
|
||||
}
|
||||
}
|
||||
@ -31,7 +37,7 @@ impl From<DeserializeDatabase> for Collection {
|
||||
pub struct DeserializeArtist {
|
||||
name: String,
|
||||
sort: Option<String>,
|
||||
musicbrainz: Option<DeserializeMbid>,
|
||||
musicbrainz: DeserializeMbRefOption,
|
||||
properties: HashMap<String, Vec<String>>,
|
||||
albums: Vec<DeserializeAlbum>,
|
||||
}
|
||||
@ -40,14 +46,34 @@ pub struct DeserializeArtist {
|
||||
pub struct DeserializeAlbum {
|
||||
title: String,
|
||||
seq: u8,
|
||||
musicbrainz: Option<DeserializeMbid>,
|
||||
musicbrainz: DeserializeMbRefOption,
|
||||
primary_type: Option<SerdeAlbumPrimaryType>,
|
||||
secondary_types: Vec<SerdeAlbumSecondaryType>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct DeserializeMbRefOption(#[serde(with = "MbRefOptionDef")] MbRefOption<DeserializeMbid>);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DeserializeMbid(Mbid);
|
||||
|
||||
macro_rules! impl_from_for_mb_ref_option {
|
||||
($ref:ty) => {
|
||||
impl From<DeserializeMbRefOption> for MbRefOption<$ref> {
|
||||
fn from(value: DeserializeMbRefOption) -> Self {
|
||||
match value.0 {
|
||||
MbRefOption::Some(val) => MbRefOption::Some(val.0.into()),
|
||||
MbRefOption::CannotHaveMbid => MbRefOption::CannotHaveMbid,
|
||||
MbRefOption::None => MbRefOption::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_for_mb_ref_option!(MbArtistRef);
|
||||
impl_from_for_mb_ref_option!(MbAlbumRef);
|
||||
|
||||
impl From<DeserializeMbid> for Mbid {
|
||||
fn from(value: DeserializeMbid) -> Self {
|
||||
value.0
|
||||
@ -89,7 +115,7 @@ impl From<DeserializeArtist> for Artist {
|
||||
meta: ArtistMeta {
|
||||
id: ArtistId::new(artist.name),
|
||||
sort: artist.sort.map(ArtistId::new),
|
||||
musicbrainz: artist.musicbrainz.map(Into::<Mbid>::into).map(Into::into),
|
||||
musicbrainz: artist.musicbrainz.into(),
|
||||
properties: artist.properties,
|
||||
},
|
||||
albums: artist.albums.into_iter().map(Into::into).collect(),
|
||||
@ -104,7 +130,7 @@ impl From<DeserializeAlbum> for Album {
|
||||
id: AlbumId { title: album.title },
|
||||
date: AlbumDate::default(),
|
||||
seq: AlbumSeq(album.seq),
|
||||
musicbrainz: album.musicbrainz.map(Into::<Mbid>::into).map(Into::into),
|
||||
musicbrainz: album.musicbrainz.into(),
|
||||
primary_type: album.primary_type.map(Into::into),
|
||||
secondary_types: album.secondary_types.into_iter().map(Into::into).collect(),
|
||||
},
|
||||
|
43
src/external/database/serde/serialize.rs
vendored
43
src/external/database/serde/serialize.rs
vendored
@ -3,19 +3,21 @@ use std::collections::BTreeMap;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
collection::musicbrainz::Mbid,
|
||||
collection::musicbrainz::{MbRefOption, Mbid},
|
||||
core::collection::{album::Album, artist::Artist, musicbrainz::IMusicBrainzRef, Collection},
|
||||
external::database::serde::common::{SerdeAlbumPrimaryType, SerdeAlbumSecondaryType},
|
||||
external::database::serde::common::{
|
||||
MbRefOptionDef, SerdeAlbumPrimaryType, SerdeAlbumSecondaryType,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub enum SerializeDatabase<'a> {
|
||||
V20240828(Vec<SerializeArtist<'a>>),
|
||||
V20240924(Vec<SerializeArtist<'a>>),
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Collection> for SerializeDatabase<'a> {
|
||||
fn from(collection: &'a Collection) -> Self {
|
||||
SerializeDatabase::V20240828(collection.iter().map(Into::into).collect())
|
||||
SerializeDatabase::V20240924(collection.iter().map(Into::into).collect())
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +25,7 @@ impl<'a> From<&'a Collection> for SerializeDatabase<'a> {
|
||||
pub struct SerializeArtist<'a> {
|
||||
name: &'a str,
|
||||
sort: Option<&'a str>,
|
||||
musicbrainz: Option<SerializeMbid<'a>>,
|
||||
musicbrainz: SerializeMbRefOption<'a>,
|
||||
properties: BTreeMap<&'a str, &'a Vec<String>>,
|
||||
albums: Vec<SerializeAlbum<'a>>,
|
||||
}
|
||||
@ -32,14 +34,31 @@ pub struct SerializeArtist<'a> {
|
||||
pub struct SerializeAlbum<'a> {
|
||||
title: &'a str,
|
||||
seq: u8,
|
||||
musicbrainz: Option<SerializeMbid<'a>>,
|
||||
musicbrainz: SerializeMbRefOption<'a>,
|
||||
primary_type: Option<SerdeAlbumPrimaryType>,
|
||||
secondary_types: Vec<SerdeAlbumSecondaryType>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct SerializeMbRefOption<'a>(
|
||||
#[serde(with = "MbRefOptionDef")] MbRefOption<SerializeMbid<'a>>,
|
||||
);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SerializeMbid<'a>(&'a Mbid);
|
||||
|
||||
impl<'a, T: IMusicBrainzRef> From<&'a MbRefOption<T>> for SerializeMbRefOption<'a> {
|
||||
fn from(value: &'a MbRefOption<T>) -> Self {
|
||||
match value {
|
||||
MbRefOption::Some(val) => {
|
||||
SerializeMbRefOption(MbRefOption::Some(SerializeMbid(val.mbid())))
|
||||
}
|
||||
MbRefOption::CannotHaveMbid => SerializeMbRefOption(MbRefOption::CannotHaveMbid),
|
||||
MbRefOption::None => SerializeMbRefOption(MbRefOption::None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Serialize for SerializeMbid<'a> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@ -54,11 +73,7 @@ impl<'a> From<&'a Artist> for SerializeArtist<'a> {
|
||||
SerializeArtist {
|
||||
name: &artist.meta.id.name,
|
||||
sort: artist.meta.sort.as_ref().map(|id| id.name.as_ref()),
|
||||
musicbrainz: artist
|
||||
.meta
|
||||
.musicbrainz
|
||||
.as_ref()
|
||||
.map(|mbref| SerializeMbid(mbref.mbid())),
|
||||
musicbrainz: (&artist.meta.musicbrainz).into(),
|
||||
properties: artist
|
||||
.meta
|
||||
.properties
|
||||
@ -75,11 +90,7 @@ impl<'a> From<&'a Album> for SerializeAlbum<'a> {
|
||||
SerializeAlbum {
|
||||
title: &album.meta.id.title,
|
||||
seq: album.meta.seq.0,
|
||||
musicbrainz: album
|
||||
.meta
|
||||
.musicbrainz
|
||||
.as_ref()
|
||||
.map(|mbref| SerializeMbid(mbref.mbid())),
|
||||
musicbrainz: (&album.meta.musicbrainz).into(),
|
||||
primary_type: album.meta.primary_type.map(Into::into),
|
||||
secondary_types: album
|
||||
.meta
|
||||
|
@ -7,7 +7,7 @@ macro_rules! full_collection {
|
||||
name: "Album_Artist ‘A’".to_string(),
|
||||
},
|
||||
sort: None,
|
||||
musicbrainz: Some(MbArtistRef::from_url_str(
|
||||
musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str(
|
||||
"https://musicbrainz.org/artist/00000000-0000-0000-0000-000000000000"
|
||||
).unwrap()),
|
||||
properties: HashMap::from([
|
||||
@ -29,7 +29,7 @@ macro_rules! full_collection {
|
||||
},
|
||||
date: 1998.into(),
|
||||
seq: AlbumSeq(1),
|
||||
musicbrainz: Some(MbAlbumRef::from_url_str(
|
||||
musicbrainz: MbRefOption::Some(MbAlbumRef::from_url_str(
|
||||
"https://musicbrainz.org/release-group/00000000-0000-0000-0000-000000000000"
|
||||
).unwrap()),
|
||||
primary_type: Some(AlbumPrimaryType::Album),
|
||||
@ -92,7 +92,7 @@ macro_rules! full_collection {
|
||||
},
|
||||
date: (2015, 4).into(),
|
||||
seq: AlbumSeq(1),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: Some(AlbumPrimaryType::Album),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -129,7 +129,7 @@ macro_rules! full_collection {
|
||||
name: "Album_Artist ‘B’".to_string(),
|
||||
},
|
||||
sort: None,
|
||||
musicbrainz: Some(MbArtistRef::from_url_str(
|
||||
musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str(
|
||||
"https://musicbrainz.org/artist/11111111-1111-1111-1111-111111111111"
|
||||
).unwrap()),
|
||||
properties: HashMap::from([
|
||||
@ -155,7 +155,7 @@ macro_rules! full_collection {
|
||||
},
|
||||
date: (2003, 6, 6).into(),
|
||||
seq: AlbumSeq(1),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: Some(AlbumPrimaryType::Album),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -194,7 +194,7 @@ macro_rules! full_collection {
|
||||
},
|
||||
date: 2008.into(),
|
||||
seq: AlbumSeq(3),
|
||||
musicbrainz: Some(MbAlbumRef::from_url_str(
|
||||
musicbrainz: MbRefOption::Some(MbAlbumRef::from_url_str(
|
||||
"https://musicbrainz.org/release-group/11111111-1111-1111-1111-111111111111"
|
||||
).unwrap()),
|
||||
primary_type: Some(AlbumPrimaryType::Album),
|
||||
@ -235,7 +235,7 @@ macro_rules! full_collection {
|
||||
},
|
||||
date: 2009.into(),
|
||||
seq: AlbumSeq(2),
|
||||
musicbrainz: Some(MbAlbumRef::from_url_str(
|
||||
musicbrainz: MbRefOption::Some(MbAlbumRef::from_url_str(
|
||||
"https://musicbrainz.org/release-group/11111111-1111-1111-1111-111111111112"
|
||||
).unwrap()),
|
||||
primary_type: Some(AlbumPrimaryType::Album),
|
||||
@ -276,7 +276,7 @@ macro_rules! full_collection {
|
||||
},
|
||||
date: 2015.into(),
|
||||
seq: AlbumSeq(4),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: Some(AlbumPrimaryType::Album),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -318,9 +318,7 @@ macro_rules! full_collection {
|
||||
sort: Some(ArtistId {
|
||||
name: "Album_Artist ‘C’, The".to_string(),
|
||||
}),
|
||||
musicbrainz: Some(MbArtistRef::from_url_str(
|
||||
"https://musicbrainz.org/artist/11111111-1111-1111-1111-111111111111"
|
||||
).unwrap()),
|
||||
musicbrainz: MbRefOption::CannotHaveMbid,
|
||||
properties: HashMap::new(),
|
||||
},
|
||||
albums: vec![
|
||||
@ -331,7 +329,7 @@ macro_rules! full_collection {
|
||||
},
|
||||
date: 1985.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: Some(AlbumPrimaryType::Album),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -370,7 +368,7 @@ macro_rules! full_collection {
|
||||
},
|
||||
date: 2018.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: Some(AlbumPrimaryType::Album),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -410,7 +408,7 @@ macro_rules! full_collection {
|
||||
name: "Album_Artist ‘D’".to_string(),
|
||||
},
|
||||
sort: None,
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
properties: HashMap::new(),
|
||||
},
|
||||
albums: vec![
|
||||
@ -421,7 +419,7 @@ macro_rules! full_collection {
|
||||
},
|
||||
date: 1995.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: Some(AlbumPrimaryType::Album),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -460,7 +458,7 @@ macro_rules! full_collection {
|
||||
},
|
||||
date: 2028.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: Some(AlbumPrimaryType::Album),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
|
@ -8,7 +8,7 @@ macro_rules! library_collection {
|
||||
name: "Album_Artist ‘A’".to_string(),
|
||||
},
|
||||
sort: None,
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
properties: HashMap::new(),
|
||||
},
|
||||
albums: vec![
|
||||
@ -19,7 +19,7 @@ macro_rules! library_collection {
|
||||
},
|
||||
date: 1998.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: None,
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -80,7 +80,7 @@ macro_rules! library_collection {
|
||||
},
|
||||
date: (2015, 4).into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: None,
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -117,7 +117,7 @@ macro_rules! library_collection {
|
||||
name: "Album_Artist ‘B’".to_string(),
|
||||
},
|
||||
sort: None,
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
properties: HashMap::new(),
|
||||
},
|
||||
albums: vec![
|
||||
@ -128,7 +128,7 @@ macro_rules! library_collection {
|
||||
},
|
||||
date: (2003, 6, 6).into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: None,
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -167,7 +167,7 @@ macro_rules! library_collection {
|
||||
},
|
||||
date: 2008.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: None,
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -206,7 +206,7 @@ macro_rules! library_collection {
|
||||
},
|
||||
date: 2009.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: None,
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -245,7 +245,7 @@ macro_rules! library_collection {
|
||||
},
|
||||
date: 2015.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: None,
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -287,7 +287,7 @@ macro_rules! library_collection {
|
||||
sort: Some(ArtistId {
|
||||
name: "Album_Artist ‘C’, The".to_string(),
|
||||
}),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
properties: HashMap::new(),
|
||||
},
|
||||
albums: vec![
|
||||
@ -298,7 +298,7 @@ macro_rules! library_collection {
|
||||
},
|
||||
date: 1985.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: None,
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -337,7 +337,7 @@ macro_rules! library_collection {
|
||||
},
|
||||
date: 2018.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: None,
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -377,7 +377,7 @@ macro_rules! library_collection {
|
||||
name: "Album_Artist ‘D’".to_string(),
|
||||
},
|
||||
sort: None,
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
properties: HashMap::new(),
|
||||
},
|
||||
albums: vec![
|
||||
@ -388,7 +388,7 @@ macro_rules! library_collection {
|
||||
},
|
||||
date: 1995.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: None,
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -427,7 +427,7 @@ macro_rules! library_collection {
|
||||
},
|
||||
date: 2028.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: None,
|
||||
secondary_types: vec![],
|
||||
},
|
||||
|
@ -6,7 +6,7 @@ use std::{
|
||||
use musichoard::collection::{
|
||||
album::AlbumMeta,
|
||||
artist::{Artist, ArtistMeta},
|
||||
musicbrainz::{IMusicBrainzRef, Mbid},
|
||||
musicbrainz::{IMusicBrainzRef, MbRefOption, Mbid},
|
||||
};
|
||||
|
||||
use crate::tui::{
|
||||
@ -35,9 +35,8 @@ impl FetchState {
|
||||
|
||||
fn try_recv(&mut self) -> Result<MbApiResult, TryRecvError> {
|
||||
if let Some(lookup_rx) = &self.lookup_rx {
|
||||
let result = lookup_rx.try_recv();
|
||||
match result {
|
||||
Ok(_) | Err(TryRecvError::Empty) => return result,
|
||||
match lookup_rx.try_recv() {
|
||||
x @ Ok(_) | x @ Err(TryRecvError::Empty) => return x,
|
||||
Err(TryRecvError::Disconnected) => {
|
||||
self.lookup_rx.take();
|
||||
}
|
||||
@ -142,15 +141,16 @@ impl AppMachine<FetchState> {
|
||||
artist: &Artist,
|
||||
) -> Result<(), DaemonError> {
|
||||
let requests = match artist.meta.musicbrainz {
|
||||
Some(ref arid) => {
|
||||
MbRefOption::Some(ref arid) => {
|
||||
let arid = arid.mbid();
|
||||
let albums = artist.albums.iter();
|
||||
albums
|
||||
.filter(|album| album.meta.musicbrainz.is_none())
|
||||
.filter(|album| matches!(album.meta.musicbrainz, MbRefOption::None))
|
||||
.map(|album| MbParams::search_release_group(arid.clone(), album.meta.clone()))
|
||||
.collect()
|
||||
}
|
||||
None => VecDeque::from([MbParams::search_artist(artist.meta.clone())]),
|
||||
MbRefOption::CannotHaveMbid => return Ok(()),
|
||||
MbRefOption::None => VecDeque::from([MbParams::search_artist(artist.meta.clone())]),
|
||||
};
|
||||
musicbrainz.submit_background_job(result_sender, requests)
|
||||
}
|
||||
@ -379,6 +379,20 @@ mod tests {
|
||||
AppMachine::app_lookup_artist(inner, fetch, &artist, mbid());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_artist_cannot_have_mbid() {
|
||||
let music_hoard = music_hoard(COLLECTION.to_owned());
|
||||
let inner = inner(music_hoard);
|
||||
|
||||
// Use third artist to match the expectation.
|
||||
let browse = AppMachine::browse_state(inner);
|
||||
let browse = browse.increment_selection(Delta::Line).unwrap_browse();
|
||||
let app = browse.increment_selection(Delta::Line);
|
||||
|
||||
let app = app.unwrap_browse().fetch_musicbrainz();
|
||||
assert!(matches!(app, AppState::Match(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_artist_job_sender_err() {
|
||||
let mut mb_job_sender = MockIMbJobSender::new();
|
||||
|
10
src/tui/lib/external/musicbrainz/api/mod.rs
vendored
10
src/tui/lib/external/musicbrainz/api/mod.rs
vendored
@ -6,7 +6,7 @@ use musichoard::{
|
||||
collection::{
|
||||
album::{AlbumDate, AlbumMeta, AlbumSeq},
|
||||
artist::{ArtistId, ArtistMeta},
|
||||
musicbrainz::Mbid,
|
||||
musicbrainz::{MbRefOption, Mbid},
|
||||
},
|
||||
external::musicbrainz::{
|
||||
api::{
|
||||
@ -100,7 +100,7 @@ fn from_lookup_artist_response(entity: LookupArtistResponse) -> Lookup<ArtistMet
|
||||
item: ArtistMeta {
|
||||
id: entity.meta.name,
|
||||
sort,
|
||||
musicbrainz: Some(entity.meta.id.into()),
|
||||
musicbrainz: MbRefOption::Some(entity.meta.id.into()),
|
||||
properties: HashMap::new(),
|
||||
},
|
||||
disambiguation: entity.meta.disambiguation,
|
||||
@ -113,7 +113,7 @@ fn from_lookup_release_group_response(entity: LookupReleaseGroupResponse) -> Loo
|
||||
id: entity.meta.title,
|
||||
date: entity.meta.first_release_date,
|
||||
seq: AlbumSeq::default(),
|
||||
musicbrainz: Some(entity.meta.id.into()),
|
||||
musicbrainz: MbRefOption::Some(entity.meta.id.into()),
|
||||
primary_type: Some(entity.meta.primary_type),
|
||||
secondary_types: entity.meta.secondary_types.unwrap_or_default(),
|
||||
},
|
||||
@ -130,7 +130,7 @@ fn from_search_artist_response_artist(entity: SearchArtistResponseArtist) -> Mat
|
||||
item: ArtistMeta {
|
||||
id: entity.meta.name,
|
||||
sort,
|
||||
musicbrainz: Some(entity.meta.id.into()),
|
||||
musicbrainz: MbRefOption::Some(entity.meta.id.into()),
|
||||
properties: HashMap::new(),
|
||||
},
|
||||
disambiguation: entity.meta.disambiguation,
|
||||
@ -146,7 +146,7 @@ fn from_search_release_group_response_release_group(
|
||||
id: entity.meta.title,
|
||||
date: entity.meta.first_release_date,
|
||||
seq: AlbumSeq::default(),
|
||||
musicbrainz: Some(entity.meta.id.into()),
|
||||
musicbrainz: MbRefOption::Some(entity.meta.id.into()),
|
||||
primary_type: Some(entity.meta.primary_type),
|
||||
secondary_types: entity.meta.secondary_types.unwrap_or_default(),
|
||||
},
|
||||
|
25
src/tui/lib/external/musicbrainz/daemon/mod.rs
vendored
25
src/tui/lib/external/musicbrainz/daemon/mod.rs
vendored
@ -316,7 +316,7 @@ mod tests {
|
||||
use musichoard::collection::{
|
||||
album::AlbumMeta,
|
||||
artist::ArtistMeta,
|
||||
musicbrainz::{IMusicBrainzRef, Mbid},
|
||||
musicbrainz::{IMusicBrainzRef, MbRefOption, Mbid},
|
||||
};
|
||||
|
||||
use crate::tui::{
|
||||
@ -327,6 +327,21 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
fn mb_ref_opt_unwrap<T>(opt: MbRefOption<T>) -> T {
|
||||
match opt {
|
||||
MbRefOption::Some(val) => val,
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn mb_ref_opt_as_ref<T>(opt: &MbRefOption<T>) -> MbRefOption<&T> {
|
||||
match *opt {
|
||||
MbRefOption::Some(ref x) => MbRefOption::Some(x),
|
||||
MbRefOption::CannotHaveMbid => MbRefOption::CannotHaveMbid,
|
||||
MbRefOption::None => MbRefOption::None,
|
||||
}
|
||||
}
|
||||
|
||||
fn musicbrainz() -> MockIMusicBrainz {
|
||||
MockIMusicBrainz::new()
|
||||
}
|
||||
@ -403,8 +418,8 @@ mod tests {
|
||||
}
|
||||
|
||||
fn search_albums_requests() -> VecDeque<MbParams> {
|
||||
let mbref = COLLECTION[1].meta.musicbrainz.as_ref();
|
||||
let arid = mbref.unwrap().mbid().clone();
|
||||
let mbref = mb_ref_opt_as_ref(&COLLECTION[1].meta.musicbrainz);
|
||||
let arid = mb_ref_opt_unwrap(mbref).mbid().clone();
|
||||
|
||||
let album_1 = COLLECTION[1].albums[0].meta.clone();
|
||||
let album_4 = COLLECTION[1].albums[3].meta.clone();
|
||||
@ -416,8 +431,8 @@ mod tests {
|
||||
}
|
||||
|
||||
fn album_arid_expectation() -> Mbid {
|
||||
let mbref = COLLECTION[1].meta.musicbrainz.as_ref();
|
||||
mbref.unwrap().mbid().clone()
|
||||
let mbref = mb_ref_opt_as_ref(&COLLECTION[1].meta.musicbrainz);
|
||||
mb_ref_opt_unwrap(mbref).mbid().clone()
|
||||
}
|
||||
|
||||
fn search_album_expectations_1() -> (AlbumMeta, Vec<Match<AlbumMeta>>) {
|
||||
|
@ -3,7 +3,7 @@ use std::collections::HashMap;
|
||||
use musichoard::collection::{
|
||||
album::{Album, AlbumId, AlbumMeta, AlbumPrimaryType, AlbumSeq},
|
||||
artist::{Artist, ArtistId, ArtistMeta},
|
||||
musicbrainz::{MbAlbumRef, MbArtistRef},
|
||||
musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption},
|
||||
track::{Track, TrackFormat, TrackId, TrackNum, TrackQuality},
|
||||
};
|
||||
use once_cell::sync::Lazy;
|
||||
|
@ -1,6 +1,7 @@
|
||||
use musichoard::collection::{
|
||||
album::{AlbumDate, AlbumMeta, AlbumPrimaryType, AlbumSecondaryType, AlbumSeq, AlbumStatus},
|
||||
artist::ArtistMeta,
|
||||
musicbrainz::{IMusicBrainzRef, MbRefOption},
|
||||
track::{TrackFormat, TrackQuality},
|
||||
};
|
||||
|
||||
@ -30,6 +31,14 @@ impl UiDisplay {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn display_mb_ref_option_as_url<T: IMusicBrainzRef>(option: &MbRefOption<T>) -> &str {
|
||||
match option {
|
||||
MbRefOption::Some(val) => val.url().as_str(),
|
||||
MbRefOption::CannotHaveMbid => "cannot have a MusicBrainz identifier",
|
||||
MbRefOption::None => "",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn display_type(
|
||||
primary: &Option<AlbumPrimaryType>,
|
||||
secondary: &Vec<AlbumSecondaryType>,
|
||||
|
@ -1,8 +1,10 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use musichoard::collection::{album::Album, artist::Artist, musicbrainz::IMusicBrainzRef};
|
||||
use musichoard::collection::{album::Album, artist::Artist};
|
||||
use ratatui::widgets::{ListState, Paragraph};
|
||||
|
||||
use super::display::UiDisplay;
|
||||
|
||||
struct InfoOverlay;
|
||||
|
||||
impl InfoOverlay {
|
||||
@ -74,8 +76,8 @@ impl<'a> ArtistOverlay<'a> {
|
||||
Properties: {}",
|
||||
artist.map(|a| a.meta.id.name.as_str()).unwrap_or(""),
|
||||
artist
|
||||
.and_then(|a| a.meta.musicbrainz.as_ref().map(|mb| mb.url().as_str()))
|
||||
.unwrap_or(""),
|
||||
.map(|a| UiDisplay::display_mb_ref_option_as_url(&a.meta.musicbrainz))
|
||||
.unwrap_or_default(),
|
||||
Self::opt_hashmap_to_string(
|
||||
artist.map(|a| &a.meta.properties),
|
||||
&double_item_indent,
|
||||
@ -102,8 +104,8 @@ impl<'a> AlbumOverlay<'a> {
|
||||
MusicBrainz: {}",
|
||||
album.map(|a| a.meta.id.title.as_str()).unwrap_or(""),
|
||||
album
|
||||
.and_then(|a| a.meta.musicbrainz.as_ref().map(|mb| mb.url().as_str()))
|
||||
.unwrap_or(""),
|
||||
.map(|a| UiDisplay::display_mb_ref_option_as_url(&a.meta.musicbrainz))
|
||||
.unwrap_or_default(),
|
||||
));
|
||||
|
||||
AlbumOverlay { properties }
|
||||
|
@ -305,7 +305,15 @@ mod tests {
|
||||
|
||||
draw_test_suite(artists, &mut selection);
|
||||
|
||||
// Change the artist (which cannot have a MBID).
|
||||
selection.increment_selection(artists, Delta::Line);
|
||||
selection.increment_selection(artists, Delta::Line);
|
||||
|
||||
draw_test_suite(artists, &mut selection);
|
||||
|
||||
// Change the track (which has a different track format).
|
||||
selection.decrement_selection(artists, Delta::Line);
|
||||
selection.decrement_selection(artists, Delta::Line);
|
||||
selection.increment_category();
|
||||
selection.increment_category();
|
||||
selection.increment_selection(artists, Delta::Line);
|
||||
|
@ -1 +1 @@
|
||||
{"V20240828":[{"name":"Аркона","sort":"Arkona","musicbrainz":"baad262d-55ef-427a-83c7-f7530964f212","properties":{"Bandcamp":["https://arkonamoscow.bandcamp.com/"],"MusicButler":["https://www.musicbutler.io/artist-page/283448581"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/arkona/download-streaming-albums"]},"albums":[{"title":"Slovo","seq":0,"musicbrainz":null,"primary_type":"Album","secondary_types":[]}]},{"name":"Eluveitie","sort":null,"musicbrainz":"8000598a-5edb-401c-8e6d-36b167feaf38","properties":{"MusicButler":["https://www.musicbutler.io/artist-page/269358403"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/eluveitie/download-streaming-albums"]},"albums":[{"title":"Vên [re‐recorded]","seq":0,"musicbrainz":null,"primary_type":"Ep","secondary_types":[]},{"title":"Slania","seq":0,"musicbrainz":null,"primary_type":"Album","secondary_types":[]}]},{"name":"Frontside","sort":null,"musicbrainz":"3a901353-fccd-4afd-ad01-9c03f451b490","properties":{"MusicButler":["https://www.musicbutler.io/artist-page/826588800"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/frontside/download-streaming-albums"]},"albums":[{"title":"…nasze jest królestwo, potęga i chwała na wieki…","seq":0,"musicbrainz":null,"primary_type":"Album","secondary_types":[]}]},{"name":"Heaven’s Basement","sort":"Heaven’s Basement","musicbrainz":"c2c4d56a-d599-4a18-bd2f-ae644e2198cc","properties":{"MusicButler":["https://www.musicbutler.io/artist-page/291158685"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/heaven-s-basement/download-streaming-albums"]},"albums":[{"title":"Paper Plague","seq":0,"musicbrainz":null,"primary_type":null,"secondary_types":[]},{"title":"Unbreakable","seq":0,"musicbrainz":null,"primary_type":"Album","secondary_types":[]}]},{"name":"Metallica","sort":null,"musicbrainz":"65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab","properties":{"MusicButler":["https://www.musicbutler.io/artist-page/3996865"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/metallica/download-streaming-albums"]},"albums":[{"title":"Ride the Lightning","seq":0,"musicbrainz":null,"primary_type":"Album","secondary_types":[]},{"title":"S&M","seq":0,"musicbrainz":null,"primary_type":"Album","secondary_types":["Live"]}]}]}
|
||||
{"V20240924":[{"name":"Аркона","sort":"Arkona","musicbrainz":{"Some":"baad262d-55ef-427a-83c7-f7530964f212"},"properties":{"Bandcamp":["https://arkonamoscow.bandcamp.com/"],"MusicButler":["https://www.musicbutler.io/artist-page/283448581"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/arkona/download-streaming-albums"]},"albums":[{"title":"Slovo","seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]}]},{"name":"Eluveitie","sort":null,"musicbrainz":{"Some":"8000598a-5edb-401c-8e6d-36b167feaf38"},"properties":{"MusicButler":["https://www.musicbutler.io/artist-page/269358403"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/eluveitie/download-streaming-albums"]},"albums":[{"title":"Vên [re‐recorded]","seq":0,"musicbrainz":"None","primary_type":"Ep","secondary_types":[]},{"title":"Slania","seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]}]},{"name":"Frontside","sort":null,"musicbrainz":{"Some":"3a901353-fccd-4afd-ad01-9c03f451b490"},"properties":{"MusicButler":["https://www.musicbutler.io/artist-page/826588800"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/frontside/download-streaming-albums"]},"albums":[{"title":"…nasze jest królestwo, potęga i chwała na wieki…","seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]}]},{"name":"Heaven’s Basement","sort":"Heaven’s Basement","musicbrainz":{"Some":"c2c4d56a-d599-4a18-bd2f-ae644e2198cc"},"properties":{"MusicButler":["https://www.musicbutler.io/artist-page/291158685"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/heaven-s-basement/download-streaming-albums"]},"albums":[{"title":"Paper Plague","seq":0,"musicbrainz":"None","primary_type":null,"secondary_types":[]},{"title":"Unbreakable","seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]}]},{"name":"Metallica","sort":null,"musicbrainz":{"Some":"65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab"},"properties":{"MusicButler":["https://www.musicbutler.io/artist-page/3996865"],"Qobuz":["https://www.qobuz.com/nl-nl/interpreter/metallica/download-streaming-albums"]},"albums":[{"title":"Ride the Lightning","seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":[]},{"title":"S&M","seq":0,"musicbrainz":"None","primary_type":"Album","secondary_types":["Live"]}]}]}
|
@ -4,7 +4,7 @@ use std::collections::HashMap;
|
||||
use musichoard::collection::{
|
||||
album::{Album, AlbumId, AlbumMeta, AlbumPrimaryType, AlbumSecondaryType, AlbumSeq},
|
||||
artist::{Artist, ArtistId, ArtistMeta},
|
||||
musicbrainz::MbArtistRef,
|
||||
musicbrainz::{MbArtistRef, MbRefOption},
|
||||
track::{Track, TrackFormat, TrackId, TrackNum, TrackQuality},
|
||||
Collection,
|
||||
};
|
||||
@ -19,7 +19,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
||||
sort: Some(ArtistId{
|
||||
name: String::from("Arkona")
|
||||
}),
|
||||
musicbrainz: Some(MbArtistRef::from_url_str(
|
||||
musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str(
|
||||
"https://musicbrainz.org/artist/baad262d-55ef-427a-83c7-f7530964f212"
|
||||
).unwrap()),
|
||||
properties: HashMap::from([
|
||||
@ -41,7 +41,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
||||
},
|
||||
date: 2011.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: Some(AlbumPrimaryType::Album),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -209,7 +209,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
||||
name: String::from("Eluveitie"),
|
||||
},
|
||||
sort: None,
|
||||
musicbrainz: Some(MbArtistRef::from_url_str(
|
||||
musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str(
|
||||
"https://musicbrainz.org/artist/8000598a-5edb-401c-8e6d-36b167feaf38"
|
||||
).unwrap()),
|
||||
properties: HashMap::from([
|
||||
@ -229,7 +229,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
||||
},
|
||||
date: 2004.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: Some(AlbumPrimaryType::Ep),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -309,7 +309,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
||||
},
|
||||
date: 2008.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: Some(AlbumPrimaryType::Album),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -456,7 +456,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
||||
name: String::from("Frontside"),
|
||||
},
|
||||
sort: None,
|
||||
musicbrainz: Some(MbArtistRef::from_url_str(
|
||||
musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str(
|
||||
"https://musicbrainz.org/artist/3a901353-fccd-4afd-ad01-9c03f451b490"
|
||||
).unwrap()),
|
||||
properties: HashMap::from([
|
||||
@ -475,7 +475,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
||||
},
|
||||
date: 2001.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: Some(AlbumPrimaryType::Album),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -612,7 +612,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
||||
sort: Some(ArtistId {
|
||||
name: String::from("Heaven’s Basement"),
|
||||
}),
|
||||
musicbrainz: Some(MbArtistRef::from_url_str(
|
||||
musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str(
|
||||
"https://musicbrainz.org/artist/c2c4d56a-d599-4a18-bd2f-ae644e2198cc"
|
||||
).unwrap()),
|
||||
properties: HashMap::from([
|
||||
@ -631,7 +631,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
||||
},
|
||||
date: 2011.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: None,
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -655,7 +655,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
||||
},
|
||||
date: 2011.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: Some(AlbumPrimaryType::Album),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -746,7 +746,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
||||
name: String::from("Metallica"),
|
||||
},
|
||||
sort: None,
|
||||
musicbrainz: Some(MbArtistRef::from_url_str(
|
||||
musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str(
|
||||
"https://musicbrainz.org/artist/65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab"
|
||||
).unwrap()),
|
||||
properties: HashMap::from([
|
||||
@ -766,7 +766,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
||||
},
|
||||
date: 1984.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: Some(AlbumPrimaryType::Album),
|
||||
secondary_types: vec![],
|
||||
},
|
||||
@ -868,7 +868,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
||||
},
|
||||
date: 1999.into(),
|
||||
seq: AlbumSeq(0),
|
||||
musicbrainz: None,
|
||||
musicbrainz: MbRefOption::None,
|
||||
primary_type: Some(AlbumPrimaryType::Album),
|
||||
secondary_types: vec![AlbumSecondaryType::Live],
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user