diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9c20dee..36ad4dd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -126,6 +126,19 @@ Die Android-App zählt eigenständig weiter (mehrere APKs pro Release). Welche d
statt einer leeren Liste.
### Changed
+- **Künstlerbilder laden endlich zügig (Web)** — im Künstlerraster lief **pro Künstler ein eigener
+ `getArtistInfo2`-Aufruf**, nur um die Bildadresse zu erfahren. Bei 200 Künstlern sind das 200
+ API-Aufrufe auf einen Schlag, die der Browser zu sechst abarbeitet (mehr Verbindungen erlaubt er
+ pro Host nicht) — und jeder davon konnte Navidrome zu einer **externen** Abfrage bei Last.fm
+ zwingen. Dass manche Bilder gar nicht kamen, lag an derselben Quelle: Last.fm liefert für viele
+ Künstler nur noch einen Platzhalter, den der Code als „kein Bild" erkennt.
+ Dabei liefert `getArtists` das Bild längst mit: `toArtistID3` setzt `coverArt`, und Navidrome löst
+ Künstlerbilder selbst auf (`ArtistArtPriority` = `artist.*, album/artist.*, external`) und legt sie
+ im eigenen Cache ab. Jetzt geht pro Künstler nur noch das Bild selbst über die Leitung, kein
+ API-Aufruf davor; ist `coverArt` leer, hat der Künstler kein Bild und wir sparen uns den Versuch.
+ Gemessen im Test: **0 statt 120 Zusatzaufrufe** bei 120 Künstlern. Gleiches gilt jetzt für die
+ Künstlerkarten in der lokalen Suche und die gefolgten Künstler in den Favoriten.
+ **Android war nie betroffen** — dort lief es immer schon über `coverArt`.
- **Top Songs fragen jetzt über die Künstler-ID (Web + Android)** — Navidrome 0.64 nimmt bei
`getTopSongs` zusätzlich `id`. Bisher lief die Abfrage nur über den **Namen**, und der Namensweg
sucht mit `LIKE` und `Max: 1` (`core/external/provider.go`): bei zwei gleichnamigen Künstlern in
diff --git a/src/views/home.js b/src/views/home.js
index 3b4b287..caf43f9 100644
--- a/src/views/home.js
+++ b/src/views/home.js
@@ -240,22 +240,18 @@ export async function loadArtists(filter = _artistsFilter) {
: '
';
return;
}
+ // Das Bild kommt direkt aus `coverArt`, das getArtists ohnehin mitliefert (Navidrome loest
+ // Kuenstlerbilder selbst auf: artist.*, album/artist.*, extern — und cacht sie). Frueher lief
+ // hier PRO KUENSTLER ein eigener getArtistInfo2-Aufruf nur um die Bild-Adresse zu erfahren:
+ // bei 200 Kuenstlern 200 API-Aufrufe auf einmal, die der Browser zu sechst abarbeitet, und
+ // jeder davon konnte Navidrome zu einer externen Abfrage zwingen. Ist coverArt leer, hat der
+ // Kuenstler schlicht kein Bild — dann sparen wir uns den Versuch ganz.
liste.forEach(a => {
- const c = makeCard(dispArtistById(a.id, a.name), a.albumCount+' Alben', null, '🎤');
+ const bild = a.coverArt ? coverUrl(a.coverArt, 300) : null;
+ const c = makeCard(dispArtistById(a.id, a.name), a.albumCount+' Alben', bild, '🎤');
c.classList.add('artist-card');
c.onclick = () => navigate('artist-detail', a);
g.appendChild(c);
- getArtistImage(a.id).then(imgUrl => {
- if(!imgUrl) return;
- const artEl = c.querySelector('.card-art');
- if(!artEl) return;
- const overlay = artEl.querySelector('.play-overlay');
- const img = document.createElement('img');
- img.src = imgUrl; img.loading = 'lazy'; img.style.cssText = 'width:100%;height:100%;object-fit:cover;transition:transform .4s';
- artEl.innerHTML = ''; artEl.appendChild(img); if(overlay) artEl.appendChild(overlay);
- c.addEventListener('mouseenter', () => img.style.transform = 'scale(1.05)');
- c.addEventListener('mouseleave', () => img.style.transform = 'scale(1)');
- });
});
} catch(e) { g.innerHTML = `${e.message}
`; }
}
diff --git a/src/views/playlists.js b/src/views/playlists.js
index a1159ab..3c96214 100644
--- a/src/views/playlists.js
+++ b/src/views/playlists.js
@@ -269,7 +269,9 @@ function _renderStarredArtists(artists) {
const art = c.querySelector('.card-art');
if (art) art.innerHTML = `
`;
};
- if (pin?.image) setzen(pin.image); else getArtistImage(a.id).then(setzen);
+ if (pin?.image) setzen(pin.image);
+ else if (a.coverArt) setzen(coverUrl(a.coverArt, 300)); // kein Extra-Aufruf noetig
+ else getArtistImage(a.id).then(setzen);
});
s.appendChild(row); wrap.appendChild(s);
}
diff --git a/src/views/search.js b/src/views/search.js
index d53da2a..ad71de5 100644
--- a/src/views/search.js
+++ b/src/views/search.js
@@ -1,6 +1,6 @@
import { S } from '../state.js';
import { esc, toast, fmtCount } from '../utils.js';
-import { api, deezerSearch, deezerLastError, deezerLookupAlbum, fetchRomajiIndex, dispArtistById, getArtistOverride } from '../api.js';
+import { api, coverUrl, deezerSearch, deezerLastError, deezerLookupAlbum, fetchRomajiIndex, dispArtistById, getArtistOverride } from '../api.js';
import { makeCard, makeAlbumCard, makeGlobalTrackItem, makeSongItem, mkSection } from '../ui/components.js';
import { playPreview } from '../player/player.js';
import { openDlModal } from '../ui/ui.js';
@@ -73,6 +73,7 @@ export async function doLocalSearch(q, el) {
// A pin's Deezer picture wins (fixes same-name artists whose Navidrome image is the wrong person).
const _pin = getArtistOverride(a.id);
if (_pin?.image) _setArt(_pin.image);
+ else if (a.coverArt) _setArt(coverUrl(a.coverArt, 300)); // kein Extra-Aufruf noetig
else getArtistImage(a.id).then(_setArt);
});
s.appendChild(g); el.appendChild(s);