Last active
July 25, 2024 21:09
-
-
Save Explosion-Scratch/bb7e6e9db855cd51bb860e132ee3cb05 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Get accent color | |
// @namespace mailto:[email protected] | |
// @version 2024-07-25 | |
// @description try to take over the world! | |
// @author You | |
// @match https://open.spotify.com/* | |
// @require https://cdnjs.cloudflare.com/ajax/libs/vibrant.js/1.0.0/Vibrant.min.js | |
// @icon https://www.google.com/s2/favicons?sz=64&domain=spotify.com | |
// @grant none | |
// ==/UserScript== | |
let IMAGE_QUERY_SELECTORS = { | |
"spotify.com": "img[data-testid*=cover-art-image]", | |
}; | |
// Can be one of: | |
// Vibrant | |
// Muted | |
// DarkVibrant | |
// DarkMuted | |
// LightVibrant | |
// LightMuted | |
const PALETTE_FUNC = "DarkVibrant"; | |
(function () { | |
"use strict"; | |
console.log("ACCENT COLOR RUNNING"); | |
let site = Object.entries(IMAGE_QUERY_SELECTORS).find(i => location.host.includes(i[0])) | |
const QS = `img:hover${site ? ", " + site : ""}` | |
const getImage = () => document.querySelector(QS); | |
setInterval(() => color(getImage()), 500); | |
let bgEl; | |
function createEl() { | |
if (bgEl) { | |
return bgEl; | |
} | |
let e = document.createElement("div"); | |
e.id = "current_album_accent"; | |
Object.assign(e.style, { | |
position: "fixed", | |
top: 0, | |
right: 0, | |
width: "5px", | |
height: "5px", | |
display: "block", | |
}); | |
document.body.appendChild(e); | |
bgEl = e; | |
return e; | |
} | |
const COLORS = {}; | |
async function color(el) { | |
if (!el) { | |
return; | |
} | |
if (COLORS[el.src]) { | |
return COLORS[el.src]; | |
} | |
let url = await fetch(el.src) | |
.then((r) => r.blob()) | |
.then((b) => URL.createObjectURL(b)); | |
let img = new Image(); | |
img.src = url; | |
await new Promise((r) => (img.onload = r)); | |
console.log("IMG loaded"); | |
let out = new Vibrant(img).swatches(); | |
window.COLOR = out; | |
console.log(out); | |
out = (out[PALETTE_FUNC] || out[Object.entries(out).find(i => i[1])[0]]).getHex(); | |
createEl().style.backgroundColor = out; | |
URL.revokeObjectURL(url); | |
console.log("COLOR:", out); | |
COLORS[el.src] = out; | |
return out; | |
} | |
function getAverageRGB(imgEl) { | |
var blockSize = 5, // only visit every 5 pixels | |
defaultRGB = { r: 0, g: 0, b: 0 }, // for non-supporting envs | |
canvas = document.createElement("canvas"), | |
context = canvas.getContext && canvas.getContext("2d"), | |
data, | |
width, | |
height, | |
i = -4, | |
length, | |
rgb = { r: 0, g: 0, b: 0 }, | |
count = 0; | |
if (!context) { | |
return defaultRGB; | |
} | |
height = canvas.height = | |
imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height; | |
width = canvas.width = | |
imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width; | |
context.drawImage(imgEl, 0, 0); | |
try { | |
data = context.getImageData(0, 0, width, height); | |
} catch (e) { | |
/* security error, img on diff domain */ | |
return defaultRGB; | |
} | |
length = data.data.length; | |
while ((i += blockSize * 4) < length) { | |
++count; | |
rgb.r += data.data[i]; | |
rgb.g += data.data[i + 1]; | |
rgb.b += data.data[i + 2]; | |
} | |
// ~~ used to floor values | |
rgb.r = ~~(rgb.r / count); | |
rgb.g = ~~(rgb.g / count); | |
rgb.b = ~~(rgb.b / count); | |
return rgb; | |
} | |
})(); | |
async function watch(fn, onchange = () => {}, int = 100) { | |
let r = await fn(); | |
let i = setInterval(async () => { | |
let new_r = await fn(); | |
if (new_r !== r) { | |
onchange(new_r, r); | |
} | |
r = new_r; | |
}, int); | |
return () => { | |
clearInterval(i); | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment