forked from Keelrleek/SoulStream
The previous .git directory was found gutted (only info/ remained), so history is unrecoverable locally. This commit restores version control with the tree exactly as it stands: the working app, the preview-tracks launcher on the artist hero, the scrollable-track-previews design bundle (docs + approved mockups), and the Phase 0 validation artifacts.
125 lines
3.4 KiB
Rust
125 lines
3.4 KiB
Rust
//! Broad discography audit over the PRODUCTION artist pipeline.
|
|
//!
|
|
//! Runs `catalog_artist` (Deezer + Apple supplement, dedup, edition folding)
|
|
//! plus the deferred `catalog_artist_identity` MusicBrainz pass for each
|
|
//! requested artist, and prints one JSON object per artist (JSONL) with the
|
|
//! final album rows and MB type hints — exactly the data the artist page
|
|
//! files into tabs. An external analyzer replicates the frontend's category
|
|
//! rules over this dump to flag duplicates and misfiled releases.
|
|
//!
|
|
//! Usage:
|
|
//! cargo run -p metadata --example discography_audit -- "Artist" ...
|
|
//! cargo run -p metadata --example discography_audit -- --broad
|
|
|
|
use metadata::MetadataClient;
|
|
use std::sync::Arc;
|
|
|
|
const BROAD_ARTISTS: [&str; 44] = [
|
|
"Weezer",
|
|
"Radiohead",
|
|
"Queen",
|
|
"The Beatles",
|
|
"Taylor Swift",
|
|
"Beyoncé",
|
|
"Coldplay",
|
|
"Nirvana",
|
|
"Fleetwood Mac",
|
|
"Elton John",
|
|
"David Bowie",
|
|
"Pink Floyd",
|
|
"Led Zeppelin",
|
|
"Bob Dylan",
|
|
"Miles Davis",
|
|
"Daft Punk",
|
|
"deadmau5",
|
|
"Fatboy Slim",
|
|
"Bonobo",
|
|
"Four Tet",
|
|
"Calvin Harris",
|
|
"Aphex Twin",
|
|
"The Chemical Brothers",
|
|
"Crazy P",
|
|
"Moby",
|
|
"Björk",
|
|
"Depeche Mode",
|
|
"Kanye West",
|
|
"Kendrick Lamar",
|
|
"Eminem",
|
|
"Drake",
|
|
"Travis Scott",
|
|
"Hans Zimmer",
|
|
"John Williams",
|
|
"Danny Elfman",
|
|
"Ludwig Göransson",
|
|
"Nine Inch Nails",
|
|
"MGMT",
|
|
"Panda Bear",
|
|
"Tame Impala",
|
|
"Mac DeMarco",
|
|
"Gorillaz",
|
|
"Metallica",
|
|
"ABBA",
|
|
];
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
let mut requested: Vec<String> = std::env::args().skip(1).collect();
|
|
if requested.iter().any(|a| a == "--broad") {
|
|
requested = BROAD_ARTISTS.iter().map(|s| s.to_string()).collect();
|
|
}
|
|
if requested.is_empty() {
|
|
eprintln!("pass artist names or --broad");
|
|
std::process::exit(2);
|
|
}
|
|
|
|
let client = Arc::new(MetadataClient::new());
|
|
for name in requested {
|
|
let search = client.catalog_search(&name).await;
|
|
let want = normalize(&name);
|
|
let artist = search
|
|
.artists
|
|
.iter()
|
|
.filter(|a| normalize(&a.name) == want)
|
|
.max_by_key(|a| a.fans)
|
|
.or_else(|| search.artists.first());
|
|
let Some(artist) = artist else {
|
|
println!(
|
|
"{}",
|
|
serde_json::json!({ "requested": name, "error": "not_found" })
|
|
);
|
|
continue;
|
|
};
|
|
let id = artist.id;
|
|
let display = artist.name.clone();
|
|
let fans = artist.fans;
|
|
let page = client.catalog_artist(id).await;
|
|
let Some(page) = page else {
|
|
println!(
|
|
"{}",
|
|
serde_json::json!({ "requested": name, "artist_id": id, "error": "page_failed" })
|
|
);
|
|
continue;
|
|
};
|
|
let identity = client.catalog_artist_identity(id, &display).await;
|
|
println!(
|
|
"{}",
|
|
serde_json::json!({
|
|
"requested": name,
|
|
"artist_id": id,
|
|
"artist": display,
|
|
"fans": fans,
|
|
"albums": page.albums,
|
|
"type_hints": identity.type_hints,
|
|
"identity_albums": identity.albums,
|
|
})
|
|
);
|
|
}
|
|
}
|
|
|
|
fn normalize(s: &str) -> String {
|
|
s.to_lowercase()
|
|
.chars()
|
|
.filter(|c| c.is_alphanumeric())
|
|
.collect()
|
|
}
|