js fixes
This commit is contained in:
parent
c3fd191072
commit
a419f38024
4 changed files with 62 additions and 76 deletions
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
7
js/ui.js
7
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue