// ==UserScript==
// @name Web3 OKX Color Theme Changer
// @namespace http://tampermonkey.net/
// @version 1.2
// @description Automaticly color changer, Written by ai
// @author mamiis
// @match https://*.okx.com/*
// @grant none
// @license MIT
// ==/UserScript==
(function(){
'use strict';
const UP_COLOR = {r:20, g:167, b:255}; // hedef mavi
const DOWN_COLOR = {r:126,g:87, b:194}; // hedef mor
const TRANSFORM_ALPHA = true;
// Geliştirilmiş grafik filtre ayarları
const CHART_FILTERS = {
green: {
hue: 210, // Mavi tonu
saturation: 1.6,
brightness: 1.05
},
red: {
hue: 280, // Mor tonu
saturation: 1.3,
brightness: 1.1
}
};
// Regex'ler
const hexRegex = /#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\b/g;
const rgbRegex = /rgba?\([^\)]+\)/gi;
const hslRegex = /hsla?\([^\)]+\)/gi;
// yardımcı DOM elemanı
const _tmp = document.createElement('div');
_tmp.style.position = 'absolute';
_tmp.style.left = '-9999px';
_tmp.style.width = _tmp.style.height = '1px';
document.documentElement.appendChild(_tmp);
/* ---------- renk parse / convert yardımcıları ---------- */
function clamp(v, a=0, b=255){ return Math.max(a, Math.min(b, v)); }
function parseHexColor(str){
let s = str.replace('#','');
if(s.length === 3){
s = s.split('').map(ch => ch+ch).join('');
} else if(s.length === 4){
s = s.split('').map(ch => ch+ch).join('');
}
let r=0,g=0,b=0,a=1;
if(s.length === 6){
r = parseInt(s.substr(0,2),16);
g = parseInt(s.substr(2,2),16);
b = parseInt(s.substr(4,2),16);
} else if(s.length === 8){
r = parseInt(s.substr(0,2),16);
g = parseInt(s.substr(2,2),16);
b = parseInt(s.substr(4,2),16);
a = parseInt(s.substr(6,2),16) / 255;
}
return {r,g,b,a};
}
function parseRgbString(str){
const nums = str.match(/[\d\.%]+/g);
if(!nums) return null;
let [r,g,b,a] = [0,0,0,1];
if(nums.length >= 3){
const parseComponent = (v) => {
if(v.endsWith('%')) return Math.round(parseFloat(v) * 2.55);
return Math.round(parseFloat(v));
};
r = parseComponent(nums[0]);
g = parseComponent(nums[1]);
b = parseComponent(nums[2]);
}
if(nums.length >= 4) a = parseFloat(nums[3]);
return {r,g,b,a};
}
function parseHslString(str){
const parts = str.match(/[\d\.%]+/g);
if(!parts) return null;
let h = parseFloat(parts[0]);
let s = parseFloat(parts[1]) / 100;
let l = parseFloat(parts[2]) / 100;
let a = parts.length >= 4 ? parseFloat(parts[3]) : 1;
const rgb = hslToRgb(h, s, l);
return {r: Math.round(rgb.r), g: Math.round(rgb.g), b: Math.round(rgb.b), a};
}
function hslToRgb(h, s, l){
h = ((h % 360) + 360) % 360;
const c = (1 - Math.abs(2*l - 1)) * s;
const x = c * (1 - Math.abs((h / 60) % 2 - 1));
const m = l - c/2;
let r=0,g=0,b=0;
if(h < 60) { r=c; g=x; b=0; }
else if(h < 120) { r=x; g=c; b=0; }
else if(h < 180) { r=0; g=c; b=x; }
else if(h < 240) { r=0; g=x; b=c; }
else if(h < 300) { r=x; g=0; b=c; }
else { r=c; g=0; b=x; }
return { r: (r+m)*255, g: (g+m)*255, b: (b+m)*255 };
}
function rgbToHsl(r,g,b){
r/=255; g/=255; b/=255;
const max = Math.max(r,g,b), min = Math.min(r,g,b);
let h=0,s=0,l=(max+min)/2;
if(max !== min){
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max){
case r: h = ((g - b) / d + (g < b ? 6 : 0)) * 60; break;
case g: h = ((b - r) / d + 2) * 60; break;
case b: h = ((r - g) / d + 4) * 60; break;
}
}
return {h, s, l};
}
function parseColorString(str){
if(!str) return null;
str = str.trim();
if(str.toLowerCase() === 'transparent' || str === 'none') return {r:0,g:0,b:0,a:0};
try{
if(str[0] === '#') return parseHexColor(str);
if(str.toLowerCase().startsWith('rgb')) return parseRgbString(str);
if(str.toLowerCase().startsWith('hsl')) return parseHslString(str);
_tmp.style.color = '';
_tmp.style.color = str;
const cs = getComputedStyle(_tmp).color;
return parseRgbString(cs);
}catch(e){
return null;
}
}
function rgbaToCss(o){
const a = (typeof o.a === 'number') ? o.a : 1;
return `rgba(${Math.round(o.r)}, ${Math.round(o.g)}, ${Math.round(o.b)}, ${+a.toFixed(3)})`;
}
/* ---------- renk tespit mantığı ---------- */
function shouldConvertByHue(rgba){
if(!rgba) return null;
if(rgba.a === 0) return null;
const {h,s,l} = rgbToHsl(rgba.r, rgba.g, rgba.b);
if(s > 0.08 && h >= 70 && h <= 170) return 'greenish';
if(s > 0.08 && (h <= 25 || h >= 335)) return 'reddish';
return null;
}
function convertBasedOnDetection(rgba){
const det = shouldConvertByHue(rgba);
if(!det) return rgba;
let {h, s, l} = rgbToHsl(rgba.r, rgba.g, rgba.b);
if(det === 'greenish'){
h = CHART_FILTERS.green.hue;
s *= CHART_FILTERS.green.saturation;
l *= CHART_FILTERS.green.brightness;
}
if(det === 'reddish'){
h = CHART_FILTERS.red.hue;
s *= CHART_FILTERS.red.saturation;
l *= CHART_FILTERS.red.brightness;
}
s = clamp(s, 0, 1);
l = clamp(l, 0, 1);
const rgb = hslToRgb(h, s, l);
return {r: Math.round(rgb.r), g: Math.round(rgb.g), b: Math.round(rgb.b), a: rgba.a};
}
/* ---------- text içindeki renk tokenlarını değiştir ---------- */
function replaceColorTokensInText(text){
if(!text || typeof text !== 'string') return text;
let out = text;
out = out.replace(hexRegex, (m) => {
const p = parseColorString(m);
if(!p) return m;
const conv = convertBasedOnDetection(p);
if(conv && (conv.r !== p.r || conv.g !== p.g || conv.b !== p.b || conv.a !== p.a)){
return rgbaToCss(conv);
}
return m;
});
out = out.replace(rgbRegex, (m) => {
const p = parseColorString(m);
if(!p) return m;
const conv = convertBasedOnDetection(p);
if(conv && (conv.r !== p.r || conv.g !== p.g || conv.b !== p.b || conv.a !== p.a)){
return rgbaToCss(conv);
}
return m;
});
out = out.replace(hslRegex, (m) => {
const p = parseColorString(m);
if(!p) return m;
const conv = convertBasedOnDetection(p);
if(conv && (conv.r !== p.r || conv.g !== p.g || conv.b !== p.b || conv.a !== p.a)){
return rgbaToCss(conv);
}
return m;
});
return out;
}
/* ---------- stylesheet / style tag işleme ---------- */
function processCssRuleList(rules){
for(let i=0;i<rules.length;i++){
const rule = rules[i];
try{
if(rule.type === CSSRule.STYLE_RULE){
const style = rule.style;
for(let j=0;j<style.length;j++){
const prop = style[j];
const val = style.getPropertyValue(prop);
const newVal = replaceColorTokensInText(val);
if(newVal !== val){
try{ style.setProperty(prop, newVal, style.getPropertyPriority(prop)); }catch(e){}
}
}
} else if(rule.cssRules && rule.cssRules.length){
processCssRuleList(rule.cssRules);
}
}catch(e){
continue;
}
}
}
function processStyleSheets(){
for(const sheet of document.styleSheets){
try{
if(!sheet.cssRules) continue;
processCssRuleList(sheet.cssRules);
}catch(e){
continue;
}
}
}
function processStyleTags(){
document.querySelectorAll('style').forEach(tag=>{
try{
const old = tag.textContent;
const neu = replaceColorTokensInText(old);
if(neu !== old) tag.textContent = neu;
}catch(e){}
});
}
/* ---------- inline attrs ve SVG fill/stroke ---------- */
function processInlineAndSvg(root=document){
root.querySelectorAll('[style]').forEach(el=>{
try{
const old = el.getAttribute('style');
const neu = replaceColorTokensInText(old);
if(neu !== old) el.setAttribute('style', neu);
}catch(e){}
});
root.querySelectorAll('[fill],[stroke]').forEach(el=>{
['fill','stroke'].forEach(attr=>{
try{
if(el.hasAttribute(attr)){
const old = el.getAttribute(attr);
const neu = replaceColorTokensInText(old);
if(neu !== old) el.setAttribute(attr, neu);
}
}catch(e){}
});
});
}
/* ---------- computed styles ---------- */
const computedCheckProps = [
'background-color','color',
'border-top-color','border-right-color','border-bottom-color','border-left-color',
'outline-color','caret-color','column-rule-color'
];
function isTransparentValue(v){
if(!v) return true;
v = v.trim();
return v === 'transparent' || v === 'rgba(0, 0, 0, 0)' || v === 'initial' || v === 'none';
}
function processComputedStylesBatch(elements, start=0){
const batch = 250;
const end = Math.min(elements.length, start + batch);
for(let i=start;i<end;i++){
const el = elements[i];
try{
const cs = getComputedStyle(el);
computedCheckProps.forEach(prop=>{
try{
const val = cs.getPropertyValue(prop);
if(!val || isTransparentValue(val)) return;
const parsed = parseColorString(val);
if(!parsed) return;
const conv = convertBasedOnDetection(parsed);
if(conv && (conv.r !== parsed.r || conv.g !== parsed.g || conv.b !== parsed.b || conv.a !== parsed.a)){
el.style.setProperty(prop, rgbaToCss(conv), 'important');
}
}catch(e){}
});
try{
const bs = cs.getPropertyValue('box-shadow');
if(bs && bs !== 'none' && /#|rgba?\(|hsla?\(/i.test(bs)){
const newBs = replaceColorTokensInText(bs);
if(newBs !== bs) el.style.setProperty('box-shadow', newBs, 'important');
}
}catch(e){}
try{
const bg = cs.getPropertyValue('background-image');
if(bg && bg !== 'none' && /#|rgba?\(|hsla?\(/i.test(bg)){
const newBg = replaceColorTokensInText(bg);
if(newBg !== bg) el.style.setProperty('background-image', newBg, 'important');
}
}catch(e){}
}catch(e){}
}
if(end < elements.length){
setTimeout(()=> processComputedStylesBatch(elements, end), 20);
}
}
function processAllComputedStylesRoot(root=document){
const elements = Array.from(root.querySelectorAll('*'));
processComputedStylesBatch(elements, 0);
}
/* ---------- canvas context patch ---------- */
function patchCanvasContext(ctx){
try{
if(!ctx) return;
if(ctx.__colorPatched) return;
ctx.__colorPatched = true;
const convertMaybe = (v) => {
if(typeof v !== 'string') return v;
const parsed = parseColorString(v);
if(!parsed) return v;
const conv = convertBasedOnDetection(parsed);
if(conv && (conv.r !== parsed.r || conv.g !== parsed.g || conv.b !== parsed.b || conv.a !== parsed.a)){
return rgbaToCss(conv);
}
return v;
};
let _fill = ctx.fillStyle;
let _stroke = ctx.strokeStyle;
Object.defineProperty(ctx, 'fillStyle', {
configurable: true,
enumerable: true,
get(){ return _fill; },
set(v){ _fill = convertMaybe(v); }
});
Object.defineProperty(ctx, 'strokeStyle', {
configurable: true,
enumerable: true,
get(){ return _stroke; },
set(v){ _stroke = convertMaybe(v); }
});
let _shadow = ctx.shadowColor;
Object.defineProperty(ctx, 'shadowColor', {
configurable: true,
enumerable: true,
get(){ return _shadow; },
set(v){ _shadow = convertMaybe(v); }
});
}catch(e){}
}
// Canvas context override (chart canvas hariç)
const origGetCtx = HTMLCanvasElement.prototype.getContext;
HTMLCanvasElement.prototype.getContext = function(type, ...args){
const ctx = origGetCtx.apply(this, [type, ...args]);
try{
if(type === '2d' && ctx){
try{
if(this.closest && this.closest('.tv-lightweight-charts')) {
return ctx;
}
}catch(e){}
patchCanvasContext(ctx);
}
}catch(e){}
return ctx;
};
/* ---------- GELİŞTİRİLMİŞ GRAFİK RENK KONTROLÜ ---------- */
function applyChartColorFilters() {
try {
const chartStyle = document.createElement('style');
chartStyle.textContent = `
/* TradingView chart renk filtreleri */
.tv-lightweight-charts {
filter: none !important;
}
/* Yeşil mumları maviye çevir */
.tv-lightweight-charts [fill="#25a750"],
.tv-lightweight-charts [stroke="#25a750"],
.tv-lightweight-charts [fill*="25a750"],
.tv-lightweight-charts [stroke*="25a750"] {
fill: ${rgbaToCss(UP_COLOR)} !important;
stroke: ${rgbaToCss(UP_COLOR)} !important;
}
/* Kırmızı mumları mora çevir */
.tv-lightweight-charts [fill="#ca3f64"],
.tv-lightweight-charts [stroke="#ca3f64"],
.tv-lightweight-charts [fill*="ca3f64"],
.tv-lightweight-charts [stroke*="ca3f64"] {
fill: ${rgbaToCss(DOWN_COLOR)} !important;
stroke: ${rgbaToCss(DOWN_COLOR)} !important;
}
/* Canvas tabanlı grafikler için CSS filtre*/
.tv-lightweight-charts canvas {
filter: hue-rotate(0deg) saturate(1.2) !important;
}
/* Arka plan renkleri */
.tv-lightweight-charts [fill*="rgba(37, 167, 80"],
.tv-lightweight-charts [style*="25a750"] {
fill: ${rgbaToCss({...UP_COLOR, a: 0.3})} !important;
}
.tv-lightweight-charts [fill*="rgba(202, 63, 100"],
.tv-lightweight-charts [style*="ca3f64"] {
fill: ${rgbaToCss({...DOWN_COLOR, a: 0.3})} !important;
}
/* Boost ikonları */
.nav-item.nav-boost-item.nav-right-item > a.nav-item.nav-boost.icon {
background-color: ${rgbaToCss({...UP_COLOR,a:0.15})} !important;
}
.nav-item.nav-boost-item.nav-right-item img.nav-boost-icon {
filter: hue-rotate(210deg) saturate(1.6) brightness(1.05) !important;
}
`;
document.head.appendChild(chartStyle);
} catch (e) {
console.error('Chart style hatası:', e);
}
}
/* ---------- GRAFİK CANVAS RENK DEĞİŞİMİ ---------- */
function monitorChartColors() {
// Canvas fill/stroke override for chart colors
const origFill = CanvasRenderingContext2D.prototype.fill;
const origStroke = CanvasRenderingContext2D.prototype.stroke;
const origFillRect = CanvasRenderingContext2D.prototype.fillRect;
CanvasRenderingContext2D.prototype.fill = function() {
if (this.fillStyle && typeof this.fillStyle === 'string') {
const parsed = parseColorString(this.fillStyle);
if (parsed) {
const converted = convertBasedOnDetection(parsed);
if (converted && (converted.r !== parsed.r || converted.g !== parsed.g || converted.b !== parsed.b)) {
this.fillStyle = rgbaToCss(converted);
}
}
}
origFill.apply(this, arguments);
};
CanvasRenderingContext2D.prototype.stroke = function() {
if (this.strokeStyle && typeof this.strokeStyle === 'string') {
const parsed = parseColorString(this.strokeStyle);
if (parsed) {
const converted = convertBasedOnDetection(parsed);
if (converted && (converted.r !== parsed.r || converted.g !== parsed.g || converted.b !== parsed.b)) {
this.strokeStyle = rgbaToCss(converted);
}
}
}
origStroke.apply(this, arguments);
};
CanvasRenderingContext2D.prototype.fillRect = function(x, y, w, h) {
if (this.fillStyle && typeof this.fillStyle === 'string') {
const parsed = parseColorString(this.fillStyle);
if (parsed) {
const converted = convertBasedOnDetection(parsed);
if (converted && (converted.r !== parsed.r || converted.g !== parsed.g || converted.b !== parsed.b)) {
this.fillStyle = rgbaToCss(converted);
}
}
}
origFillRect.apply(this, arguments);
};
}
/* ---------- mutation observer & iş akışı ---------- */
function processNodeAndChildren(node){
try{
if(node.nodeType !== 1) return;
processInlineAndSvg(node);
processAllComputedStylesRoot(node);
}catch(e){}
}
const mo = new MutationObserver((mutations)=>{
const added = [];
for(const m of mutations){
if(m.type === 'attributes'){
const target = m.target;
try{
if(m.attributeName === 'style' || m.attributeName === 'class' || m.attributeName === 'fill' || m.attributeName === 'stroke'){
processNodeAndChildren(target);
}
}catch(e){}
}
if(m.addedNodes && m.addedNodes.length){
m.addedNodes.forEach(n => {
if(n.nodeType === 1) added.push(n);
});
}
}
if(added.length){
setTimeout(()=> added.forEach(n => processNodeAndChildren(n)), 10);
}
});
function kickAll(){
try{
processStyleSheets();
processStyleTags();
processInlineAndSvg(document);
processAllComputedStylesRoot(document);
applyChartColorFilters();
}catch(e){}
}
function init() {
kickAll();
mo.observe(document.body || document.documentElement, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['style', 'class', 'fill', 'stroke']
});
monitorChartColors();
// Sayfa yüklendikten sonra tekrar çalıştır
window.addEventListener('load', () => {
setTimeout(kickAll, 500);
setTimeout(kickAll, 2000);
setTimeout(kickAll, 5000);
});
// URL değişimlerini izle
let lastUrl = location.href;
setInterval(() => {
if (location.href !== lastUrl) {
lastUrl = location.href;
setTimeout(kickAll, 1000);
}
}, 1000);
}
// Başlat
if(document.body){
init();
} else {
window.addEventListener('DOMContentLoaded', init);
}
})();