From 015003225cd8fdefe1f07de5a446b8cf4266b86d Mon Sep 17 00:00:00 2001 From: Eduard Prigoana Date: Wed, 4 Feb 2026 23:12:58 +0200 Subject: [PATCH] (TEMPORARY) stop DDOSING apis on search --- js/api.js | 4 +-- js/storage.js | 29 ++++++++-------------- js/ui.js | 69 ++++++++++++++++++++++++--------------------------- 3 files changed, 45 insertions(+), 57 deletions(-) diff --git a/js/api.js b/js/api.js index 23cca36..04c80e3 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)); - const enrichedTracks = await this.enrichTracksWithAlbumDates(preparedTracks); + // Note: Skipping enrichTracksWithAlbumDates for search results to avoid excessive album API calls const result = { ...normalized, - items: enrichedTracks, + items: preparedTracks, }; await this.cache.set('search_tracks', query, result); diff --git a/js/storage.js b/js/storage.js index ad8ebac..74482c2 100644 --- a/js/storage.js +++ b/js/storage.js @@ -215,33 +215,26 @@ 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); - const urlsToTest = targetUrls.filter((url) => !speedCache.speeds[getCacheKey(url)]); + // Sort by cached speeds if we have any cached data + const hasCachedData = targetUrls.some((url) => speedCache.speeds[getCacheKey(url)]); - 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) => { + if (hasCachedData) { + const sortedList = [...targetUrls].sort((a, b) => { const speedA = speedCache.speeds[getCacheKey(a)]?.speed ?? Infinity; const speedB = speedCache.speeds[getCacheKey(b)]?.speed ?? Infinity; return speedA - speedB; }); - }; + return sortedList; + } - const sortedList = sortList(targetUrls); - - // Persist the sorted order - instancesObj[type] = sortedList; - this.saveInstances(instancesObj); - - return sortedList; + // No cached data - return in default order without testing + return targetUrls; }, async refreshSpeedTests() { diff --git a/js/ui.js b/js/ui.js index 75aeafd..5f15238 100644 --- a/js/ui.js +++ b/js/ui.js @@ -1510,44 +1510,39 @@ export class UIRenderer { const signal = this.searchAbortController.signal; try { - const [tracksResult, artistsResult, albumsResult, playlistsResult] = await Promise.all([ + // Optimize: Only make 2 API calls (tracks and playlists), extract artists/albums from tracks + const [tracksResult, 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; - 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 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 (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()); - } + // 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 (finalTracks.length) { this.renderListWithTracks(tracksContainer, finalTracks, true); @@ -1658,10 +1653,10 @@ export class UIRenderer { dateDisplay = window.innerWidth > 768 ? releaseDate.toLocaleDateString('en-US', { - year: 'numeric', - month: 'long', - day: 'numeric', - }) + year: 'numeric', + month: 'long', + day: 'numeric', + }) : year; } } @@ -2395,9 +2390,9 @@ export class UIRenderer { ${artist.popularity}% popularity
${(artist.artistRoles || []) - .filter((role) => role.category) - .map((role) => `${role.category}`) - .join('')} + .filter((role) => role.category) + .map((role) => `${role.category}`) + .join('')}
`;