artifacts: rewrite the entire artifact querying layer to create modular 'tools' and 'datasource's
This commit is contained in:
+127
-41
@@ -1,50 +1,136 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use musicbrainz_rs::entity::recording::Recording;
|
||||
use musicbrainz_rs::{ApiEndpointError, entity::recording::Recording};
|
||||
use musicbrainz_rs::prelude::*;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::artifacts::{Album, Artifact, Artist, SourceID, Track};
|
||||
use crate::artifacts::tools::{DataSource, ToolDescription};
|
||||
use crate::artifacts::{Album, Artifact, ArtifactBuilder, Artist, Contents, Merge, SourceID, Track};
|
||||
|
||||
pub struct MBQuery;
|
||||
|
||||
impl DataSource for MBQuery {
|
||||
type Error = ApiEndpointError;
|
||||
type Args = MusicbrainzQueryArgs;
|
||||
|
||||
async fn synchronize(&mut self, artifact: &mut Artifact) -> Result<Vec<Artifact>, Self::Error> {
|
||||
let mut new_artifacts = vec![];
|
||||
if artifact.mbid.is_none() {
|
||||
return Ok(new_artifacts);
|
||||
}
|
||||
let artifact_id = artifact.mbid.clone().unwrap();
|
||||
log::debug!("Synchronizing {} with musicbrainz", artifact_id);
|
||||
match artifact.contents {
|
||||
Contents::Track(ref mut target_track) => {
|
||||
let mb_track = Recording::fetch()
|
||||
.id(&artifact_id.to_string())
|
||||
.with_releases().with_artists().with_annotations().execute_async().await;
|
||||
|
||||
let track = match mb_track {
|
||||
Ok(track) => track,
|
||||
Err(err) => {
|
||||
log::error!("Failed to grab musicbrainz data: {:?}", err);
|
||||
return Err(err);
|
||||
}
|
||||
};
|
||||
|
||||
artifact.sources.insert(SourceID::Musicbrainz);
|
||||
|
||||
for release in track.releases.unwrap_or_default() {
|
||||
log::debug!("Found new release: {:?}", release);
|
||||
let first_artist = release.artist_credit.unwrap_or_default().first().unwrap().clone();
|
||||
new_artifacts.push(ArtifactBuilder::new(SourceID::Musicbrainz)
|
||||
.contents(Album {
|
||||
title: release.title.clone(),
|
||||
artist: first_artist.name.clone(),
|
||||
about: release.annotation,
|
||||
..Default::default()
|
||||
})
|
||||
.mbid(Uuid::parse_str(&release.id).unwrap()).build());
|
||||
target_track.merge(Track {
|
||||
album: Some(release.title),
|
||||
title: track.title.clone(),
|
||||
artist: Some(first_artist.artist.name.clone()),
|
||||
..Default::default()
|
||||
});
|
||||
new_artifacts.push(ArtifactBuilder::new(SourceID::Musicbrainz)
|
||||
.contents(Artist {
|
||||
name: first_artist.name,
|
||||
bio: first_artist.artist.annotation,
|
||||
location: first_artist.artist.area.and_then(|area| { Some(area.name) }),
|
||||
..Default::default()
|
||||
})
|
||||
.mbid(Uuid::parse_str(&first_artist.artist.id).unwrap()).build());
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
|
||||
Ok(new_artifacts)
|
||||
}
|
||||
|
||||
async fn query(&mut self, args: &Self::Args) -> Result<Vec<Artifact>, Self::Error> {
|
||||
let mut ret = vec![];
|
||||
|
||||
for mbid in &args.mb_ids {
|
||||
log::debug!("Fetching recording id {}", mbid);
|
||||
let track = Recording::fetch()
|
||||
.id(&mbid)
|
||||
.with_releases().with_artists().with_annotations().execute_async().await;
|
||||
|
||||
let track = match track {
|
||||
Ok(track) => track,
|
||||
Err(err) => {
|
||||
log::error!("Failed to grab musicbrainz data: {:?}", err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
for release in track.releases.unwrap_or_default() {
|
||||
log::debug!("Found new release: {:?}", release);
|
||||
let first_artist = release.artist_credit.unwrap_or_default().first().unwrap().clone();
|
||||
ret.push(ArtifactBuilder::new(SourceID::Musicbrainz)
|
||||
.contents(Album {
|
||||
title: release.title.clone(),
|
||||
artist: first_artist.name.clone(),
|
||||
about: release.annotation,
|
||||
..Default::default()
|
||||
})
|
||||
.mbid(Uuid::parse_str(&release.id).unwrap()).build());
|
||||
ret.push(ArtifactBuilder::new(SourceID::Musicbrainz)
|
||||
.contents(Track {
|
||||
album: Some(release.title),
|
||||
title: track.title.clone(),
|
||||
artist: Some(first_artist.artist.name.clone()),
|
||||
..Default::default()
|
||||
})
|
||||
.mbid(Uuid::parse_str(&mbid).unwrap()).build());
|
||||
ret.push(ArtifactBuilder::new(SourceID::Musicbrainz)
|
||||
.contents(Artist {
|
||||
name: first_artist.name,
|
||||
bio: first_artist.artist.annotation,
|
||||
location: first_artist.artist.area.and_then(|area| { Some(area.name) }),
|
||||
..Default::default()
|
||||
})
|
||||
.mbid(Uuid::parse_str(&first_artist.artist.id).unwrap()).build());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToolDescription for MBQuery {
|
||||
fn description(&self) -> &str {
|
||||
"Fetches artifacts from Musicbrainz"
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"query_musicbrainz"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, JsonSchema)]
|
||||
pub struct MusicbrainzQueryArgs {
|
||||
pub mb_ids: Vec<String>
|
||||
}
|
||||
|
||||
pub async fn search_artifacts(query: MusicbrainzQueryArgs) -> Result<Vec<Artifact>, musicbrainz_rs::ApiEndpointError> {
|
||||
let mut ret = vec![];
|
||||
for mbid in query.mb_ids {
|
||||
let track = Recording::fetch()
|
||||
.id(&mbid)
|
||||
.with_releases().with_artists().with_annotations().execute_async().await?;
|
||||
|
||||
for release in track.releases.unwrap_or_default() {
|
||||
log::debug!("Found new release: {:?}", release);
|
||||
let first_artist = release.artist_credit.unwrap_or_default().first().unwrap().clone();
|
||||
ret.push(Artifact::Album(Album {
|
||||
title: release.title.clone(),
|
||||
artist: first_artist.name.clone(),
|
||||
about: release.annotation,
|
||||
sources: HashSet::from([SourceID::Musicbrainz(release.id.clone())]),
|
||||
..Default::default()
|
||||
}));
|
||||
ret.push(Artifact::Track(Track {
|
||||
album: Some(release.title),
|
||||
title: track.title.clone(),
|
||||
artist: Some(first_artist.artist.name.clone()),
|
||||
sources: HashSet::from([SourceID::Musicbrainz(release.id.clone())]),
|
||||
..Default::default()
|
||||
}));
|
||||
ret.push(Artifact::Artist(Artist {
|
||||
name: first_artist.name,
|
||||
bio: first_artist.artist.annotation,
|
||||
location: first_artist.artist.area.and_then(|area| { Some(area.name) }),
|
||||
sources: HashSet::from([SourceID::Musicbrainz(release.id)]),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
Reference in New Issue
Block a user