top songs flow
This commit is contained in:
+84
-1
@@ -2,7 +2,7 @@ use actix_session::Session;
|
||||
use actix_web::{HttpResponse, web};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use shanty_data::{ArtistBioFetcher, ArtistImageFetcher, MetadataFetcher};
|
||||
use shanty_data::{ArtistBioFetcher, ArtistImageFetcher, MetadataFetcher, SimilarArtistFetcher};
|
||||
use shanty_db::entities::wanted_item::WantedStatus;
|
||||
use shanty_db::queries;
|
||||
use shanty_search::SearchProvider;
|
||||
@@ -383,6 +383,87 @@ pub async fn enrich_artist(
|
||||
.await;
|
||||
tracing::debug!(mbid = %mbid, has_photo = artist_photo.is_some(), has_bio = artist_bio.is_some(), has_banner = artist_banner.is_some(), "artist enrichment data");
|
||||
|
||||
// Fetch top songs from Last.fm (cached 7 days)
|
||||
let top_songs: Vec<serde_json::Value> = if let Some(ref key) = lastfm_api_key {
|
||||
let cache_key = format!("lastfm_top_tracks:{mbid}");
|
||||
let cached: Option<Vec<shanty_data::PopularTrack>> =
|
||||
if let Ok(Some(json)) = queries::cache::get(state.db.conn(), &cache_key).await {
|
||||
serde_json::from_str(&json).ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let tracks = if let Some(cached) = cached {
|
||||
cached
|
||||
} else {
|
||||
match shanty_data::LastFmSimilarFetcher::new(key.clone()) {
|
||||
Ok(fetcher) => {
|
||||
match fetcher.get_top_tracks(&artist.name, Some(&mbid)).await {
|
||||
Ok(tracks) => {
|
||||
// Cache for 7 days
|
||||
if let Ok(json) = serde_json::to_string(&tracks) {
|
||||
let _ = queries::cache::set(
|
||||
state.db.conn(),
|
||||
&cache_key,
|
||||
"lastfm",
|
||||
&json,
|
||||
7 * 86400,
|
||||
)
|
||||
.await;
|
||||
// Also persist on artist record
|
||||
if let Some(local_id) = id {
|
||||
let _ = queries::artists::update_top_songs(
|
||||
state.db.conn(),
|
||||
local_id,
|
||||
&json,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
tracks
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!(error = %e, "failed to fetch Last.fm top tracks");
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!(error = %e, "failed to create Last.fm fetcher");
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Cross-reference with wanted items to add status
|
||||
let all_wanted = queries::wanted::list(state.db.conn(), None, None).await?;
|
||||
tracks
|
||||
.iter()
|
||||
.map(|t| {
|
||||
let status = t.mbid.as_deref().and_then(|track_mbid| {
|
||||
all_wanted
|
||||
.iter()
|
||||
.find(|w| w.musicbrainz_id.as_deref() == Some(track_mbid))
|
||||
.map(|w| match w.status {
|
||||
WantedStatus::Owned => "owned",
|
||||
WantedStatus::Downloaded => "downloaded",
|
||||
WantedStatus::Wanted => "wanted",
|
||||
WantedStatus::Available => "available",
|
||||
})
|
||||
});
|
||||
serde_json::json!({
|
||||
"name": t.name,
|
||||
"playcount": t.playcount,
|
||||
"mbid": t.mbid,
|
||||
"status": status,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
let lastfm_available = lastfm_api_key.is_some();
|
||||
|
||||
// Fetch release groups and split into primary vs featured
|
||||
let all_release_groups = state
|
||||
.search
|
||||
@@ -656,6 +737,8 @@ pub async fn enrich_artist(
|
||||
"artist_photo": artist_photo,
|
||||
"artist_bio": artist_bio,
|
||||
"artist_banner": artist_banner,
|
||||
"top_songs": top_songs,
|
||||
"lastfm_available": lastfm_available,
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user