您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Drag and drop the pop-up window, set the slider for minutes + seconds, the small ball in the upper left corner shows the remaining time, and the theme can be switched.
// ==UserScript== // @name 定时自动关闭网页🧐🧐🧐🤓🤓 // @namespace https://github.com/yingchen6 // @version 1.8.19.16 // @description Drag and drop the pop-up window, set the slider for minutes + seconds, the small ball in the upper left corner shows the remaining time, and the theme can be switched. // @author yingchen6 // @match *://*/* // @grant GM_registerMenuCommand // @license MIT // ==/UserScript== (function(){ 'use strict'; let timerId=null; let remainingSeconds=0; let totalSeconds=0; let ball=null; let canvas=null; let paused=false; let theme='green'; let settingPanel=null; const THEMES={ green:{bg:'rgba(150,180,160,0.6)',progress:'#5B7A63',panel:'rgba(150,180,160,0.5)',label:'#ffffff',btnBg:'#8DA897',btnText:'#fff'}, bluegray:{bg:'rgba(120,140,160,0.6)',progress:'#3E586C',panel:'rgba(120,140,160,0.5)',label:'#ffffff',btnBg:'#708090',btnText:'#fff'}, yellow:{bg:'rgba(200,180,120,0.6)',progress:'#A1864D',panel:'rgba(200,180,120,0.5)',label:'#ffffff',btnBg:'#BFA76F',btnText:'#fff'}, purple:{bg:'rgba(160,140,180,0.6)',progress:'#7A637A',panel:'rgba(160,140,180,0.5)',label:'#ffffff',btnBg:'#8F7090',btnText:'#fff'}, blackgray:{bg:'rgba(50,50,50,0.7)',progress:'#222',panel:'rgba(60,60,60,0.8)',label:'#ffffff',btnBg:'#444',btnText:'#fff'}, pink:{bg:'rgba(255,182,193,0.6)',progress:'#FF69B4',panel:'rgba(255,182,193,0.5)',label:'#fff',btnBg:'#FF99CC',btnText:'#fff'} }; function formatTime(seconds){ const m=Math.floor(seconds/60); const s=seconds%60; return `${m}:${s.toString().padStart(2,'0')}`; } function createBall(seconds){ totalSeconds=remainingSeconds=seconds; paused=false; if(ball) ball.remove(); ball=document.createElement("div"); ball.id="timer-ball"; Object.assign(ball.style,{ position:"fixed",top:"20px",left:"20px",width:"120px",height:"120px", borderRadius:"50%",zIndex:"999999",cursor:"grab",display:"flex", justifyContent:"center",alignItems:"center",userSelect:"none", background:THEMES[theme].bg,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"; Object.assign(label.style,{position:"absolute",color:THEMES[theme].label,fontWeight:"bold",fontSize:"20px"}); ball.appendChild(label); const pauseBtn=document.createElement("div"); pauseBtn.id="pause-btn"; Object.assign(pauseBtn.style,{ position:"absolute",bottom:"10px",fontSize:"16px",color:THEMES[theme].btnText, background:THEMES[theme].btnBg,borderRadius:"10px",padding:"6px 12px",cursor:"pointer" }); pauseBtn.textContent="暂停"; ball.appendChild(pauseBtn); pauseBtn.addEventListener("click",e=>{ e.stopPropagation(); paused=!paused; pauseBtn.textContent=paused?"继续":"暂停"; }); let isDown=false,isDragging=false,startX=0,startY=0,downTime=0; ball.addEventListener("mousedown",e=>{ if(e.target===pauseBtn) return; isDown=true;isDragging=false; startX=e.clientX-ball.offsetLeft;startY=e.clientY-ball.offsetTop; downTime=Date.now(); ball.style.cursor="grabbing"; }); document.addEventListener("mousemove",e=>{ if(!isDown) return; const dx=e.clientX-startX-ball.offsetLeft; const dy=e.clientY-startY-ball.offsetTop; 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){ showTimeSetting(); } }); startCountdown(seconds); } function startCountdown(seconds){ totalSeconds=remainingSeconds=seconds; paused=false; if(timerId) clearInterval(timerId); timerId=setInterval(()=>{ if(!paused){ remainingSeconds--; if(remainingSeconds<=0){clearInterval(timerId);window.location.href="about:blank";return;} const label=document.getElementById("timer-label"); if(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=THEMES[theme].progress; ctx.lineWidth=10;ctx.lineCap="round";ctx.stroke(); } },1000); } function showTimeSetting(){ if(settingPanel){ settingPanel.remove(); settingPanel=null; } const wrapper=document.createElement("div"); settingPanel=wrapper; Object.assign(wrapper.style,{ display:"flex", flexDirection:"column", alignItems:"center", gap:"10px", padding:"15px", borderRadius:"12px", background:THEMES[theme].panel, position:"fixed", top:`${window.innerHeight/2 - 150}px`, left:`${window.innerWidth/2 - 150}px`, transform:"translate(0,0)", zIndex:"1000000", cursor:"grab", minWidth:"450px" }); wrapper.innerHTML=` <div style="width:100%;display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;"> <div style="font-size:35px;font-weight:bold;color:${THEMES[theme].label}">设 置 倒 计 时 </div> <select id="themeSelect" style="border-radius:6px;padding:6px 10px;background:${THEMES[theme].btnBg};color:${THEMES[theme].btnText};border:none;cursor:pointer;"> <option value="green">莫兰迪绿</option> <option value="bluegray">蓝灰</option> <option value="yellow">莫兰迪黄</option> <option value="purple">莫兰迪紫</option> <option value="blackgray">黑灰</option> <option value="pink">莫兰迪粉</option> </select> </div> <div style="display:flex;align-items:center;gap:8px;width:100%;"> <button id="minMinus" style="border:none;border-radius:50%;width:32px;height:32px;line-height:32px;background:${THEMES[theme].btnBg};color:${THEMES[theme].btnText};cursor:pointer;font-weight:bold;font-size:30px;">-</button> <input id="timeMin" type="range" min="0" max="360" step="1" value="${Math.floor(remainingSeconds/60)}" style="flex:1;"> <button id="minPlus" style="border:none;border-radius:50%;width:32px;height:32px;line-height:32px;background:${THEMES[theme].btnBg};color:${THEMES[theme].btnText};cursor:pointer;font-weight:bold;font-size:30px;">+</button> <span id="minLabel" style="min-width:70px;text-align:center;font-weight:bold;font-size:30px;color:${THEMES[theme].label};">${Math.floor(remainingSeconds/60)} 分</span> </div> <div style="display:flex;align-items:center;gap:8px;width:100%;"> <button id="secMinus" style="border:none;border-radius:50%;width:32px;height:32px;line-height:32px;background:${THEMES[theme].btnBg};color:${THEMES[theme].btnText};cursor:pointer;font-weight:bold;font-size:30px;">-</button> <input id="timeSec" type="range" min="0" max="59" step="1" value="${remainingSeconds%60}" style="flex:1;"> <button id="secPlus" style="border:none;border-radius:50%;width:32px;height:32px;line-height:32px;background:${THEMES[theme].btnBg};color:${THEMES[theme].btnText};cursor:pointer;font-weight:bold;font-size:30px;">+</button> <span id="secLabel" style="min-width:70px;text-align:center;font-weight:bold;font-size:30px;color:${THEMES[theme].label};">${remainingSeconds%60} 秒</span> </div> <div style="display:flex;gap:15px;margin-top:25px;width:100%;"> <button id="confirmBtn" style="font-size:25px;font-weight:bold;">确认</button> <button id="cancelBtn" style="font-size:25px;font-weight:bold;">取消</button> </div> `; document.body.appendChild(wrapper); const minInput=wrapper.querySelector("#timeMin"); const secInput=wrapper.querySelector("#timeSec"); const minLabel=wrapper.querySelector("#minLabel"); const secLabel=wrapper.querySelector("#secLabel"); minInput.addEventListener("input",()=>{minLabel.textContent=minInput.value+" 分";}); secInput.addEventListener("input",()=>{secLabel.textContent=secInput.value+" 秒";}); wrapper.querySelector("#minMinus").addEventListener("click",()=>{ if(minInput.value>0) minInput.value--; minLabel.textContent=minInput.value+" 分"; }); wrapper.querySelector("#minPlus").addEventListener("click",()=>{ if(minInput.value<180) minInput.value++; minLabel.textContent=minInput.value+" 分"; }); wrapper.querySelector("#secMinus").addEventListener("click",()=>{ if(secInput.value>0) secInput.value--; secLabel.textContent=secInput.value+" 秒"; }); wrapper.querySelector("#secPlus").addEventListener("click",()=>{ if(secInput.value<59) secInput.value++; secLabel.textContent=secInput.value+" 秒"; }); function styleBtn(btn){ Object.assign(btn.style,{ padding:"8px 14px",border:"none",borderRadius:"8px", fontSize:"25px",fontWeight:"bold", background:THEMES[theme].btnBg,color:THEMES[theme].btnText, cursor:"pointer",flex:"1" }); } styleBtn(wrapper.querySelector("#confirmBtn")); styleBtn(wrapper.querySelector("#cancelBtn")); let isDown=false,startX=0,startY=0; wrapper.addEventListener("mousedown",e=>{ if(["confirmBtn","cancelBtn","themeSelect","timeMin","timeSec"].includes(e.target.id) || e.target.tagName==="INPUT") return; isDown=true; startX=e.clientX-wrapper.offsetLeft; startY=e.clientY-wrapper.offsetTop; wrapper.style.cursor="grabbing"; }); document.addEventListener("mousemove",e=>{ if(!isDown) return; wrapper.style.left=(e.clientX-startX)+"px"; wrapper.style.top=(e.clientY-startY)+"px"; wrapper.style.transform="translate(0,0)"; }); document.addEventListener("mouseup",()=>{isDown=false; wrapper.style.cursor="grab";}); const themeSelect=wrapper.querySelector("#themeSelect"); themeSelect.value=theme; themeSelect.addEventListener("change",()=>{ theme=themeSelect.value; }); wrapper.querySelector("#confirmBtn").addEventListener("click",()=>{ const min=parseInt(minInput.value); const sec=parseInt(secInput.value); remainingSeconds=totalSeconds=min*60+sec; wrapper.remove(); settingPanel=null; createBall(totalSeconds); }); wrapper.querySelector("#cancelBtn").addEventListener("click",()=>{wrapper.remove(); settingPanel=null;}); } function registerMenu(){ if(typeof GM_registerMenuCommand==="undefined") return; GM_registerMenuCommand("设置自动关闭时长", showTimeSetting); } setTimeout(registerMenu, 500); })();