Du skal logge ind eller oprette en konto for at kunne fortsætte.

tampermonkey parallel

github.com/Tampermonkey/tampermonkey/issues/2215

Este script no debería instalarse directamente. Es una biblioteca que utilizan otros scripts mediante la meta-directiva de inclusión // @require https://update.greasyfork.org/scripts/522123/1511104/tampermonkey%20parallel.js

  1. /*
  2. * https://github.com/Tampermonkey/tampermonkey/issues/2215
  3. *
  4. * This script provides a workaround for a Chrome MV3 issue (https://github.com/w3c/webextensions/issues/694)
  5. * where extensions can't set/delete headers that are preserved over redirects.
  6. *
  7. * By setting `redirect: 'manual'` and following redirects manually, this script ensures request redirects work
  8. * as intended and requests to different URLs are made in parallel (again).
  9. *
  10. * Userscript authors should include this as a `@require` when they need to make parallel requests with GM_xmlhttpRequest,
  11. * especially if requests might take a long time to complete.
  12. *
  13. * Including this script will modify the behavior of GM_xmlhttpRequest and GM.xmlHttpRequest in Tampermonkey only.
  14. *
  15. * Usage:
  16. *
  17. * Add this to the metadata block of your userscript:
  18. *
  19. * // @grant GM_xmlhttpRequest
  20. * // @require https://raw.githubusercontent.com/Tampermonkey/utils/refs/heads/main/requires/gh_2215_make_GM_xhr_more_parallel_again.js
  21. *
  22. **/
  23.  
  24. /* global GM_info, GM_xmlhttpRequest, GM */
  25.  
  26. const HAS_GM = typeof GM !== "undefined";
  27. const NEW_GM = ((scope, GM) => {
  28. // Check if running in Tampermonkey and if version supports redirect control
  29. if (
  30. GM_info.scriptHandler !== "Tampermonkey" ||
  31. compareVersions(GM_info.version, "5.3.2") < 0
  32. )
  33. return;
  34.  
  35. // Backup original functions
  36. const GM_xmlhttpRequestOrig = GM_xmlhttpRequest;
  37. const GM_xmlHttpRequestOrig = GM.xmlHttpRequest;
  38.  
  39. function compareVersions(v1, v2) {
  40. const parts1 = v1.split(".").map(Number);
  41. const parts2 = v2.split(".").map(Number);
  42. const length = Math.max(parts1.length, parts2.length);
  43.  
  44. for (let i = 0; i < length; i++) {
  45. const num1 = parts1[i] || 0;
  46. const num2 = parts2[i] || 0;
  47.  
  48. if (num1 > num2) return 1;
  49. if (num1 < num2) return -1;
  50. }
  51. return 0;
  52. }
  53.  
  54. // Wrapper for GM_xmlhttpRequest
  55. function GM_xmlhttpRequestWrapper(odetails) {
  56. // If redirect is manually set, simply pass odetails to the original function
  57. if (odetails.redirect !== undefined) {
  58. return GM_xmlhttpRequestOrig(odetails);
  59. }
  60.  
  61. // Warn if onprogress is used with settings incompatible with fetch mode used in background
  62. if (odetails.onprogress || odetails.fetch === false) {
  63. console.warn("Fetch mode does not support onprogress in the background.");
  64. }
  65.  
  66. const { onload, onloadend, onerror, onabort, ontimeout, ...details } =
  67. odetails;
  68.  
  69. // Set redirect to manual and handle redirects
  70. const handleRedirects = (initialDetails) => {
  71. const request = GM_xmlhttpRequestOrig({
  72. ...initialDetails,
  73. redirect: "manual",
  74. onload: function (response) {
  75. if (response.status >= 300 && response.status < 400) {
  76. const m = response.responseHeaders.match(/Location:\s*(\S+)/i);
  77. // Follow redirect manually
  78. const redirectUrl = m && m[1];
  79. if (redirectUrl) {
  80. const absoluteUrl = new URL(redirectUrl, initialDetails.url).href;
  81. handleRedirects({ ...initialDetails, url: absoluteUrl });
  82. return;
  83. }
  84. }
  85.  
  86. if (onload) onload.call(this, response);
  87. if (onloadend) onloadend.call(this, response);
  88. },
  89. onerror: function (response) {
  90. if (onerror) onerror.call(this, response);
  91. if (onloadend) onloadend.call(this, response);
  92. },
  93. onabort: function (response) {
  94. if (onabort) onabort.call(this, response);
  95. if (onloadend) onloadend.call(this, response);
  96. },
  97. ontimeout: function (response) {
  98. if (ontimeout) ontimeout.call(this, response);
  99. if (onloadend) onloadend.call(this, response);
  100. },
  101. });
  102. return request;
  103. };
  104.  
  105. return handleRedirects(details);
  106. }
  107.  
  108. // Wrapper for GM.xmlHttpRequest
  109. function GM_xmlHttpRequestWrapper(odetails) {
  110. let abort;
  111.  
  112. const p = new Promise((resolve, reject) => {
  113. const { onload, ontimeout, onerror, ...send } = odetails;
  114.  
  115. send.onerror = function (r) {
  116. if (onerror) {
  117. resolve(r);
  118. onerror.call(this, r);
  119. } else {
  120. reject(r);
  121. }
  122. };
  123. send.ontimeout = function (r) {
  124. if (ontimeout) {
  125. // See comment above
  126. resolve(r);
  127. ontimeout.call(this, r);
  128. } else {
  129. reject(r);
  130. }
  131. };
  132. send.onload = function (r) {
  133. resolve(r);
  134. if (onload) onload.call(this, r);
  135. };
  136.  
  137. const a = GM_xmlhttpRequestWrapper(send).abort;
  138. if (abort === true) {
  139. a();
  140. } else {
  141. abort = a;
  142. }
  143. });
  144.  
  145. p.abort = () => {
  146. if (typeof abort === "function") {
  147. abort();
  148. } else {
  149. abort = true;
  150. }
  151. };
  152.  
  153. return p;
  154. }
  155.  
  156. // Export wrappers
  157. GM_xmlhttpRequest = GM_xmlhttpRequestWrapper;
  158. scope.GM_xmlhttpRequestOrig = GM_xmlhttpRequestOrig;
  159.  
  160. const gopd = Object.getOwnPropertyDescriptor(GM, "xmlHttpRequest");
  161. if (gopd && gopd.configurable === false) {
  162. return {
  163. __proto__: GM,
  164. xmlHttpRequest: GM_xmlHttpRequestWrapper,
  165. xmlHttpRequestOrig: GM_xmlHttpRequestOrig,
  166. };
  167. } else {
  168. GM.xmlHttpRequest = GM_xmlHttpRequestWrapper;
  169. GM.xmlHttpRequestOrig = GM_xmlHttpRequestOrig;
  170. }
  171. })(this, HAS_GM ? GM : {});
  172.  
  173. if (HAS_GM && NEW_GM) GM = NEW_GM;