musicbrainz: dedupe some code
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
use log::Record;
|
||||
use musicbrainz_rs::entity::artist_credit::ArtistCredit;
|
||||
use musicbrainz_rs::entity::release::Release;
|
||||
use musicbrainz_rs::{ApiEndpointError, entity::recording::Recording};
|
||||
use musicbrainz_rs::prelude::*;
|
||||
use schemars::JsonSchema;
|
||||
@@ -7,16 +10,94 @@ use uuid::Uuid;
|
||||
use crate::artifacts::tools::{DataSource, ToolDescription};
|
||||
use crate::artifacts::{Album, Artifact, ArtifactBuilder, Artist, Contents, Merge, SourceID, Track};
|
||||
|
||||
impl From<Recording> for Track {
|
||||
fn from(value: Recording) -> Self {
|
||||
let artist = if let Some(artist) = value.artist_credit.unwrap_or_default().first() {
|
||||
Some(artist.name.clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let album = if let Some(album) = value.releases.unwrap_or_default().first() {
|
||||
Some(album.title.clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Self {
|
||||
title: value.title,
|
||||
artist,
|
||||
album,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Release> for Album {
|
||||
fn from(value: Release) -> Self {
|
||||
let artist = if let Some(artist) = value.artist_credit.unwrap_or_default().first() {
|
||||
Some(artist.name.clone())
|
||||
} else {
|
||||
None
|
||||
}.unwrap_or_default();
|
||||
|
||||
Self {
|
||||
about: value.annotation,
|
||||
title: value.title,
|
||||
artist,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ArtistCredit> for Artist {
|
||||
fn from(value: ArtistCredit) -> Self {
|
||||
Self {
|
||||
bio: value.artist.annotation,
|
||||
location: value.artist.country,
|
||||
name: value.name,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MBQuery;
|
||||
|
||||
impl MBQuery {
|
||||
fn extract_recording_data(track: Recording) -> (Artifact, Vec<Artifact>) {
|
||||
let mut ret = vec![];
|
||||
|
||||
let ret_track = ArtifactBuilder::new(SourceID::Musicbrainz)
|
||||
.contents(Track::from(track.clone()))
|
||||
.mbid(Uuid::parse_str(&track.id).unwrap())
|
||||
.build();
|
||||
|
||||
for release in track.releases.unwrap_or_default() {
|
||||
log::debug!("Found new release: {:?}", release);
|
||||
ret.push(ArtifactBuilder::new(SourceID::Musicbrainz)
|
||||
.mbid(Uuid::parse_str(&release.id).unwrap())
|
||||
.contents(Album::from(release))
|
||||
.build());
|
||||
}
|
||||
for artist in track.artist_credit.unwrap_or_default() {
|
||||
ret.push(ArtifactBuilder::new(SourceID::Musicbrainz)
|
||||
.mbid(Uuid::parse_str(&artist.artist.id).unwrap())
|
||||
.contents(Artist::from(artist))
|
||||
.build());
|
||||
}
|
||||
|
||||
(ret_track, ret)
|
||||
}
|
||||
}
|
||||
|
||||
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![];
|
||||
let mut ret = vec![];
|
||||
if artifact.mbid.is_none() {
|
||||
return Ok(new_artifacts);
|
||||
return Ok(ret);
|
||||
}
|
||||
let artifact_id = artifact.mbid.clone().unwrap();
|
||||
log::debug!("Synchronizing {} with musicbrainz", artifact_id);
|
||||
@@ -34,39 +115,21 @@ impl DataSource for MBQuery {
|
||||
}
|
||||
};
|
||||
|
||||
let (track, mut new_artifacts) = Self::extract_recording_data(track);
|
||||
|
||||
ret.push(track.clone());
|
||||
ret.append(&mut new_artifacts);
|
||||
|
||||
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());
|
||||
if let Contents::Track(track) = track.contents {
|
||||
target_track.merge(track);
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
|
||||
Ok(new_artifacts)
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
async fn query(&mut self, args: &Self::Args) -> Result<Vec<Artifact>, Self::Error> {
|
||||
@@ -86,34 +149,10 @@ impl DataSource for MBQuery {
|
||||
}
|
||||
};
|
||||
|
||||
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());
|
||||
}
|
||||
let (track, mut new_artifacts) = Self::extract_recording_data(track);
|
||||
|
||||
ret.push(track);
|
||||
ret.append(&mut new_artifacts);
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
|
||||
@@ -148,7 +148,6 @@ impl Session {
|
||||
let tools = vec![
|
||||
Tool { name: "log_stage_event".into(), description: "Inserts an event into the current scene script".into(), schema: schema_for!(StageEventArgs)}.into(),
|
||||
// TODO: There should only be two queries, one against the ship's onboard archive, and another against the relay network, or whatever we call it. Both should be structured with the same arguments schema
|
||||
// TODO: A relay search should try to grab first from beets, then musicbrainz, then from bandcamp.
|
||||
// TODO: A query should specify what parts of metadata are sufficient for the result, so we don't always have to hit all the layers of data. beets can of course, ignore this.
|
||||
// TODO: A query should be hierarchical somehow? eg, "I already know about artist X, but I want to know everything about track Y from album Z" or "I don't know anything about artist X/album Y, please give me an overview"
|
||||
Tool::from_datasource(&MBQuery).into(),
|
||||
|
||||
Reference in New Issue
Block a user