GM Fetch

A fetch API of GM_xmlhttpRequest

Tento skript by neměl být instalován přímo. Jedná se o knihovnu, kterou by měly jiné skripty využívat pomocí meta příkazu // @require https://update.greasyfork.org/scripts/472236/1868041/GM%20Fetch.js

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==UserScript==
// @name         GM Fetch
// @namespace    https://github.com/Sec-ant
// @version      1.2.5
// @author       Ze-Zheng Wu
// @description  A fetch API for GM_xmlhttpRequest / GM.xmlHttpRequest
// @license      MIT
// @homepage     https://github.com/Sec-ant/gm-fetch
// @homepageURL  https://github.com/Sec-ant/gm-fetch
// @source       https://github.com/Sec-ant/gm-fetch.git
// @supportURL   https://github.com/Sec-ant/gm-fetch/issues
// @downloadURL  https://fastly.jsdelivr.net/npm/@sec-ant/gm-fetch@latest/dist/gm-fetch.user.js
// @updateURL    https://fastly.jsdelivr.net/npm/@sec-ant/gm-fetch@latest/dist/gm-fetch.meta.js
// @match        *://*/*
// @grant        GM.xmlHttpRequest
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function() {
	"use strict";
	var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
	__commonJSMin(((exports, module) => {
		(function(global, factory) {
			typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define([], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, global.gmFetch = factory());
		})(exports, function() {
			function getGmXhr() {
				if (typeof GM_xmlhttpRequest === "function") return GM_xmlhttpRequest;
				if (typeof GM !== "undefined" && typeof GM.xmlHttpRequest === "function") return GM.xmlHttpRequest;
			}
			function parseHeaders(rawHeaders) {
				const headers = new Headers();
				const preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, " ");
				for (const line of preProcessedHeaders.split(/\r?\n/)) {
					const parts = line.split(":");
					const key = parts.shift()?.trim();
					if (key) {
						const value = parts.join(":").trim();
						try {
							headers.append(key, value);
						} catch (error) {
							console.warn(`Response ${error.message}`);
						}
					}
				}
				return headers;
			}
			var gmFetch = async (input, init) => {
				const gmXhr = getGmXhr();
				if (!gmXhr) throw new DOMException("GM_xmlhttpRequest or GM.xmlHttpRequest is not granted.", "NotFoundError");
				const request = new Request(input, init);
				if (request.signal.aborted) throw new DOMException("Network request aborted.", "AbortError");
				const data = await request.blob();
				const headers = Object.fromEntries(request.headers);
				new Headers(init?.headers).forEach((value, key) => {
					headers[key] = value;
				});
				return new Promise((resolve, reject) => {
					let settled = false;
					const responseBlobPromise = new Promise((resolveBlob) => {
						const { abort } = gmXhr({
							method: request.method.toUpperCase(),
							url: request.url || location.href,
							headers,
							data: data.size ? data : void 0,
							redirect: request.redirect,
							binary: true,
							nocache: request.cache === "no-store",
							revalidate: request.cache === "reload",
							timeout: 3e5,
							responseType: gmXhr.RESPONSE_TYPE_STREAM ?? "blob",
							overrideMimeType: request.headers.get("Content-Type") ?? void 0,
							anonymous: request.credentials === "omit",
							onload: ({ response: responseBody }) => {
								if (settled) {
									resolveBlob(null);
									return;
								}
								resolveBlob(responseBody);
							},
							async onreadystatechange({ readyState, responseHeaders, status, statusText, finalUrl, response: responseBody }) {
								if (readyState === XMLHttpRequest.DONE) request.signal.removeEventListener("abort", abort);
								else if (readyState !== XMLHttpRequest.HEADERS_RECEIVED) return;
								if (settled) {
									resolveBlob(null);
									return;
								}
								const parsedHeaders = parseHeaders(responseHeaders);
								const redirected = request.url !== finalUrl;
								const response = new Response(responseBody instanceof ReadableStream ? responseBody : await responseBlobPromise, {
									headers: parsedHeaders,
									status,
									statusText
								});
								Object.defineProperties(response, {
									url: { value: finalUrl },
									type: { value: "basic" },
									...response.redirected !== redirected ? { redirected: { value: redirected } } : {},
									...parsedHeaders.has("set-cookie") || parsedHeaders.has("set-cookie2") ? { headers: { value: parsedHeaders } } : {}
								});
								resolve(response);
								settled = true;
							},
							onerror: ({ statusText, error }) => {
								reject(new TypeError(statusText || error || "Network request failed."));
								resolveBlob(null);
							},
							ontimeout() {
								reject(new TypeError("Network request timeout."));
								resolveBlob(null);
							},
							onabort() {
								reject(new DOMException("Network request aborted.", "AbortError"));
								resolveBlob(null);
							}
						});
						request.signal.addEventListener("abort", abort);
					});
				});
			};
			return gmFetch;
		});
	}))();
})();