GM Fetch

A fetch API of GM_xmlhttpRequest

このスクリプトは単体で利用できません。右のようなメタデータを含むスクリプトから、ライブラリとして読み込まれます: // @require https://update.greatest.deepsurf.us/scripts/472236/1811775/GM%20Fetch.js

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

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

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

作者のサイトでサポートを受ける。または、このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         GM Fetch
// @namespace    https://github.com/Sec-ant
// @version      1.2.4
// @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() {
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() {
			var _GM = typeof GM != "undefined" ? GM : void 0;
			var _GM_xmlhttpRequest = typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0;
			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 = _GM_xmlhttpRequest || _GM.xmlHttpRequest;
				if (typeof gmXhr !== "function") 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;
		});
	})))();
})();