您需要先安装一个扩展,例如 篡改猴、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);