perf(web): Künstlerbilder ohne einen API-Aufruf pro Künstler
Das Künstlerraster feuerte pro Künstler ein getArtistInfo2 nur für die Bildadresse: bei 200 Künstlern 200 gleichzeitige Aufrufe, die der Browser zu sechst abarbeitet, und jeder konnte Navidrome zu einer externen Last.fm-Abfrage zwingen. Fehlende Bilder kamen aus derselben Quelle — Last.fm liefert für viele Künstler nur noch einen Platzhalter. getArtists liefert das Bild längst mit (toArtistID3 setzt coverArt, und Navidrome löst Künstlerbilder selbst über ArtistArtPriority auf und cacht sie). Jetzt geht nur noch das Bild über die Leitung; ohne coverArt sparen wir uns den Versuch ganz. Im Test 0 statt 120 Zusatzaufrufe. Gleiches für die Künstlerkarten in der lokalen Suche und die gefolgten Künstler in den Favoriten. Android war nie betroffen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f3d54158d3
commit
ea7167f851
4 files changed
+26
-14
No files matched your search
@@ -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
|
||||
|
||||
+8
-12
@@ -240,22 +240,18 @@ export async function loadArtists(filter = _artistsFilter) {
|
||||
: '<div class="empty-state"><div class="icon">🎤</div><p>Keine Künstler</p></div>';
|
||||
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 = `<p style="color:var(--danger)">${e.message}</p>`; }
|
||||
}
|
||||
|
||||
@@ -269,7 +269,9 @@ function _renderStarredArtists(artists) {
|
||||
const art = c.querySelector('.card-art');
|
||||
if (art) art.innerHTML = `<img src="${img}" loading="lazy" onerror="this.parentNode.innerHTML='<div class=\'no-art\'>🎤</div>'">`;
|
||||
};
|
||||
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);
|
||||
}
|
||||
|
||||
+2
-1
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user