Absolute Visibility

Makes tabs and windows think they're visible even when they're not.

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/456228/1309113/Absolute%20Visibility.js

  1. // ==UserScript==
  2. // @name Absolute Visibility
  3. // @namespace https://naeembolchhi.github.io/
  4. // @version 0.2
  5. // @description Makes tabs and windows think they're visible even when they're not.
  6. // @author NaeemBolchhi
  7. // @license Mozilla Public License 2.0
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. const knife = `const script = document.currentScript;
  12. const isFirefox = /Firefox/.test(navigator.userAgent) || typeof InstallTrigger !== 'undefined';
  13.  
  14. const block = e => {
  15. e.preventDefault();
  16. e.stopPropagation();
  17. e.stopImmediatePropagation();
  18. };
  19.  
  20. const once = {
  21. focus: true,
  22. visibilitychange: true,
  23. webkitvisibilitychange: true
  24. };
  25.  
  26. /* visibility */
  27. Object.defineProperty(document, 'visibilityState', {
  28. get() {
  29. return 'visible';
  30. }
  31. });
  32. if (isFirefox === false) {
  33. Object.defineProperty(document, 'webkitVisibilityState', {
  34. get() {
  35. return 'visible';
  36. }
  37. });
  38. }
  39. document.addEventListener('visibilitychange', e => {
  40. script.dispatchEvent(new Event('state'));
  41. if (script.dataset.visibility !== 'false') {
  42. if (once.visibilitychange) {
  43. once.visibilitychange = false;
  44. return;
  45. }
  46. return block(e);
  47. }
  48. }, true);
  49. document.addEventListener('webkitvisibilitychange', e => {
  50. if (script.dataset.visibility !== 'false') {
  51. if (once.webkitvisibilitychange) {
  52. once.webkitvisibilitychange = false;
  53. return;
  54. }
  55. return block(e);
  56. }
  57. }, true);
  58.  
  59.  
  60. window.addEventListener('pagehide', e => script.dataset.visibility !== 'false' && block(e), true);
  61.  
  62. /* hidden */
  63. Object.defineProperty(document, 'hidden', {
  64. get() {
  65. return false;
  66. }
  67. });
  68. Object.defineProperty(document, isFirefox ? 'mozHidden' : 'webkitHidden', {
  69. get() {
  70. return false;
  71. }
  72. });
  73.  
  74. /* focus */
  75. Document.prototype.hasFocus = new Proxy(Document.prototype.hasFocus, {
  76. apply(target, self, args) {
  77. if (script.dataset.focus !== 'false') {
  78. return true;
  79. }
  80. return Reflect.apply(target, self, args);
  81. }
  82. });
  83.  
  84. const onfocus = e => {
  85. if (script.dataset.focus !== 'false') {
  86. if (e.target === document || e.target === window) {
  87. if (once.focus && document.readyState === 'complete' && e.target === window) {
  88. once.focus = false;
  89. return;
  90. }
  91. return block(e);
  92. }
  93. }
  94. };
  95. // document.addEventListener('focus', onfocus, true);
  96. window.addEventListener('focus', onfocus, true);
  97.  
  98.  
  99. /* blur */
  100. const onblur = e => {
  101. if (script.dataset.blur !== 'false') {
  102. if (e.target === document || e.target === window) {
  103. return block(e);
  104. }
  105. }
  106. };
  107. document.addEventListener('blur', onblur, true);
  108. window.addEventListener('blur', onblur, true);
  109.  
  110. /* mouse */
  111. window.addEventListener('mouseleave', e => {
  112. if (script.dataset.mouseleave !== 'false') {
  113. if (e.target === document || e.target === window) {
  114. return block(e);
  115. }
  116. }
  117. }, true);
  118.  
  119. /* requestAnimationFrame */
  120. let lastTime = 0;
  121. window.requestAnimationFrame = new Proxy(window.requestAnimationFrame, {
  122. apply(target, self, args) {
  123. if (script.dataset.hidden === 'true') {
  124. const currTime = Date.now();
  125. const timeToCall = Math.max(0, 16 - (currTime - lastTime));
  126. const id = window.setTimeout(function() {
  127. args[0](performance.now());
  128. }, timeToCall);
  129. lastTime = currTime + timeToCall;
  130. return id;
  131. } else {
  132. return Reflect.apply(target, self, args);
  133. }
  134. }
  135. });
  136. window.cancelAnimationFrame = new Proxy(window.cancelAnimationFrame, {
  137. apply(target, self, args) {
  138. if (script.dataset.hidden === 'true') {
  139. clearTimeout(args[0]);
  140. }
  141. return Reflect.apply(target, self, args);
  142. }
  143. });`;
  144.  
  145. (function eyeStabber() {
  146. let html, script;
  147. html = document.documentElement;
  148. if (!html) {window.location.reload();}
  149. script = document.createElement("script");
  150. script.setAttribute("type", "text/javascript");
  151. script.innerHTML = knife;
  152. html.appendChild(script);
  153. script.remove();
  154. })();