Userscript Runtime

Try to make userscripts work on non-tempermonkey environments(e.g. X Browser, Via Browser, etc.) as well. Attention: All data that are expected to be saved in browser storage will actually NOT be saved, that means, everytime the userscript executes will act as this is the first time.

  1. // ==UserScript==
  2. // @name Userscript Runtime
  3. // @name:zh 用户脚本运行环境
  4. // @name:zh-CN 用户脚本运行环境
  5. // @namespace GM_PolyFill for Users
  6. // @version 0.1
  7. // @description Try to make userscripts work on non-tempermonkey environments(e.g. X Browser, Via Browser, etc.) as well. Attention: All data that are expected to be saved in browser storage will actually NOT be saved, that means, everytime the userscript executes will act as this is the first time.
  8. // @description:zh 尝试使其他用户脚本适配没有油猴支持的运行环境(如:X浏览器,via浏览器等等)。注意:所有的脚本存储在本地的数据都将不会被真正储存,而是会随着浏览器页面的关闭而被丢弃,也就是说,每次脚本运行时,都将如同第一次运行一样。
  9. // @description:zh-CN 尝试使其他用户脚本适配没有油猴支持的运行环境(如:X浏览器,via浏览器等等)。注意:所有的脚本存储在本地的数据都将不会被真正储存,而是会随着浏览器页面的关闭而被丢弃,也就是说,每次脚本运行时,都将如同第一次运行一样。
  10. // @author PY-DNG
  11. // @include *
  12. // @include http?://*
  13. // @include *
  14. // @include http://*
  15. // @include https://*
  16. // @include file://*
  17. // @include file:///*
  18. // @include ftp://*
  19. // @include ftp:///*
  20. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  21. // @grant GM_setValue
  22. // @grant GM_getValue
  23. // @grant GM_listValue
  24. // @grant GM_deleteValue
  25. // @grant GM_xmlhttpRequest
  26. // @grant GM_openInTab
  27. // @grant GM_setClipboard
  28. // @grant unsafeWindow
  29. // @run-at document-start
  30. // ==/UserScript==
  31.  
  32. (function() {
  33. 'use strict';
  34.  
  35. bypassXB();
  36. GM_PolyFill_Once();
  37.  
  38. // Bypass xbrowser's useless GM_functions
  39. function bypassXB() {
  40. if (typeof(mbrowser) === 'object') {
  41. window.unsafeWindow = window.GM_setClipboard = window.GM_openInTab = window.GM_xmlhttpRequest = window.GM_getValue = window.GM_setValue = window.GM_listValues = window.GM_deleteValue = undefined;
  42. }
  43. }
  44.  
  45. // GM_Polyfill By PY-DNG
  46. // Special Edition For Userscript Users
  47. // 2021.07.18 - 2021.07.19, 2021.10.03 - 2021.10.03
  48. // Simply provides the following GM_functions using localStorage, XMLHttpRequest and window.open:
  49. // Returns object GM_POLYFILLED which has the following properties that shows you which GM_functions are actually polyfilled:
  50. // GM_setValue, GM_getValue, GM_deleteValue, GM_listValues, GM_xmlhttpRequest, GM_openInTab, GM_setClipboard, unsafeWindow(object)
  51. // All polyfilled GM_functions are accessable in window object/Global_Scope(only without Tempermonkey Sandboxing environment)
  52. // -!!!- IMPORTANT: PROVIDED GM_*FUNCTIONS WILL ONLY BE ABLE IN SINGLE USE - THAT MEANS THAT ALL DATA YOU EXPECTED TO BE STORED IN BROWSER USING GM_SETVALUE WILL ACTUALLY NOT BE STORED! GM_SETVALUE WILL JUST STORE DATA INTO A CACHE OBJECT! -!!!-
  53. function GM_PolyFill_Once() {
  54. let GM_POLYFILL_storage = {};
  55. const GM_POLYFILLED = {
  56. GM_setValue: true,
  57. GM_getValue: true,
  58. GM_deleteValue: true,
  59. GM_listValues: true,
  60. GM_xmlhttpRequest: true,
  61. GM_openInTab: true,
  62. GM_setClipboard: true,
  63. unsafeWindow: true,
  64. once: true
  65. }
  66.  
  67. GM_setValue_polyfill();
  68. GM_getValue_polyfill();
  69. GM_deleteValue_polyfill();
  70. GM_listValues_polyfill();
  71. GM_xmlhttpRequest_polyfill();
  72. GM_openInTab_polyfill();
  73. GM_setClipboard_polyfill();
  74. unsafeWindow_polyfill();
  75.  
  76. // GM_setValue
  77. function GM_setValue_polyfill() {
  78. typeof (GM_setValue) === 'function' ? GM_POLYFILLED.GM_setValue = false: window.GM_setValue = PF_GM_setValue;;
  79.  
  80. function PF_GM_setValue(name, value) {
  81. name = String(name);
  82. GM_POLYFILL_storage[name] = value;
  83. }
  84. }
  85.  
  86. // GM_getValue
  87. function GM_getValue_polyfill() {
  88. typeof (GM_getValue) === 'function' ? GM_POLYFILLED.GM_getValue = false: window.GM_getValue = PF_GM_getValue;
  89.  
  90. function PF_GM_getValue(name, defaultValue) {
  91. name = String(name);
  92. if (GM_POLYFILL_storage.hasOwnProperty(name)) {
  93. return GM_POLYFILL_storage[name];
  94. } else {
  95. return defaultValue;
  96. }
  97. }
  98. }
  99.  
  100. // GM_deleteValue
  101. function GM_deleteValue_polyfill() {
  102. typeof (GM_deleteValue) === 'function' ? GM_POLYFILLED.GM_deleteValue = false: window.GM_deleteValue = PF_GM_deleteValue;
  103.  
  104. function PF_GM_deleteValue(name) {
  105. name = String(name);
  106. if (GM_POLYFILL_storage.hasOwnProperty(name)) {
  107. delete GM_POLYFILL_storage[name];
  108. }
  109. }
  110. }
  111.  
  112. // GM_listValues
  113. function GM_listValues_polyfill() {
  114. typeof (GM_listValues) === 'function' ? GM_POLYFILLED.GM_listValues = false: window.GM_listValues = PF_GM_listValues;
  115.  
  116. function PF_GM_listValues() {
  117. return Object.keys(GM_POLYFILL_storage);
  118. }
  119. }
  120.  
  121. // unsafeWindow
  122. function unsafeWindow_polyfill() {
  123. typeof (unsafeWindow) === 'object' ? GM_POLYFILLED.unsafeWindow = false: window.unsafeWindow = window;
  124. }
  125.  
  126. // GM_xmlhttpRequest
  127. // not supported properties of details: synchronous binary nocache revalidate context fetch
  128. // not supported properties of response(onload arguments[0]): finalUrl
  129. // ---!IMPORTANT!--- DOES NOT SUPPORT CROSS-ORIGIN REQUESTS!!!!! ---!IMPORTANT!---
  130. function GM_xmlhttpRequest_polyfill() {
  131. typeof (GM_xmlhttpRequest) === 'function' ? GM_POLYFILLED.GM_xmlhttpRequest = false: window.GM_xmlhttpRequest = PF_GM_xmlhttpRequest;
  132.  
  133. // details.synchronous is not supported as Tempermonkey
  134. function PF_GM_xmlhttpRequest(details) {
  135. const xhr = new XMLHttpRequest();
  136.  
  137. // open request
  138. const openArgs = [details.method, details.url, true];
  139. if (details.user && details.password) {
  140. openArgs.push(details.user);
  141. openArgs.push(details.password);
  142. }
  143. xhr.open.apply(xhr, openArgs);
  144.  
  145. // set headers
  146. if (details.headers) {
  147. for (const key of Object.keys(details.headers)) {
  148. xhr.setRequestHeader(key, details.headers[key]);
  149. }
  150. }
  151. details.cookie ? xhr.setRequestHeader('cookie', details.cookie) : function () {};
  152. details.anonymous ? xhr.setRequestHeader('cookie', '') : function () {};
  153.  
  154. // properties
  155. xhr.timeout = details.timeout;
  156. xhr.responseType = details.responseType;
  157. details.overrideMimeType ? xhr.overrideMimeType(details.overrideMimeType) : function () {};
  158.  
  159. // events
  160. xhr.onabort = details.onabort;
  161. xhr.onerror = details.onerror;
  162. xhr.onloadstart = details.onloadstart;
  163. xhr.onprogress = details.onprogress;
  164. xhr.onreadystatechange = details.onreadystatechange;
  165. xhr.ontimeout = details.ontimeout;
  166. xhr.onload = function (e) {
  167. const response = {
  168. readyState: xhr.readyState,
  169. status: xhr.status,
  170. statusText: xhr.statusText,
  171. responseHeaders: xhr.getAllResponseHeaders(),
  172. response: xhr.response
  173. };
  174. (details.responseType === '' || details.responseType === 'text') ? (response.responseText = xhr.responseText) : function () {};
  175. (details.responseType === '' || details.responseType === 'document') ? (response.responseXML = xhr.responseXML) : function () {};
  176. details.onload(response);
  177. }
  178.  
  179. // send request
  180. details.data ? xhr.send(details.data) : xhr.send();
  181.  
  182. return {
  183. abort: xhr.abort
  184. };
  185. }
  186. }
  187.  
  188. // NOTE: options(arg2) is NOT SUPPORTED! if provided, then will just be skipped.
  189. function GM_openInTab_polyfill() {
  190. typeof (GM_openInTab) === 'function' ? GM_POLYFILLED.GM_openInTab = false: window.GM_openInTab = PF_GM_openInTab;
  191.  
  192. function PF_GM_openInTab(url) {
  193. window.open(url);
  194. }
  195. }
  196.  
  197. // NOTE: needs to be called in an event handler function, and info(arg2) is NOT SUPPORTED!
  198. function GM_setClipboard_polyfill() {
  199. typeof (GM_setClipboard) === 'function' ? GM_POLYFILLED.GM_setClipboard = false: window.GM_setClipboard = PF_GM_setClipboard;
  200.  
  201. function PF_GM_setClipboard(text) {
  202. // Create a new textarea for copying
  203. const newInput = document.createElement('textarea');
  204. document.body.appendChild(newInput);
  205. newInput.value = text;
  206. newInput.select();
  207. document.execCommand('copy');
  208. document.body.removeChild(newInput);
  209. }
  210. }
  211.  
  212. window.GM_POLYFILLED = GM_POLYFILLED;
  213. return GM_POLYFILLED;
  214. }
  215. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址