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;