From 9ab3dab508efdcfefe56efa477aec51a35da939a Mon Sep 17 00:00:00 2001 From: Honey Date: Thu, 28 May 2026 00:36:32 +0200 Subject: [PATCH] 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 --- index.html | 5 +---- src/player.js | 45 +++++++++++++++++++++++++++++++++++++++++++-- styles.css | 7 +++---- 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/index.html b/index.html index b80583f..b7f9976 100644 --- a/index.html +++ b/index.html @@ -664,10 +664,7 @@
-
- Dynamische Hintergrundfarbe -
Jetzt-Läuft-Hintergrund nach Cover-Hauptfarbe
-
+ Einfarbiger Player-Hintergrund
diff --git a/src/player.js b/src/player.js index 7e20340..dd8a8a0 100644 --- a/src/player.js +++ b/src/player.js @@ -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'; diff --git a/styles.css b/styles.css index f807cc1..74fe185 100644 --- a/styles.css +++ b/styles.css @@ -590,10 +590,9 @@ button:focus{outline:none} will-change:opacity; z-index:0; } -/* Dynamic cover color mode: more vivid/saturated background */ -.np-overlay.dynamic-color .np-bg{ - filter:blur(60px) brightness(.5) saturate(3); -} +/* Solid cover-color mode: hide blurred layers, use extracted color as background */ +.np-overlay.dynamic-color{background:rgb(var(--np-solid,20,20,40));transition:background .5s ease,transform .35s cubic-bezier(.4,0,.2,1)} +.np-overlay.dynamic-color .np-bg{opacity:0!important;pointer-events:none} .np-inner{ position:relative;z-index:1;