您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
带可拖动悬浮计时器、智能黑屏及网页端自定义时长
// ==UserScript== // @name 抖音自律助手终极版(右键可自定义时长) // @namespace http://tampermonkey.net/ // @version 1.6 // @description 带可拖动悬浮计时器、智能黑屏及网页端自定义时长 // @author potato // @match *://*.douyin.com/* // @grant GM_addStyle // ==/UserScript== (function () { 'use strict'; /*************** 样式 ***************/ GM_addStyle(` /* 黑屏遮罩 */ #timeout-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background:rgba(0,0,0,.9);z-index:999999;display:none;justify-content:center;align-items:center;color:#fff;font-size:2em;text-align:center;cursor:not-allowed;flex-direction:column;} /* 倒计时小球 */ #countdown-ball{position:fixed;right:20px;bottom:20px;width:60px;height:60px;background:linear-gradient(135deg,#ff6b6b,#ff4757);border-radius:50%;box-shadow:0 4px 15px rgba(255,107,107,.3);cursor:move;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:bold;font-size:14px;text-align:center;line-height:1.2;z-index:999998;user-select:none;transition:all .3s cubic-bezier(.4,0,.2,1);} #countdown-ball:hover{transform:scale(1.1);box-shadow:0 6px 20px rgba(255,107,107,.4);} #countdown-ball.dragging{transition:none;opacity:.9;} /* 黑屏提示文字 */ .timeout-text{animation:pulse 2s infinite;} @keyframes pulse{0%{transform:scale(1);}50%{transform:scale(1.05);}100%{transform:scale(1);}} `); /*************** DOM 构造 ***************/ const createOverlay = () => { const overlay = document.createElement('div'); overlay.id = 'timeout-overlay'; document.body.appendChild(overlay); return overlay; }; const createCountdownBall = () => { const ball = document.createElement('div'); ball.id = 'countdown-ball'; document.body.appendChild(ball); return ball; }; /*************** 定时器控制 ***************/ class TimerController { STORAGE_KEY = 'douyin_focus_duration_ms'; constructor() { // 读取持久化时长,默认 10 分钟 const saved = parseInt(localStorage.getItem(this.STORAGE_KEY), 10); this.totalTime = Number.isFinite(saved) && saved > 0 ? saved : 10 * 60 * 1000; this.startTime = Date.now(); this.remaining = this.totalTime; this.timer = null; this.ball = createCountdownBall(); this.overlay = createOverlay(); this.setupOverlayText(); // 根据时长渲染提示 this.init(); } /***** 初始化 *****/ init() { this.setupDrag(); this.setupCustomTimeListener(); // 新增:自定义时长 this.setupVisibilityListener(); this.startCountdown(); } /***** 倒计时循环 *****/ startCountdown() { this.clearTimer(); this.startTime = Date.now(); this.updateDisplay(); this.timer = setInterval(() => { this.remaining = this.totalTime - (Date.now() - this.startTime); if (this.remaining <= 0) return this.triggerTimeout(); this.updateDisplay(); }, 200); } clearTimer() { if (this.timer) clearInterval(this.timer); this.timer = null; } /***** UI 更新 *****/ updateDisplay() { const m = Math.floor(this.remaining / 60000); const s = Math.floor((this.remaining % 60000) / 1000) .toString() .padStart(2, '0'); this.ball.textContent = `${m}:${s}`; // 渐变色随进度变化 const p = this.remaining / this.totalTime; this.ball.style.background = `linear-gradient(135deg, hsl(${p * 120},70%,50%), hsl(${p * 120},80%,45%) )`; } setupOverlayText() { const minutes = this.totalTime / 60000; this.overlay.innerHTML = ` <div class="timeout-text"> <div>🕒 已连续使用${minutes}分钟</div> <div style="font-size:0.6em;margin-top:20px;">请休息片刻再继续</div> <div style="font-size:0.4em;margin-top:10px;">(刷新页面可恢复)</div> </div> `; } /***** 超时处理 *****/ triggerTimeout() { this.clearTimer(); document.querySelectorAll('video').forEach(v => v.pause()); this.overlay.style.display = 'flex'; this.ball.style.display = 'none'; document.body.style.overflow = 'hidden'; this.addOverlayBlockers(); } addOverlayBlockers() { const blocker = e => { e.preventDefault(); e.stopPropagation(); }; ['click', 'touchstart', 'keydown'].forEach(evt => document.addEventListener(evt, blocker, true) ); } /***** 自定义时长 *****/ setupCustomTimeListener() { const handler = e => { e.preventDefault(); // 阻止默认菜单 const currentMin = Math.round(this.totalTime / 60000); const input = prompt('设置专注时长 (分钟):', currentMin); if (input === null) return; const mins = parseInt(input.trim(), 10); if (!Number.isFinite(mins) || mins <= 0) { alert('请输入正整数分钟数'); return; } // 更新时长 & 持久化 this.totalTime = mins * 60 * 1000; localStorage.setItem(this.STORAGE_KEY, this.totalTime); this.remaining = this.totalTime; this.setupOverlayText(); // 重新渲染遮罩文案 this.ball.style.display = 'flex'; this.overlay.style.display = 'none'; document.body.style.overflow = ''; this.startCountdown(); }; // 双击 or 右键均可触发 this.ball.addEventListener('contextmenu', handler); this.ball.addEventListener('dblclick', handler); } /***** 可见性监控 *****/ setupVisibilityListener() { let hiddenAt = 0; document.addEventListener('visibilitychange', () => { if (document.hidden) { hiddenAt = Date.now(); this.clearTimer(); } else { this.startTime += Date.now() - hiddenAt; this.startCountdown(); } }); } /***** 拖动 *****/ setupDrag() { let dragging = false, startX, startY, origX, origY; const move = e => { if (!dragging) return; const dx = e.clientX - startX, dy = e.clientY - startY; const maxX = window.innerWidth - this.ball.offsetWidth; const maxY = window.innerHeight - this.ball.offsetHeight; const newX = Math.min(Math.max(0, origX + dx), maxX); const newY = Math.min(Math.max(0, origY + dy), maxY); this.ball.style.left = `${newX}px`; this.ball.style.top = `${newY}px`; }; this.ball.addEventListener('mousedown', e => { dragging = true; this.ball.classList.add('dragging'); startX = e.clientX; startY = e.clientY; const rect = this.ball.getBoundingClientRect(); origX = rect.left; origY = rect.top; document.addEventListener('mousemove', move); }); document.addEventListener('mouseup', () => { if (!dragging) return; dragging = false; this.ball.classList.remove('dragging'); document.removeEventListener('mousemove', move); }); } } // 启动 new TimerController(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址