GM web hooks

Makes GM_xmlhttpRequest and GM_download queued

目前为 2023-02-20 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/scripts/460385/1152021/GM%20web%20hooks.js

  1. /* eslint-disable no-multi-spaces */
  2.  
  3. // ==UserScript==
  4. // @name GM web hooks
  5. // @namespace GM-web-hooks
  6. // @version 0.1.1
  7. // @description Makes GM_xmlhttpRequest and GM_download queued
  8. // @author PY-DNG
  9. // @license GPL-v3
  10. // ==/UserScript==
  11.  
  12. /* global LogLevel DoLog Err $ $All $CrE $AEL addStyle destroyEvent copyProp copyProps parseArgs escJsStr replaceText getUrlArgv dl_browser dl_GM AsyncManager */
  13.  
  14. let [GMXHRHook, GMDLHOOK] = (function __MAIN__() {
  15. 'use strict';
  16.  
  17. return [GMXHRHook, GMDLHOOK];
  18.  
  19. // GM_XHR HOOK: The number of running GM_XHRs in a time must under maxXHR
  20. // Returns the abort function to stop the request anyway(no matter it's still waiting, or requesting)
  21. // (If the request is invalid, such as url === '', will return false and will NOT make this request)
  22. // If the abort function called on a request that is not running(still waiting or finished), there will be NO onabort event
  23. // Requires: function delItem(){...} & function uniqueIDMaker(){...}
  24. function GMXHRHook(maxXHR=5) {
  25. const GM_XHR = GM_xmlhttpRequest;
  26. const getID = function() {
  27. let id = 0;
  28. return () => id++;
  29. }();
  30. let todoList = [], ongoingList = [];
  31. GM_xmlhttpRequest = safeGMxhr;
  32.  
  33. function safeGMxhr() {
  34. // Get an id for this request, arrange a request object for it.
  35. const id = getID();
  36. const request = {id: id, args: arguments, aborter: null};
  37.  
  38. // Deal onload function first
  39. dealEndingEvents(request);
  40.  
  41. /* DO NOT DO THIS! KEEP ITS ORIGINAL PROPERTIES!
  42. // Stop invalid requests
  43. if (!validCheck(request)) {
  44. return false;
  45. }
  46. */
  47.  
  48. // Judge if we could start the request now or later?
  49. todoList.push(request);
  50. checkXHR();
  51. return makeAbortFunc(id);
  52.  
  53. // Decrease activeXHRCount while GM_XHR onload;
  54. function dealEndingEvents(request) {
  55. const e = request.args[0];
  56.  
  57. // onload event
  58. const oriOnload = e.onload;
  59. e.onload = function() {
  60. reqFinish(request.id);
  61. checkXHR();
  62. oriOnload ? oriOnload.apply(null, arguments) : function() {};
  63. }
  64.  
  65. // onerror event
  66. const oriOnerror = e.onerror;
  67. e.onerror = function() {
  68. reqFinish(request.id);
  69. checkXHR();
  70. oriOnerror ? oriOnerror.apply(null, arguments) : function() {};
  71. }
  72.  
  73. // ontimeout event
  74. const oriOntimeout = e.ontimeout;
  75. e.ontimeout = function() {
  76. reqFinish(request.id);
  77. checkXHR();
  78. oriOntimeout ? oriOntimeout.apply(null, arguments) : function() {};
  79. }
  80.  
  81. // onabort event
  82. const oriOnabort = e.onabort;
  83. e.onabort = function() {
  84. reqFinish(request.id);
  85. checkXHR();
  86. oriOnabort ? oriOnabort.apply(null, arguments) : function() {};
  87. }
  88. }
  89.  
  90. // Check if the request is invalid
  91. function validCheck(request) {
  92. const e = request.args[0];
  93.  
  94. if (!e.url) {
  95. return false;
  96. }
  97.  
  98. return true;
  99. }
  100.  
  101. // Call a XHR from todoList and push the request object to ongoingList if called
  102. function checkXHR() {
  103. if (ongoingList.length >= maxXHR) {return false;};
  104. if (todoList.length === 0) {return false;};
  105. const req = todoList.shift();
  106. const reqArgs = req.args;
  107. const aborter = GM_XHR.apply(null, reqArgs);
  108. req.aborter = aborter;
  109. ongoingList.push(req);
  110. return req;
  111. }
  112.  
  113. // Make a function that aborts a certain request
  114. function makeAbortFunc(id) {
  115. return function() {
  116. let i;
  117.  
  118. // Check if the request haven't been called
  119. for (i = 0; i < todoList.length; i++) {
  120. const req = todoList[i];
  121. if (req.id === id) {
  122. // found this request: haven't been called
  123. todoList.splice(i, 1);
  124. return true;
  125. }
  126. }
  127.  
  128. // Check if the request is running now
  129. for (i = 0; i < ongoingList.length; i++) {
  130. const req = todoList[i];
  131. if (req.id === id) {
  132. // found this request: running now
  133. req.aborter();
  134. reqFinish(id);
  135. checkXHR();
  136. }
  137. }
  138.  
  139. // Oh no, this request is already finished...
  140. return false;
  141. }
  142. }
  143.  
  144. // Remove a certain request from ongoingList
  145. function reqFinish(id) {
  146. let i;
  147. for (i = 0; i < ongoingList.length; i++) {
  148. const req = ongoingList[i];
  149. if (req.id === id) {
  150. ongoingList = ongoingList.splice(i, 1);
  151. return true;
  152. }
  153. }
  154. return false;
  155. }
  156. }
  157. }
  158.  
  159. // GM_DL HOOK: The number of running GM_download in a time must under maxDL
  160. // Returns the abort function to stop the request anyway(no matter it's still waiting, or requesting)
  161. // (If the request is invalid, such as url === '', will return false and will NOT make this request)
  162. // If the abort function called on a request that is not running(still waiting or finished), there will be NO onabort event
  163. // Requires: function delItem(){...} & function uniqueIDMaker(){...}
  164. function GMDLHOOK(maxDL=5) {
  165. const GM_DL = GM_download;
  166. const getID = function() {
  167. let id = 0;
  168. return () => id++;
  169. }();
  170. let todoList = [], ongoingList = [];
  171. GM_download = safeGMdl;
  172.  
  173. function safeGMdl() {
  174. // Get an id for this request, arrange a request object for it.
  175. const id = getID();
  176. const request = {id: id, args: arguments, aborter: null};
  177.  
  178. // Deal onload function first
  179. dealEndingEvents(request);
  180.  
  181. /* DO NOT DO THIS! KEEP ITS ORIGINAL PROPERTIES!
  182. // Stop invalid requests
  183. if (!validCheck(request)) {
  184. return false;
  185. }
  186. */
  187.  
  188. // Judge if we could start the request now or later?
  189. todoList.push(request);
  190. checkDL();
  191. return makeAbortFunc(id);
  192.  
  193. // Decrease activeXHRCount while GM_DL onload;
  194. function dealEndingEvents(request) {
  195. const e = request.args[0];
  196.  
  197. // onload event
  198. const oriOnload = e.onload;
  199. e.onload = function() {
  200. reqFinish(request.id);
  201. checkDL();
  202. oriOnload ? oriOnload.apply(null, arguments) : function() {};
  203. }
  204.  
  205. // onerror event
  206. const oriOnerror = e.onerror;
  207. e.onerror = function() {
  208. reqFinish(request.id);
  209. checkDL();
  210. oriOnerror ? oriOnerror.apply(null, arguments) : function() {};
  211. }
  212.  
  213. // ontimeout event
  214. const oriOntimeout = e.ontimeout;
  215. e.ontimeout = function() {
  216. reqFinish(request.id);
  217. checkDL();
  218. oriOntimeout ? oriOntimeout.apply(null, arguments) : function() {};
  219. }
  220.  
  221. // onabort event
  222. const oriOnabort = e.onabort;
  223. e.onabort = function() {
  224. reqFinish(request.id);
  225. checkDL();
  226. oriOnabort ? oriOnabort.apply(null, arguments) : function() {};
  227. }
  228. }
  229.  
  230. // Check if the request is invalid
  231. function validCheck(request) {
  232. const e = request.args[0];
  233.  
  234. if (!e.url) {
  235. return false;
  236. }
  237.  
  238. return true;
  239. }
  240.  
  241. // Call a XHR from todoList and push the request object to ongoingList if called
  242. function checkDL() {
  243. if (ongoingList.length >= maxDL) {return false;};
  244. if (todoList.length === 0) {return false;};
  245. const req = todoList.shift();
  246. const reqArgs = req.args;
  247. const aborter = GM_DL.apply(null, reqArgs);
  248. req.aborter = aborter;
  249. ongoingList.push(req);
  250. return req;
  251. }
  252.  
  253. // Make a function that aborts a certain request
  254. function makeAbortFunc(id) {
  255. return function() {
  256. let i;
  257.  
  258. // Check if the request haven't been called
  259. for (i = 0; i < todoList.length; i++) {
  260. const req = todoList[i];
  261. if (req.id === id) {
  262. // found this request: haven't been called
  263. todoList.splice(i, 1);
  264. return true;
  265. }
  266. }
  267.  
  268. // Check if the request is running now
  269. for (i = 0; i < ongoingList.length; i++) {
  270. const req = todoList[i];
  271. if (req.id === id) {
  272. // found this request: running now
  273. req.aborter();
  274. reqFinish(id);
  275. checkDL();
  276. }
  277. }
  278.  
  279. // Oh no, this request is already finished...
  280. return false;
  281. }
  282. }
  283.  
  284. // Remove a certain request from ongoingList
  285. function reqFinish(id) {
  286. let i;
  287. for (i = 0; i < ongoingList.length; i++) {
  288. const req = ongoingList[i];
  289. if (req.id === id) {
  290. ongoingList = ongoingList.splice(i, 1);
  291. return true;
  292. }
  293. }
  294. return false;
  295. }
  296. }
  297. }
  298. })();

QingJ © 2025

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