//! Hardened cover-resolution report across a whole discography. //! cargo run -p metadata --example cover_probe -- input.json output.json //! //! input.json: { "albums": [ { "artist": "...", "title": "...", "cover": "" }, ... ] } //! output.json: [ CoverReport, ... ] (reference + candidates + chosen, with dHash distances) #[derive(serde::Deserialize)] struct Album { artist: String, title: String, cover: Option, } #[derive(serde::Deserialize)] struct Input { albums: Vec, } #[tokio::main] async fn main() { let in_path = std::env::args().nth(1).expect("input.json"); let out_path = std::env::args().nth(2).expect("output.json"); let raw = std::fs::read_to_string(&in_path).expect("read input"); let input: Input = serde_json::from_str(raw.trim_start_matches('\u{feff}')).expect("parse input"); let client = metadata::MetadataClient::new(); let mut reports = Vec::new(); let total = input.albums.len(); for (i, a) in input.albums.iter().enumerate() { let reference = a.cover.clone().unwrap_or_default(); let report = client.cover_report(&a.artist, &a.title, &reference).await; eprintln!( "[{}/{}] {} :: chosen={:?} ({} candidates)", i + 1, total, a.title, report.chosen_source, report.candidates.len() ); reports.push(report); } std::fs::write(&out_path, serde_json::to_string(&reports).unwrap()).expect("write output"); eprintln!("wrote {out_path}"); }