Compare commits

..

1 Commits

Author SHA1 Message Date
Connor Johnstone
324c409db0 Added artist bio and art stuff 2026-03-19 14:53:22 -04:00
2 changed files with 79 additions and 2 deletions

View File

@@ -5,8 +5,8 @@ use tokio::time::{Duration, Instant};
use crate::cleaning::escape_lucene;
use crate::error::{TagError, TagResult};
use crate::provider::{
ArtistSearchResult, DiscographyEntry, MetadataProvider, RecordingDetails, RecordingMatch,
ReleaseGroupEntry, ReleaseMatch, ReleaseRef, ReleaseTrack,
ArtistInfo, ArtistSearchResult, ArtistUrl, DiscographyEntry, MetadataProvider,
RecordingDetails, RecordingMatch, ReleaseGroupEntry, ReleaseMatch, ReleaseRef, ReleaseTrack,
};
const BASE_URL: &str = "https://musicbrainz.org/ws/2";
@@ -61,6 +61,36 @@ impl MusicBrainzClient {
let resp: MbArtistLookup = self.get_json(&url).await?;
Ok((resp.name, resp.disambiguation.filter(|s| !s.is_empty())))
}
/// Look up detailed artist info by MBID, including URLs and metadata.
pub async fn get_artist_info(&self, mbid: &str) -> TagResult<ArtistInfo> {
let url = format!("{BASE_URL}/artist/{mbid}?inc=url-rels&fmt=json");
let resp: MbArtistFull = self.get_json(&url).await?;
let begin_year = resp.life_span
.and_then(|ls| ls.begin)
.and_then(|d| d.split('-').next().map(String::from));
let urls = resp.relations
.unwrap_or_default()
.into_iter()
.filter_map(|rel| {
rel.url.map(|u| ArtistUrl {
url: u.resource,
link_type: rel.relation_type,
})
})
.collect();
Ok(ArtistInfo {
name: resp.name,
disambiguation: resp.disambiguation.filter(|s| !s.is_empty()),
country: resp.country.filter(|s| !s.is_empty()),
artist_type: resp.artist_type,
begin_year,
urls,
})
}
}
impl MetadataProvider for MusicBrainzClient {
@@ -334,6 +364,35 @@ struct MbArtistLookup {
disambiguation: Option<String>,
}
#[derive(Deserialize)]
struct MbArtistFull {
name: String,
disambiguation: Option<String>,
country: Option<String>,
#[serde(rename = "type")]
artist_type: Option<String>,
#[serde(rename = "life-span")]
life_span: Option<MbLifeSpan>,
relations: Option<Vec<MbRelation>>,
}
#[derive(Deserialize)]
struct MbLifeSpan {
begin: Option<String>,
}
#[derive(Deserialize)]
struct MbRelation {
#[serde(rename = "type")]
relation_type: String,
url: Option<MbRelationUrl>,
}
#[derive(Deserialize)]
struct MbRelationUrl {
resource: String,
}
#[derive(Deserialize)]
struct MbRecordingSearchResponse {
recordings: Vec<MbRecordingResult>,

View File

@@ -50,6 +50,24 @@ pub struct RecordingDetails {
pub secondary_artists: Vec<(String, String)>,
}
/// Detailed artist info from a direct MBID lookup.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArtistInfo {
pub name: String,
pub disambiguation: Option<String>,
pub country: Option<String>,
pub artist_type: Option<String>,
pub begin_year: Option<String>,
pub urls: Vec<ArtistUrl>,
}
/// An external URL linked to an artist on MusicBrainz.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArtistUrl {
pub url: String,
pub link_type: String,
}
/// An artist match from a search query.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArtistSearchResult {