mod db; mod filesystem; mod lastfm; mod metadata; use std::env; use std::path::Path; fn main() { let args: Vec = env::args().collect(); let verbose = args.iter().any(|a| a == "-v"); let rest: Vec<&String> = args.iter().skip(1).filter(|a| *a != "-v").collect(); if rest.len() != 2 || rest[0] != "index" { eprintln!("Usage: {} index [-v] ", args[0]); std::process::exit(1); } dotenvy::dotenv().ok(); let api_key = env::var("LASTFM_API_KEY").unwrap_or_default(); if api_key.is_empty() { eprintln!("Error: LASTFM_API_KEY not set"); std::process::exit(1); } let conn = db::open("playlists.db").expect("failed to open database"); let lastfm = lastfm::LastfmClient::new(api_key); let dir = Path::new(rest[1].as_str()); for path in filesystem::walk_music_files(dir) { let artist_mbid = match metadata::read_artist_mbid(&path) { Ok(Some(mbid)) => mbid, Ok(None) => continue, Err(e) => { eprintln!("{}: could not read artist MBID: {e}", path.display()); continue; } }; let already_indexed = match db::artist_exists(&conn, &artist_mbid) { Ok(exists) => exists, Err(e) => { eprintln!("DB error checking artist {artist_mbid}: {e}"); continue; } }; let artist_name = metadata::read_artist_name(&path).ok().flatten(); let display_name = artist_name.as_deref().unwrap_or(&artist_mbid); if already_indexed { if verbose { println!("Skipping {display_name} (already indexed)"); } continue; } if verbose { println!("Indexing {display_name}..."); } match lastfm.get_similar_artists(&artist_mbid) { Ok(similar) => { if let Err(e) = db::insert_artist_with_similar( &conn, &artist_mbid, artist_name.as_deref(), &similar, ) { eprintln!("DB error inserting artist {artist_mbid}: {e}"); } } Err(e) => eprintln!("Last.fm error for {artist_mbid}: {e}"), } } }