feat(lastfm): disambiguation picker for same-named MB artists
Last.fm's artist MBID can point at the wrong same-named band (it mapped
"Looking Glass" to an Australian stoner band, not the US pop group), and the
/lastfm rows trusted it verbatim — so opening/following grabbed the wrong
artist and the grabbed album never showed on the artist page. Now open/follow
resolve via MB search: resolveArtistChoice keeps candidates whose name matches
exactly — 1 match is used directly (even over a disagreeing Last.fm MBID), 2+
surface an ArtistPicker showing each MB disambiguation ("70's US pop group,
track 'Brandy'" vs "Australian stoner rock") with MB's top hit flagged
Suggested. Core decision logic unit-tested; no worker/schema change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
"use client";
|
||||
|
||||
import { Modal } from "./modal";
|
||||
import type { ArtistHit } from "@/lib/artist-resolve";
|
||||
|
||||
/** Disambiguation picker: several MusicBrainz artists share a name (e.g. two bands both called
|
||||
* "Looking Glass"), so let the user choose the right one by its MB disambiguation text instead
|
||||
* of silently trusting Last.fm's — sometimes wrong — MBID. Candidates arrive in MB relevance
|
||||
* order, so the first is flagged "Suggested". */
|
||||
export function ArtistPicker({
|
||||
open,
|
||||
name,
|
||||
candidates,
|
||||
onPick,
|
||||
onClose,
|
||||
}: {
|
||||
open: boolean;
|
||||
name: string;
|
||||
candidates: ArtistHit[];
|
||||
onPick: (mbid: string, name: string) => void;
|
||||
onClose: () => void;
|
||||
}) {
|
||||
return (
|
||||
<Modal open={open} onClose={onClose} title="Which artist?">
|
||||
<p className="muted-note">
|
||||
More than one artist is named “{name}”. Pick the right one.
|
||||
</p>
|
||||
<ul className="list">
|
||||
{candidates.map((c, i) => (
|
||||
<li key={c.mbid} className="list-row">
|
||||
<div className="main">
|
||||
<div className="rtitle">
|
||||
<button className="linkish" onClick={() => onPick(c.mbid, c.name)}>
|
||||
{c.name}
|
||||
</button>
|
||||
</div>
|
||||
<div className="rmeta">
|
||||
<span>{c.disambiguation || "no description on MusicBrainz"}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="actions">
|
||||
{i === 0 ? <span className="chip working">Suggested</span> : null}
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user