TimerHooker Android MD3 Version (Enhanced)

Speeds up countdown timers without affecting video playback, now with a movable UI and adjustable speed.

目前为 2025-04-03 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name TimerHooker Android MD3 Version (Enhanced)
  3. // @version 3.0.0
  4. // @description Speeds up countdown timers without affecting video playback, now with a movable UI and adjustable speed.
  5. // @include *
  6. // @author Govindarajulu
  7. // @match http://*/*
  8. // @run-at document-start
  9. // @grant none
  10. // @license GPL-3.0-or-later
  11. // @namespace https://greasyfork.org/users/1356925
  12. // ==/UserScript==
  13.  
  14. (function (global) {
  15. let isSpeedActive = false;
  16. let autoHideTimeout;
  17. let speedMultiplier = localStorage.getItem("timerHookerSpeed") || 50;
  18.  
  19. function overrideTimers(factor) {
  20. ["setTimeout", "setInterval"].forEach((method) => {
  21. window[method] = ((original) => (fn, time) => {
  22. // **Prevent changes to video-related timers**
  23. const fnString = fn.toString();
  24. if (fnString.includes("playback") || fnString.includes("video")) {
  25. return original(fn, time); // Keep normal speed for videos
  26. }
  27. return original(fn, time / factor);
  28. })(window[method]);
  29. });
  30. }
  31.  
  32. const TimerHooker = {
  33. toggleSpeed: function () {
  34. isSpeedActive = !isSpeedActive;
  35. overrideTimers(isSpeedActive ? speedMultiplier : 1);
  36.  
  37. const btn = document.getElementById("toggleSpeedBtn");
  38. if (btn) btn.textContent = isSpeedActive ? "Stop" : "Speed";
  39.  
  40. console.log(`[TimerHooker] Countdown timers accelerated: x${isSpeedActive ? speedMultiplier : 1}`);
  41.  
  42. // **Ensure auto-hide after 3 seconds**
  43. TimerHooker.resetAutoHide();
  44. },
  45.  
  46. adjustSpeed: function (multiplier) {
  47. speedMultiplier = multiplier;
  48. localStorage.setItem("timerHookerSpeed", multiplier);
  49. if (isSpeedActive) overrideTimers(speedMultiplier);
  50. },
  51.  
  52. createUI: function () {
  53. if (document.getElementById("timerHookerUI")) return;
  54.  
  55. const speedControl = document.createElement("div");
  56. speedControl.id = "timerHookerUI";
  57. speedControl.style = `
  58. position: fixed; top: 50%; left: -40px; z-index: 99999;
  59. background: rgba(0,0,0,0.3); color: white; padding: 8px 16px; border-radius: 40px;
  60. font-size: clamp(10px, 1vw, 16px); text-align: center; cursor: grab;
  61. backdrop-filter: blur(8px); box-shadow: 0px 3px 8px rgba(0,0,0,0.2);
  62. user-select: none; transition: left 0.3s ease;
  63. touch-action: none; display: flex; flex-direction: column;
  64. `;
  65.  
  66. const toggleBtn = document.createElement("button");
  67. toggleBtn.id = "toggleSpeedBtn";
  68. toggleBtn.textContent = "Speed";
  69. toggleBtn.style = "width: 100%; margin-bottom: 5px; padding: 6px;";
  70. toggleBtn.addEventListener("click", () => {
  71. speedControl.style.left = "10px"; // Bring fully into view
  72. TimerHooker.toggleSpeed();
  73. });
  74.  
  75. const speedSlider = document.createElement("input");
  76. speedSlider.id = "speedSlider";
  77. speedSlider.type = "range";
  78. speedSlider.min = "1";
  79. speedSlider.max = "100";
  80. speedSlider.value = speedMultiplier;
  81. speedSlider.style = "width: 100%;";
  82. speedSlider.addEventListener("input", (event) => {
  83. TimerHooker.adjustSpeed(event.target.value);
  84. });
  85.  
  86. speedControl.appendChild(toggleBtn);
  87. speedControl.appendChild(speedSlider);
  88.  
  89. let startX, startY, isDragging = false;
  90.  
  91. speedControl.addEventListener("touchstart", (e) => {
  92. isDragging = true;
  93. clearTimeout(autoHideTimeout);
  94. const touch = e.touches[0];
  95. startX = touch.clientX - speedControl.getBoundingClientRect().left;
  96. startY = touch.clientY - speedControl.getBoundingClientRect().top;
  97. speedControl.style.cursor = "grabbing";
  98. });
  99.  
  100. document.addEventListener("touchmove", (e) => {
  101. if (!isDragging) return;
  102. const touch = e.touches[0];
  103. speedControl.style.left = `${Math.min(window.innerWidth - speedControl.offsetWidth, Math.max(0, touch.clientX - startX))}px`;
  104. speedControl.style.top = `${Math.min(window.innerHeight - speedControl.offsetHeight, Math.max(0, touch.clientY - startY))}px`;
  105. });
  106.  
  107. document.addEventListener("touchend", () => {
  108. isDragging = false;
  109. speedControl.style.cursor = "grab";
  110. TimerHooker.resetAutoHide();
  111. });
  112.  
  113. document.body.appendChild(speedControl);
  114. TimerHooker.resetAutoHide();
  115. console.log("[TimerHooker] UI optimized for Android successfully.");
  116. },
  117.  
  118. resetAutoHide: function () {
  119. clearTimeout(autoHideTimeout);
  120. autoHideTimeout = setTimeout(() => {
  121. const speedControl = document.getElementById("timerHookerUI");
  122. if (!isDragging) speedControl.style.left = "-40px"; // Move button back
  123. }, 3000);
  124. },
  125.  
  126. handleFullscreen: function () {
  127. document.addEventListener("fullscreenchange", () => {
  128. const speedControl = document.getElementById("timerHookerUI");
  129. speedControl.style.display = document.fullscreenElement ? "none" : "block";
  130. });
  131. },
  132.  
  133. init: function () {
  134. console.log("[TimerHooker] Android MD3 version activated");
  135. this.createUI();
  136. this.handleFullscreen();
  137. }
  138. };
  139.  
  140. if (document.readyState === "complete") {
  141. TimerHooker.init();
  142. } else {
  143. window.addEventListener("load", () => TimerHooker.init());
  144. }
  145. })(window);