[雪星实验室] Google Calendar 谷歌日历自动上色

【功能测试中, bug反馈:[email protected]】Google日历自动上色、根据匹配到的关键词显示特定颜色,例如: 休|睡、洗漱|收拾|整理|日记|日志、研究|学习|探索|背词|了解、上学|上班|上课、健身|锻练|热身、路上|通勤、料理|做饭、仪式|典礼|祭祀、紧急|重要|考试|测验、群聊|交流|玩|游戏|知乎、电影|看书|阅书|影评,(20210709)加入英文支持

目前为 2022-04-21 提交的版本。查看 最新版本

// ==UserScript==
// @name            [雪星实验室] Google Calendar 谷歌日历自动上色
// @name:zh         [雪星实验室] Google Calendar 谷歌日历自动上色
// @name:en         [SNOLAB] Google Calendar Colorize
// @namespace       https://userscript.snomiao.com/
// @version         0.1.3
// @description    【功能测试中, bug反馈:[email protected]】Google日历自动上色、根据匹配到的关键词显示特定颜色,例如: 休|睡、洗漱|收拾|整理|日记|日志、研究|学习|探索|背词|了解、上学|上班|上课、健身|锻练|热身、路上|通勤、料理|做饭、仪式|典礼|祭祀、紧急|重要|考试|测验、群聊|交流|玩|游戏|知乎、电影|看书|阅书|影评,(20210709)加入英文支持
// @description:zh 【功能测试中, bug反馈:[email protected]】Google日历自动上色、根据匹配到的关键词显示特定颜色,例如: 休|睡、洗漱|收拾|整理|日记|日志、研究|学习|探索|背词|了解、上学|上班|上课、健身|锻练|热身、路上|通勤、料理|做饭、仪式|典礼|祭祀、紧急|重要|考试|测验、群聊|交流|玩|游戏|知乎、电影|看书|阅书|影评,(20210709)加入英文支持
// @description:en 【Functional testing, bug feedback: [email protected]】Google Calendar automatically color, according to the keywords matched to show specific colors, such as: rest|sleep, wash|pack|organize|diary|journal, research|study|explore|recite words|understand, school|work|class, fitness|workout|warm-up, on the road|commute, cooking|cooking ritual|ceremony|sacrifice, urgent|important|exam|quiz, group chat|communicate|play|game|know, movie|watch|read|review, (20210709) Add English support
// @author          [email protected]
// @match           *://calendar.google.com/*
// @grant           none
// ==/UserScript==
//
// updates:
// (20220421) set the text color on dark background to white.
//
// [颜色名 — HTML颜色代码](https://htmlcolorcodes.com/zh/yanse-ming/)
// input: h in [0,360] and s,v in [0,1] - output: r,g,b in [0,1]
// [LCH colors in CSS: what, why, and how? – Lea Verou](https://lea.verou.me/2020/04/lch-colors-in-css-what-why-and-how/)
// [javascript - RGB to XYZ and LAB colours conversion - Stack Overflow](https://stackoverflow.com/questions/15408522/rgb-to-xyz-and-lab-colours-conversion)
// [rgb-lab/color.js at master · antimatter15/rgb-lab](https://github.com/antimatter15/rgb-lab/blob/master/color.js)
// [Color math and programming code examples](https://www.easyrgb.com/en/math.php)

globalThis.googleCalendarColorize?.unload?.();

const D65_2deg = [95.047, 100.0, 108.883];
const rad = (deg) => (deg / 180) * Math.PI;
const 向向内积 = (a, b) => a.map((_, i) => a[i] * b[i]).reduce((a, b) => a + b);
const 向向乘 = (a, b) => a.map((_, i) => a[i] * b[i]);
const 向数除 = (a, b) => a.map((_, i) => a[i] / b);
const lch2lab = (l, c, h_deg) => [
    l,
    Math.cos(rad(h_deg)) * c,
    Math.sin(rad(h_deg)) * c,
];
const lab2xyz = (l, a, b) => {
    let vy = (l + 16) / 116;
    let vx = a / 500 + vy;
    let vz = vy - b / 200;
    let xyz = [vx, vy, vz].map((v) =>
        v ** 3 > 0.008856 ? v ** 3 : (v - 16 / 116) / 7.787
    );
    return 向向乘(xyz, D65_2deg);
};
const xyz2srgb = (x, y, z) => {
    let vxyz = 向数除([x, y, z], 100);
    let vr = 向向内积(vxyz, [3.2406, -1.5372, -0.4986]);
    let vg = 向向内积(vxyz, [-0.9689, 1.8758, 0.0415]);
    let vb = 向向内积(vxyz, [0.0557, -0.204, 1.057]);
    return [vr, vg, vb]
        .map((v) =>
            v > 0.0031308 ? 1.055 * v ** (1 / 2.4) - 0.055 : 12.92 * v
        )
        .map((v) => v * 255);
};
const srgb2str = (r, g, b) =>
    `rgb(${[r, g, b].map((e) => Math.min(Math.max(0, e | 0), 255)).join(',')})`;
// const lch2str = (l, c, h) =>
//     srgb2str(...xyz2srgb(...lab2xyz(...lch2lab(l, c, h))));
const ss_lch2rgba_str = (l, c, h) =>
    srgb2str(...xyz2srgb(...lab2xyz(...lch2lab(l, c, h ** 1.2 * 300 + 30))));
