Compare commits

..

1 Commits

Author SHA1 Message Date
Connor Johnstone cb63619610 fixed deduplication once again. for real this time I think 2026-03-24 12:51:42 -04:00
3 changed files with 38 additions and 2 deletions
+36 -1
View File
@@ -60,11 +60,15 @@ impl fmt::Display for LibrarySummary {
} }
/// Add an artist to the watchlist by expanding into individual track wanted items. /// 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( pub async fn add_artist(
conn: &DatabaseConnection, conn: &DatabaseConnection,
name: Option<&str>, name: Option<&str>,
musicbrainz_id: Option<&str>, musicbrainz_id: Option<&str>,
provider: &impl MetadataProvider, provider: &impl MetadataProvider,
allowed_secondary_types: &[String],
user_id: Option<i32>, user_id: Option<i32>,
) -> WatchResult<AddSummary> { ) -> WatchResult<AddSummary> {
let (resolved_name, resolved_mbid) = 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)"); 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) .get_artist_release_groups(&artist_mbid)
.await .await
.map_err(|e| WatchError::Other(format!("failed to fetch release groups: {e}")))?; .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"); tracing::info!(count = release_groups.len(), "found release groups");
let mut summary = AddSummary::default(); let mut summary = AddSummary::default();
let mut seen_mbids: std::collections::HashSet<String> = std::collections::HashSet::new();
for rg in &release_groups { for rg in &release_groups {
// Resolve a concrete release MBID from the release group // Resolve a concrete release MBID from the release group
@@ -128,6 +149,9 @@ pub async fn add_artist(
}; };
for track in &tracks { 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( match add_track_inner(
conn, conn,
&resolved_name, &resolved_name,
@@ -277,6 +301,17 @@ async fn add_track_inner(
artist_mbid: Option<&str>, artist_mbid: Option<&str>,
user_id: Option<i32>, user_id: Option<i32>,
) -> WatchResult<bool> { ) -> WatchResult<bool> {
// 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 artist = queries::artists::upsert(conn, artist_name, artist_mbid).await?;
let is_owned = matching::track_is_owned(conn, artist_name, title).await?; let is_owned = matching::track_is_owned(conn, artist_name, title).await?;
+1
View File
@@ -135,6 +135,7 @@ async fn main() -> anyhow::Result<()> {
name.as_deref(), name.as_deref(),
mbid.as_deref(), mbid.as_deref(),
&mb_client, &mb_client,
&[], // CLI: studio releases only (default)
None, None,
) )
.await?; .await?;
+1 -1
View File
@@ -204,7 +204,7 @@ async fn test_add_artist_expands_to_tracks() {
let db = test_db().await; let db = test_db().await;
let provider = MockProvider; 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 .await
.unwrap(); .unwrap();
assert_eq!(summary.tracks_added, 2); assert_eq!(summary.tracks_added, 2);