Add option for manual input during fetch #219
126
src/external/musicbrainz/api/lookup.rs
vendored
126
src/external/musicbrainz/api/lookup.rs
vendored
@ -2,20 +2,15 @@ use serde::Deserialize;
|
|||||||
use url::form_urlencoded;
|
use url::form_urlencoded;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
collection::{
|
collection::musicbrainz::Mbid,
|
||||||
album::{AlbumDate, AlbumId, AlbumPrimaryType, AlbumSecondaryType},
|
|
||||||
artist::ArtistId,
|
|
||||||
musicbrainz::Mbid,
|
|
||||||
},
|
|
||||||
external::musicbrainz::{
|
external::musicbrainz::{
|
||||||
api::{
|
api::{Error, MusicBrainzClient, MB_BASE_URL},
|
||||||
Error, MusicBrainzClient, SerdeAlbumDate, SerdeAlbumPrimaryType,
|
|
||||||
SerdeAlbumSecondaryType, SerdeMbid, MB_BASE_URL,
|
|
||||||
},
|
|
||||||
IMusicBrainzHttp,
|
IMusicBrainzHttp,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::{MbArtistMeta, MbReleaseGroupMeta, SerdeMbArtistMeta, SerdeMbReleaseGroupMeta};
|
||||||
|
|
||||||
impl<Http: IMusicBrainzHttp> MusicBrainzClient<Http> {
|
impl<Http: IMusicBrainzHttp> MusicBrainzClient<Http> {
|
||||||
pub fn lookup_artist(
|
pub fn lookup_artist(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -73,30 +68,22 @@ impl<'a> LookupArtistRequest<'a> {
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct LookupArtistResponse {
|
pub struct LookupArtistResponse {
|
||||||
pub id: Mbid,
|
pub meta: MbArtistMeta,
|
||||||
pub name: ArtistId,
|
pub release_groups: Vec<MbReleaseGroupMeta>,
|
||||||
pub sort_name: ArtistId,
|
|
||||||
pub disambiguation: Option<String>,
|
|
||||||
pub release_groups: Vec<LookupArtistResponseReleaseGroup>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(rename_all(deserialize = "kebab-case"))]
|
#[serde(rename_all(deserialize = "kebab-case"))]
|
||||||
struct DeserializeLookupArtistResponse {
|
struct DeserializeLookupArtistResponse {
|
||||||
id: SerdeMbid,
|
#[serde(flatten)]
|
||||||
name: String,
|
meta: SerdeMbArtistMeta,
|
||||||
sort_name: String,
|
release_groups: Option<Vec<SerdeMbReleaseGroupMeta>>,
|
||||||
disambiguation: Option<String>,
|
|
||||||
release_groups: Option<Vec<DeserializeLookupArtistResponseReleaseGroup>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DeserializeLookupArtistResponse> for LookupArtistResponse {
|
impl From<DeserializeLookupArtistResponse> for LookupArtistResponse {
|
||||||
fn from(value: DeserializeLookupArtistResponse) -> Self {
|
fn from(value: DeserializeLookupArtistResponse) -> Self {
|
||||||
LookupArtistResponse {
|
LookupArtistResponse {
|
||||||
id: value.id.into(),
|
meta: value.meta.into(),
|
||||||
name: value.name.into(),
|
|
||||||
sort_name: value.sort_name.into(),
|
|
||||||
disambiguation: value.disambiguation,
|
|
||||||
release_groups: value
|
release_groups: value
|
||||||
.release_groups
|
.release_groups
|
||||||
.map(|rgs| rgs.into_iter().map(Into::into).collect())
|
.map(|rgs| rgs.into_iter().map(Into::into).collect())
|
||||||
@ -105,37 +92,6 @@ impl From<DeserializeLookupArtistResponse> for LookupArtistResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub struct LookupArtistResponseReleaseGroup {
|
|
||||||
pub id: Mbid,
|
|
||||||
pub title: AlbumId,
|
|
||||||
pub first_release_date: AlbumDate,
|
|
||||||
pub primary_type: AlbumPrimaryType,
|
|
||||||
pub secondary_types: Vec<AlbumSecondaryType>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Deserialize)]
|
|
||||||
#[serde(rename_all(deserialize = "kebab-case"))]
|
|
||||||
struct DeserializeLookupArtistResponseReleaseGroup {
|
|
||||||
id: SerdeMbid,
|
|
||||||
title: String,
|
|
||||||
first_release_date: SerdeAlbumDate,
|
|
||||||
primary_type: SerdeAlbumPrimaryType,
|
|
||||||
secondary_types: Vec<SerdeAlbumSecondaryType>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<DeserializeLookupArtistResponseReleaseGroup> for LookupArtistResponseReleaseGroup {
|
|
||||||
fn from(value: DeserializeLookupArtistResponseReleaseGroup) -> Self {
|
|
||||||
LookupArtistResponseReleaseGroup {
|
|
||||||
id: value.id.into(),
|
|
||||||
title: value.title.into(),
|
|
||||||
first_release_date: value.first_release_date.into(),
|
|
||||||
primary_type: value.primary_type.into(),
|
|
||||||
secondary_types: value.secondary_types.into_iter().map(Into::into).collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct LookupReleaseGroupRequest<'a> {
|
pub struct LookupReleaseGroupRequest<'a> {
|
||||||
mbid: &'a Mbid,
|
mbid: &'a Mbid,
|
||||||
}
|
}
|
||||||
@ -148,33 +104,20 @@ impl<'a> LookupReleaseGroupRequest<'a> {
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct LookupReleaseGroupResponse {
|
pub struct LookupReleaseGroupResponse {
|
||||||
pub id: Mbid,
|
pub meta: MbReleaseGroupMeta,
|
||||||
pub title: AlbumId,
|
|
||||||
pub first_release_date: AlbumDate,
|
|
||||||
pub primary_type: AlbumPrimaryType,
|
|
||||||
pub secondary_types: Option<Vec<AlbumSecondaryType>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(rename_all(deserialize = "kebab-case"))]
|
#[serde(rename_all(deserialize = "kebab-case"))]
|
||||||
struct DeserializeLookupReleaseGroupResponse {
|
struct DeserializeLookupReleaseGroupResponse {
|
||||||
id: SerdeMbid,
|
#[serde(flatten)]
|
||||||
title: String,
|
meta: SerdeMbReleaseGroupMeta,
|
||||||
first_release_date: SerdeAlbumDate,
|
|
||||||
primary_type: SerdeAlbumPrimaryType,
|
|
||||||
secondary_types: Option<Vec<SerdeAlbumSecondaryType>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DeserializeLookupReleaseGroupResponse> for LookupReleaseGroupResponse {
|
impl From<DeserializeLookupReleaseGroupResponse> for LookupReleaseGroupResponse {
|
||||||
fn from(value: DeserializeLookupReleaseGroupResponse) -> Self {
|
fn from(value: DeserializeLookupReleaseGroupResponse) -> Self {
|
||||||
LookupReleaseGroupResponse {
|
LookupReleaseGroupResponse {
|
||||||
id: value.id.into(),
|
meta: value.meta.into(),
|
||||||
title: value.title.into(),
|
|
||||||
first_release_date: value.first_release_date.into(),
|
|
||||||
primary_type: value.primary_type.into(),
|
|
||||||
secondary_types: value
|
|
||||||
.secondary_types
|
|
||||||
.map(|v| v.into_iter().map(Into::into).collect()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,7 +126,13 @@ impl From<DeserializeLookupReleaseGroupResponse> for LookupReleaseGroupResponse
|
|||||||
mod tests {
|
mod tests {
|
||||||
use mockall::predicate;
|
use mockall::predicate;
|
||||||
|
|
||||||
use crate::external::musicbrainz::MockIMusicBrainzHttp;
|
use crate::{
|
||||||
|
collection::album::{AlbumPrimaryType, AlbumSecondaryType},
|
||||||
|
external::musicbrainz::{
|
||||||
|
api::{SerdeAlbumDate, SerdeAlbumPrimaryType, SerdeAlbumSecondaryType, SerdeMbid},
|
||||||
|
MockIMusicBrainzHttp,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -193,41 +142,38 @@ mod tests {
|
|||||||
let mut http = MockIMusicBrainzHttp::new();
|
let mut http = MockIMusicBrainzHttp::new();
|
||||||
let url = format!("https://musicbrainz.org/ws/2/artist/{mbid}?inc=release-groups",);
|
let url = format!("https://musicbrainz.org/ws/2/artist/{mbid}?inc=release-groups",);
|
||||||
|
|
||||||
let de_id = SerdeMbid(mbid.try_into().unwrap());
|
let de_meta = SerdeMbArtistMeta {
|
||||||
let de_name = String::from("the artist");
|
id: SerdeMbid(mbid.try_into().unwrap()),
|
||||||
let de_sort_name = String::from("artist, the");
|
name: String::from("the artist"),
|
||||||
let de_disambiguation = Some(String::from("disambig"));
|
sort_name: String::from("artist, the"),
|
||||||
let de_release_group = DeserializeLookupArtistResponseReleaseGroup {
|
disambiguation: Some(String::from("disambig")),
|
||||||
|
};
|
||||||
|
let de_release_group = SerdeMbReleaseGroupMeta {
|
||||||
id: SerdeMbid("11111111-1111-1111-1111-111111111111".try_into().unwrap()),
|
id: SerdeMbid("11111111-1111-1111-1111-111111111111".try_into().unwrap()),
|
||||||
title: String::from("an album"),
|
title: String::from("an album"),
|
||||||
first_release_date: SerdeAlbumDate((1986, 4).into()),
|
first_release_date: SerdeAlbumDate((1986, 4).into()),
|
||||||
primary_type: SerdeAlbumPrimaryType(AlbumPrimaryType::Album),
|
primary_type: SerdeAlbumPrimaryType(AlbumPrimaryType::Album),
|
||||||
secondary_types: vec![SerdeAlbumSecondaryType(AlbumSecondaryType::Compilation)],
|
secondary_types: Some(vec![SerdeAlbumSecondaryType(
|
||||||
|
AlbumSecondaryType::Compilation,
|
||||||
|
)]),
|
||||||
};
|
};
|
||||||
let de_response = DeserializeLookupArtistResponse {
|
let de_response = DeserializeLookupArtistResponse {
|
||||||
id: de_id.clone(),
|
meta: de_meta.clone(),
|
||||||
name: de_name.clone(),
|
|
||||||
sort_name: de_sort_name.clone(),
|
|
||||||
disambiguation: de_disambiguation.clone(),
|
|
||||||
release_groups: Some(vec![de_release_group.clone()]),
|
release_groups: Some(vec![de_release_group.clone()]),
|
||||||
};
|
};
|
||||||
|
|
||||||
let release_group = LookupArtistResponseReleaseGroup {
|
let release_group = MbReleaseGroupMeta {
|
||||||
id: de_release_group.id.0,
|
id: de_release_group.id.0,
|
||||||
title: de_release_group.title.into(),
|
title: de_release_group.title.into(),
|
||||||
first_release_date: de_release_group.first_release_date.0,
|
first_release_date: de_release_group.first_release_date.0,
|
||||||
primary_type: de_release_group.primary_type.0,
|
primary_type: de_release_group.primary_type.0,
|
||||||
secondary_types: de_release_group
|
secondary_types: de_release_group
|
||||||
.secondary_types
|
.secondary_types
|
||||||
.into_iter()
|
.as_ref()
|
||||||
.map(|st| st.0)
|
.map(|v| v.into_iter().map(|st| st.0).collect()),
|
||||||
.collect(),
|
|
||||||
};
|
};
|
||||||
let response = LookupArtistResponse {
|
let response = LookupArtistResponse {
|
||||||
id: de_id.0,
|
meta: de_meta.into(),
|
||||||
name: de_name.into(),
|
|
||||||
sort_name: de_sort_name.into(),
|
|
||||||
disambiguation: de_disambiguation,
|
|
||||||
release_groups: vec![release_group],
|
release_groups: vec![release_group],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
64
src/external/musicbrainz/api/mod.rs
vendored
64
src/external/musicbrainz/api/mod.rs
vendored
@ -4,7 +4,8 @@ use serde::{de::Visitor, Deserialize, Deserializer};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
collection::{
|
collection::{
|
||||||
album::{AlbumDate, AlbumPrimaryType, AlbumSecondaryType},
|
album::{AlbumDate, AlbumId, AlbumPrimaryType, AlbumSecondaryType},
|
||||||
|
artist::ArtistId,
|
||||||
musicbrainz::Mbid,
|
musicbrainz::Mbid,
|
||||||
Error as CollectionError,
|
Error as CollectionError,
|
||||||
},
|
},
|
||||||
@ -58,6 +59,67 @@ impl<Http> MusicBrainzClient<Http> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct MbArtistMeta {
|
||||||
|
pub id: Mbid,
|
||||||
|
pub name: ArtistId,
|
||||||
|
pub sort_name: ArtistId,
|
||||||
|
pub disambiguation: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize)]
|
||||||
|
#[serde(rename_all(deserialize = "kebab-case"))]
|
||||||
|
struct SerdeMbArtistMeta {
|
||||||
|
id: SerdeMbid,
|
||||||
|
name: String,
|
||||||
|
sort_name: String,
|
||||||
|
disambiguation: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SerdeMbArtistMeta> for MbArtistMeta {
|
||||||
|
fn from(value: SerdeMbArtistMeta) -> Self {
|
||||||
|
MbArtistMeta {
|
||||||
|
id: value.id.into(),
|
||||||
|
name: value.name.into(),
|
||||||
|
sort_name: value.sort_name.into(),
|
||||||
|
disambiguation: value.disambiguation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct MbReleaseGroupMeta {
|
||||||
|
pub id: Mbid,
|
||||||
|
pub title: AlbumId,
|
||||||
|
pub first_release_date: AlbumDate,
|
||||||
|
pub primary_type: AlbumPrimaryType,
|
||||||
|
pub secondary_types: Option<Vec<AlbumSecondaryType>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize)]
|
||||||
|
#[serde(rename_all(deserialize = "kebab-case"))]
|
||||||
|
pub struct SerdeMbReleaseGroupMeta {
|
||||||
|
id: SerdeMbid,
|
||||||
|
title: String,
|
||||||
|
first_release_date: SerdeAlbumDate,
|
||||||
|
primary_type: SerdeAlbumPrimaryType,
|
||||||
|
secondary_types: Option<Vec<SerdeAlbumSecondaryType>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SerdeMbReleaseGroupMeta> for MbReleaseGroupMeta {
|
||||||
|
fn from(value: SerdeMbReleaseGroupMeta) -> Self {
|
||||||
|
MbReleaseGroupMeta {
|
||||||
|
id: value.id.into(),
|
||||||
|
title: value.title.into(),
|
||||||
|
first_release_date: value.first_release_date.into(),
|
||||||
|
primary_type: value.primary_type.into(),
|
||||||
|
secondary_types: value
|
||||||
|
.secondary_types
|
||||||
|
.map(|v| v.into_iter().map(Into::into).collect()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ApiDisplay;
|
pub struct ApiDisplay;
|
||||||
|
|
||||||
impl ApiDisplay {
|
impl ApiDisplay {
|
||||||
|
35
src/external/musicbrainz/api/search/artist.rs
vendored
35
src/external/musicbrainz/api/search/artist.rs
vendored
@ -2,12 +2,9 @@ use std::fmt;
|
|||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::external::musicbrainz::api::{
|
||||||
collection::{artist::ArtistId, musicbrainz::Mbid},
|
|
||||||
external::musicbrainz::api::{
|
|
||||||
search::query::{impl_term, EmptyQuery, EmptyQueryJoin, Query, QueryJoin},
|
search::query::{impl_term, EmptyQuery, EmptyQueryJoin, Query, QueryJoin},
|
||||||
SerdeMbid,
|
MbArtistMeta, SerdeMbArtistMeta,
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum SearchArtist<'a> {
|
pub enum SearchArtist<'a> {
|
||||||
@ -48,30 +45,22 @@ impl From<DeserializeSearchArtistResponse> for SearchArtistResponse {
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct SearchArtistResponseArtist {
|
pub struct SearchArtistResponseArtist {
|
||||||
pub score: u8,
|
pub score: u8,
|
||||||
pub id: Mbid,
|
pub meta: MbArtistMeta,
|
||||||
pub name: ArtistId,
|
|
||||||
pub sort_name: ArtistId,
|
|
||||||
pub disambiguation: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Deserialize)]
|
#[derive(Clone, Deserialize)]
|
||||||
#[serde(rename_all(deserialize = "kebab-case"))]
|
#[serde(rename_all(deserialize = "kebab-case"))]
|
||||||
struct DeserializeSearchArtistResponseArtist {
|
struct DeserializeSearchArtistResponseArtist {
|
||||||
score: u8,
|
score: u8,
|
||||||
id: SerdeMbid,
|
#[serde(flatten)]
|
||||||
name: String,
|
meta: SerdeMbArtistMeta,
|
||||||
sort_name: String,
|
|
||||||
disambiguation: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DeserializeSearchArtistResponseArtist> for SearchArtistResponseArtist {
|
impl From<DeserializeSearchArtistResponseArtist> for SearchArtistResponseArtist {
|
||||||
fn from(value: DeserializeSearchArtistResponseArtist) -> Self {
|
fn from(value: DeserializeSearchArtistResponseArtist) -> Self {
|
||||||
SearchArtistResponseArtist {
|
SearchArtistResponseArtist {
|
||||||
score: value.score,
|
score: value.score,
|
||||||
id: value.id.into(),
|
meta: value.meta.into(),
|
||||||
name: value.name.into(),
|
|
||||||
sort_name: value.sort_name.into(),
|
|
||||||
disambiguation: value.disambiguation,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,17 +69,22 @@ impl From<DeserializeSearchArtistResponseArtist> for SearchArtistResponseArtist
|
|||||||
mod tests {
|
mod tests {
|
||||||
use mockall::predicate;
|
use mockall::predicate;
|
||||||
|
|
||||||
use crate::external::musicbrainz::{api::MusicBrainzClient, MockIMusicBrainzHttp};
|
use crate::external::musicbrainz::{
|
||||||
|
api::{MusicBrainzClient, SerdeMbid},
|
||||||
|
MockIMusicBrainzHttp,
|
||||||
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn de_response() -> DeserializeSearchArtistResponse {
|
fn de_response() -> DeserializeSearchArtistResponse {
|
||||||
let de_artist = DeserializeSearchArtistResponseArtist {
|
let de_artist = DeserializeSearchArtistResponseArtist {
|
||||||
score: 67,
|
score: 67,
|
||||||
|
meta: SerdeMbArtistMeta {
|
||||||
id: SerdeMbid("11111111-1111-1111-1111-111111111111".try_into().unwrap()),
|
id: SerdeMbid("11111111-1111-1111-1111-111111111111".try_into().unwrap()),
|
||||||
name: String::from("an artist"),
|
name: String::from("an artist"),
|
||||||
sort_name: String::from("artist, an"),
|
sort_name: String::from("artist, an"),
|
||||||
disambiguation: None,
|
disambiguation: None,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
DeserializeSearchArtistResponse {
|
DeserializeSearchArtistResponse {
|
||||||
artists: vec![de_artist.clone()],
|
artists: vec![de_artist.clone()],
|
||||||
@ -104,10 +98,7 @@ mod tests {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|a| SearchArtistResponseArtist {
|
.map(|a| SearchArtistResponseArtist {
|
||||||
score: 67,
|
score: 67,
|
||||||
id: a.id.0,
|
meta: a.meta.into(),
|
||||||
name: a.name.clone().into(),
|
|
||||||
sort_name: a.sort_name.clone().into(),
|
|
||||||
disambiguation: a.disambiguation,
|
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,10 @@ use std::fmt;
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
collection::{
|
collection::{album::AlbumDate, musicbrainz::Mbid},
|
||||||
album::{AlbumDate, AlbumId, AlbumPrimaryType, AlbumSecondaryType},
|
|
||||||
musicbrainz::Mbid,
|
|
||||||
},
|
|
||||||
external::musicbrainz::api::{
|
external::musicbrainz::api::{
|
||||||
search::query::{impl_term, EmptyQuery, EmptyQueryJoin, Query, QueryJoin},
|
search::query::{impl_term, EmptyQuery, EmptyQueryJoin, Query, QueryJoin},
|
||||||
ApiDisplay, SerdeAlbumDate, SerdeAlbumPrimaryType, SerdeAlbumSecondaryType, SerdeMbid,
|
ApiDisplay, MbReleaseGroupMeta, SerdeMbReleaseGroupMeta,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -72,22 +69,15 @@ impl From<DeserializeSearchReleaseGroupResponse> for SearchReleaseGroupResponse
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct SearchReleaseGroupResponseReleaseGroup {
|
pub struct SearchReleaseGroupResponseReleaseGroup {
|
||||||
pub score: u8,
|
pub score: u8,
|
||||||
pub id: Mbid,
|
pub meta: MbReleaseGroupMeta,
|
||||||
pub title: AlbumId,
|
|
||||||
pub first_release_date: AlbumDate,
|
|
||||||
pub primary_type: AlbumPrimaryType,
|
|
||||||
pub secondary_types: Option<Vec<AlbumSecondaryType>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Deserialize)]
|
#[derive(Clone, Deserialize)]
|
||||||
#[serde(rename_all(deserialize = "kebab-case"))]
|
#[serde(rename_all(deserialize = "kebab-case"))]
|
||||||
pub struct DeserializeSearchReleaseGroupResponseReleaseGroup {
|
pub struct DeserializeSearchReleaseGroupResponseReleaseGroup {
|
||||||
score: u8,
|
score: u8,
|
||||||
id: SerdeMbid,
|
#[serde(flatten)]
|
||||||
title: String,
|
meta: SerdeMbReleaseGroupMeta,
|
||||||
first_release_date: SerdeAlbumDate,
|
|
||||||
primary_type: SerdeAlbumPrimaryType,
|
|
||||||
secondary_types: Option<Vec<SerdeAlbumSecondaryType>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DeserializeSearchReleaseGroupResponseReleaseGroup>
|
impl From<DeserializeSearchReleaseGroupResponseReleaseGroup>
|
||||||
@ -96,13 +86,7 @@ impl From<DeserializeSearchReleaseGroupResponseReleaseGroup>
|
|||||||
fn from(value: DeserializeSearchReleaseGroupResponseReleaseGroup) -> Self {
|
fn from(value: DeserializeSearchReleaseGroupResponseReleaseGroup) -> Self {
|
||||||
SearchReleaseGroupResponseReleaseGroup {
|
SearchReleaseGroupResponseReleaseGroup {
|
||||||
score: value.score,
|
score: value.score,
|
||||||
id: value.id.into(),
|
meta: value.meta.into(),
|
||||||
title: value.title.into(),
|
|
||||||
first_release_date: value.first_release_date.into(),
|
|
||||||
primary_type: value.primary_type.into(),
|
|
||||||
secondary_types: value
|
|
||||||
.secondary_types
|
|
||||||
.map(|v| v.into_iter().map(Into::into).collect()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,18 +95,29 @@ impl From<DeserializeSearchReleaseGroupResponseReleaseGroup>
|
|||||||
mod tests {
|
mod tests {
|
||||||
use mockall::predicate;
|
use mockall::predicate;
|
||||||
|
|
||||||
use crate::external::musicbrainz::{api::MusicBrainzClient, MockIMusicBrainzHttp};
|
use crate::{
|
||||||
|
collection::album::{AlbumPrimaryType, AlbumSecondaryType},
|
||||||
|
external::musicbrainz::{
|
||||||
|
api::{
|
||||||
|
MusicBrainzClient, SerdeAlbumDate, SerdeAlbumPrimaryType, SerdeAlbumSecondaryType,
|
||||||
|
SerdeMbid,
|
||||||
|
},
|
||||||
|
MockIMusicBrainzHttp,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn de_response() -> DeserializeSearchReleaseGroupResponse {
|
fn de_response() -> DeserializeSearchReleaseGroupResponse {
|
||||||
let de_release_group = DeserializeSearchReleaseGroupResponseReleaseGroup {
|
let de_release_group = DeserializeSearchReleaseGroupResponseReleaseGroup {
|
||||||
score: 67,
|
score: 67,
|
||||||
|
meta: SerdeMbReleaseGroupMeta {
|
||||||
id: SerdeMbid("11111111-1111-1111-1111-111111111111".try_into().unwrap()),
|
id: SerdeMbid("11111111-1111-1111-1111-111111111111".try_into().unwrap()),
|
||||||
title: String::from("an album"),
|
title: String::from("an album"),
|
||||||
first_release_date: SerdeAlbumDate((1986, 4).into()),
|
first_release_date: SerdeAlbumDate((1986, 4).into()),
|
||||||
primary_type: SerdeAlbumPrimaryType(AlbumPrimaryType::Album),
|
primary_type: SerdeAlbumPrimaryType(AlbumPrimaryType::Album),
|
||||||
secondary_types: Some(vec![SerdeAlbumSecondaryType(AlbumSecondaryType::Live)]),
|
secondary_types: Some(vec![SerdeAlbumSecondaryType(AlbumSecondaryType::Live)]),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
DeserializeSearchReleaseGroupResponse {
|
DeserializeSearchReleaseGroupResponse {
|
||||||
release_groups: vec![de_release_group.clone()],
|
release_groups: vec![de_release_group.clone()],
|
||||||
@ -136,13 +131,7 @@ mod tests {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|rg| SearchReleaseGroupResponseReleaseGroup {
|
.map(|rg| SearchReleaseGroupResponseReleaseGroup {
|
||||||
score: 67,
|
score: 67,
|
||||||
id: rg.id.0,
|
meta: rg.meta.into(),
|
||||||
title: rg.title.into(),
|
|
||||||
first_release_date: rg.first_release_date.0,
|
|
||||||
primary_type: rg.primary_type.0,
|
|
||||||
secondary_types: rg
|
|
||||||
.secondary_types
|
|
||||||
.map(|v| v.into_iter().map(|st| st.0).collect()),
|
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
|
40
src/tui/lib/external/musicbrainz/api/mod.rs
vendored
40
src/tui/lib/external/musicbrainz/api/mod.rs
vendored
@ -93,47 +93,47 @@ impl<Http: IMusicBrainzHttp> IMusicBrainz for MusicBrainz<Http> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn from_lookup_artist_response(entity: LookupArtistResponse) -> Lookup<ArtistMeta> {
|
fn from_lookup_artist_response(entity: LookupArtistResponse) -> Lookup<ArtistMeta> {
|
||||||
let sort: Option<ArtistId> = Some(entity.sort_name)
|
let sort: Option<ArtistId> = Some(entity.meta.sort_name)
|
||||||
.filter(|s| s != &entity.name)
|
.filter(|s| s != &entity.meta.name)
|
||||||
.map(Into::into);
|
.map(Into::into);
|
||||||
Lookup {
|
Lookup {
|
||||||
item: ArtistMeta {
|
item: ArtistMeta {
|
||||||
id: entity.name,
|
id: entity.meta.name,
|
||||||
sort,
|
sort,
|
||||||
musicbrainz: Some(entity.id.into()),
|
musicbrainz: Some(entity.meta.id.into()),
|
||||||
properties: HashMap::new(),
|
properties: HashMap::new(),
|
||||||
},
|
},
|
||||||
disambiguation: entity.disambiguation,
|
disambiguation: entity.meta.disambiguation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_lookup_release_group_response(entity: LookupReleaseGroupResponse) -> Lookup<AlbumMeta> {
|
fn from_lookup_release_group_response(entity: LookupReleaseGroupResponse) -> Lookup<AlbumMeta> {
|
||||||
Lookup {
|
Lookup {
|
||||||
item: AlbumMeta {
|
item: AlbumMeta {
|
||||||
id: entity.title,
|
id: entity.meta.title,
|
||||||
date: entity.first_release_date,
|
date: entity.meta.first_release_date,
|
||||||
seq: AlbumSeq::default(),
|
seq: AlbumSeq::default(),
|
||||||
musicbrainz: Some(entity.id.into()),
|
musicbrainz: Some(entity.meta.id.into()),
|
||||||
primary_type: Some(entity.primary_type),
|
primary_type: Some(entity.meta.primary_type),
|
||||||
secondary_types: entity.secondary_types.unwrap_or_default(),
|
secondary_types: entity.meta.secondary_types.unwrap_or_default(),
|
||||||
},
|
},
|
||||||
disambiguation: None,
|
disambiguation: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_search_artist_response_artist(entity: SearchArtistResponseArtist) -> Match<ArtistMeta> {
|
fn from_search_artist_response_artist(entity: SearchArtistResponseArtist) -> Match<ArtistMeta> {
|
||||||
let sort: Option<ArtistId> = Some(entity.sort_name)
|
let sort: Option<ArtistId> = Some(entity.meta.sort_name)
|
||||||
.filter(|s| s != &entity.name)
|
.filter(|s| s != &entity.meta.name)
|
||||||
.map(Into::into);
|
.map(Into::into);
|
||||||
Match {
|
Match {
|
||||||
score: entity.score,
|
score: entity.score,
|
||||||
item: ArtistMeta {
|
item: ArtistMeta {
|
||||||
id: entity.name,
|
id: entity.meta.name,
|
||||||
sort,
|
sort,
|
||||||
musicbrainz: Some(entity.id.into()),
|
musicbrainz: Some(entity.meta.id.into()),
|
||||||
properties: HashMap::new(),
|
properties: HashMap::new(),
|
||||||
},
|
},
|
||||||
disambiguation: entity.disambiguation,
|
disambiguation: entity.meta.disambiguation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,12 +143,12 @@ fn from_search_release_group_response_release_group(
|
|||||||
Match {
|
Match {
|
||||||
score: entity.score,
|
score: entity.score,
|
||||||
item: AlbumMeta {
|
item: AlbumMeta {
|
||||||
id: entity.title,
|
id: entity.meta.title,
|
||||||
date: entity.first_release_date,
|
date: entity.meta.first_release_date,
|
||||||
seq: AlbumSeq::default(),
|
seq: AlbumSeq::default(),
|
||||||
musicbrainz: Some(entity.id.into()),
|
musicbrainz: Some(entity.meta.id.into()),
|
||||||
primary_type: Some(entity.primary_type),
|
primary_type: Some(entity.meta.primary_type),
|
||||||
secondary_types: entity.secondary_types.unwrap_or_default(),
|
secondary_types: entity.meta.secondary_types.unwrap_or_default(),
|
||||||
},
|
},
|
||||||
disambiguation: None,
|
disambiguation: None,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user