diff --git a/js/api.js b/js/api.js index 04c80e3..23cca36 100644 --- a/js/api.js +++ b/js/api.js @@ -304,10 +304,10 @@ export class LosslessAPI { const data = await response.json(); const normalized = this.normalizeSearchResponse(data, 'tracks'); const preparedTracks = normalized.items.map((t) => this.prepareTrack(t)); - // Note: Skipping enrichTracksWithAlbumDates for search results to avoid excessive album API calls + const enrichedTracks = await this.enrichTracksWithAlbumDates(preparedTracks); const result = { ...normalized, - items: preparedTracks, + items: enrichedTracks, }; await this.cache.set('search_tracks', query, result); diff --git a/js/storage.js b/js/storage.js index 3f4c159..f08f561 100644 --- a/js/storage.js +++ b/js/storage.js @@ -206,26 +206,33 @@ export const apiSettings = { const targetUrls = instancesObj[type] || instancesObj.api || []; if (targetUrls.length === 0) return []; - // Use cached speed results to sort if available, but DON'T run new speed tests - // Speed tests should only run explicitly via refreshSpeedTests() to avoid - // mass /track API calls when playing a song const speedCache = this.getCachedSpeedTests(); + // Construct cache key based on type const getCacheKey = (u) => (type === 'streaming' ? `${u}#streaming` : u); - // Sort by cached speeds if we have any cached data - const hasCachedData = targetUrls.some((url) => speedCache.speeds[getCacheKey(url)]); + const urlsToTest = targetUrls.filter((url) => !speedCache.speeds[getCacheKey(url)]); - if (hasCachedData) { - const sortedList = [...targetUrls].sort((a, b) => { + if (urlsToTest.length > 0) { + const results = await this.testSpecificUrls(urlsToTest, type); + this.updateSpeedCache(results); + Object.assign(speedCache, this.getCachedSpeedTests()); + } + + const sortList = (list) => { + return [...list].sort((a, b) => { const speedA = speedCache.speeds[getCacheKey(a)]?.speed ?? Infinity; const speedB = speedCache.speeds[getCacheKey(b)]?.speed ?? Infinity; return speedA - speedB; }); - return sortedList; - } + }; - // No cached data - return in default order without testing - return targetUrls; + const sortedList = sortList(targetUrls); + + // Persist the sorted order + instancesObj[type] = sortedList; + this.saveInstances(instancesObj); + + return sortedList; }, async refreshSpeedTests() { diff --git a/js/ui.js b/js/ui.js index 9dd2016..8f97063 100644 --- a/js/ui.js +++ b/js/ui.js @@ -1693,39 +1693,44 @@ export class UIRenderer { const signal = this.searchAbortController.signal; try { - // Optimize: Only make 2 API calls (tracks and playlists), extract artists/albums from tracks - const [tracksResult, playlistsResult] = await Promise.all([ + const [tracksResult, artistsResult, albumsResult, playlistsResult] = await Promise.all([ this.api.searchTracks(query, { signal }), + this.api.searchArtists(query, { signal }), + this.api.searchAlbums(query, { signal }), this.api.searchPlaylists(query, { signal }), ]); let finalTracks = tracksResult.items; + let finalArtists = artistsResult.items; + let finalAlbums = albumsResult.items; let finalPlaylists = playlistsResult.items; - // Extract artists from tracks - const artistMap = new Map(); - finalTracks.forEach((track) => { - if (track.artist && !artistMap.has(track.artist.id)) { - artistMap.set(track.artist.id, track.artist); - } - if (track.artists) { - track.artists.forEach((artist) => { - if (!artistMap.has(artist.id)) { - artistMap.set(artist.id, artist); - } - }); - } - }); - let finalArtists = Array.from(artistMap.values()); + if (finalArtists.length === 0 && finalTracks.length > 0) { + const artistMap = new Map(); + finalTracks.forEach((track) => { + if (track.artist && !artistMap.has(track.artist.id)) { + artistMap.set(track.artist.id, track.artist); + } + if (track.artists) { + track.artists.forEach((artist) => { + if (!artistMap.has(artist.id)) { + artistMap.set(artist.id, artist); + } + }); + } + }); + finalArtists = Array.from(artistMap.values()); + } - // Extract albums from tracks - const albumMap = new Map(); - finalTracks.forEach((track) => { - if (track.album && !albumMap.has(track.album.id)) { - albumMap.set(track.album.id, track.album); - } - }); - let finalAlbums = Array.from(albumMap.values()); + if (finalAlbums.length === 0 && finalTracks.length > 0) { + const albumMap = new Map(); + finalTracks.forEach((track) => { + if (track.album && !albumMap.has(track.album.id)) { + albumMap.set(track.album.id, track.album); + } + }); + finalAlbums = Array.from(albumMap.values()); + } if (finalTracks.length) { this.renderListWithTracks(tracksContainer, finalTracks, true);