From a419f380244e3271ac5b39de430309136734fec2 Mon Sep 17 00:00:00 2001 From: Julien Maille Date: Sun, 11 Jan 2026 00:58:55 +0100 Subject: [PATCH] js fixes --- js/api.js | 5 +- js/storage.js | 10 ++-- js/ui.js | 7 +-- js/vibrant-color.js | 116 +++++++++++++++++++++----------------------- 4 files changed, 62 insertions(+), 76 deletions(-) diff --git a/js/api.js b/js/api.js index 293bc88..84400dc 100644 --- a/js/api.js +++ b/js/api.js @@ -69,10 +69,7 @@ export class LosslessAPI { } if (response.status === 401) { - let errorData; - try { - errorData = await response.clone().json(); - } catch {} + let errorData = await response.clone().json(); if (errorData?.subStatus === 11002) { lastError = new Error(errorData?.userMessage || 'Authentication failed'); diff --git a/js/storage.js b/js/storage.js index a4c7399..91b8ccb 100644 --- a/js/storage.js +++ b/js/storage.js @@ -166,12 +166,10 @@ export const apiSettings = { async getInstances(type = 'api') { let instancesObj; - try { - const stored = localStorage.getItem(this.STORAGE_KEY); - if (stored) { - instancesObj = JSON.parse(stored); - } - } catch (e) {} + const stored = localStorage.getItem(this.STORAGE_KEY); + if (stored) { + instancesObj = JSON.parse(stored); + } if (!instancesObj) { instancesObj = await this.loadInstancesFromGitHub(); diff --git a/js/ui.js b/js/ui.js index 6bbc6e8..f0de792 100644 --- a/js/ui.js +++ b/js/ui.js @@ -1311,12 +1311,7 @@ export class UIRenderer { } // Render API playlist - let apiResult; - try { - apiResult = await this.api.getPlaylist(playlistId); - } catch (error) { - throw error; - } + let apiResult = await this.api.getPlaylist(playlistId); const { playlist, tracks } = apiResult; diff --git a/js/vibrant-color.js b/js/vibrant-color.js index 60a5fc0..f2886de 100644 --- a/js/vibrant-color.js +++ b/js/vibrant-color.js @@ -75,77 +75,73 @@ export function getVibrantColorFromImage(imgElement) { const ctx = canvas.getContext('2d'); if (!ctx) return null; - try { - const maxDimension = 64; - let w = imgElement.naturalWidth || imgElement.width; - let h = imgElement.naturalHeight || imgElement.height; + const maxDimension = 64; + let w = imgElement.naturalWidth || imgElement.width; + let h = imgElement.naturalHeight || imgElement.height; - if (w > maxDimension || h > maxDimension) { - const scale = Math.min(maxDimension / w, maxDimension / h); - w = Math.floor(w * scale); - h = Math.floor(h * scale); + if (w > maxDimension || h > maxDimension) { + const scale = Math.min(maxDimension / w, maxDimension / h); + w = Math.floor(w * scale); + h = Math.floor(h * scale); + } + + canvas.width = w; + canvas.height = h; + + // Draw image directly at small size + // Note: For best quality downscaling, one might step down, but for color extraction, + // direct browser downscaling is sufficient and much faster/lighter. + ctx.drawImage(imgElement, 0, 0, w, h); + + const imageData = ctx.getImageData(0, 0, w, h); + const pixels = imageData.data; + const candidates = []; + + // Iterate through pixels + for (let i = 0; i < pixels.length; i += 4) { + const r = pixels[i]; + const g = pixels[i + 1]; + const b = pixels[i + 2]; + const a = pixels[i + 3]; + + if (a < 125) continue; // Skip transparent + + const [h, s, l] = rgbToHsl(r, g, b); + + // Filter out very dark, very bright, or very desaturated pixels for the "vibrant" candidate list + // Vibrant: High saturation (s > 0.3), Moderate lightness (0.3 < l < 0.8) + if (s >= 0.3 && l >= 0.3 && l <= 0.8) { + candidates.push({ r, g, b, h, s, l }); } + } - canvas.width = w; - canvas.height = h; - - // Draw image directly at small size - // Note: For best quality downscaling, one might step down, but for color extraction, - // direct browser downscaling is sufficient and much faster/lighter. - ctx.drawImage(imgElement, 0, 0, w, h); - - const imageData = ctx.getImageData(0, 0, w, h); - const pixels = imageData.data; - const candidates = []; - - // Iterate through pixels + // If no candidates found with strict criteria, relax criteria + if (candidates.length === 0) { for (let i = 0; i < pixels.length; i += 4) { const r = pixels[i]; const g = pixels[i + 1]; const b = pixels[i + 2]; const a = pixels[i + 3]; - - if (a < 125) continue; // Skip transparent - + if (a < 125) continue; const [h, s, l] = rgbToHsl(r, g, b); - - // Filter out very dark, very bright, or very desaturated pixels for the "vibrant" candidate list - // Vibrant: High saturation (s > 0.3), Moderate lightness (0.3 < l < 0.8) - if (s >= 0.3 && l >= 0.3 && l <= 0.8) { + // Allow anything not practically black or white + if (l > 0.1 && l < 0.95) { candidates.push({ r, g, b, h, s, l }); } } - - // If no candidates found with strict criteria, relax criteria - if (candidates.length === 0) { - for (let i = 0; i < pixels.length; i += 4) { - const r = pixels[i]; - const g = pixels[i + 1]; - const b = pixels[i + 2]; - const a = pixels[i + 3]; - if (a < 125) continue; - const [h, s, l] = rgbToHsl(r, g, b); - // Allow anything not practically black or white - if (l > 0.1 && l < 0.95) { - candidates.push({ r, g, b, h, s, l }); - } - } - } - - // If still no candidates, return null (caller will handle fallback to default) - if (candidates.length === 0) return null; - - // Sort by saturation (descending) then lightness (proximity to 0.5) - candidates.sort((c1, c2) => { - return c2.s - c1.s || 0.5 - Math.abs(c1.l - 0.5) - (0.5 - Math.abs(c2.l - 0.5)); - }); - - // Pick the top candidate (most vibrant) - // Optionally averaging top N could be done, but simplified "best single pixel" is usually sufficient for "Vibrant" - const best = candidates[0]; - - return hslToHex(best.h, best.s, best.l); - } catch (e) { - throw e; // Re-throw to allow UI to handle CORS retry } + + // If still no candidates, return null (caller will handle fallback to default) + if (candidates.length === 0) return null; + + // Sort by saturation (descending) then lightness (proximity to 0.5) + candidates.sort((c1, c2) => { + return c2.s - c1.s || 0.5 - Math.abs(c1.l - 0.5) - (0.5 - Math.abs(c2.l - 0.5)); + }); + + // Pick the top candidate (most vibrant) + // Optionally averaging top N could be done, but simplified "best single pixel" is usually sufficient for "Vibrant" + const best = candidates[0]; + + return hslToHex(best.h, best.s, best.l); }