Hardened the lookups
This commit is contained in:
62
src/main.rs
62
src/main.rs
@@ -82,7 +82,7 @@ fn cmd_index(args: &[String]) {
|
||||
println!("Indexing {display_name}...");
|
||||
}
|
||||
|
||||
match lastfm.get_similar_artists(&artist_mbid) {
|
||||
match lastfm.get_similar_artists(&artist_mbid, artist_name.as_deref()) {
|
||||
Ok(similar) => {
|
||||
if let Err(e) = db::insert_artist_with_similar(
|
||||
&conn,
|
||||
@@ -99,12 +99,25 @@ fn cmd_index(args: &[String]) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
match lastfm.get_top_tracks(&artist_mbid, artist_name.as_deref()) {
|
||||
Ok(top_tracks) => {
|
||||
if let Err(e) = db::insert_top_tracks(&conn, &artist_mbid, &top_tracks) {
|
||||
eprintln!("DB error inserting top tracks for {display_name}: {e}");
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Last.fm top tracks error for {display_name}: {e}");
|
||||
}
|
||||
}
|
||||
} else if verbose {
|
||||
println!("Skipping {display_name} (already indexed)");
|
||||
}
|
||||
|
||||
let track_title = metadata::read_track_title(&path).ok().flatten();
|
||||
|
||||
let path_str = path.to_string_lossy();
|
||||
if let Err(e) = db::insert_track(&conn, &path_str, &artist_mbid, recording_mbid.as_deref()) {
|
||||
if let Err(e) = db::insert_track(&conn, &path_str, &artist_mbid, recording_mbid.as_deref(), track_title.as_deref()) {
|
||||
eprintln!("DB error inserting track {}: {e}", path.display());
|
||||
}
|
||||
}
|
||||
@@ -153,14 +166,7 @@ fn cmd_build(args: &[String]) {
|
||||
}
|
||||
|
||||
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 (artist_mbid, seed_name) = if let Some(file_arg) = rest.first() {
|
||||
let path = Path::new(file_arg.as_str());
|
||||
@@ -198,12 +204,11 @@ fn cmd_build(args: &[String]) {
|
||||
}
|
||||
};
|
||||
|
||||
build_playlist(&conn, &lastfm, &artist_mbid, &seed_name, count, verbose, mpd, shuffle, random);
|
||||
build_playlist(&conn, &artist_mbid, &seed_name, count, verbose, mpd, shuffle, random);
|
||||
}
|
||||
|
||||
fn build_playlist(
|
||||
conn: &rusqlite::Connection,
|
||||
lastfm: &lastfm::LastfmClient,
|
||||
artist_mbid: &str,
|
||||
seed_name: &str,
|
||||
count: usize,
|
||||
@@ -242,36 +247,35 @@ fn build_playlist(
|
||||
continue;
|
||||
}
|
||||
|
||||
// Fetch top tracks from Last.fm for popularity data
|
||||
let top_tracks = match lastfm.get_top_tracks(mbid) {
|
||||
// Look up pre-indexed top tracks from DB
|
||||
let top_tracks_by_name = match db::get_top_tracks_by_name(conn, mbid) {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
eprintln!("Last.fm error for {name}: {e}");
|
||||
eprintln!("DB error fetching top tracks for {name}: {e}");
|
||||
Vec::new()
|
||||
}
|
||||
};
|
||||
|
||||
// Build a map from recording_mbid -> playcount
|
||||
let mut playcount_by_mbid: std::collections::HashMap<String, u64> =
|
||||
std::collections::HashMap::new();
|
||||
for tt in &top_tracks {
|
||||
if let Some(ref mbid) = tt.mbid {
|
||||
playcount_by_mbid.insert(mbid.clone(), tt.playcount);
|
||||
}
|
||||
}
|
||||
let playcount_by_name: std::collections::HashMap<String, u64> =
|
||||
top_tracks_by_name.into_iter().collect();
|
||||
|
||||
// Find max playcount for this artist to normalize
|
||||
let max_playcount = top_tracks
|
||||
.iter()
|
||||
.map(|t| t.playcount)
|
||||
let max_playcount = playcount_by_name
|
||||
.values()
|
||||
.copied()
|
||||
.max()
|
||||
.unwrap_or(1)
|
||||
.max(1);
|
||||
|
||||
for (track_path, recording_mbid) in &local_tracks {
|
||||
let playcount = recording_mbid
|
||||
for (track_path, _recording_mbid, title) in &local_tracks {
|
||||
// Match by title (lowercased), fall back to recording MBID
|
||||
let playcount = title
|
||||
.as_ref()
|
||||
.and_then(|rec_mbid| playcount_by_mbid.get(rec_mbid).copied());
|
||||
.and_then(|t| playcount_by_name.get(&t.to_lowercase()).copied())
|
||||
.or_else(|| {
|
||||
_recording_mbid
|
||||
.as_ref()
|
||||
.and_then(|id| playcount_by_name.get(id).copied())
|
||||
});
|
||||
|
||||
// Skip tracks not in the artist's top 1000
|
||||
let Some(playcount) = playcount else { continue };
|
||||
|
||||
Reference in New Issue
Block a user