您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Speeds up countdown timers without affecting video playback, now with a movable UI and adjustable speed.
当前为
// ==UserScript== // @name TimerHooker Android MD3 Version (Enhanced) // @version 3.0.0 // @description Speeds up countdown timers without affecting video playback, now with a movable UI and adjustable speed. // @include * // @author Govindarajulu // @match http://*/* // @run-at document-start // @grant none // @license GPL-3.0-or-later // @namespace https://greasyfork.org/users/1356925 // ==/UserScript== (function (global) { let isSpeedActive = false; let autoHideTimeout; let speedMultiplier = localStorage.getItem("timerHookerSpeed") || 50; function overrideTimers(factor) { ["setTimeout", "setInterval"].forEach((method) => { window[method] = ((original) => (fn, time) => { // **Prevent changes to video-related timers** const fnString = fn.toString(); if (fnString.includes("playback") || fnString.includes("video")) { return original(fn, time); // Keep normal speed for videos } return original(fn, time / factor); })(window[method]); }); } const TimerHooker = { toggleSpeed: function () { isSpeedActive = !isSpeedActive; overrideTimers(isSpeedActive ? speedMultiplier : 1); const btn = document.getElementById("toggleSpeedBtn"); if (btn) btn.textContent = isSpeedActive ? "Stop" : "Speed"; console.log(`[TimerHooker] Countdown timers accelerated: x${isSpeedActive ? speedMultiplier : 1}`); // **Ensure auto-hide after 3 seconds** TimerHooker.resetAutoHide(); }, adjustSpeed: function (multiplier) { speedMultiplier = multiplier; localStorage.setItem("timerHookerSpeed", multiplier); if (isSpeedActive) overrideTimers(speedMultiplier); }, createUI: function () { if (document.getElementById("timerHookerUI")) return; const speedControl = document.createElement("div"); speedControl.id = "timerHookerUI"; speedControl.style = ` position: fixed; top: 50%; left: -40px; z-index: 99999; background: rgba(0,0,0,0.3); color: white; padding: 8px 16px; border-radius: 40px; font-size: clamp(10px, 1vw, 16px); text-align: center; cursor: grab; backdrop-filter: blur(8px); box-shadow: 0px 3px 8px rgba(0,0,0,0.2); user-select: none; transition: left 0.3s ease; touch-action: none; display: flex; flex-direction: column; `; const toggleBtn = document.createElement("button"); toggleBtn.id = "toggleSpeedBtn"; toggleBtn.textContent = "Speed"; toggleBtn.style = "width: 100%; margin-bottom: 5px; padding: 6px;"; toggleBtn.addEventListener("click", () => { speedControl.style.left = "10px"; // Bring fully into view TimerHooker.toggleSpeed(); }); const speedSlider = document.createElement("input"); speedSlider.id = "speedSlider"; speedSlider.type = "range"; speedSlider.min = "1"; speedSlider.max = "100"; speedSlider.value = speedMultiplier; speedSlider.style = "width: 100%;"; speedSlider.addEventListener("input", (event) => { TimerHooker.adjustSpeed(event.target.value); }); speedControl.appendChild(toggleBtn); speedControl.appendChild(speedSlider); let startX, startY, isDragging = false; speedControl.addEventListener("touchstart", (e) => { isDragging = true; clearTimeout(autoHideTimeout); const touch = e.touches[0]; startX = touch.clientX - speedControl.getBoundingClientRect().left; startY = touch.clientY - speedControl.getBoundingClientRect().top; speedControl.style.cursor = "grabbing"; }); document.addEventListener("touchmove", (e) => { if (!isDragging) return; const touch = e.touches[0]; speedControl.style.left = `${Math.min(window.innerWidth - speedControl.offsetWidth, Math.max(0, touch.clientX - startX))}px`; speedControl.style.top = `${Math.min(window.innerHeight - speedControl.offsetHeight, Math.max(0, touch.clientY - startY))}px`; }); document.addEventListener("touchend", () => { isDragging = false; speedControl.style.cursor = "grab"; TimerHooker.resetAutoHide(); }); document.body.appendChild(speedControl); TimerHooker.resetAutoHide(); console.log("[TimerHooker] UI optimized for Android successfully."); }, resetAutoHide: function () { clearTimeout(autoHideTimeout); autoHideTimeout = setTimeout(() => { const speedControl = document.getElementById("timerHookerUI"); if (!isDragging) speedControl.style.left = "-40px"; // Move button back }, 3000); }, handleFullscreen: function () { document.addEventListener("fullscreenchange", () => { const speedControl = document.getElementById("timerHookerUI"); speedControl.style.display = document.fullscreenElement ? "none" : "block"; }); }, init: function () { console.log("[TimerHooker] Android MD3 version activated"); this.createUI(); this.handleFullscreen(); } }; if (document.readyState === "complete") { TimerHooker.init(); } else { window.addEventListener("load", () => TimerHooker.init()); } })(window);