diff options
author | metamuffin <metamuffin@disroot.org> | 2025-04-25 21:34:59 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-04-25 21:34:59 +0200 |
commit | 2c6f753797b8e223c5982c4790f1be8b08fe63d6 (patch) | |
tree | 32b77bae2fd83927bc37dbbf3fa666e10beb4703 /import | |
parent | b84ac0b04c45aa353ba1a302f96fa5f0f5895d59 (diff) | |
download | jellything-2c6f753797b8e223c5982c4790f1be8b08fe63d6.tar jellything-2c6f753797b8e223c5982c4790f1be8b08fe63d6.tar.bz2 jellything-2c6f753797b8e223c5982c4790f1be8b08fe63d6.tar.zst |
images from wikidata works
Diffstat (limited to 'import')
-rw-r--r-- | import/src/lib.rs | 72 | ||||
-rw-r--r-- | import/src/musicbrainz.rs | 107 |
2 files changed, 155 insertions, 24 deletions
diff --git a/import/src/lib.rs b/import/src/lib.rs index 0f89ab0..fa74b9c 100644 --- a/import/src/lib.rs +++ b/import/src/lib.rs @@ -700,26 +700,60 @@ fn apply_musicbrainz_recording( for rel in &rec.relations { use musicbrainz::reltypes::*; - match rel.type_id.as_str() { - INSTRUMENT => { - node.people - .entry(PeopleGroup::Instrument) - .or_default() - .push(Appearance { - jobs: rel.attributes.clone(), - characters: vec![], - person: Person { - name: rel - .artist - .as_ref() - .map(|a| a.name.clone()) - .unwrap_or_default(), - headshot: None, - ids: ObjectIds::default(), - }, - }); + let a = match rel.type_id.as_str() { + INSTRUMENT => Some(("", PeopleGroup::Instrument)), + VOCAL => Some(("", PeopleGroup::Vocal)), + PRODUCER => Some(("", PeopleGroup::Producer)), + MIX => Some(("mix ", PeopleGroup::Engineer)), + PHONOGRAPHIC_COPYRIGHT => Some(("phonographic copyright ", PeopleGroup::Engineer)), + PROGRAMMING => Some(("programming ", PeopleGroup::Engineer)), + _ => None, + }; + + if let Some((note, group)) = a { + let artist = rel.artist.as_ref().unwrap(); + + let artist = + rthandle.block_on(apis.musicbrainz.lookup_artist(artist.id.clone()))?; + + let mut image = None; + + for rel in &artist.relations { + match rel.type_id.as_str() { + WIKIDATA => { + let url = rel.url.as_ref().unwrap().resource.clone(); + if let Some(id) = url.strip_prefix("https://www.wikidata.org/wiki/") { + if let Some(filename) = rthandle + .block_on(apis.wikidata.query_image_path(id.to_owned()))? + { + let path = rthandle.block_on( + apis.wikimedia_commons.image_by_filename(filename), + )?; + image = Some(AssetInner::Cache(path).ser()); + } + } + } + _ => (), + } } - _ => (), + let mut jobs = vec![]; + if !note.is_empty() { + jobs.push(note.to_string()); + } + jobs.extend(rel.attributes.clone()); + node.people.entry(group).or_default().push(Appearance { + jobs, + characters: vec![], + person: Person { + name: if rel.target_credit.is_empty() { + artist.name.clone() + } else { + rel.target_credit.clone() + }, + headshot: image, + ids: ObjectIds::default(), + }, + }); } } diff --git a/import/src/musicbrainz.rs b/import/src/musicbrainz.rs index 0fe839b..704807b 100644 --- a/import/src/musicbrainz.rs +++ b/import/src/musicbrainz.rs @@ -55,6 +55,24 @@ pub struct MbRecordingRel { #[derive(Debug, Deserialize, Encode, Decode)] #[serde(rename_all = "kebab-case")] +pub struct MbArtistRel { + pub id: String, + pub isnis: Vec<String>, + pub ipis: Vec<String>, + pub name: String, + pub disambiguation: String, + pub country: Option<String>, + pub sort_name: String, + pub gender_id: Option<String>, + pub area: Option<MbArea>, + pub begin_area: Option<MbArea>, + pub end_area: Option<MbArea>, + pub life_span: MbTimespan, + pub relations: Vec<MbRelation>, +} + +#[derive(Debug, Deserialize, Encode, Decode)] +#[serde(rename_all = "kebab-case")] pub struct MbArtistCredit { pub name: String, pub artist: MbArtist, @@ -81,6 +99,7 @@ pub struct MbRelation { pub url: Option<MbUrl>, pub recording: Option<MbRecording>, pub series: Option<MbSeries>, + pub event: Option<MbEvent>, } #[derive(Debug, Deserialize, Encode, Decode)] @@ -98,10 +117,12 @@ pub struct MbSeries { pub struct MbRecording { pub id: String, pub title: String, + #[serde(default)] pub isrcs: Vec<String>, pub video: bool, pub disambiguation: String, - pub length: u32, + pub length: Option<u32>, + #[serde(default)] pub artist_credit: Vec<MbArtistCredit>, } @@ -109,8 +130,8 @@ pub struct MbRecording { #[serde(rename_all = "kebab-case")] pub struct MbWork { pub id: String, - pub r#type: String, - pub type_id: String, + pub r#type: Option<String>, + pub type_id: Option<String>, pub languages: Vec<String>, pub iswcs: Vec<String>, pub language: Option<String>, @@ -121,6 +142,19 @@ pub struct MbWork { #[derive(Debug, Deserialize, Encode, Decode)] #[serde(rename_all = "kebab-case")] +pub struct MbEvent { + pub id: String, + pub r#type: String, + pub type_id: String, + pub name: String, + pub time: String, + pub cancelled: bool, + pub setlist: String, + pub life_span: MbTimespan, +} + +#[derive(Debug, Deserialize, Encode, Decode)] +#[serde(rename_all = "kebab-case")] pub struct MbArtist { pub id: String, pub r#type: Option<String>, @@ -133,9 +167,28 @@ pub struct MbArtist { #[derive(Debug, Deserialize, Encode, Decode)] #[serde(rename_all = "kebab-case")] +pub struct MbTimespan { + pub begin: Option<String>, + pub end: Option<String>, + pub ended: bool, +} + +#[derive(Debug, Deserialize, Encode, Decode)] +#[serde(rename_all = "kebab-case")] +pub struct MbArea { + pub name: String, + pub sort_name: String, + #[serde(default)] + pub iso_3166_1_codes: Vec<String>, + pub id: String, + pub disambiguation: String, +} + +#[derive(Debug, Deserialize, Encode, Decode)] +#[serde(rename_all = "kebab-case")] pub struct MbUrl { - id: String, - resource: String, + pub id: String, + pub resource: String, } impl MusicBrainz { @@ -206,4 +259,48 @@ impl MusicBrainz { }) .await } + + pub async fn lookup_artist(&self, id: String) -> Result<Arc<MbArtistRel>> { + async_cache_memory("api-musicbrainz-artist", id.clone(), || async move { + let _permit = self.rate_limit.clone().acquire_owned().await?; + let permit_drop_ts = Instant::now() + Duration::from_secs(10); + info!("artist lookup: {id}"); + + let inc = [ + "area-rels", + "artist-rels", + "event-rels", + "genre-rels", + "instrument-rels", + "label-rels", + "place-rels", + "recording-rels", + "release-rels", + "release-group-rels", + "series-rels", + "url-rels", + "work-rels", + ] + .join("+"); + + let resp = self + .client + .get(format!( + "https://musicbrainz.org/ws/2/artist/{id}?inc={inc}" + )) + .send() + .await? + .error_for_status()? + .json::<MbArtistRel>() + .await?; + + tokio::task::spawn(async move { + sleep_until(permit_drop_ts).await; + drop(_permit); + }); + + Ok(resp) + }) + .await + } } |