fix: solid cover-color NP background via canvas extraction
Replace saturated blur filter with actual dominant-color extraction: fetch cover as blob (avoids canvas CORS taint), draw on 24x24 canvas, find most vivid pixel, darken to ~28% for a moody solid background. Blurred bg layers hidden when mode is active. Transitions smoothly between songs via CSS transition on background. Renamed setting label to "Einfarbiger Player-Hintergrund". Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
20545f71be
commit
9ab3dab508
3 files changed
+47
-10
No files matched your search
+43
-2
@@ -484,9 +484,49 @@ export function updatePlayerUI(s, _skipMediaSession = false) {
|
||||
if (_npCv && _npCv !== _npBgLastUrl) { const _pre = new Image(); _pre.src = _npCv; }
|
||||
}
|
||||
|
||||
// Apply/remove dynamic-color mode based on current setting.
|
||||
// ── Solid cover-color background ────────────────────────────────────────────
|
||||
// Fetch the cover as a blob (bypasses canvas CORS taint), draw on a tiny
|
||||
// canvas, find the most vivid pixel, darken it to a moody solid background.
|
||||
let _npColorActiveUrl = '';
|
||||
async function _extractAndApplyColor(cv) {
|
||||
if (!cv || !S.cfg?.coverColorBg) return;
|
||||
if (cv === _npColorActiveUrl) return;
|
||||
_npColorActiveUrl = cv;
|
||||
try {
|
||||
const res = await fetch(cv, { signal: AbortSignal.timeout(6000) });
|
||||
const blob = await res.blob();
|
||||
const burl = URL.createObjectURL(blob);
|
||||
const img = await new Promise((ok, err) => {
|
||||
const i = new Image(); i.onload = () => ok(i); i.onerror = err; i.src = burl;
|
||||
});
|
||||
URL.revokeObjectURL(burl);
|
||||
if (cv !== _npColorActiveUrl) return; // superseded by next song
|
||||
const c = document.createElement('canvas'); c.width = c.height = 24;
|
||||
const ctx = c.getContext('2d'); ctx.drawImage(img, 0, 0, 24, 24);
|
||||
const d = ctx.getImageData(0, 0, 24, 24).data;
|
||||
let br = 20, bg2 = 20, bb = 40, best = 0;
|
||||
for (let i = 0; i < d.length; i += 4) {
|
||||
const r = d[i], g = d[i+1], b = d[i+2];
|
||||
const mx = Math.max(r,g,b), mn = Math.min(r,g,b);
|
||||
const sat = mx > 0 ? (mx-mn)/mx : 0;
|
||||
const lum = (r+g+b)/3;
|
||||
const score = sat * 2 + (lum > 30 && lum < 220 ? 1 : 0);
|
||||
if (score > best) { best = score; br = r; bg2 = g; bb = b; }
|
||||
}
|
||||
// Darken significantly for a moody solid bg
|
||||
const el = document.getElementById('np-overlay');
|
||||
if (el && S.cfg?.coverColorBg)
|
||||
el.style.setProperty('--np-solid', `${Math.round(br*.28)},${Math.round(bg2*.28)},${Math.round(bb*.28)}`);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
export function updateNpColorMode() {
|
||||
document.getElementById('np-overlay')?.classList.toggle('dynamic-color', !!S.cfg?.coverColorBg);
|
||||
const el = document.getElementById('np-overlay');
|
||||
if (!el) return;
|
||||
const on = !!S.cfg?.coverColorBg;
|
||||
el.classList.toggle('dynamic-color', on);
|
||||
if (!on) { el.style.removeProperty('--np-solid'); _npColorActiveUrl = ''; }
|
||||
else if (_npBgLastUrl) _extractAndApplyColor(_npBgLastUrl);
|
||||
}
|
||||
|
||||
let _npBgCurr = 'a';
|
||||
@@ -494,6 +534,7 @@ let _npBgLastUrl = '';
|
||||
function _crossfadeNpBg(cv) {
|
||||
if ((cv || '') === _npBgLastUrl) return;
|
||||
_npBgLastUrl = cv || '';
|
||||
if (S.cfg?.coverColorBg) _extractAndApplyColor(cv || '');
|
||||
const doFade = () => {
|
||||
const currEl = document.getElementById(`np-bg-${_npBgCurr}`);
|
||||
const nextId = _npBgCurr === 'a' ? 'b' : 'a';
|
||||
|
||||
Reference in new issue
Block a user