您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Script allowing you to control time.
- // ==UserScript==
- // @name Time Control
- // @description Script allowing you to control time.
- // @icon https://parsefiles.back4app.com/JPaQcFfEEQ1ePBxbf6wvzkPMEqKYHhPYv8boI1Rc/ce262758ff44d053136358dcd892979d_low_res_Time_Machine.png
- // @namespace mailto:lucaszheng2011@outlook.com
- // @version 1.2.6
- // @author lucaszheng
- // @license MIT
- //
- // @match *://*/*
- // @grant unsafeWindow
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM_deleteValue
- // @inject-into page
- // @run-at document-start
- // ==/UserScript==
- /*globals unsafeWindow,GM_setValue,GM_getValue,GM_deleteValue*/
- (function (window) {
- 'use strict';
- let scale = 1, pristine = true;
- /** @type {null | number} */
- let timeJump = null;
- let timeReset = false;
- let debug = false;
- const {
- Reflect: {
- apply, construct,
- setPrototypeOf,
- getPrototypeOf
- },
- Object: {
- defineProperty,
- freeze
- },
- Number: {
- isFinite
- },
- Symbol: {
- toPrimitive,
- toStringTag
- },
- console: {
- trace: log
- }
- } = window;
- function update() {
- for (let idx = 0; idx < updaters.length; idx++) {
- updaters[idx]();
- }
- }
- /**
- * @param {'string' | 'number' | 'default'} type
- */
- function timeToPrimitive(type) {
- switch (type) {
- case 'string': return this.toString();
- default: return this.now;
- }
- }
- function timeToString() {
- return apply(date.toString, construct(DateConstructor, [this.now]), []);
- }
- const time = {
- [toStringTag]: 'time',
- [toPrimitive]: timeToPrimitive,
- toString: timeToString,
- /**
- * @param {number} newTime
- */
- jump(newTime) {
- if (newTime == null) return;
- pristine = false;
- timeJump = +newTime;
- update();
- timeJump = null;
- },
- reset(resetTime = true, resetScale = true, resetDebug = true) {
- if (resetDebug) debug = false;
- if (pristine) return;
- if (resetScale) scale = 1;
- if (!resetTime) return;
- timeReset = true;
- update();
- timeReset = false;
- pristine = scale === 1;
- },
- storage: {
- [toStringTag]: 'storage',
- [toPrimitive]: timeToPrimitive,
- toString: timeToString,
- /**
- * @param {number} newTime
- */
- jump(newTime) {
- GM_setValue('baseTime', time.real);
- GM_setValue('contTime', +newTime);
- },
- save(saveTime = true, saveScale = true, saveDebug = true) {
- if (saveDebug) {
- if (debug === false) time.storage.reset(false, false, true);
- else time.storage.debug = debug;
- }
- if (saveTime) {
- if (pristine) time.storage.reset(true, false, false);
- else time.storage.now = time.now;
- }
- if (saveScale) {
- if (scale === 1) time.storage.reset(false, true, false);
- else time.storage.scale = scale;
- }
- },
- load(loadTime = true, loadScale = true, loadDebug = true) {
- if (loadDebug) time.debug = time.storage.debug;
- if (time.storage.pristine) return time.reset(true, true, false);
- if (loadTime) {
- let baseTime = GM_getValue('baseTime', null);
- let contTime = GM_getValue('contTime', null);
- if (baseTime != null && contTime != null)
- time.jump((time.real - baseTime) + contTime);
- }
- if (loadScale) time.scale = time.storage.scale;
- },
- reset(resetTime = true, resetScale = true, resetDebug = true) {
- if (resetTime) {
- GM_deleteValue('baseTime');
- GM_deleteValue('contTime');
- }
- if (resetScale) GM_deleteValue('scale');
- if (resetDebug) GM_deleteValue('debug');
- },
- get debug() { return GM_getValue('debug', false); },
- set debug(value) { GM_setValue('debug', !!value); },
- get now() {
- let baseTime = GM_getValue('baseTime', null);
- let contTime = GM_getValue('contTime', null);
- if (baseTime != null && contTime != null)
- return (time.real - baseTime) + contTime;
- return time.real;
- },
- set now(value) { time.storage.jump(value); },
- get pristine() {
- let baseTime = GM_getValue('baseTime', null);
- let contTime = GM_getValue('contTime', null);
- let scale = GM_getValue('scale', null);
- return (baseTime == null || contTime == null) && scale == null;
- },
- set pristine(value) {
- if (!value) return;
- time.storage.reset(true, true, false);
- },
- get real() { return apply(date.realTime, DateConstructor, []); },
- get scale() {
- let scale = GM_getValue('scale', null);
- if (scale != null) return scale;
- return 1;
- },
- set scale(value) {
- if (value === time.storage.scale) return;
- GM_setValue('scale', +value);
- }
- },
- get debug() { return debug; },
- set debug(value) { debug = !!value; },
- get now() { return apply(date.now, DateConstructor, []); },
- set now(value) { time.jump(value); },
- get pristine() { return pristine; },
- set pristine(value) { if (value) time.reset(); },
- get real() { return apply(date.realTime, DateConstructor, []); },
- get scale() { return scale; },
- set scale(value) {
- value = +value;
- if (value === scale) return;
- pristine = false; update(); scale = value;
- }
- };
- freeze(time.storage);
- defineProperty(getPrototypeOf(window), 'time', {
- value: freeze(time),
- writable: true,
- enumerable: false,
- configurable: true
- });
- /** @type {(() => void)[]} */
- const updaters = [];
- /**
- * @param {() => number} func
- * @param {any} self
- */
- function wrap_now(func, self, offset = 0) {
- let baseTime = 0;
- let contTime = baseTime;
- /** @type {ProxyHandler<typeof func>} */
- const handler = {
- apply(target, self, args) {
- if (debug) log('apply(%o, %o, %o)', target, self, args);
- let time = apply(target, self, args);
- if (pristine || !isFinite(time)) return time;
- return ((time - baseTime) * scale) + contTime;
- }
- };
- setPrototypeOf(handler, null);
- updaters[updaters.length] =
- function update() {
- if (!handler.apply) return;
- contTime = timeJump == null ? handler.apply(func, self, []) : timeJump + offset;
- baseTime = apply(func, self, []);
- if (timeReset) contTime = baseTime;
- };
- return new Proxy(func, handler);
- }
- window.Performance.prototype.now = wrap_now(
- window.Performance.prototype.now,
- window.performance,
- window.performance.now() - window.Date.now()
- );
- const DateConstructor = window.Date;
- /** @type {{ realTime: typeof Date.now, now: typeof Date.now, toString: typeof Date.prototype.toString, handler: ProxyHandler<DateConstructor> }} */
- const date = {
- realTime: window.Date.now,
- now: wrap_now(window.Date.now, window.Date),
- toString: DateConstructor.prototype.toString,
- handler: {
- apply(target, self, args) {
- if (debug) log('apply(%o, %o, %o)', target, self, args);
- if (pristine) return DateConstructor();
- return time.toString();
- },
- construct(target, args, newTarget) {
- if (debug) log('construct(%o, %o, %o)', target, args, newTarget);
- if (!pristine && args.length < 1) {
- args[0] = time.now;
- }
- return construct(DateConstructor, args, newTarget);
- }
- }
- };
- setPrototypeOf(date, null);
- setPrototypeOf(date.handler, null);
- DateConstructor.now = date.now;
- window.Date = new Proxy(DateConstructor, date.handler);
- window.Date.prototype.constructor = window.Date;
- function noop() { }
- /**
- * @param {(handler: TimerHandler, timeout?: number | undefined, ...args: any[]) => number} func
- */
- function wrap_timer(func) {
- /** @type {ProxyHandler<typeof func>} */
- const handler = {
- apply(target, self, args) {
- if (debug) log('apply(%o, %o, %o)', target, self, args);
- if (!pristine && args.length > 1) {
- args[1] = +args[1];
- if (args[1] && scale === 0)
- args[0] = noop;
- else if (args[1] && isFinite(args[1]))
- args[1] /= scale;
- }
- return apply(target, self, args);
- }
- };
- setPrototypeOf(handler, null);
- return new Proxy(func, handler);
- }
- window.setTimeout = wrap_timer(window.setTimeout);
- window.setInterval = wrap_timer(window.setInterval);
- time.storage.load();
- })(/** @type {typeof window} */(unsafeWindow));