feat(artist): pin a local artist to a specific Deezer artist (same-name fix, shared)
Fixes same-name collisions where NovaSonic guessed the wrong Deezer artist (e.g. 'Nana' → a random DJ): fans, top songs, missing albums and the hero image were all off. A '⚙ Falscher Künstler?' button on the artist page opens a picker (same-name Deezer candidates with image + fan count); the chosen mapping is stored SERVER-SIDE (shared across users, like the romaji overrides) in /data/deezer-artist-overrides.json. Once pinned, the artist page short-circuits the name search to the pinned Deezer id (drives albums/top-songs/fans) and overrides the hero image with the pinned artist's Deezer picture (NovaSonic-side, so it works even for tag-merged same-name artists — Navidrome can't disambiguate them without an MBID). New endpoints GET/POST/DELETE /api/artist-overrides; api.js load/get/set/remove; loaded at startup. SW cache -> ns-v74. Needs on-device runtime test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
b788fedec3
commit
02960cf886
6 files changed
+204
-7
No files matched your search
+24
-5
@@ -1,6 +1,7 @@
|
||||
import { S } from '../state.js';
|
||||
import { esc, toast, fmtCount } from '../utils.js';
|
||||
import { api, coverUrl, deezerSearch, deezerLookupAlbum, deezerLookupArtistSongs, deezerLookupArtistAlbums, deezerArtistImage, fetchRomajiIndex, dispArtistById, dispAlbumName, cacheArtistSortNames, ensureArtistSortMap } from '../api.js';
|
||||
import { api, coverUrl, deezerSearch, deezerLookupAlbum, deezerLookupArtistSongs, deezerLookupArtistAlbums, deezerArtistImage, fetchRomajiIndex, dispArtistById, dispAlbumName, cacheArtistSortNames, ensureArtistSortMap, getArtistOverride } from '../api.js';
|
||||
import { openArtistPin } from '../ui/artistPin.js';
|
||||
import { makeCard, makeAlbumCard, makeGlobalTrackItem, makeSongItem } from '../ui/components.js';
|
||||
import { playQueue, dlSongLocal, toggleStar, parseArtists } from '../player/player.js';
|
||||
import { showCtxMenu, openDlModal } from '../ui/ui.js';
|
||||
@@ -87,12 +88,30 @@ export async function loadArtistDetail(artist) {
|
||||
if(albEl) albEl.innerHTML = '<div class="spinner"></div>';
|
||||
|
||||
const hasND = !!artist.id;
|
||||
const knownDeezer = artist.deezerArtistId || null;
|
||||
const knownFans = artist.deezerFanCount ?? null;
|
||||
if (knownFans) _showFans(knownFans); // from the global-search card — show immediately
|
||||
// Manual pin (same-name fix): use the pinned Deezer artist for id/fans/image instead of guessing.
|
||||
const _pin = hasND ? getArtistOverride(artist.id) : null;
|
||||
const knownDeezer = _pin?.deezerArtistId || artist.deezerArtistId || null;
|
||||
const knownFans = _pin?.fanCount ?? artist.deezerFanCount ?? null;
|
||||
if (knownFans) _showFans(knownFans); // from the global-search card / pin — show immediately
|
||||
|
||||
// "Falscher Künstler?" pin button (local artists only) — fix a wrong same-name Deezer match.
|
||||
if (hasND) {
|
||||
const infoEl = hero.querySelector('.artist-hero-info');
|
||||
infoEl?.querySelector('.artist-pin-btn')?.remove();
|
||||
if (infoEl) {
|
||||
const pinBtn = document.createElement('button');
|
||||
pinBtn.className = 'artist-pin-btn';
|
||||
pinBtn.textContent = _pin ? '⚙ Künstler gepinnt' : '⚙ Falscher Künstler?';
|
||||
pinBtn.title = 'Richtigen Deezer-Künstler wählen';
|
||||
pinBtn.style.cssText = 'margin-top:8px;padding:5px 12px;border-radius:999px;border:1px solid var(--border2);background:rgba(0,0,0,.35);color:#fff;font-family:var(--font);font-size:12px;font-weight:600;cursor:pointer';
|
||||
pinBtn.onclick = () => openArtistPin(artist.id, artist.name);
|
||||
infoEl.appendChild(pinBtn);
|
||||
}
|
||||
}
|
||||
|
||||
// Fire all requests immediately so they run in parallel.
|
||||
const imgP = hasND ? getArtistImage(artist.id) : Promise.resolve(null);
|
||||
const imgP = _pin?.image ? Promise.resolve(_pin.image)
|
||||
: hasND ? getArtistImage(artist.id) : Promise.resolve(null);
|
||||
const albumP = hasND ? api('getArtist', `&id=${artist.id}`) : Promise.resolve(null);
|
||||
const infoP = hasND ? api('getArtistInfo2',`&id=${artist.id}&count=8`) : Promise.resolve(null);
|
||||
const topP = hasND ? api('getTopSongs', `&artist=${encodeURIComponent(artist.name)}&count=10`) : Promise.resolve(null);
|
||||
|
||||
Reference in new issue
Block a user