fix: artist page resolved "Flay!" to the far more popular "K.FLAY"

The Deezer artist match required only that every query word appear in the candidate name, so
"Flay!" (query word: flay) matched "K.FLAY" (words: k, flay). Sorted by fan count, K.FLAY
(54,822 fans) buried the real "Flay!" (39 fans) — the page showed K.FLAY's fans + top tracks.

Now prefer an EXACT normalized-name match ("flay" == "flay", not "kflay"), falling back to the
loose match only when there's no exact one. Web (detail.js) + Android (ArtistViewModel).
Verified against Deezer: exact match selects the real Flay! (id 12242284, whose top tracks
are actually Flay!). SW ns-v60.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Opus 4.8 committed 2026-07-31 23:53:42 +02:00
1 parent b3cf01dd3b
commit e4f030c98d
3 files changed
+17 -8

No files matched your search

+8 -2
View File
@@ -142,14 +142,20 @@ export async function loadArtistDetail(artist) {
const [infoRes, topRes, iArtistRes, eventsRes] = await Promise.allSettled([infoP, topP, iArtistP, eventsP]);
const _normWords = s => new Set((s || '').toLowerCase().replace(/[^a-z0-9]/g, ' ').split(/\s+/).filter(Boolean));
const _normName = s => (s || '').toLowerCase().replace(/[^a-z0-9]/g, '');
const _queryWords = _normWords(artist.name);
const _qNorm = _normName(artist.name);
const iArtistResults = iArtistRes.status === 'fulfilled' ? (iArtistRes.value || []) : [];
// Name-matching candidates, already ordered by fanCount (itunesSearch sorts musicArtist by nb_fan).
const nameMatches = iArtistResults.filter(r => {
// Prefer EXACT normalized-name matches. "Flay!" must not resolve to the far more popular "K.FLAY"
// (whose name merely contains the word "flay") — exact "flay" == "flay" wins over "kflay". Only fall
// back to the looser word-subset match when there's no exact match. Both lists are fan-sorted already.
const exactMatches = iArtistResults.filter(r => _normName(r.artistName) === _qNorm);
const looseMatches = iArtistResults.filter(r => {
if (_queryWords.size === 0) return true;
const rw = _normWords(r.artistName);
return [..._queryWords].every(w => rw.has(w));
});
const nameMatches = exactMatches.length ? exactMatches : looseMatches;
// Default pick = most popular name match (fixes "5× Joji": Deezer's order buries the real one).
let iArtistMatch = nameMatches[0] || null;