use std::{error::Error, sync::Arc}; use anyhow::Context; use musicbrainz::{Area, Country, Language, Script}; use reqwest::{Method, Request, Response}; use serde::{Deserialize, Serialize}; use tower::{retry::Policy, Service, ServiceExt}; #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "kebab-case")] struct Release { title: String, release_events: Option>, status: Option, cover_art_archive: CoverArtArchive, packaging: Option, asin: Option, quality: ReleaseQuality, barcode: Option, country: Option, disambiguation: String, packaging_id: Option, id: String, status_id: Option, text_representation: ReleaseTextRepresentation, } impl Release { #[tracing::instrument(skip(svc))] pub async fn lookup(svc: &mut S, id: &str) -> anyhow::Result where S: Service, S::Error: 'static + Send + Sync + Error, { let lookup_url = url::Url::parse("https://musicbrainz.org/ws/2/release/")?.join(id)?; tracing::debug!(%lookup_url); let json = svc .ready() .await .context("wait for client to be ready")? .call(Request::new(Method::GET, lookup_url)) .await .context("GET release")? .text() .await .context("parse release as UTF-8")?; let jd = &mut serde_json::Deserializer::from_str(&json); let release: Release = match serde_path_to_error::deserialize(jd) { Ok(r) => r, Err(e) => { tracing::error!(?e); tracing::error!("{}", e.path().to_string()); tracing::error!("{}", serde_json::to_string_pretty(&json).unwrap()); panic!("Failed to deserialize release"); // FIXME } }; Ok(release) } } #[derive(Debug, Deserialize, Serialize)] struct CoverArtArchive { front: bool, artwork: bool, count: u64, darkened: bool, back: bool, } #[derive(Debug, Deserialize, Serialize)] struct ReleaseTextRepresentation { language: Option, script: Option