Greasy Fork is available in English.
Uses a Web Worker to ensure high-precision timing for setInterval and setTimeout, minimizing throttling.
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/552983/1681317/HackTimer%20V2.js
// ==UserScript==
// @license MIT
// @name HackTimer V2
// @namespace HackTimer
// @version 1.1.2 (Gemini version)
// @description Uses a Web Worker to ensure high-precision timing for setInterval and setTimeout, minimizing throttling.
// @grant none
// @run-at document-start
// ==/UserScript==
(function () {
const logPrefix = 'HackTimer V2: ';
let workerScriptUrl = null;
// --- 1. Generate Worker Script Blob URL ---
try {
const workerCode = `
var fakeIdToId = {};
onmessage = function (event) {
var data = event.data;
var name = data.name;
var fakeId = data.fakeId;
// Ensure time is treated as a number, defaulting to 0
var time = data.time || 0;
switch (name) {
case 'setInterval':
fakeIdToId[fakeId] = setInterval(function () {
postMessage({ fakeId: fakeId });
}, time);
break;
case 'clearInterval':
if (fakeIdToId[fakeId]) {
clearInterval(fakeIdToId[fakeId]);
delete fakeIdToId[fakeId];
}
break;
case 'setTimeout':
fakeIdToId[fakeId] = setTimeout(function () {
postMessage({ fakeId: fakeId });
// Timeouts clear themselves after firing
delete fakeIdToId[fakeId];
}, time);
break;
case 'clearTimeout':
if (fakeIdToId[fakeId]) {
clearTimeout(fakeIdToId[fakeId]);
delete fakeIdToId[fakeId];
}
break;
}
};
`;
const blob = new Blob([workerCode], { type: 'application/javascript' });
workerScriptUrl = window.URL.createObjectURL(blob);
} catch (error) {
console.warn(logPrefix + 'Blob creation failed. Web Worker replacement disabled.', error);
return; // Cannot proceed without Blob support
}
if (typeof Worker === 'undefined') {
console.warn(logPrefix + 'Web Workers not supported. Replacement disabled.');
if (workerScriptUrl) window.URL.revokeObjectURL(workerScriptUrl);
return;
}
let worker;
const fakeIdToCallback = new Map();
let lastFakeId = 1;
// --- 2. ID Generation ---
function getFakeId() {
// Simple incrementing ID, wrapping safely (using a large limit)
lastFakeId = (lastFakeId % 0xFFFFFFF) + 1;
while (fakeIdToCallback.has(lastFakeId)) {
lastFakeId++;
}
return lastFakeId;
}
// --- 3. Callback Execution Logic ---
function executeCallback(fakeId) {
const request = fakeIdToCallback.get(fakeId);
if (!request) return;
const { callback, parameters, isTimeout } = request;
if (isTimeout) {
fakeIdToCallback.delete(fakeId);
}
let callbackFunc = callback;
// Handle string callbacks (legacy support)
if (typeof callback === 'string') {
try {
// eslint-disable-next-line no-new-func
callbackFunc = new Function(callback);
} catch (error) {
console.error(logPrefix + 'Error parsing string callback:', error);
return;
}
}
if (typeof callbackFunc === 'function') {
try {
// Execute in the global scope
callbackFunc.apply(window, parameters);
} catch (error) {
console.error(logPrefix + 'Error executing callback:', error);
}
}
}
// --- 4. Worker Initialization and Overrides ---
try {
worker = new Worker(workerScriptUrl);
// Store originals (useful if users mix native and hacked timers)
const originalClearInterval = window.clearInterval;
const originalClearTimeout = window.clearTimeout;
// Override setInterval
window.setInterval = function (callback, time, ...parameters) {
const fakeId = getFakeId();
fakeIdToCallback.set(fakeId, {
callback: callback,
parameters: parameters,
isTimeout: false
});
worker.postMessage({
name: 'setInterval',
fakeId: fakeId,
time: Math.max(0, time || 0)
});
return fakeId;
};
// Override clearInterval
window.clearInterval = function (fakeId) {
if (fakeIdToCallback.has(fakeId)) {
fakeIdToCallback.delete(fakeId);
worker.postMessage({
name: 'clearInterval',
fakeId: fakeId
});
} else if (typeof fakeId === 'number' && fakeId > 0) {
// Allow clearing native timers if the ID wasn't tracked by us
originalClearInterval(fakeId);
}
};
// Override setTimeout
window.setTimeout = function (callback, time, ...parameters) {
const fakeId = getFakeId();
fakeIdToCallback.set(fakeId, {
callback: callback,
parameters: parameters,
isTimeout: true
});
worker.postMessage({
name: 'setTimeout',
fakeId: fakeId,
time: Math.max(0, time || 0)
});
return fakeId;
};
// Override clearTimeout
window.clearTimeout = function (fakeId) {
if (fakeIdToCallback.has(fakeId)) {
fakeIdToCallback.delete(fakeId);
worker.postMessage({
name: 'clearTimeout',
fakeId: fakeId
});
} else if (typeof fakeId === 'number' && fakeId > 0) {
// Allow clearing native timers
originalClearTimeout(fakeId);
}
};
// Worker Message Handlers
worker.onmessage = function (event) {
const { fakeId } = event.data;
executeCallback(fakeId);
};
worker.onerror = function (event) {
console.error(logPrefix + 'Worker runtime error:', event);
};
// Clean up the temporary Blob URL
window.URL.revokeObjectURL(workerScriptUrl);
} catch (error) {
console.error(logPrefix + 'Initialisation failed. Using standard timers.', error);
if (workerScriptUrl) window.URL.revokeObjectURL(workerScriptUrl);
}
})();