Decide carefully where external::musicbrainz
belongs
#196
@ -45,14 +45,14 @@ name = "musichoard-edit"
|
||||
required-features = ["bin", "database-json"]
|
||||
|
||||
[[example]]
|
||||
name = "musicbrainz-api---lookup-artist-release-groups"
|
||||
path = "examples/musicbrainz_api/lookup_artist_release_groups.rs"
|
||||
required-features = ["bin", "musicbrainz-api"]
|
||||
name = "musicbrainz-api---lookup-artist"
|
||||
path = "examples/musicbrainz_api/lookup_artist.rs"
|
||||
required-features = ["bin", "musicbrainz"]
|
||||
|
||||
[[example]]
|
||||
name = "musicbrainz-api---search-release-group"
|
||||
path = "examples/musicbrainz_api/search_release_group.rs"
|
||||
required-features = ["bin", "musicbrainz-api"]
|
||||
required-features = ["bin", "musicbrainz"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
@ -1,14 +1,14 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use musichoard::{
|
||||
external::musicbrainz::api::{client::MusicBrainzApiClient, MusicBrainzApi},
|
||||
interface::musicbrainz::{IMusicBrainz, Mbid},
|
||||
external::musicbrainz::{http::MusicBrainzHttp, LookupArtistRequest, MusicBrainzClient},
|
||||
interface::musicbrainz::Mbid,
|
||||
};
|
||||
use structopt::StructOpt;
|
||||
use uuid::Uuid;
|
||||
|
||||
const USER_AGENT: &str = concat!(
|
||||
"MusicHoard---examples---musicbrainz-api---lookup-artist-release-groups/",
|
||||
"MusicHoard---examples---musicbrainz-api---lookup-artist/",
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
" ( musichoard@thenineworlds.net )"
|
||||
);
|
||||
@ -24,12 +24,15 @@ fn main() {
|
||||
|
||||
println!("USER_AGENT: {USER_AGENT}");
|
||||
|
||||
let client = MusicBrainzApiClient::new(USER_AGENT).expect("failed to create API client");
|
||||
let mut api = MusicBrainzApi::new(client);
|
||||
let http = MusicBrainzHttp::new(USER_AGENT).expect("failed to create API client");
|
||||
let mut client = MusicBrainzClient::new(http);
|
||||
|
||||
let mbid: Mbid = opt.mbid.into();
|
||||
let albums = api
|
||||
.lookup_artist_release_groups(&mbid)
|
||||
let mut request = LookupArtistRequest::new(&mbid);
|
||||
request.include_release_groups();
|
||||
|
||||
let albums = client
|
||||
.lookup_artist(request)
|
||||
.expect("failed to make API call");
|
||||
|
||||
println!("{albums:#?}");
|
@ -3,9 +3,9 @@
|
||||
use std::{num::ParseIntError, str::FromStr};
|
||||
|
||||
use musichoard::{
|
||||
collection::album::{Album, AlbumDate, AlbumId},
|
||||
external::musicbrainz::api::{client::MusicBrainzApiClient, MusicBrainzApi},
|
||||
interface::musicbrainz::{IMusicBrainz, Mbid},
|
||||
collection::album::AlbumDate,
|
||||
external::musicbrainz::{http::MusicBrainzHttp, MusicBrainzClient, SearchReleaseGroupRequest},
|
||||
interface::musicbrainz::Mbid,
|
||||
};
|
||||
use structopt::StructOpt;
|
||||
use uuid::Uuid;
|
||||
@ -18,16 +18,13 @@ const USER_AGENT: &str = concat!(
|
||||
|
||||
#[derive(StructOpt)]
|
||||
struct Opt {
|
||||
#[structopt(help = "Release group's artist MBID")]
|
||||
arid: Uuid,
|
||||
|
||||
#[structopt(subcommand)]
|
||||
command: OptCommand,
|
||||
}
|
||||
|
||||
#[derive(StructOpt)]
|
||||
enum OptCommand {
|
||||
#[structopt(about = "Search by title (and date)")]
|
||||
#[structopt(about = "Search by artist MBID, title(, and date)")]
|
||||
Title(OptTitle),
|
||||
#[structopt(about = "Search by release group MBID")]
|
||||
Rgid(OptRgid),
|
||||
@ -35,6 +32,9 @@ enum OptCommand {
|
||||
|
||||
#[derive(StructOpt)]
|
||||
struct OptTitle {
|
||||
#[structopt(help = "Release group's artist MBID")]
|
||||
arid: Uuid,
|
||||
|
||||
#[structopt(help = "Release group title")]
|
||||
title: String,
|
||||
|
||||
@ -80,30 +80,32 @@ fn main() {
|
||||
|
||||
println!("USER_AGENT: {USER_AGENT}");
|
||||
|
||||
let client = MusicBrainzApiClient::new(USER_AGENT).expect("failed to create API client");
|
||||
let mut api = MusicBrainzApi::new(client);
|
||||
let http = MusicBrainzHttp::new(USER_AGENT).expect("failed to create API client");
|
||||
let mut client = MusicBrainzClient::new(http);
|
||||
|
||||
let arid: Mbid = opt.arid.into();
|
||||
|
||||
let album = match opt.command {
|
||||
let mut request = SearchReleaseGroupRequest::default();
|
||||
let arid: Mbid;
|
||||
let date: AlbumDate;
|
||||
let title: String;
|
||||
let rgid: Mbid;
|
||||
match opt.command {
|
||||
OptCommand::Title(opt_title) => {
|
||||
let date: AlbumDate = opt_title.date.map(Into::into).unwrap_or_default();
|
||||
Album::new(AlbumId::new(opt_title.title), date, None, vec![])
|
||||
arid = opt_title.arid.into();
|
||||
date = opt_title.date.map(Into::into).unwrap_or_default();
|
||||
title = opt_title.title;
|
||||
request
|
||||
.arid(&arid)
|
||||
.first_release_date(&date)
|
||||
.release_group(&title);
|
||||
}
|
||||
OptCommand::Rgid(opt_rgid) => {
|
||||
let mut album = Album::new(
|
||||
AlbumId::new(String::default()),
|
||||
AlbumDate::default(),
|
||||
None,
|
||||
vec![],
|
||||
);
|
||||
album.set_musicbrainz_ref(opt_rgid.rgid.into());
|
||||
album
|
||||
rgid = opt_rgid.rgid.into();
|
||||
request.rgid(&rgid);
|
||||
}
|
||||
};
|
||||
|
||||
let matches = api
|
||||
.search_release_group(&arid, &album)
|
||||
let matches = client
|
||||
.search_release_group(request)
|
||||
.expect("failed to make API call");
|
||||
|
||||
println!("{matches:#?}");
|
||||
|
115
src/external/musicbrainz/mod.rs
vendored
115
src/external/musicbrainz/mod.rs
vendored
@ -78,7 +78,7 @@ impl<Http> MusicBrainzClient<Http> {
|
||||
}
|
||||
|
||||
impl<Http: IMusicBrainzHttp> MusicBrainzClient<Http> {
|
||||
fn display_album_date(date: &AlbumDate) -> Option<String> {
|
||||
fn format_album_date(date: &AlbumDate) -> Option<String> {
|
||||
match date.year {
|
||||
Some(year) => match date.month {
|
||||
Some(month) => match date.day {
|
||||
@ -91,6 +91,26 @@ impl<Http: IMusicBrainzHttp> MusicBrainzClient<Http> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lookup_artist(
|
||||
&mut self,
|
||||
request: LookupArtistRequest,
|
||||
) -> Result<LookupArtistResponse, Error> {
|
||||
let mut include: Vec<String> = vec![];
|
||||
|
||||
let mbid: String = request.mbid.uuid().as_hyphenated().to_string();
|
||||
|
||||
if request.release_groups {
|
||||
include.push(String::from("release-groups"));
|
||||
}
|
||||
|
||||
let include: String =
|
||||
form_urlencoded::byte_serialize(include.join("+").as_bytes()).collect();
|
||||
let url = format!("{MB_BASE_URL}/artist/{mbid}?inc={include}");
|
||||
|
||||
let response: DeserializeLookupArtistResponse = self.http.get(&url)?;
|
||||
Ok(response.into())
|
||||
}
|
||||
|
||||
pub fn search_release_group(
|
||||
&mut self,
|
||||
request: SearchReleaseGroupRequest,
|
||||
@ -102,7 +122,7 @@ impl<Http: IMusicBrainzHttp> MusicBrainzClient<Http> {
|
||||
}
|
||||
|
||||
if let Some(date) = request.first_release_date {
|
||||
if let Some(date_string) = Self::display_album_date(date) {
|
||||
if let Some(date_string) = Self::format_album_date(date) {
|
||||
query.push(format!("firstreleasedate:{date_string}"))
|
||||
}
|
||||
}
|
||||
@ -124,6 +144,75 @@ impl<Http: IMusicBrainzHttp> MusicBrainzClient<Http> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LookupArtistRequest<'a> {
|
||||
mbid: &'a Mbid,
|
||||
release_groups: bool,
|
||||
}
|
||||
|
||||
impl<'a> LookupArtistRequest<'a> {
|
||||
pub fn new(mbid: &'a Mbid) -> Self {
|
||||
LookupArtistRequest {
|
||||
mbid,
|
||||
release_groups: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn include_release_groups(&mut self) -> &mut Self {
|
||||
self.release_groups = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LookupArtistResponse {
|
||||
pub release_groups: Vec<LookupArtistResponseReleaseGroup>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all(deserialize = "kebab-case"))]
|
||||
struct DeserializeLookupArtistResponse {
|
||||
release_groups: Vec<DeserializeLookupArtistResponseReleaseGroup>,
|
||||
}
|
||||
|
||||
impl From<DeserializeLookupArtistResponse> for LookupArtistResponse {
|
||||
fn from(value: DeserializeLookupArtistResponse) -> Self {
|
||||
LookupArtistResponse {
|
||||
release_groups: value.release_groups.into_iter().map(Into::into).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LookupArtistResponseReleaseGroup {
|
||||
pub id: Mbid,
|
||||
pub title: String,
|
||||
pub first_release_date: AlbumDate,
|
||||
pub primary_type: AlbumPrimaryType,
|
||||
pub secondary_types: Vec<AlbumSecondaryType>,
|
||||
}
|
||||
|
||||
#[derive(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,
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SearchReleaseGroupRequest<'a> {
|
||||
arid: Option<&'a Mbid>,
|
||||
@ -133,6 +222,10 @@ pub struct SearchReleaseGroupRequest<'a> {
|
||||
}
|
||||
|
||||
impl<'a> SearchReleaseGroupRequest<'a> {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn arid(&mut self, arid: &'a Mbid) -> &mut Self {
|
||||
self.arid = Some(arid);
|
||||
self
|
||||
@ -154,14 +247,15 @@ impl<'a> SearchReleaseGroupRequest<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SearchReleaseGroupResponse {
|
||||
pub release_groups: Vec<SearchReleaseGroupResponseUnit>,
|
||||
pub release_groups: Vec<SearchReleaseGroupResponseReleaseGroup>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all(deserialize = "kebab-case"))]
|
||||
struct DeserializeSearchReleaseGroupResponse {
|
||||
release_groups: Vec<DeserializeSearchReleaseGroupResponseUnit>,
|
||||
release_groups: Vec<DeserializeSearchReleaseGroupResponseReleaseGroup>,
|
||||
}
|
||||
|
||||
impl From<DeserializeSearchReleaseGroupResponse> for SearchReleaseGroupResponse {
|
||||
@ -172,7 +266,8 @@ impl From<DeserializeSearchReleaseGroupResponse> for SearchReleaseGroupResponse
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SearchReleaseGroupResponseUnit {
|
||||
#[derive(Debug)]
|
||||
pub struct SearchReleaseGroupResponseReleaseGroup {
|
||||
pub score: u8,
|
||||
pub id: Mbid,
|
||||
pub title: String,
|
||||
@ -183,7 +278,7 @@ pub struct SearchReleaseGroupResponseUnit {
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all(deserialize = "kebab-case"))]
|
||||
struct DeserializeSearchReleaseGroupResponseUnit {
|
||||
struct DeserializeSearchReleaseGroupResponseReleaseGroup {
|
||||
score: u8,
|
||||
id: SerdeMbid,
|
||||
title: String,
|
||||
@ -192,9 +287,11 @@ struct DeserializeSearchReleaseGroupResponseUnit {
|
||||
secondary_types: Option<Vec<SerdeAlbumSecondaryType>>,
|
||||
}
|
||||
|
||||
impl From<DeserializeSearchReleaseGroupResponseUnit> for SearchReleaseGroupResponseUnit {
|
||||
fn from(value: DeserializeSearchReleaseGroupResponseUnit) -> Self {
|
||||
SearchReleaseGroupResponseUnit {
|
||||
impl From<DeserializeSearchReleaseGroupResponseReleaseGroup>
|
||||
for SearchReleaseGroupResponseReleaseGroup
|
||||
{
|
||||
fn from(value: DeserializeSearchReleaseGroupResponseReleaseGroup) -> Self {
|
||||
SearchReleaseGroupResponseReleaseGroup {
|
||||
score: value.score,
|
||||
id: value.id.into(),
|
||||
title: value.title,
|
||||
|
8
src/tui/lib/external/musicbrainz/mod.rs
vendored
8
src/tui/lib/external/musicbrainz/mod.rs
vendored
@ -4,7 +4,7 @@ use musichoard::{
|
||||
collection::album::{Album, AlbumDate},
|
||||
external::musicbrainz::{
|
||||
IMusicBrainzHttp, MusicBrainzClient, SearchReleaseGroupRequest,
|
||||
SearchReleaseGroupResponseUnit,
|
||||
SearchReleaseGroupResponseReleaseGroup,
|
||||
},
|
||||
interface::musicbrainz::Mbid,
|
||||
};
|
||||
@ -42,12 +42,14 @@ impl<Http: IMusicBrainzHttp> IMusicBrainz for MusicBrainz<Http> {
|
||||
Ok(mb_response
|
||||
.release_groups
|
||||
.into_iter()
|
||||
.map(from_search_release_group_response_unit)
|
||||
.map(from_search_release_group_response_release_group)
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
fn from_search_release_group_response_unit(entity: SearchReleaseGroupResponseUnit) -> Match<Album> {
|
||||
fn from_search_release_group_response_release_group(
|
||||
entity: SearchReleaseGroupResponseReleaseGroup,
|
||||
) -> Match<Album> {
|
||||
let mut album = Album::new(
|
||||
entity.title,
|
||||
entity.first_release_date,
|
||||
|
Loading…
Reference in New Issue
Block a user