简易赛事计时器

在页面左下角添加计时器

// ==UserScript==
// @name         简易赛事计时器
// @namespace    http://xiezheyuan.github.io/
// @version      0.6
// @description  在页面左下角添加计时器
// @author       xiezheyuan
// @license      MIT
// @match        *://*/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=luogu.com.cn
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    let countdown_config = {
        dates: [
            { id: "countdown-to-noip", date: "2024-11-30T08:00:00Z", text: "NOIP 2024" },
            { id: "countdown-to-hnoi", date: "2025-03-01T08:00:00Z", text: "HNOI 2025" },
        ],
        urls: [
            { keyword: ["zhihu"], text: "知乎", verb: "刷" },
            { keyword: ["bilibili"], text: "B站", verb: "刷" },
            { keyword: ["tieba"], text: "贴吧", verb: "看" },
            { keyword: ["generals"], text: "Gen", verb: "打" },
            { keyword: ["florr"], text: "Florr", verb: "玩" }
        ],
        suggest: { url: "https://www.luogu.com.cn/", text: "洛谷" }
    }

    let countdown_dates = countdown_config.dates;
    let countdown_urls = countdown_config.urls;
    let countdown_suggest_url = countdown_config.suggest;
    const time2str = (countDownDate, now) => {
        let distance = countDownDate - now - 8 * 60 * 60 * 1000;
        if (distance < 0) {
            return "已经开始";
        }
        let days = Math.floor(distance / (1000 * 60 * 60 * 24));
        let hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
        let minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
        let seconds = Math.floor((distance % (1000 * 60)) / 1000);
        return days + "天 " + hours + "小时 " + minutes + "分钟 " + seconds + "秒 ";
    }
    const short_time2str = (countDownDate, now) => {
        let distance = countDownDate - now - 8 * 60 * 60 * 1000;
        if (distance < 0) {
            return "(好吧,已经过了)";
        }
        let days = Math.floor(distance / (1000 * 60 * 60 * 24));
        return days + "天";
    }
    const init = () => {
        let sticky = document.createElement("div");
        sticky.id = "sticky-countdown";
        sticky.style.position = "fixed";
        sticky.style.bottom = "10px";
        sticky.style.left = "10px";
        sticky.style.backgroundColor = "rgba(240, 240, 240, 0.6)";
        sticky.style.padding = "10px";
        sticky.style.borderRadius = "3px";
        sticky.style.zIndex = "999";
        sticky.style.display = "flex";
        sticky.style.flexDirection = "column";
        sticky.style.gap = "5px";
        sticky.style.color = "#333";
        countdown_dates = countdown_dates.filter((date) => {
            const time = new Date(date.date).getTime() - 8 * 60 * 60 * 1000;
            return time - new Date().getTime() > 0;
        });
        for (let i = 0; i < countdown_dates.length; i++) {
            const display = i == 0 ? "flex" : "none";
            sticky.innerHTML += `<div id="${countdown_dates[i].id}-div" style="display: ${display}; align-items: center; gap: 5px;">距离 <b>${countdown_dates[i].text}</b> 还剩下<b id="${countdown_dates[i].id}">Loading</b></div>`;
        }
        document.body.appendChild(sticky);
        let isMouseOver = false;
        let timeoutId;
        sticky.addEventListener('mouseenter', () => {
            clearTimeout(timeoutId);
            isMouseOver = true;
            timeoutId = setTimeout(() => {
                if (isMouseOver) {
                    for (let i = 1; i < countdown_dates.length; i++) {
                        document.getElementById(countdown_dates[i].id + "-div").style.display = "flex";
                    }
                }
            }, 100);
        });
        let flag = false;
        for (let i = 0; i < countdown_urls.length; i++) {
            for (let j = 0; j < countdown_urls[i].keyword.length; j++) {
                if (location.href.indexOf(countdown_urls[i].keyword[j]) != -1) {
                    let msg = "";
                    const now = new Date().getTime();
                    for (let k = 0; k < countdown_dates.length; k++) {
                        msg += `距离${countdown_dates[k].text}还剩下${short_time2str(new Date(countdown_dates[k].date).getTime(), now)}。\n`
                    }
                    msg += `时间如此紧迫,怎么还可以${countdown_urls[i].verb}${countdown_urls[i].text}!\n`
                    msg += `继续${countdown_urls[i].verb}${countdown_urls[i].text}请选择【确定】。\n跳转到${countdown_suggest_url.text}请选择【取消】。`
                    if (!confirm(msg)) {
                        location.href = countdown_suggest_url.url;
                    }
                    flag = true;
                    break;
                }
            }
            if (flag) {
                break;
            }
        }
        sticky.addEventListener('mouseleave', () => {
            isMouseOver = false;
            timeoutId = setTimeout(() => {
                if (!isMouseOver) {
                    for (let i = 1; i < countdown_dates.length; i++) {
                        document.getElementById(countdown_dates[i].id + "-div").style.display = "none";
                    }
                }
            }, 100);
        });
        const interval = () => {
            const now = new Date().getTime();
            for (let i = 0; i < countdown_dates.length; i++) {
                let countDownDate = new Date(countdown_dates[i].date).getTime();
                document.getElementById(countdown_dates[i].id).textContent = time2str(countDownDate, now);
            }
        };
        interval();
        setInterval(interval, 1000);
    };
    if(!(window.frames.length != parent.frames.length)) init();
})();