定时关闭网页

一个炫酷的定时关闭网页工具)

当前为 2025-08-18 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         定时关闭网页
// @namespace    https://github.com/yingchen6
// @version      0.7
// @description  一个炫酷的定时关闭网页工具)
// @author       yingchen6
// @match        *://*/*
// @grant        GM_addStyle
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    let timerId = null;
    let remainingSeconds = 0;
    let totalSeconds = 0;
    let ball = null;
    let canvas = null;
    let paused = false;

    function formatTime(seconds) {
        const m = Math.floor(seconds / 60);
        const s = seconds % 60;
        return `${m}:${s.toString().padStart(2,'0')}`;
    }

    function createBall(minutes) {
        totalSeconds = remainingSeconds = minutes * 60;
        paused = false;

        if (ball) ball.remove();

        ball = document.createElement("div");
        ball.id = "timer-ball";
        ball.style.position = "fixed";
        ball.style.top = "20px";
        ball.style.left = "20px";
        ball.style.width = "120px";
        ball.style.height = "120px";
        ball.style.borderRadius = "50%";
        ball.style.zIndex = "999999";
        ball.style.cursor = "grab";
        ball.style.display = "flex";
        ball.style.justifyContent = "center";
        ball.style.alignItems = "center";
        ball.style.userSelect = "none";
        ball.style.background = "radial-gradient(circle at 30% 30%, #4facfe, #00f2fe)";
        ball.style.boxShadow = "0 8px 25px rgba(0,0,0,0.5)";
        document.body.appendChild(ball);

        canvas = document.createElement("canvas");
        canvas.width = 120;
        canvas.height = 120;
        canvas.style.position = "absolute";
        canvas.style.top = "0";
        canvas.style.left = "0";
        ball.appendChild(canvas);

        const label = document.createElement("div");
        label.id = "timer-label";
        label.style.position = "absolute";
        label.style.color = "white";
        label.style.fontWeight = "bold";
        label.style.fontSize = "18px";
        ball.appendChild(label);

        const pauseBtn = document.createElement("div");
        pauseBtn.id = "pause-btn";
        pauseBtn.style.position = "absolute";
        pauseBtn.style.bottom = "5px";
        pauseBtn.style.fontSize = "12px";
        pauseBtn.style.color = "#fff";
        pauseBtn.style.background = "rgba(0,0,0,0.3)";
        pauseBtn.style.borderRadius = "6px";
        pauseBtn.style.padding = "2px 6px";
        pauseBtn.style.cursor = "pointer";
        pauseBtn.textContent = "暂停";
        ball.appendChild(pauseBtn);

        pauseBtn.addEventListener("click", (e)=>{
            e.stopPropagation(); // 防止触发球点击事件
            paused = !paused;
            pauseBtn.textContent = paused ? "继续" : "暂停";
        });

        // 拖拽 + 点击判定
        let isDown = false;
        let isDragging = false;
        let startX = 0, startY = 0;
        let downTime = 0;

        ball.addEventListener("mousedown", (e)=>{
            isDown = true;
            isDragging = false;
            startX = e.clientX;
            startY = e.clientY;
            downTime = Date.now();
            ball.style.cursor="grabbing";
        });

        document.addEventListener("mousemove", (e)=>{
            if(!isDown) return;
            const dx = e.clientX - startX;
            const dy = e.clientY - startY;
            if(Math.sqrt(dx*dx + dy*dy) > 5){
                isDragging = true;
            }
            if(isDragging){
                ball.style.left = e.clientX - startX + "px";
                ball.style.top = e.clientY - startY + "px";
            }
        });

        document.addEventListener("mouseup", (e)=>{
            if(!isDown) return;
            isDown = false;
            ball.style.cursor = "grab";

            const elapsed = Date.now() - downTime;
            if(!isDragging && elapsed < 400){
                const input = prompt("请输入定时分钟数 (≥1):", Math.ceil(remainingSeconds/60));
                const minutes = parseInt(input);
                if(!isNaN(minutes) && minutes>0){
                    startCountdown(minutes);
                }
            }
        });

        startCountdown(minutes);
    }

    function startCountdown(minutes){
        totalSeconds = remainingSeconds = minutes*60;
        paused = false;

        if(timerId) clearInterval(timerId);

        timerId = setInterval(()=>{
            if(!paused){
                remainingSeconds--;
                if(remainingSeconds <= 0){
                    clearInterval(timerId);
                    window.close();
                    return;
                }
                const label = document.getElementById("timer-label");
                label.textContent = formatTime(remainingSeconds);

                const ctx = canvas.getContext("2d");
                ctx.clearRect(0,0,canvas.width,canvas.height);

                // 背景圆
                ctx.beginPath();
                ctx.arc(canvas.width/2,canvas.height/2,50,0,2*Math.PI);
                ctx.strokeStyle = "rgba(255,255,255,0.2)";
                ctx.lineWidth = 10;
                ctx.stroke();

                // 进度圆
                const fraction = remainingSeconds / totalSeconds;
                ctx.beginPath();
                ctx.arc(canvas.width/2,canvas.height/2,50,-Math.PI/2, -Math.PI/2 + 2*Math.PI*fraction);
                ctx.strokeStyle = "#ffd700";
                ctx.lineWidth = 10;
                ctx.lineCap = "round";
                ctx.stroke();
            }
        },1000);
    }

    GM_registerMenuCommand("启动定时关闭网页", ()=>{
        const input = prompt("请输入定时分钟数 (≥1):","5");
        const minutes = parseInt(input);
        if(!isNaN(minutes) && minutes>0){
            createBall(minutes);
        }else{
            alert("请输入合法的分钟数!");
        }
    });

})();