From cb6361961000bfb68f9478751d8bebfe2bce6472 Mon Sep 17 00:00:00 2001 From: Connor Johnstone Date: Tue, 24 Mar 2026 12:51:42 -0400 Subject: [PATCH] fixed deduplication once again. for real this time I think --- src/library.rs | 37 ++++++++++++++++++++++++++++++++++++- src/main.rs | 1 + tests/integration.rs | 2 +- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/library.rs b/src/library.rs index 930d42e..6d9bdda 100644 --- a/src/library.rs +++ b/src/library.rs @@ -60,11 +60,15 @@ impl fmt::Display for LibrarySummary { } /// Add an artist to the watchlist by expanding into individual track wanted items. +/// +/// `allowed_secondary_types` filters release groups by secondary type (e.g., Compilation, Live). +/// An empty slice means studio releases only. pub async fn add_artist( conn: &DatabaseConnection, name: Option<&str>, musicbrainz_id: Option<&str>, provider: &impl MetadataProvider, + allowed_secondary_types: &[String], user_id: Option, ) -> WatchResult { let (resolved_name, resolved_mbid) = @@ -91,14 +95,31 @@ pub async fn add_artist( tracing::info!(name = %resolved_name, mbid = %artist_mbid, "fetching discography (release groups)"); - let release_groups = provider + let all_release_groups = provider .get_artist_release_groups(&artist_mbid) .await .map_err(|e| WatchError::Other(format!("failed to fetch release groups: {e}")))?; + // Only include release groups where this artist is the primary credit, + // filtered by allowed secondary types (same as the artist detail page) + let release_groups: Vec<_> = all_release_groups + .into_iter() + .filter(|rg| !rg.featured) + .filter(|rg| { + if rg.secondary_types.is_empty() { + true + } else { + rg.secondary_types + .iter() + .all(|st| allowed_secondary_types.contains(st)) + } + }) + .collect(); + tracing::info!(count = release_groups.len(), "found release groups"); let mut summary = AddSummary::default(); + let mut seen_mbids: std::collections::HashSet = std::collections::HashSet::new(); for rg in &release_groups { // Resolve a concrete release MBID from the release group @@ -128,6 +149,9 @@ pub async fn add_artist( }; for track in &tracks { + if !seen_mbids.insert(track.recording_mbid.clone()) { + continue; // Already processed this recording in another release group + } match add_track_inner( conn, &resolved_name, @@ -277,6 +301,17 @@ async fn add_track_inner( artist_mbid: Option<&str>, user_id: Option, ) -> WatchResult { + // Skip if a wanted_item with this recording MBID already exists + if let Some(mbid) = recording_mbid { + if queries::wanted::find_by_mbid(conn, mbid) + .await? + .is_some() + { + tracing::debug!(title = title, mbid = mbid, "already in watchlist, skipping"); + return Ok(false); + } + } + let artist = queries::artists::upsert(conn, artist_name, artist_mbid).await?; let is_owned = matching::track_is_owned(conn, artist_name, title).await?; diff --git a/src/main.rs b/src/main.rs index 9b28a1b..c60bb0e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -135,6 +135,7 @@ async fn main() -> anyhow::Result<()> { name.as_deref(), mbid.as_deref(), &mb_client, + &[], // CLI: studio releases only (default) None, ) .await?; diff --git a/tests/integration.rs b/tests/integration.rs index 412cc7b..020cec4 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -204,7 +204,7 @@ async fn test_add_artist_expands_to_tracks() { let db = test_db().await; let provider = MockProvider; - let summary = add_artist(db.conn(), Some("Test Artist"), None, &provider, None) + let summary = add_artist(db.conn(), Some("Test Artist"), None, &provider, &[], None) .await .unwrap(); assert_eq!(summary.tracks_added, 2);