Time Control

Script allowing you to control time.

当前为 2024-03-30 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Time Control
  3. // @description Script allowing you to control time.
  4. // @icon https://parsefiles.back4app.com/JPaQcFfEEQ1ePBxbf6wvzkPMEqKYHhPYv8boI1Rc/ce262758ff44d053136358dcd892979d_low_res_Time_Machine.png
  5. // @namespace mailto:lucaszheng2011@outlook.com
  6. // @version 1.2
  7. // @author lucaszheng
  8. // @license MIT
  9. //
  10. // @match *://*/*
  11. // @grant unsafeWindow
  12. // @inject-into page
  13. // @run-at document-start
  14. // ==/UserScript==
  15.  
  16. (window => {
  17. "use strict";
  18. let scale = 1, pristine = true;
  19. let timeJump = 0;
  20. let timeSync = false;
  21. let debug = false;
  22.  
  23. const { isFinite,
  24. Reflect: {
  25. apply, construct,
  26. setPrototypeOf
  27. },
  28. Object: {
  29. defineProperty,
  30. freeze
  31. },
  32. console: {
  33. trace: log
  34. }
  35. } = window;
  36.  
  37. function update() {
  38. for (let idx = 0; idx < updaters.length; idx++) {
  39. updaters[idx]();
  40. }
  41. }
  42.  
  43. const time = freeze({
  44. get debug() { return debug; },
  45. set debug(value) { debug = !!value; },
  46.  
  47. get scale() { return scale; },
  48. set scale(value) { pristine = false; update(); scale = +value; },
  49.  
  50. get pristine() { return pristine; },
  51. set pristine(value) { if (value) time.sync(); },
  52.  
  53. get now() { return apply(date.now, DateConstructor, []); },
  54. set now(value) { time.jump(value); },
  55.  
  56. get real() { return apply(date.realTime, DateConstructor, []); },
  57.  
  58. jump(newTime) {
  59. if (newTime == null) return;
  60. pristine = false;
  61. timeJump = +newTime;
  62. update();
  63. timeJump = 0;
  64. },
  65.  
  66. sync(resetScale = true) {
  67. if (pristine) return;
  68. if (resetScale) scale = 1;
  69. timeSync = true;
  70. update();
  71. timeSync = false;
  72. pristine = scale === 1;
  73. }
  74. });
  75. defineProperty(window, 'time', {
  76. value: time,
  77. writeable: true,
  78. enumerable: false,
  79. configurable: true
  80. });
  81. const updaters = [];
  82.  
  83. function wrap_now(func, self, offset = 0) {
  84. let baseTime = 0;
  85. let contTime = baseTime;
  86.  
  87. const handler = {
  88. apply(target, self, args) {
  89. if (debug) log('apply(%o, %o, %o)', target, self, args);
  90. let time = apply(target, self, args);
  91. if (pristine || !isFinite(time)) return time;
  92. return ((time - baseTime) * scale) + contTime;
  93. }
  94. };
  95. setPrototypeOf(handler, null);
  96.  
  97. updaters[updaters.length] =
  98. function update() {
  99. contTime = timeJump ?
  100. timeJump + offset :
  101. handler.apply(func, self, []);
  102. baseTime = apply(func, self, []);
  103. if (timeSync) contTime = baseTime;
  104. };
  105.  
  106. return new Proxy(func, handler);
  107. }
  108.  
  109. window.Performance.prototype.now = wrap_now(
  110. window.Performance.prototype.now,
  111. window.performance,
  112. window.performance.now() - window.Date.now()
  113. );
  114.  
  115. const DateConstructor = window.Date;
  116. const date = {
  117. realTime: window.Date.now,
  118. now: wrap_now(window.Date.now, window.Date),
  119. toString: DateConstructor.prototype.toString,
  120. handler: {
  121. apply(target, self, args) {
  122. if (debug) log('apply(%o, %o, %o)', target, self, args);
  123. if (!pristine) {
  124. args.length = 1;
  125. args[0] = apply(date.now, DateConstructor, []);
  126. } else return DateConstructor();
  127. return apply(date.toString, construct(DateConstructor, args), []);
  128. },
  129. construct(target, args, newTarget) {
  130. if (debug) log('construct(%o, %o, %o)', target, args, newTarget);
  131. if (!pristine && args.length < 1) {
  132. args[0] = apply(date.now, DateConstructor, []);
  133. }
  134. return construct(DateConstructor, args, newTarget);
  135. }
  136. }
  137. };
  138. setPrototypeOf(date, null);
  139. setPrototypeOf(date.handler, null);
  140. DateConstructor.now = date.now;
  141.  
  142. window.Date = new Proxy(DateConstructor, date.handler);
  143. window.Date.prototype.constructor = window.Date;
  144.  
  145. function noop() { }
  146.  
  147. function wrap_timer(func, self) {
  148. const handler = {
  149. apply(target, self, args) {
  150. if (debug) log('apply(%o, %o, %o)', target, self, args);
  151. if (!pristine && args.length > 1) {
  152. args[1] = +args[1];
  153. if (args[1] && scale === 0)
  154. args[0] = noop;
  155. else if (args[1] && isFinite(args[1]))
  156. args[1] /= scale;
  157. }
  158. return apply(target, self, args);
  159. }
  160. };
  161. setPrototypeOf(handler, null);
  162. return new Proxy(func, handler);
  163. }
  164.  
  165. window.setTimeout = wrap_timer(window.setTimeout);
  166. window.setInterval = wrap_timer(window.setInterval);
  167. })(typeof unsafeWindow === 'object' ? unsafeWindow : globalThis);