Update to artist credit handling
This commit is contained in:
@@ -162,14 +162,38 @@ async fn add_album(
|
||||
if body.artist.is_none() && body.album.is_none() && body.mbid.is_none() {
|
||||
return Err(ApiError::BadRequest("provide artist+album or mbid".into()));
|
||||
}
|
||||
let summary = shanty_watch::add_album(
|
||||
|
||||
// Try adding with the given MBID first. If it fails (e.g., the MBID is a release-group,
|
||||
// not a release), resolve it to an actual release MBID and retry.
|
||||
let mut mbid = body.mbid.clone();
|
||||
let result = shanty_watch::add_album(
|
||||
state.db.conn(),
|
||||
body.artist.as_deref(),
|
||||
body.album.as_deref(),
|
||||
body.mbid.as_deref(),
|
||||
mbid.as_deref(),
|
||||
&state.mb_client,
|
||||
)
|
||||
.await?;
|
||||
.await;
|
||||
|
||||
let summary = match result {
|
||||
Ok(s) => s,
|
||||
Err(_) if mbid.is_some() => {
|
||||
// MBID might be a release-group — resolve to the first release
|
||||
let rg_mbid = mbid.as_deref().unwrap();
|
||||
let release_mbid = resolve_release_from_group(&state, rg_mbid).await?;
|
||||
mbid = Some(release_mbid);
|
||||
shanty_watch::add_album(
|
||||
state.db.conn(),
|
||||
body.artist.as_deref(),
|
||||
body.album.as_deref(),
|
||||
mbid.as_deref(),
|
||||
&state.mb_client,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
|
||||
Ok(HttpResponse::Ok().json(serde_json::json!({
|
||||
"tracks_added": summary.tracks_added,
|
||||
"tracks_already_owned": summary.tracks_already_owned,
|
||||
|
||||
@@ -148,6 +148,7 @@ async fn get_cached_album_tracks(
|
||||
rg_id: &str,
|
||||
first_release_id: Option<&str>,
|
||||
ttl_seconds: i64,
|
||||
extend_ttl: bool,
|
||||
) -> Result<CachedAlbumTracks, ApiError> {
|
||||
let cache_key = format!("artist_rg_tracks:{rg_id}");
|
||||
|
||||
@@ -156,6 +157,10 @@ async fn get_cached_album_tracks(
|
||||
.map_err(|e| ApiError::Internal(e.to_string()))?
|
||||
{
|
||||
if let Ok(cached) = serde_json::from_str::<CachedAlbumTracks>(&json) {
|
||||
// Extend TTL if artist is now watched (upgrades 7-day browse cache to permanent)
|
||||
if extend_ttl {
|
||||
let _ = queries::cache::set(state.db.conn(), &cache_key, "musicbrainz", &json, ttl_seconds).await;
|
||||
}
|
||||
return Ok(cached);
|
||||
}
|
||||
}
|
||||
@@ -353,13 +358,15 @@ async fn get_artist_full(
|
||||
|
||||
// If artist has any watched items, cache permanently (10 years);
|
||||
// otherwise cache for 7 days (just browsing)
|
||||
let cache_ttl = if artist_wanted.is_empty() { 7 * 86400 } else { 10 * 365 * 86400 };
|
||||
let is_watched = !artist_wanted.is_empty();
|
||||
let cache_ttl = if is_watched { 10 * 365 * 86400 } else { 7 * 86400 };
|
||||
|
||||
let cached = match get_cached_album_tracks(
|
||||
&state,
|
||||
&rg.id,
|
||||
rg.first_release_id.as_deref(),
|
||||
cache_ttl,
|
||||
is_watched,
|
||||
).await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
|
||||
@@ -87,17 +87,6 @@ async fn trigger_process(
|
||||
let tid = task_id.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
// Count total pending for progress reporting
|
||||
let total = shanty_db::queries::downloads::list(
|
||||
state.db.conn(),
|
||||
Some(shanty_db::entities::download_queue::DownloadStatus::Pending),
|
||||
)
|
||||
.await
|
||||
.map(|v| v.len() as u64)
|
||||
.unwrap_or(0);
|
||||
|
||||
state.tasks.update_progress(&tid, 0, total, "Starting downloads...");
|
||||
|
||||
let cookies = state.config.download.cookies_path.clone();
|
||||
let format: shanty_dl::AudioFormat = state.config.download.format.parse().unwrap_or(shanty_dl::AudioFormat::Opus);
|
||||
let source: shanty_dl::SearchSource = state.config.download.search_source.parse().unwrap_or(shanty_dl::SearchSource::YouTubeMusic);
|
||||
@@ -108,8 +97,19 @@ async fn trigger_process(
|
||||
format,
|
||||
cookies_path: cookies,
|
||||
};
|
||||
match shanty_dl::run_queue(state.db.conn(), &backend, &backend_config, false).await {
|
||||
Ok(stats) => state.tasks.complete(&tid, format!("{stats}")),
|
||||
|
||||
let task_state = state.clone();
|
||||
let progress_tid = tid.clone();
|
||||
let on_progress: shanty_dl::ProgressFn = Box::new(move |current, total, msg| {
|
||||
task_state.tasks.update_progress(&progress_tid, current, total, msg);
|
||||
});
|
||||
|
||||
match shanty_dl::run_queue_with_progress(state.db.conn(), &backend, &backend_config, false, Some(on_progress)).await {
|
||||
Ok(stats) => {
|
||||
// Invalidate cached artist totals so library/detail pages show fresh data
|
||||
let _ = shanty_db::queries::cache::purge_prefix(state.db.conn(), "artist_totals:").await;
|
||||
state.tasks.complete(&tid, format!("{stats}"));
|
||||
}
|
||||
Err(e) => state.tasks.fail(&tid, e.to_string()),
|
||||
}
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ pub struct AlbumTrackSearchParams {
|
||||
limit: u32,
|
||||
}
|
||||
|
||||
fn default_limit() -> u32 { 10 }
|
||||
fn default_limit() -> u32 { 25 }
|
||||
|
||||
pub fn configure(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(web::resource("/search/artist").route(web::get().to(search_artist)))
|
||||
|
||||
@@ -126,6 +126,8 @@ async fn trigger_organize(
|
||||
let promoted = queries::wanted::promote_downloaded_to_owned(state.db.conn())
|
||||
.await
|
||||
.unwrap_or(0);
|
||||
// Invalidate cached artist totals so library/detail pages show fresh data
|
||||
let _ = queries::cache::purge_prefix(state.db.conn(), "artist_totals:").await;
|
||||
let msg = if promoted > 0 {
|
||||
format!("{stats} — {promoted} items marked as owned")
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user