// document.body.style.background = lch2str(100, 80, 30)
const 深色事件 = {
    // 一般红到青,如果写了就用写的颜色
    'urgent|important|exam|quiz|quarrel|accident|紧急|重要|考试|测验|吵架|事故':
        'red',
    'ritual|ceremony|sacrifice|仪式|典礼|祭祀': '',
    'groupchat|communication|know|blog|little red book|video|jitter|bilibili|B station|群聊|交流|知乎|微博|小红书|视频|抖音|bilibili|B站':
        '',
    'play|games|玩|游戏': '',
    'bill|payment|finance|economic|账单|还款|金融|经济': '',
    'Study|Memorize|Understand|Read|Movies|Watch|Read|Books|Reviews|The|学习|背词|了解|阅读|电影|看书|阅书|影评|《':
        '',
    'Think|Research|R&D|Develop|Research|Explore|思考|科研|研发|开发|研究|探索':
        '',
};
const 浅色事件 = {
    // 从浅红到天蓝
    'shop|buy|购物|购买': '',
    'rest|sleep|休|睡': '',
    'shower|wash|clean|organize|clean up|洗澡|洗漱|收拾|整理|大扫除': '',
    'workout|body building|warm up|cook|cook|eat|exercise|健身|锻练|热身|料理|做饭|吃|运动':
        '',
    'diary|schedule|journal|jour|日记|日程|日志': '',
    'maintenance|maintain|Operation|ops|Configuration|conf|维护|运维|配置': '',
    'On the road|commute|school|work|class|course|路上|通勤|上学|上班|上课|课程':
        '',
};
const lch表值色带转换 = (预设颜色表, s, e) =>
    Object.fromEntries(
        Object.entries(预设颜色表).map(([k, v], i, a) => [
            k,
            v || ss_lch2rgba_str(s, e, i / a.length),
        ])
    );
Object.assign(深色事件, lch表值色带转换(深色事件, 70, 80));
Object.assign(浅色事件, lch表值色带转换(浅色事件, 100, 20));

const 更新颜色 = () => {
    const 事件元素列 = [...document.querySelectorAll('div[data-eventid]')];
    const 颜色分析 = 事件元素列.map((e) => ({
        元素: e,
        文本: e.textContent,
        颜色: window.getComputedStyle(e).getPropertyValue('background-color'),
    }));
    颜色分析.forEach(({ 元素, 文本 }) =>
        Object.keys(浅色事件)
            .filter((正则) => 文本.match(new RegExp(正则, 'i')))
            .sort(
                (正则1, 正则2) =>
                    文本.match(new RegExp(正则1, 'i')).index -
                    文本.match(new RegExp(正则2, 'i')).index
            )
            .forEach((正则) => (元素.style.backgroundColor = 浅色事件[正则]))
    );
    颜色分析.forEach(({ 元素, 文本 }) =>
        Object.keys(深色事件)
            .filter((正则) => 文本.match(new RegExp(正则, 'i')))
            .sort(
                (正则1, 正则2) =>
                    文本.match(new RegExp(正则1, 'i')).index -
                    文本.match(new RegExp(正则2, 'i')).index
            )
            .forEach((正则) => {
                // console.log(元素);
                元素.style.backgroundColor = 深色事件[正则];
                [...元素.querySelectorAll('span,div')].map(
                    (e) => (e.style.color = 'white')
                );
            })
    );
};

更新颜色();

const 节流 =
    (
        间隔,
        函数 = async () => null,
        提示函数 = async () => null,
        上次执行 = 0
    ) =>
    async (...参数) =>
        +new Date() - 上次执行 > 间隔
            ? ((上次执行 = +new Date()), await 函数(...参数))
            : await 提示函数(...参数);
const 防抖 =
    (
        间隔,
        函数 = async () => null,
        提示函数 = async () => null,
        timerId = null
    ) =>
    (...参数) =>
        new Promise(
            (resolve) => (
                timerId && (clearTimeout(timerId), resolve(提示函数(...参数))),
                (timerId = setTimeout(() => resolve(函数(...参数)), 间隔))
            )
        );
const 节流防抖 = (间隔, 函数 = async () => null, 提示函数 = async () => null) =>
    节流(间隔, 函数, 防抖(间隔, 函数, 提示函数));
const 刷新函数 = 节流防抖(10e3 /* 10s */, () => !document.hidden && 更新颜色());
const 主动刷新函数 = 节流防抖(200, () => !document.hidden && 更新颜色());

// オブザーバインスタンスを作成
const 目标 = document.documentElement || document.body;
const 监视配置 = { attributes: false, childList: true, characterData: false };
const 页面变动监视器 = new MutationObserver((mutations) => {
    if (!mutations.some((record) => record.addedNodes.length)) return;
    页面变动监视器.disconnect();
    刷新函数();
    目标 && 页面变动监视器.observe(目标, 监视配置);
});
页面变动监视器.observe(目标, 监视配置);
const onvisibilitychange = () => setTimeout(刷新函数, 100);
const onmouseup = () => setTimeout(主动刷新函数, 100);
document.addEventListener('visibilitychange', onvisibilitychange, false);
document.addEventListener('mouseup', onmouseup, false);
document.addEventListener('keyup', () => setTimeout(主动刷新函数, 100), false);
window.addEventListener('load', 刷新函数, false);

刷新函数();
const unload = () => {
    页面变动监视器.disconnect();
    document.removeEventListener('visibilitychange', onvisibilitychange, false);
    document.removeEventListener('mouseup', onmouseup, false);
    document.removeEventListener(
        'keyup',
        () => setTimeout(主动刷新函数, 100),
        false
    );
    window.removeEventListener('load', 刷新函数, false);
};
globalThis.googleCalendarColorize = { unload };

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址