forked from Keelrleek/SoulStream
discography: drop guest appearances, but only where MusicBrainz can arbitrate
Deezer's /artist/{id}/albums returns records the artist merely contributed to,
alongside their own. Mid-Air Thief's page carried four Rooby Jeantal lo-fi EPs
that way -- his real discography is two albums.
This is not the namesake bug that was hardened in July. Every identity step here
is correct: MusicBrainz links the artist to Deezer 51082452, that is the id we
open, and the MB supplement injects both real albums. The leak is credit ROLE,
which is why an identity fix never touched it.
Deezer cannot answer it alone. Album details expose the primary artist, so a
guest spot is visible -- but every contributor is marked role "Main", so Kanye
West on "Watch the Throne" (primary artist JAY-Z) is byte-for-byte the same
shape as a guest EP. A "not primary, therefore drop" rule deletes a real album.
MusicBrainz separates them, because it credits a genuine collaboration under
BOTH artists: Kanye's own MBID returns "Watch the Throne", Mid-Air Thief's
returns only his two albums. So the backend only FLAGS (`appears_on`, set from
the details pass where the release's primary artist is finally visible) and the
frontend drops a flagged row at the identity merge only when MB answered for
this artist and does not credit the row. No MB albums means no arbiter and
every row is kept -- thin-coverage artists never silently lose real releases.
EPs now enter the album-details pass, which is what made this invisible: the
pass was album-only, and all four guest releases are typed "ep". They already
sort ahead of singles for the details cap.
Replay recipe bumped to v2: pages cached before this are stamped
identity_merged and would skip the pass that drops the rows.
Verified live -- Mid-Air Thief 6 albums -> 2 (무너지기/Crumbling, 공중도덕);
Kanye West keeps "Watch The Throne (Deluxe)", flagged appears_on but MB-credited,
with all 58 rows intact.
This commit is contained in:
1 parent
9cd03a6ecc
commit
e536e96180
2 files changed
+72
-3
No files matched your search
@@ -340,6 +340,22 @@ pub struct CatalogAlbum {
|
||||
/// Only set once album details (hence the tracklist) are known.
|
||||
#[serde(default)]
|
||||
pub is_live: bool,
|
||||
/// True when Deezer's album details credit a DIFFERENT artist as the
|
||||
/// release's primary artist — i.e. this artist is a contributor on someone
|
||||
/// else's record. `/artist/{id}/albums` returns those alongside the
|
||||
/// artist's own releases, which is how four Rooby Jeantal lo-fi records
|
||||
/// arrived in Mid-Air Thief's discography.
|
||||
///
|
||||
/// A flag rather than a filter, deliberately: Deezer marks EVERY
|
||||
/// contributor `role: "Main"`, so a guest spot and a genuine joint album
|
||||
/// (Kanye West on "Watch the Throne", primary artist JAY-Z) are
|
||||
/// indistinguishable here. Only corroboration can separate them, and that
|
||||
/// happens where the MusicBrainz identity is merged.
|
||||
///
|
||||
/// Only set once album details are known; false means "own release, or not
|
||||
/// yet checked".
|
||||
#[serde(default)]
|
||||
pub appears_on: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize)]
|
||||
@@ -3129,6 +3145,14 @@ impl MetadataClient {
|
||||
.filter(|a| {
|
||||
a.release_date.is_none()
|
||||
|| (a.track_count.is_none() && feat_collision_ids.contains(&a.id))
|
||||
// EPs are pulled in for the ownership check: the list
|
||||
// endpoint carries no artist object, so details are the only
|
||||
// place a release's PRIMARY artist is visible, and a guest
|
||||
// appearance is typed "ep" as often as "album" — the four
|
||||
// Rooby Jeantal records in Mid-Air Thief's discography are
|
||||
// all EPs, which is why an album-only pass never saw them.
|
||||
// They already sort ahead of singles for the cap below.
|
||||
|| a.record_type.as_deref() == Some("ep")
|
||||
|| (a.record_type.as_deref() == Some("album")
|
||||
&& (a.track_count.is_none_or(|n| n <= 14)
|
||||
|| is_edition_title(&a.title)
|
||||
@@ -3185,6 +3209,13 @@ impl MetadataClient {
|
||||
a.track_count = nb;
|
||||
}
|
||||
a.is_soundtrack = detail_is_soundtrack(d);
|
||||
// The list endpoint carries no artist object at all, so this pass is
|
||||
// the only place the release's PRIMARY artist is visible. A mismatch
|
||||
// means the artist is a contributor on someone else's record.
|
||||
a.appears_on = d
|
||||
.pointer("/artist/id")
|
||||
.and_then(|id| id.as_u64())
|
||||
.is_some_and(|primary| primary != artist_id);
|
||||
// These albums arrived from search (no tracklist); the details pass
|
||||
// is the first look at their tracks, so read live-ness here. Titles
|
||||
// like "Ballet Slippers" give no hint — the tracks do.
|
||||
@@ -4148,6 +4179,7 @@ impl MetadataClient {
|
||||
edition_group: None,
|
||||
is_soundtrack: false,
|
||||
is_live: false,
|
||||
appears_on: false,
|
||||
});
|
||||
}
|
||||
albums
|
||||
@@ -4242,6 +4274,7 @@ impl MetadataClient {
|
||||
edition_group: None,
|
||||
is_soundtrack: false,
|
||||
is_live: false,
|
||||
appears_on: false,
|
||||
};
|
||||
Some(CatalogAlbumPage { album, tracks })
|
||||
}
|
||||
@@ -4333,6 +4366,7 @@ impl MetadataClient {
|
||||
edition_group: None,
|
||||
is_soundtrack: false,
|
||||
is_live: false,
|
||||
appears_on: false,
|
||||
};
|
||||
Some(CatalogAlbumPage { album, tracks })
|
||||
}
|
||||
@@ -5204,6 +5238,7 @@ impl MetadataClient {
|
||||
edition_group: None,
|
||||
is_soundtrack: false,
|
||||
is_live: false,
|
||||
appears_on: false,
|
||||
});
|
||||
}
|
||||
if !registered.is_empty() {
|
||||
@@ -5604,6 +5639,9 @@ fn parse_album(v: &serde_json::Value) -> Option<CatalogAlbum> {
|
||||
// later from the album-details pass; a full album fetch (catalog_album)
|
||||
// does include /tracks/data and resolves it here directly.
|
||||
is_live: detail_is_live(v),
|
||||
// Needs the requested artist's id to mean anything, which this parser
|
||||
// does not have. Resolved in the album-details pass.
|
||||
appears_on: false,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -9222,6 +9260,7 @@ mod tests {
|
||||
edition_group: None,
|
||||
is_soundtrack: false,
|
||||
is_live: false,
|
||||
appears_on: false,
|
||||
};
|
||||
let releases = [release(1, "single"), release(2, "album")];
|
||||
let matches = releases
|
||||
@@ -10092,6 +10131,7 @@ mod tests {
|
||||
edition_group: None,
|
||||
is_soundtrack: false,
|
||||
is_live: false,
|
||||
appears_on: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user