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) { : '
🎤

Keine Künstler

'; 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);