ostrich

适用于Gazelle等架构站点的音乐转种工具

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

Advertisement:

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

Advertisement:

// ==UserScript==
// @name               ostrich
// @namespace          https://dvxg.de/
// @version            0.3.10
// @author             davidxuang
// @description        Reposting music torrents on sites built on Gazelle and other frameworks
// @description:zh-CN  适用于Gazelle等架构站点的音乐转种工具
// @license            AGPL-3.0-only
// @icon               https://cdn.jsdelivr.net/gh/microsoft/fluentui-emoji/assets/Musical%20score/3D/musical_score_3d.png
// @homepage           https://github.com/davidxuang/ostrich
// @homepageURL        https://github.com/davidxuang/ostrich
// @match              https://logs.musichoarders.xyz/
// @match              https://*.dicmusic.com/torrents.php*
// @match              https://*.dicmusic.com/artist.php*
// @match              https://*.dicmusic.com/collages.php*
// @match              https://*.dicmusic.com/upload.php*
// @match              https://*.jpopsuki.eu/torrents.php*
// @match              https://*.jpopsuki.eu/artist.php*
// @match              https://*.jpopsuki.eu/collages.php*
// @match              https://*.jpopsuki.eu/upload.php*
// @match              https://*.orpheus.network/torrents.php*
// @match              https://*.orpheus.network/artist.php*
// @match              https://*.orpheus.network/collages.php*
// @match              https://*.orpheus.network/upload.php*
// @match              https://*.redacted.sh/torrents.php*
// @match              https://*.redacted.sh/artist.php*
// @match              https://*.redacted.sh/collages.php*
// @match              https://*.redacted.sh/upload.php*
// @match              https://*.open.cd/plugin_details.php*
// @match              https://*.open.cd/plugin_upload.php*
// @match              https://*.tjupt.org/details.php*
// @match              https://*.tjupt.org/upload.php*
// @resource           brotli_wasm_bg  https://cdn.jsdelivr.net/npm/[email protected]/pkg.web/brotli_wasm_bg.wasm
// @grant              GM.getResourceUrl
// @grant              GM.xmlHttpRequest
// ==/UserScript==

(async function() {
	"use strict";
	var __create = Object.create;
	var __defProp = Object.defineProperty;
	var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
	var __getOwnPropNames = Object.getOwnPropertyNames;
	var __getProtoOf = Object.getPrototypeOf;
	var __hasOwnProp = Object.prototype.hasOwnProperty;
	var __commonJSMin$1 = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
	var __exportAll = (all, no_symbols) => {
		let target = {};
		for (var name in all) __defProp(target, name, {
			get: all[name],
			enumerable: true
		});
		if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
		return target;
	};
	var __copyProps = (to, from, except, desc) => {
		if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
			key = keys[i];
			if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
				get: ((k) => from[k]).bind(null, key),
				enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
			});
		}
		return to;
	};
	var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
		value: mod,
		enumerable: true
	}) : target, mod));
	var _GM = (() => typeof GM != "undefined" ? GM : void 0)();
	var require_truncate = __commonJSMin$1(((exports, module) => {
		function isHighSurrogate(codePoint) {
			return codePoint >= 55296 && codePoint <= 56319;
		}
		function isLowSurrogate(codePoint) {
			return codePoint >= 56320 && codePoint <= 57343;
		}
		module.exports = function truncate(getLength, string, byteLength) {
			if (typeof string !== "string") throw new Error("Input must be string");
			var charLength = string.length;
			var curByteLength = 0;
			var codePoint;
			var segment;
			for (var i = 0; i < charLength; i += 1) {
				codePoint = string.charCodeAt(i);
				segment = string[i];
				if (isHighSurrogate(codePoint) && isLowSurrogate(string.charCodeAt(i + 1))) {
					i += 1;
					segment += string[i];
				}
				curByteLength += getLength(segment);
				if (curByteLength === byteLength) return string.slice(0, i + 1);
				else if (curByteLength > byteLength) return string.slice(0, i - segment.length + 1);
			}
			return string;
		};
	}));
	var require_browser$1 = __commonJSMin$1(((exports, module) => {
		function isHighSurrogate(codePoint) {
			return codePoint >= 55296 && codePoint <= 56319;
		}
		function isLowSurrogate(codePoint) {
			return codePoint >= 56320 && codePoint <= 57343;
		}
		module.exports = function getByteLength(string) {
			if (typeof string !== "string") throw new Error("Input must be string");
			var charLength = string.length;
			var byteLength = 0;
			var codePoint = null;
			var prevCodePoint = null;
			for (var i = 0; i < charLength; i++) {
				codePoint = string.charCodeAt(i);
				if (isLowSurrogate(codePoint)) if (prevCodePoint != null && isHighSurrogate(prevCodePoint)) byteLength += 1;
				else byteLength += 3;
				else if (codePoint <= 127) byteLength += 1;
				else if (codePoint >= 128 && codePoint <= 2047) byteLength += 2;
				else if (codePoint >= 2048 && codePoint <= 65535) byteLength += 3;
				prevCodePoint = codePoint;
			}
			return byteLength;
		};
	}));
	var require_browser = __commonJSMin$1(((exports, module) => {
		var truncate = require_truncate();
		var getLength = require_browser$1();
		module.exports = truncate.bind(null, getLength);
	}));
	var import_sanitize_filename = __toESM(__commonJSMin$1(((exports, module) => {
		var truncate = require_browser();
		var illegalRe = /[\/\?<>\\:\*\|"]/g;
		var controlRe = /[\x00-\x1f\x80-\x9f]/g;
		var reservedRe = /^\.+$/;
		var windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i;
		function replaceTrailingDotsAndSpaces(str, replacement) {
			var end = str.length;
			while (end > 0 && (str[end - 1] === "." || str[end - 1] === " ")) end--;
			return end < str.length ? str.slice(0, end) + replacement : str;
		}
		function sanitize(input, replacement) {
			if (typeof input !== "string") throw new Error("Input must be string");
			var sanitized = input.replace(illegalRe, replacement).replace(controlRe, replacement).replace(reservedRe, replacement).replace(windowsReservedRe, replacement);
			sanitized = replaceTrailingDotsAndSpaces(sanitized, replacement);
			return truncate(sanitized, 255);
		}
		module.exports = function(input, options) {
			var replacement = options && options.replacement || "";
			var output = sanitize(input, replacement);
			if (replacement === "") return output;
			return sanitize(output, "");
		};
	}))(), 1);
	var version = "3.7.8";
	var VERSION = version;
	var _hasBuffer = typeof Buffer === "function";
	var _TD = typeof TextDecoder === "function" ? new TextDecoder() : void 0;
	var _TE = typeof TextEncoder === "function" ? new TextEncoder() : void 0;
	var b64chs = Array.prototype.slice.call("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=");
	var b64tab = ((a) => {
		let tab = {};
		a.forEach((c, i) => tab[c] = i);
		return tab;
	})(b64chs);
	var b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
	var _fromCC = String.fromCharCode.bind(String);
	var _U8Afrom = typeof Uint8Array.from === "function" ? Uint8Array.from.bind(Uint8Array) : (it) => new Uint8Array(Array.prototype.slice.call(it, 0));
	var _mkUriSafe = (src) => src.replace(/=/g, "").replace(/[+\/]/g, (m0) => m0 == "+" ? "-" : "_");
	var _tidyB64 = (s) => s.replace(/[^A-Za-z0-9\+\/]/g, "");
	var btoaPolyfill = (bin) => {
		let u32, c0, c1, c2, asc = "";
		const pad = bin.length % 3;
		for (let i = 0; i < bin.length;) {
			if ((c0 = bin.charCodeAt(i++)) > 255 || (c1 = bin.charCodeAt(i++)) > 255 || (c2 = bin.charCodeAt(i++)) > 255) throw new TypeError("invalid character found");
			u32 = c0 << 16 | c1 << 8 | c2;
			asc += b64chs[u32 >> 18 & 63] + b64chs[u32 >> 12 & 63] + b64chs[u32 >> 6 & 63] + b64chs[u32 & 63];
		}
		return pad ? asc.slice(0, pad - 3) + "===".substring(pad) : asc;
	};
	var _btoa = typeof btoa === "function" ? (bin) => btoa(bin) : _hasBuffer ? (bin) => Buffer.from(bin, "binary").toString("base64") : btoaPolyfill;
	var _fromUint8Array = _hasBuffer ? (u8a) => Buffer.from(u8a).toString("base64") : (u8a) => {
		const maxargs = 4096;
		let strs = [];
		for (let i = 0, l = u8a.length; i < l; i += maxargs) strs.push(_fromCC.apply(null, u8a.subarray(i, i + maxargs)));
		return _btoa(strs.join(""));
	};
	var fromUint8Array = (u8a, urlsafe = false) => urlsafe ? _mkUriSafe(_fromUint8Array(u8a)) : _fromUint8Array(u8a);
	var cb_utob = (c) => {
		if (c.length < 2) {
			var cc = c.charCodeAt(0);
			return cc < 128 ? c : cc < 2048 ? _fromCC(192 | cc >>> 6) + _fromCC(128 | cc & 63) : _fromCC(224 | cc >>> 12 & 15) + _fromCC(128 | cc >>> 6 & 63) + _fromCC(128 | cc & 63);
		} else {
			var cc = 65536 + (c.charCodeAt(0) - 55296) * 1024 + (c.charCodeAt(1) - 56320);
			return _fromCC(240 | cc >>> 18 & 7) + _fromCC(128 | cc >>> 12 & 63) + _fromCC(128 | cc >>> 6 & 63) + _fromCC(128 | cc & 63);
		}
	};
	var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;
	var utob = (u) => u.replace(re_utob, cb_utob);
	var _encode = _hasBuffer ? (s) => Buffer.from(s, "utf8").toString("base64") : _TE ? (s) => _fromUint8Array(_TE.encode(s)) : (s) => _btoa(utob(s));
	var encode$2 = (src, urlsafe = false) => urlsafe ? _mkUriSafe(_encode(src)) : _encode(src);
	var encodeURI = (src) => encode$2(src, true);
	var re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g;
	var cb_btou = (cccc) => {
		switch (cccc.length) {
			case 4:
				var offset = ((7 & cccc.charCodeAt(0)) << 18 | (63 & cccc.charCodeAt(1)) << 12 | (63 & cccc.charCodeAt(2)) << 6 | 63 & cccc.charCodeAt(3)) - 65536;
				return _fromCC((offset >>> 10) + 55296) + _fromCC((offset & 1023) + 56320);
			case 3: return _fromCC((15 & cccc.charCodeAt(0)) << 12 | (63 & cccc.charCodeAt(1)) << 6 | 63 & cccc.charCodeAt(2));
			default: return _fromCC((31 & cccc.charCodeAt(0)) << 6 | 63 & cccc.charCodeAt(1));
		}
	};
	var btou = (b) => b.replace(re_btou, cb_btou);
	var atobPolyfill = (asc) => {
		asc = asc.replace(/\s+/g, "");
		if (!b64re.test(asc)) throw new TypeError("malformed base64.");
		asc += "==".slice(2 - (asc.length & 3));
		let u24, r1, r2;
		let binArray = [];
		for (let i = 0; i < asc.length;) {
			u24 = b64tab[asc.charAt(i++)] << 18 | b64tab[asc.charAt(i++)] << 12 | (r1 = b64tab[asc.charAt(i++)]) << 6 | (r2 = b64tab[asc.charAt(i++)]);
			if (r1 === 64) binArray.push(_fromCC(u24 >> 16 & 255));
			else if (r2 === 64) binArray.push(_fromCC(u24 >> 16 & 255, u24 >> 8 & 255));
			else binArray.push(_fromCC(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255));
		}
		return binArray.join("");
	};
	var _atob = typeof atob === "function" ? (asc) => atob(_tidyB64(asc)) : _hasBuffer ? (asc) => Buffer.from(asc, "base64").toString("binary") : atobPolyfill;
	var _toUint8Array = _hasBuffer ? (a) => _U8Afrom(Buffer.from(a, "base64")) : (a) => _U8Afrom(_atob(a).split("").map((c) => c.charCodeAt(0)));
	var toUint8Array = (a) => _toUint8Array(_unURI(a));
	var _decode = _hasBuffer ? (a) => Buffer.from(a, "base64").toString("utf8") : _TD ? (a) => _TD.decode(_toUint8Array(a)) : (a) => btou(_atob(a));
	var _unURI = (a) => _tidyB64(a.replace(/[-_]/g, (m0) => m0 == "-" ? "+" : "/"));
	var decode$2 = (src) => _decode(_unURI(src));
	var isValid = (src) => {
		if (typeof src !== "string") return false;
		const s = src.replace(/\s+/g, "").replace(/={0,2}$/, "");
		return !/[^\s0-9a-zA-Z\+/]/.test(s) || !/[^\s0-9a-zA-Z\-_]/.test(s);
	};
	var _noEnum = (v) => {
		return {
			value: v,
			enumerable: false,
			writable: true,
			configurable: true
		};
	};
	var extendString = function() {
		const _add = (name, body) => Object.defineProperty(String.prototype, name, _noEnum(body));
		_add("fromBase64", function() {
			return decode$2(this);
		});
		_add("toBase64", function(urlsafe) {
			return encode$2(this, urlsafe);
		});
		_add("toBase64URI", function() {
			return encode$2(this, true);
		});
		_add("toBase64URL", function() {
			return encode$2(this, true);
		});
		_add("toUint8Array", function() {
			return toUint8Array(this);
		});
	};
	var extendUint8Array = function() {
		const _add = (name, body) => Object.defineProperty(Uint8Array.prototype, name, _noEnum(body));
		_add("toBase64", function(urlsafe) {
			return fromUint8Array(this, urlsafe);
		});
		_add("toBase64URI", function() {
			return fromUint8Array(this, true);
		});
		_add("toBase64URL", function() {
			return fromUint8Array(this, true);
		});
	};
	var extendBuiltins = () => {
		extendString();
		extendUint8Array();
	};
	var gBase64 = {
		version,
		VERSION,
		atob: _atob,
		atobPolyfill,
		btoa: _btoa,
		btoaPolyfill,
		fromBase64: decode$2,
		toBase64: encode$2,
		encode: encode$2,
		encodeURI,
		encodeURL: encodeURI,
		utob,
		btou,
		decode: decode$2,
		isValid,
		fromUint8Array,
		toUint8Array,
		extendString,
		extendUint8Array,
		extendBuiltins
	};
	var brotli_wasm_exports = __exportAll({
		BrotliStreamResult: () => BrotliStreamResult,
		BrotliStreamResultCode: () => BrotliStreamResultCode,
		CompressStream: () => CompressStream,
		DecompressStream: () => DecompressStream,
		compress: () => compress,
		decompress: () => decompress,
		default: () => init
	});
	var wasm;
	var heap = new Array(32).fill(void 0);
	heap.push(void 0, null, true, false);
	function getObject(idx) {
		return heap[idx];
	}
	var cachedTextDecoder = new TextDecoder("utf-8", {
		ignoreBOM: true,
		fatal: true
	});
	cachedTextDecoder.decode();
	var cachegetUint8Memory0 = null;
	function getUint8Memory0() {
		if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
		return cachegetUint8Memory0;
	}
	function getStringFromWasm0(ptr, len) {
		return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
	}
	var heap_next = heap.length;
	function addHeapObject(obj) {
		if (heap_next === heap.length) heap.push(heap.length + 1);
		const idx = heap_next;
		heap_next = heap[idx];
		heap[idx] = obj;
		return idx;
	}
	var WASM_VECTOR_LEN = 0;
	var cachedTextEncoder = new TextEncoder("utf-8");
	var encodeString = typeof cachedTextEncoder.encodeInto === "function" ? function(arg, view) {
		return cachedTextEncoder.encodeInto(arg, view);
	} : function(arg, view) {
		const buf = cachedTextEncoder.encode(arg);
		view.set(buf);
		return {
			read: arg.length,
			written: buf.length
		};
	};
	function passStringToWasm0(arg, malloc, realloc) {
		if (realloc === void 0) {
			const buf = cachedTextEncoder.encode(arg);
			const ptr = malloc(buf.length);
			getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);
			WASM_VECTOR_LEN = buf.length;
			return ptr;
		}
		let len = arg.length;
		let ptr = malloc(len);
		const mem = getUint8Memory0();
		let offset = 0;
		for (; offset < len; offset++) {
			const code = arg.charCodeAt(offset);
			if (code > 127) break;
			mem[ptr + offset] = code;
		}
		if (offset !== len) {
			if (offset !== 0) arg = arg.slice(offset);
			ptr = realloc(ptr, len, len = offset + arg.length * 3);
			const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
			const ret = encodeString(arg, view);
			offset += ret.written;
		}
		WASM_VECTOR_LEN = offset;
		return ptr;
	}
	var cachegetInt32Memory0 = null;
	function getInt32Memory0() {
		if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer);
		return cachegetInt32Memory0;
	}
	function dropObject(idx) {
		if (idx < 36) return;
		heap[idx] = heap_next;
		heap_next = idx;
	}
	function takeObject(idx) {
		const ret = getObject(idx);
		dropObject(idx);
		return ret;
	}
	function passArray8ToWasm0(arg, malloc) {
		const ptr = malloc(arg.length * 1);
		getUint8Memory0().set(arg, ptr / 1);
		WASM_VECTOR_LEN = arg.length;
		return ptr;
	}
	var stack_pointer = 32;
	function addBorrowedObject(obj) {
		if (stack_pointer == 1) throw new Error("out of js stack");
		heap[--stack_pointer] = obj;
		return stack_pointer;
	}
	function getArrayU8FromWasm0(ptr, len) {
		return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
	}
	function compress(buf, raw_options) {
		try {
			const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
			const ptr0 = passArray8ToWasm0(buf, wasm.__wbindgen_malloc);
			const len0 = WASM_VECTOR_LEN;
			wasm.compress(retptr, ptr0, len0, addBorrowedObject(raw_options));
			var r0 = getInt32Memory0()[retptr / 4 + 0];
			var r1 = getInt32Memory0()[retptr / 4 + 1];
			var r2 = getInt32Memory0()[retptr / 4 + 2];
			if (getInt32Memory0()[retptr / 4 + 3]) throw takeObject(r2);
			var v1 = getArrayU8FromWasm0(r0, r1).slice();
			wasm.__wbindgen_free(r0, r1 * 1);
			return v1;
		} finally {
			wasm.__wbindgen_add_to_stack_pointer(16);
			heap[stack_pointer++] = void 0;
		}
	}
	function decompress(buf) {
		try {
			const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
			const ptr0 = passArray8ToWasm0(buf, wasm.__wbindgen_malloc);
			const len0 = WASM_VECTOR_LEN;
			wasm.decompress(retptr, ptr0, len0);
			var r0 = getInt32Memory0()[retptr / 4 + 0];
			var r1 = getInt32Memory0()[retptr / 4 + 1];
			var r2 = getInt32Memory0()[retptr / 4 + 2];
			if (getInt32Memory0()[retptr / 4 + 3]) throw takeObject(r2);
			var v1 = getArrayU8FromWasm0(r0, r1).slice();
			wasm.__wbindgen_free(r0, r1 * 1);
			return v1;
		} finally {
			wasm.__wbindgen_add_to_stack_pointer(16);
		}
	}
	function isLikeNone(x) {
		return x === void 0 || x === null;
	}
	var BrotliStreamResultCode = Object.freeze({
		ResultSuccess: 1,
		"1": "ResultSuccess",
		NeedsMoreInput: 2,
		"2": "NeedsMoreInput",
		NeedsMoreOutput: 3,
		"3": "NeedsMoreOutput"
	});
	var BrotliStreamResult = class BrotliStreamResult {
		static __wrap(ptr) {
			const obj = Object.create(BrotliStreamResult.prototype);
			obj.ptr = ptr;
			return obj;
		}
		__destroy_into_raw() {
			const ptr = this.ptr;
			this.ptr = 0;
			return ptr;
		}
		free() {
			const ptr = this.__destroy_into_raw();
			wasm.__wbg_brotlistreamresult_free(ptr);
		}
		get code() {
			return wasm.__wbg_get_brotlistreamresult_code(this.ptr) >>> 0;
		}
		set code(arg0) {
			wasm.__wbg_set_brotlistreamresult_code(this.ptr, arg0);
		}
		get buf() {
			try {
				const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
				wasm.__wbg_get_brotlistreamresult_buf(retptr, this.ptr);
				var r0 = getInt32Memory0()[retptr / 4 + 0];
				var r1 = getInt32Memory0()[retptr / 4 + 1];
				var v0 = getArrayU8FromWasm0(r0, r1).slice();
				wasm.__wbindgen_free(r0, r1 * 1);
				return v0;
			} finally {
				wasm.__wbindgen_add_to_stack_pointer(16);
			}
		}
		set buf(arg0) {
			const ptr0 = passArray8ToWasm0(arg0, wasm.__wbindgen_malloc);
			const len0 = WASM_VECTOR_LEN;
			wasm.__wbg_set_brotlistreamresult_buf(this.ptr, ptr0, len0);
		}
		get input_offset() {
			return wasm.__wbg_get_brotlistreamresult_input_offset(this.ptr) >>> 0;
		}
		set input_offset(arg0) {
			wasm.__wbg_set_brotlistreamresult_input_offset(this.ptr, arg0);
		}
	};
	var CompressStream = class CompressStream {
		static __wrap(ptr) {
			const obj = Object.create(CompressStream.prototype);
			obj.ptr = ptr;
			return obj;
		}
		__destroy_into_raw() {
			const ptr = this.ptr;
			this.ptr = 0;
			return ptr;
		}
		free() {
			const ptr = this.__destroy_into_raw();
			wasm.__wbg_compressstream_free(ptr);
		}
		constructor(quality) {
			const ret = wasm.compressstream_new(!isLikeNone(quality), isLikeNone(quality) ? 0 : quality);
			return CompressStream.__wrap(ret);
		}
		compress(input_opt, output_size) {
			try {
				const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
				var ptr0 = isLikeNone(input_opt) ? 0 : passArray8ToWasm0(input_opt, wasm.__wbindgen_malloc);
				var len0 = WASM_VECTOR_LEN;
				wasm.compressstream_compress(retptr, this.ptr, ptr0, len0, output_size);
				var r0 = getInt32Memory0()[retptr / 4 + 0];
				var r1 = getInt32Memory0()[retptr / 4 + 1];
				if (getInt32Memory0()[retptr / 4 + 2]) throw takeObject(r1);
				return BrotliStreamResult.__wrap(r0);
			} finally {
				wasm.__wbindgen_add_to_stack_pointer(16);
			}
		}
		total_out() {
			return wasm.compressstream_total_out(this.ptr) >>> 0;
		}
	};
	var DecompressStream = class DecompressStream {
		static __wrap(ptr) {
			const obj = Object.create(DecompressStream.prototype);
			obj.ptr = ptr;
			return obj;
		}
		__destroy_into_raw() {
			const ptr = this.ptr;
			this.ptr = 0;
			return ptr;
		}
		free() {
			const ptr = this.__destroy_into_raw();
			wasm.__wbg_decompressstream_free(ptr);
		}
		constructor() {
			const ret = wasm.decompressstream_new();
			return DecompressStream.__wrap(ret);
		}
		decompress(input, output_size) {
			try {
				const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
				const ptr0 = passArray8ToWasm0(input, wasm.__wbindgen_malloc);
				const len0 = WASM_VECTOR_LEN;
				wasm.decompressstream_decompress(retptr, this.ptr, ptr0, len0, output_size);
				var r0 = getInt32Memory0()[retptr / 4 + 0];
				var r1 = getInt32Memory0()[retptr / 4 + 1];
				if (getInt32Memory0()[retptr / 4 + 2]) throw takeObject(r1);
				return BrotliStreamResult.__wrap(r0);
			} finally {
				wasm.__wbindgen_add_to_stack_pointer(16);
			}
		}
		total_out() {
			return wasm.decompressstream_total_out(this.ptr) >>> 0;
		}
	};
	async function load(module, imports) {
		if (typeof Response === "function" && module instanceof Response) {
			if (typeof WebAssembly.instantiateStreaming === "function") try {
				return await WebAssembly.instantiateStreaming(module, imports);
			} catch (e) {
				if (module.headers.get("Content-Type") != "application/wasm") console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
				else throw e;
			}
			const bytes = await module.arrayBuffer();
			return await WebAssembly.instantiate(bytes, imports);
		} else {
			const instance = await WebAssembly.instantiate(module, imports);
			if (instance instanceof WebAssembly.Instance) return {
				instance,
				module
			};
			else return instance;
		}
	}
	async function init(input) {
		const imports = {};
		imports.wbg = {};
		imports.wbg.__wbindgen_is_undefined = function(arg0) {
			return getObject(arg0) === void 0;
		};
		imports.wbg.__wbindgen_is_object = function(arg0) {
			const val = getObject(arg0);
			return typeof val === "object" && val !== null;
		};
		imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
			return addHeapObject(getStringFromWasm0(arg0, arg1));
		};
		imports.wbg.__wbindgen_error_new = function(arg0, arg1) {
			return addHeapObject(new Error(getStringFromWasm0(arg0, arg1)));
		};
		imports.wbg.__wbindgen_json_serialize = function(arg0, arg1) {
			const obj = getObject(arg1);
			const ptr0 = passStringToWasm0(JSON.stringify(obj === void 0 ? null : obj), wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
			const len0 = WASM_VECTOR_LEN;
			getInt32Memory0()[arg0 / 4 + 1] = len0;
			getInt32Memory0()[arg0 / 4 + 0] = ptr0;
		};
		imports.wbg.__wbg_new_693216e109162396 = function() {
			return addHeapObject(new Error());
		};
		imports.wbg.__wbg_stack_0ddaca5d1abfb52f = function(arg0, arg1) {
			const ret = getObject(arg1).stack;
			const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
			const len0 = WASM_VECTOR_LEN;
			getInt32Memory0()[arg0 / 4 + 1] = len0;
			getInt32Memory0()[arg0 / 4 + 0] = ptr0;
		};
		imports.wbg.__wbg_error_09919627ac0992f5 = function(arg0, arg1) {
			try {
				console.error(getStringFromWasm0(arg0, arg1));
			} finally {
				wasm.__wbindgen_free(arg0, arg1);
			}
		};
		imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
			takeObject(arg0);
		};
		imports.wbg.__wbindgen_throw = function(arg0, arg1) {
			throw new Error(getStringFromWasm0(arg0, arg1));
		};
		if (typeof input === "string" || typeof Request === "function" && input instanceof Request || typeof URL === "function" && input instanceof URL) input = fetch(input);
		const { instance, module } = await load(await input, imports);
		wasm = instance.exports;
		init.__wbindgen_wasm_module = module;
		return wasm;
	}
	async function _init() {
		const url = await _GM.getResourceUrl("brotli_wasm_bg");
		await init(gBase64.toUint8Array(url.slice(url.indexOf(","))).buffer);
		return brotli_wasm_exports;
	}
	var brotli = await(_init());
	var base64url = {
		decode: gBase64.decode,
		encode: (v) => gBase64.encode(v, true),
		decodeBytes: (v) => gBase64.toUint8Array(v),
		encodeBytes: (v) => gBase64.fromUint8Array(v, true)
	};
	function marshal(object) {
		return base64url.encodeBytes(brotli.compress(new TextEncoder().encode(JSON.stringify(object))));
	}
	function unmarshal(str) {
		return JSON.parse(new TextDecoder().decode(brotli.decompress(base64url.decodeBytes(str))));
	}
	function parseHeaders(value) {
		return Object.fromEntries(value.split("\r\n").map((line) => {
			var c = line.indexOf(":");
			return [line.substring(0, c), line.substring(c + 1).trimStart()];
		}));
	}
	function toDataTransfer(file) {
		const data = new DataTransfer();
		if (file instanceof Array) file.forEach((f) => {
			data.items.add(f);
		});
		else data.items.add(file);
		return data;
	}
	function unescapeHtml(value) {
		const textarea = document.createElement("textarea");
		textarea.innerHTML = value;
		return textarea.value;
	}
	async function nextMutation(target, type, subtree, timeout, sender) {
		try {
			console.debug(`Waiting for mutations with timeout of ${timeout ??= 3e4}.`);
			return await Promise.race([new Promise((_, reject) => {
				setTimeout(() => reject("Timeout"), timeout);
			}), new Promise((resolve) => {
				const observer = new MutationObserver((mutations) => {
					if (mutations.some((m) => m.type === type)) {
						observer.disconnect();
						resolve();
					}
				});
				observer.observe(target, {
					[type]: true,
					subtree
				});
				sender?.dispatchEvent(new Event("change"));
			})]);
		} catch (reason) {
			console.warn(reason);
		}
	}
	function onDescendantAdded(target, subtree, callback) {
		new MutationObserver((mutations) => {
			mutations.filter((m) => m.type === "childList" && m.addedNodes.length).flatMap((m) => [...m.addedNodes]).forEach(callback);
		}).observe(target, {
			childList: true,
			subtree
		});
	}
	var _reSplit = /^((?:\p{L}|\p{P}|\s)+)\s+[(()]((?:\p{L}|\p{P}|\s)+)[))]$/u;
	function trySelect(select, name) {
		name = name.toLowerCase();
		let options = [...select.options].map((option) => ({
			name: option.textContent?.toLowerCase(),
			key: option.value
		})).filter((p) => p.name);
		let seq = options.filter((p) => p.name === name);
		if (seq.length) return seq.length === 1 && (select.value = seq.at(0).key);
		seq = options.filter((p) => (p.name?.indexOf(name) ?? NaN) >= 0 || p.name && (name?.indexOf(p.name) ?? NaN) >= 0);
		if (seq.length) return seq.length === 1 && (select.value = seq.at(0).key);
		const match = name.match(_reSplit);
		const names = match ? [match[1], match[2]] : [name];
		options = options.flatMap((p) => {
			const m = p.name.match(_reSplit);
			return m ? [{
				name: m[1],
				key: p.key
			}, {
				name: m[2],
				key: p.key
			}] : p;
		}).filter((p) => p.name);
		seq = options.filter((p) => names.some((n) => (p.name?.indexOf(n) ?? NaN) >= 0 || p.name && (n?.indexOf(p.name) ?? NaN) >= 0));
		return seq.length === 1 && (select.value = seq.at(0).key);
	}
	var l10n_default = {
		parse: function(val) {
			val = val.trim().normalize();
			const match = val.match(/^(.+?)\s*\((.+)\)$/);
			if (!match) return val;
			let [latin, native] = match.slice(1);
			const trilingual = native.trim().match(/^(.+?)(?:\s+\/\s+|\s*/\s*)(.*\p{Script=Han}.*)$/u);
			if (trilingual) return {
				latin,
				native: trilingual[1]
			};
			let l = match[1].match(/[^\P{L}\p{Script=Latin}]/gu)?.length ?? 0;
			let r = match[2].match(/[^\P{L}\p{Script=Latin}]/gu)?.length ?? 0;
			if (l === r) {
				l = match[1].match(/[^\P{L}a-zA-Z]/gu)?.length ?? 0;
				r = match[2].match(/[^\P{L}a-zA-Z]/gu)?.length ?? 0;
			}
			if (l > r) [latin, native] = [native, latin];
			else if (l === r && latin.length < native.length) [latin, native] = [native, latin];
			return {
				latin,
				native
			};
		},
		format: function(val, prefer = "latin") {
			if (typeof val === "string") return val;
			switch (prefer) {
				default: return `${val.latin} (${val.native})`;
				case "native": return `${val.native} (${val.latin})`;
				case "cjk": return this.format(val, /\p{Script=Han}|\p{Script=Hiragana}|\p{Script=Katakana}|\p{Script=Hangul}/u.test(val.native) ? "native" : "latin");
				case "zh":
					const z = /\p{Script=Han}/u.test(val.native) && !/\p{Script=Hiragana}|\p{Script=Katakana}|\p{Script=Hangul}/u.test(val.native);
					return this.format(val, z ? "native" : "latin");
			}
		},
		select: function(val, prefer = "latin") {
			if (typeof val === "string") return val;
			return prefer === "latin" ? val.latin : val.native;
		}
	};
	function _throw(ex) {
		throw ex;
	}
	var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
	var alphabet = "0123456789abcdef";
	var encodeLookup = [];
	var decodeLookup = [];
	for (let i = 0; i < 256; i++) {
		encodeLookup[i] = alphabet[i >> 4 & 15] + alphabet[i & 15];
		if (i < 16) if (i < 10) decodeLookup[48 + i] = i;
		else decodeLookup[87 + i] = i;
	}
	var arr2hex = (data) => {
		const length = data.length;
		let string = "";
		let i = 0;
		while (i < length) string += encodeLookup[data[i++]];
		return string;
	};
	var hex2arr = (str) => {
		const sizeof = str.length >> 1;
		const length = sizeof << 1;
		const array = new Uint8Array(sizeof);
		let n = 0;
		let i = 0;
		while (i < length) array[n++] = decodeLookup[str.charCodeAt(i++)] << 4 | decodeLookup[str.charCodeAt(i++)];
		return array;
	};
	var concat = (chunks, size = 0) => {
		const length = chunks.length || 0;
		if (!size) {
			let i = length;
			while (i--) size += chunks[i].length;
		}
		const b = new Uint8Array(size);
		let offset = size;
		let i = length;
		while (i--) {
			offset -= chunks[i].length;
			b.set(chunks[i], offset);
		}
		return b;
	};
	var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	var lookup = typeof Uint8Array === "undefined" ? [] : new Uint8Array(256);
	for (var i = 0; i < chars.length; i++) lookup[chars.charCodeAt(i)] = i;
	var encode$1 = function(arraybuffer) {
		var bytes = new Uint8Array(arraybuffer), i, len = bytes.length, base64 = "";
		for (i = 0; i < len; i += 3) {
			base64 += chars[bytes[i] >> 2];
			base64 += chars[(bytes[i] & 3) << 4 | bytes[i + 1] >> 4];
			base64 += chars[(bytes[i + 1] & 15) << 2 | bytes[i + 2] >> 6];
			base64 += chars[bytes[i + 2] & 63];
		}
		if (len % 3 === 2) base64 = base64.substring(0, base64.length - 1) + "=";
		else if (len % 3 === 1) base64 = base64.substring(0, base64.length - 2) + "==";
		return base64;
	};
	var decoder = new TextDecoder();
	var arr2text = (data, enc) => {
		if (!enc) return decoder.decode(data);
		return new TextDecoder(enc).decode(data);
	};
	var encoder$1 = new TextEncoder();
	var text2arr = (str) => encoder$1.encode(str);
	var arr2base = (data) => encode$1(data);
	var scope = typeof window !== "undefined" ? window : self;
	var crypto = scope.crypto || scope.msCrypto || {};
	var subtle = crypto.subtle || crypto.webkitSubtle;
	var formatMap = {
		hex: arr2hex,
		base64: arr2base
	};
	var hash = async (data, format, algo = "sha-1") => {
		if (!subtle) throw new Error("no web crypto support");
		if (typeof data === "string") data = text2arr(data);
		const out = new Uint8Array(await subtle.digest(algo, data));
		return format ? formatMap[format](out) : out;
	};
	function digitCount(value) {
		const sign = value < 0 ? 1 : 0;
		value = Math.abs(Number(value || 1));
		return Math.floor(Math.log10(value)) + 1 + sign;
	}
	function getType(value) {
		if (ArrayBuffer.isView(value)) return "arraybufferview";
		if (Array.isArray(value)) return "array";
		if (value instanceof Number) return "number";
		if (value instanceof Boolean) return "boolean";
		if (value instanceof Set) return "set";
		if (value instanceof Map) return "map";
		if (value instanceof String) return "string";
		if (value instanceof ArrayBuffer) return "arraybuffer";
		return typeof value;
	}
	function encode(data, buffer, offset) {
		const buffers = [];
		let result = null;
		encode._encode(buffers, data);
		result = concat(buffers);
		encode.bytes = result.length;
		if (ArrayBuffer.isView(buffer)) {
			buffer.set(result, offset);
			return buffer;
		}
		return result;
	}
	encode.bytes = -1;
	encode._floatConversionDetected = false;
	encode._encode = function(buffers, data) {
		if (data == null) return;
		switch (getType(data)) {
			case "object":
				encode.dict(buffers, data);
				break;
			case "map":
				encode.dictMap(buffers, data);
				break;
			case "array":
				encode.list(buffers, data);
				break;
			case "set":
				encode.listSet(buffers, data);
				break;
			case "string":
				encode.string(buffers, data);
				break;
			case "number":
				encode.number(buffers, data);
				break;
			case "boolean":
				encode.number(buffers, data);
				break;
			case "arraybufferview":
				encode.buffer(buffers, new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
				break;
			case "arraybuffer":
				encode.buffer(buffers, new Uint8Array(data));
				break;
		}
	};
	var buffE = new Uint8Array([101]);
	var buffD = new Uint8Array([100]);
	var buffL = new Uint8Array([108]);
	encode.buffer = function(buffers, data) {
		buffers.push(text2arr(data.length + ":"), data);
	};
	encode.string = function(buffers, data) {
		buffers.push(text2arr(text2arr(data).byteLength + ":" + data));
	};
	encode.number = function(buffers, data) {
		if (Number.isInteger(data)) return buffers.push(text2arr("i" + BigInt(data) + "e"));
		const maxLo = 2147483648;
		const hi = data / maxLo << 0;
		const lo = data % maxLo << 0;
		const val = hi * maxLo + lo;
		buffers.push(text2arr("i" + val + "e"));
		if (val !== data && !encode._floatConversionDetected) {
			encode._floatConversionDetected = true;
			console.warn("WARNING: Possible data corruption detected with value \"" + data + "\":", "Bencoding only defines support for integers, value was converted to \"" + val + "\"");
			console.trace();
		}
	};
	encode.dict = function(buffers, data) {
		buffers.push(buffD);
		let j = 0;
		let k;
		const keys = Object.keys(data).sort();
		const kl = keys.length;
		for (; j < kl; j++) {
			k = keys[j];
			if (data[k] == null) continue;
			encode.string(buffers, k);
			encode._encode(buffers, data[k]);
		}
		buffers.push(buffE);
	};
	encode.dictMap = function(buffers, data) {
		buffers.push(buffD);
		const keys = Array.from(data.keys()).sort();
		for (const key of keys) {
			if (data.get(key) == null) continue;
			ArrayBuffer.isView(key) ? encode._encode(buffers, key) : encode.string(buffers, String(key));
			encode._encode(buffers, data.get(key));
		}
		buffers.push(buffE);
	};
	encode.list = function(buffers, data) {
		let i = 0;
		const c = data.length;
		buffers.push(buffL);
		for (; i < c; i++) {
			if (data[i] == null) continue;
			encode._encode(buffers, data[i]);
		}
		buffers.push(buffE);
	};
	encode.listSet = function(buffers, data) {
		buffers.push(buffL);
		for (const item of data) {
			if (item == null) continue;
			encode._encode(buffers, item);
		}
		buffers.push(buffE);
	};
	var INTEGER_START = 105;
	var STRING_DELIM = 58;
	var DICTIONARY_START = 100;
	var LIST_START = 108;
	var END_OF_TYPE = 101;
	function getIntFromBuffer(buffer, start, end) {
		let sum = 0;
		let sign = 1;
		for (let i = start; i < end; i++) {
			const num = buffer[i];
			if (num < 58 && num >= 48) {
				sum = sum * 10 + (num - 48);
				continue;
			}
			if (i === start && num === 43) continue;
			if (i === start && num === 45) {
				sign = -1;
				continue;
			}
			if (num === 46) break;
			throw new Error("not a number: buffer[" + i + "] = " + num);
		}
		return sum * sign;
	}
	function decode$1(data, start, end, encoding) {
		if (data == null || data.length === 0) return null;
		if (typeof start !== "number" && encoding == null) {
			encoding = start;
			start = void 0;
		}
		if (typeof end !== "number" && encoding == null) {
			encoding = end;
			end = void 0;
		}
		decode$1.position = 0;
		decode$1.encoding = encoding || null;
		decode$1.data = !ArrayBuffer.isView(data) ? text2arr(data) : new Uint8Array(data.slice(start, end));
		decode$1.bytes = decode$1.data.length;
		return decode$1.next();
	}
	decode$1.bytes = 0;
	decode$1.position = 0;
	decode$1.data = null;
	decode$1.encoding = null;
	decode$1.next = function() {
		switch (decode$1.data[decode$1.position]) {
			case DICTIONARY_START: return decode$1.dictionary();
			case LIST_START: return decode$1.list();
			case INTEGER_START: return decode$1.integer();
			default: return decode$1.buffer();
		}
	};
	decode$1.find = function(chr) {
		let i = decode$1.position;
		const c = decode$1.data.length;
		const d = decode$1.data;
		while (i < c) {
			if (d[i] === chr) return i;
			i++;
		}
		throw new Error("Invalid data: Missing delimiter \"" + String.fromCharCode(chr) + "\" [0x" + chr.toString(16) + "]");
	};
	decode$1.dictionary = function() {
		decode$1.position++;
		const dict = {};
		while (decode$1.data[decode$1.position] !== END_OF_TYPE) {
			const buffer = decode$1.buffer();
			let key = arr2text(buffer);
			if (key.includes("�")) key = arr2hex(buffer);
			dict[key] = decode$1.next();
		}
		decode$1.position++;
		return dict;
	};
	decode$1.list = function() {
		decode$1.position++;
		const lst = [];
		while (decode$1.data[decode$1.position] !== END_OF_TYPE) lst.push(decode$1.next());
		decode$1.position++;
		return lst;
	};
	decode$1.integer = function() {
		const end = decode$1.find(END_OF_TYPE);
		const number = getIntFromBuffer(decode$1.data, decode$1.position + 1, end);
		decode$1.position += end + 1 - decode$1.position;
		return number;
	};
	decode$1.buffer = function() {
		let sep = decode$1.find(STRING_DELIM);
		const length = getIntFromBuffer(decode$1.data, decode$1.position, sep);
		const end = ++sep + length;
		decode$1.position = end;
		return decode$1.encoding ? arr2text(decode$1.data.slice(sep, end)) : decode$1.data.slice(sep, end);
	};
	function listLength(list) {
		let length = 2;
		for (const value of list) length += encodingLength$1(value);
		return length;
	}
	function mapLength(map) {
		let length = 2;
		for (const [key, value] of map) {
			const keyLength = text2arr(key).byteLength;
			length += digitCount(keyLength) + 1 + keyLength;
			length += encodingLength$1(value);
		}
		return length;
	}
	function objectLength(value) {
		let length = 2;
		const keys = Object.keys(value);
		for (let i = 0; i < keys.length; i++) {
			const keyLength = text2arr(keys[i]).byteLength;
			length += digitCount(keyLength) + 1 + keyLength;
			length += encodingLength$1(value[keys[i]]);
		}
		return length;
	}
	function stringLength(value) {
		const length = text2arr(value).byteLength;
		return digitCount(length) + 1 + length;
	}
	function arrayBufferLength(value) {
		const length = value.byteLength - value.byteOffset;
		return digitCount(length) + 1 + length;
	}
	function encodingLength$1(value) {
		const length = 0;
		if (value == null) return length;
		const type = getType(value);
		switch (type) {
			case "arraybufferview": return arrayBufferLength(value);
			case "string": return stringLength(value);
			case "array":
			case "set": return listLength(value);
			case "number": return 1 + digitCount(Math.floor(value)) + 1;
			case "bigint": return 1 + value.toString().length + 1;
			case "object": return objectLength(value);
			case "map": return mapLength(value);
			default: throw new TypeError(`Unsupported value of type "${type}"`);
		}
	}
	var bencode_default = {
		encode,
		decode: decode$1,
		byteLength: encodingLength$1,
		encodingLength: encodingLength$1
	};
	__commonJSMin(((exports, module) => {
		module.exports = {};
	}))();
	self.Blob;
	self.File;
	self.FormData;
	self.Headers;
	self.Request;
	self.Response;
	self.AbortController;
	self.AbortSignal;
	self.fetch;
	var byteTable = [
		255,
		255,
		26,
		27,
		28,
		29,
		30,
		31,
		255,
		255,
		255,
		255,
		255,
		255,
		255,
		255,
		255,
		0,
		1,
		2,
		3,
		4,
		5,
		6,
		7,
		8,
		9,
		10,
		11,
		12,
		13,
		14,
		15,
		16,
		17,
		18,
		19,
		20,
		21,
		22,
		23,
		24,
		25,
		255,
		255,
		255,
		255,
		255,
		255,
		0,
		1,
		2,
		3,
		4,
		5,
		6,
		7,
		8,
		9,
		10,
		11,
		12,
		13,
		14,
		15,
		16,
		17,
		18,
		19,
		20,
		21,
		22,
		23,
		24,
		25,
		255,
		255,
		255,
		255,
		255
	];
	var decode = function(encoded) {
		if (!ArrayBuffer.isView(encoded) && typeof encoded !== "string") throw new TypeError("base32.decode only takes Buffer or string as parameter");
		let shiftIndex = 0;
		let plainDigit = 0;
		let plainChar;
		let plainPos = 0;
		if (!ArrayBuffer.isView(encoded)) encoded = text2arr(encoded);
		const decoded = new Uint8Array(Math.ceil(encoded.length * 5 / 8));
		for (let i = 0; i < encoded.length; i++) {
			if (encoded[i] === 61) break;
			const encodedByte = encoded[i] - 48;
			if (encodedByte < byteTable.length) {
				plainDigit = byteTable[encodedByte];
				if (shiftIndex <= 3) {
					shiftIndex = (shiftIndex + 5) % 8;
					if (shiftIndex === 0) {
						plainChar |= plainDigit;
						decoded[plainPos] = plainChar;
						plainPos++;
						plainChar = 0;
					} else plainChar |= 255 & plainDigit << 8 - shiftIndex;
				} else {
					shiftIndex = (shiftIndex + 5) % 8;
					plainChar |= 255 & plainDigit >>> shiftIndex;
					decoded[plainPos] = plainChar;
					plainPos++;
					plainChar = 255 & plainDigit << 8 - shiftIndex;
				}
			} else throw new Error("Invalid input - it is not base32 encoded string");
		}
		return decoded.subarray(0, plainPos);
	};
	function parseRange(range) {
		const generateRange = (start, end = start) => Array.from({ length: end - start + 1 }, (cur, idx) => idx + start);
		return range.reduce((acc, cur, idx, arr) => {
			const r = cur.split("-").map((cur) => parseInt(cur));
			return acc.concat(generateRange(...r));
		}, []);
	}
	function magnetURIDecode(uri) {
		const result = {};
		const data = uri.split("magnet:?")[1];
		(data && data.length >= 0 ? data.split("&") : []).forEach((param) => {
			const keyval = param.split("=");
			if (keyval.length !== 2) return;
			const key = keyval[0];
			let val = keyval[1];
			if (key === "dn") val = decodeURIComponent(val).replace(/\+/g, " ");
			if (key === "tr" || key === "xs" || key === "as" || key === "ws") val = decodeURIComponent(val);
			if (key === "kt") val = decodeURIComponent(val).split("+");
			if (key === "ix") val = Number(val);
			if (key === "so") val = parseRange(decodeURIComponent(val).split(","));
			if (result[key]) {
				if (!Array.isArray(result[key])) result[key] = [result[key]];
				result[key].push(val);
			} else result[key] = val;
		});
		let m;
		if (result.xt) (Array.isArray(result.xt) ? result.xt : [result.xt]).forEach((xt) => {
			if (m = xt.match(/^urn:btih:(.{40})/)) result.infoHash = m[1].toLowerCase();
			else if (m = xt.match(/^urn:btih:(.{32})/)) result.infoHash = arr2hex(decode(m[1]));
			else if (m = xt.match(/^urn:btmh:1220(.{64})/)) result.infoHashV2 = m[1].toLowerCase();
		});
		if (result.xs) (Array.isArray(result.xs) ? result.xs : [result.xs]).forEach((xs) => {
			if (m = xs.match(/^urn:btpk:(.{64})/)) result.publicKey = m[1].toLowerCase();
		});
		if (result.infoHash) result.infoHashBuffer = hex2arr(result.infoHash);
		if (result.infoHashV2) result.infoHashV2Buffer = hex2arr(result.infoHashV2);
		if (result.publicKey) result.publicKeyBuffer = hex2arr(result.publicKey);
		if (result.dn) result.name = result.dn;
		if (result.kt) result.keywords = result.kt;
		result.announce = [];
		if (typeof result.tr === "string" || Array.isArray(result.tr)) result.announce = result.announce.concat(result.tr);
		result.urlList = [];
		if (typeof result.as === "string" || Array.isArray(result.as)) result.urlList = result.urlList.concat(result.as);
		if (typeof result.ws === "string" || Array.isArray(result.ws)) result.urlList = result.urlList.concat(result.ws);
		result.peerAddresses = [];
		if (typeof result["x.pe"] === "string" || Array.isArray(result["x.pe"])) result.peerAddresses = result.peerAddresses.concat(result["x.pe"]);
		result.announce = Array.from(new Set(result.announce));
		result.urlList = Array.from(new Set(result.urlList));
		result.peerAddresses = Array.from(new Set(result.peerAddresses));
		return result;
	}
	function join(...args) {
		return args.filter(Boolean).join("/").replace(/\/+/g, "/");
	}
	var path_default = {
		sep: "/",
		join
	};
	__commonJSMin(((exports, module) => {
		var promise;
		module.exports = typeof queueMicrotask === "function" ? queueMicrotask.bind(typeof window !== "undefined" ? window : global) : (cb) => (promise || (promise = Promise.resolve())).then(cb).catch((err) => setTimeout(() => {
			throw err;
		}, 0));
	}))();
	async function parseTorrent(torrentId) {
		if (typeof torrentId === "string" && /^(stream-)?magnet:/.test(torrentId)) {
			const torrentObj = magnetURIDecode(torrentId);
			if (!torrentObj.infoHash) throw new Error("Invalid torrent identifier");
			return torrentObj;
		} else if (typeof torrentId === "string" && (/^[a-f0-9]{40}$/i.test(torrentId) || /^[a-z2-7]{32}$/i.test(torrentId))) return magnetURIDecode(`magnet:?xt=urn:btih:${torrentId}`);
		else if (ArrayBuffer.isView(torrentId) && torrentId.length === 20) return magnetURIDecode(`magnet:?xt=urn:btih:${arr2hex(torrentId)}`);
		else if (ArrayBuffer.isView(torrentId)) return await decodeTorrentFile(torrentId);
		else if (torrentId && torrentId.infoHash) {
			torrentId.infoHash = torrentId.infoHash.toLowerCase();
			if (!torrentId.announce) torrentId.announce = [];
			if (typeof torrentId.announce === "string") torrentId.announce = [torrentId.announce];
			if (!torrentId.urlList) torrentId.urlList = [];
			return torrentId;
		} else throw new Error("Invalid torrent identifier");
	}
	async function decodeTorrentFile(torrent) {
		if (ArrayBuffer.isView(torrent)) torrent = bencode_default.decode(torrent);
		ensure(torrent.info, "info");
		ensure(torrent.info["name.utf-8"] || torrent.info.name, "info.name");
		ensure(torrent.info["piece length"], "info['piece length']");
		ensure(torrent.info.pieces, "info.pieces");
		if (torrent.info.files) torrent.info.files.forEach((file) => {
			ensure(typeof file.length === "number", "info.files[0].length");
			ensure(file["path.utf-8"] || file.path, "info.files[0].path");
		});
		else ensure(typeof torrent.info.length === "number", "info.length");
		const result = {
			info: torrent.info,
			infoBuffer: bencode_default.encode(torrent.info),
			name: arr2text(torrent.info["name.utf-8"] || torrent.info.name),
			announce: []
		};
		result.infoHashBuffer = await hash(result.infoBuffer);
		result.infoHash = arr2hex(result.infoHashBuffer);
		if (torrent.info.private !== void 0) result.private = !!torrent.info.private;
		if (torrent["creation date"]) result.created = new Date(torrent["creation date"] * 1e3);
		if (torrent["created by"]) result.createdBy = arr2text(torrent["created by"]);
		if (ArrayBuffer.isView(torrent.comment)) result.comment = arr2text(torrent.comment);
		if (Array.isArray(torrent["announce-list"]) && torrent["announce-list"].length > 0) torrent["announce-list"].forEach((urls) => {
			urls.forEach((url) => {
				result.announce.push(arr2text(url));
			});
		});
		else if (torrent.announce) result.announce.push(arr2text(torrent.announce));
		if (ArrayBuffer.isView(torrent["url-list"])) torrent["url-list"] = torrent["url-list"].length > 0 ? [torrent["url-list"]] : [];
		result.urlList = (torrent["url-list"] || []).map((url) => arr2text(url));
		result.announce = Array.from(new Set(result.announce));
		result.urlList = Array.from(new Set(result.urlList));
		let sum = 0;
		result.files = (torrent.info.files || [torrent.info]).map((file, i) => {
			const parts = [].concat(result.name, file["path.utf-8"] || file.path || []).map((p) => ArrayBuffer.isView(p) ? arr2text(p) : p);
			sum += file.length;
			return {
				path: path_default.join.apply(null, [path_default.sep].concat(parts)).slice(1),
				name: parts[parts.length - 1],
				length: file.length,
				offset: sum - file.length
			};
		});
		result.length = sum;
		const lastFile = result.files[result.files.length - 1];
		result.pieceLength = torrent.info["piece length"];
		result.lastPieceLength = (lastFile.offset + lastFile.length) % result.pieceLength || result.pieceLength;
		result.pieces = splitPieces(torrent.info.pieces);
		return result;
	}
	function encodeTorrentFile(parsed) {
		const torrent = { info: parsed.info };
		torrent["announce-list"] = (parsed.announce || []).map((url) => {
			if (!torrent.announce) torrent.announce = url;
			url = text2arr(url);
			return [url];
		});
		torrent["url-list"] = parsed.urlList || [];
		if (parsed.private !== void 0) torrent.private = Number(parsed.private);
		if (parsed.created) torrent["creation date"] = parsed.created.getTime() / 1e3 | 0;
		if (parsed.createdBy) torrent["created by"] = parsed.createdBy;
		if (parsed.comment) torrent.comment = parsed.comment;
		return bencode_default.encode(torrent);
	}
	function splitPieces(buf) {
		const pieces = [];
		for (let i = 0; i < buf.length; i += 20) pieces.push(arr2hex(buf.slice(i, i + 20)));
		return pieces;
	}
	function ensure(bool, fieldName) {
		if (!bool) throw new Error(`Torrent is missing required field: ${fieldName}`);
	}
	async function patch(torrent, source) {
		const record = await parseTorrent(torrent);
		record.announce = [];
		record.comment = "";
		record.info.private = true;
		record.info.source = source;
		return encodeTorrentFile(record);
	}
	var data_default = {
		base: {
			"gazelle": {
				"include": {
					"source": [
						"/torrents.php",
						"/artist.php",
						"/collages.php"
					],
					"target": "/upload.php"
				},
				"exclude": { "download": "/torrents.php" },
				"actions": { "log": "viewlog" }
			},
			"nexusphp": {
				"include": {
					"source": "/plugin_details.php",
					"target": "/plugin_upload.php"
				},
				"exclude": { "download": "/download.php" }
			}
		},
		override: {
			"gazelle": {
				"DIC": {
					"hostname": "dicmusic.com",
					"selects": { "releaseType": {
						"1": "Album",
						"3": "Soundtrack",
						"5": "EP",
						"6": "Anthology",
						"7": "Compilation",
						"9": "Single",
						"11": "Live album",
						"13": "Remix",
						"14": "Bootleg",
						"15": "Interview",
						"16": "Mixtape",
						"17": "Demo",
						"18": "Concert recording",
						"19": "DJ Mix",
						"21": "Unknown"
					} }
				},
				"JPopsuki": {
					"hostname": "jpopsuki.eu",
					"selects": { "releaseType": {
						"Album": "Album",
						"Single": "Single",
						"PV": "PV",
						"DVD": "DVD",
						"TV-Music": "TV-Music",
						"TV-Variety": "TV-Variety",
						"TV-Drama": "TV-Drama",
						"Fansubs": "Fansubs",
						"Pictures": "Pictures",
						"Misc": "Misc"
					} },
					"actions": { "log": null }
				},
				"OPS": {
					"hostname": "orpheus.network",
					"selects": { "releaseType": {
						"1": "Album",
						"3": "Soundtrack",
						"5": "EP",
						"6": "Anthology",
						"7": "Compilation",
						"9": "Single",
						"11": "Live album",
						"13": "Remix",
						"14": "Bootleg",
						"15": "Interview",
						"16": "Mixtape",
						"17": "DJ Mix",
						"18": "Concert recording",
						"21": "Unknown"
					} }
				},
				"Redacted": {
					"hostname": "redacted.sh",
					"selects": { "releaseType": {
						"1": "Album",
						"3": "Soundtrack",
						"5": "EP",
						"6": "Anthology",
						"7": "Compilation",
						"9": "Single",
						"11": "Live album",
						"13": "Remix",
						"14": "Bootleg",
						"15": "Interview",
						"16": "Mixtape",
						"17": "Demo",
						"18": "Concert Recording",
						"19": "DJ Mix",
						"21": "Unknown"
					} },
					"actions": { "log": "loglist" }
				}
			},
			"nexusphp": {
				"OpenCD": { "hostname": "open.cd" },
				"TJUPT": {
					"hostname": "tjupt.org",
					"include": {
						"source": "/details.php",
						"target": "/upload.php"
					}
				}
			}
		}
	};
	var data = {};
	Object.keys(data_default.override).forEach((fw) => ((fw) => {
		data[fw] = {};
		Object.keys(data_default.override[fw]).forEach((st) => {
			const base = data_default.base[fw];
			let site = data_default.override[fw][st];
			site.include = {
				...base.include,
				...site.include
			};
			site.exclude = {
				...base.exclude,
				...site.exclude
			};
			site.actions = {
				...base.actions,
				...site.actions
			};
			data[fw][st] = site;
		});
	})(fw));
	var VoidElement = class {
		"#";
		constructor(tag) {
			this["#"] = tag;
		}
	};
	function Void(tag) {
		return () => new VoidElement(tag);
	}
	var ValueVoidElement = class {
		"#";
		$;
		constructor(tag, value) {
			this["#"] = tag;
			this.$ = value;
		}
	};
	var ViewElement = class {
		"#";
		$$;
		constructor(tag, children) {
			this["#"] = tag;
			this.$$ = children;
		}
	};
	function View(tag) {
		return (children) => new ViewElement(tag, children);
	}
	var ValueViewElement = class {
		"#";
		$;
		$$;
		constructor(tag, value, children) {
			this["#"] = tag;
			this.$$ = children;
			this.$ = value;
		}
	};
	function ValueView(tag) {
		return (value, children) => new ValueViewElement(tag, value, children);
	}
	var Bold = View("b");
	var Italic = View("i");
	var Underline = View("u");
	var Strikethrough = View("s");
	var Font = ValueView("font");
	var Size = ValueView("size");
	var Color = ValueView("color");
	var Heading = ValueView("h");
	var Sub = View("sub");
	var Sup = View("sup");
	var Anchor = ValueView("url");
	var ImageElement = class extends ValueVoidElement {
		alt;
		constructor(value, alt) {
			super("img", value);
			this.alt = alt;
		}
	};
	var Image = (value, alt) => new ImageElement(value, alt);
	var Code = View("code");
	var Spoiler = View("#spoiler");
	var HorizontalRule = Void("hr");
	var Align = ValueView("align");
	var Quote = ValueView("quote");
	var Pre = ValueView("pre");
	var Collapse = ValueView("#collapse");
	var ListItem = View("li");
	var UList = View("ul");
	var OList = View("ol");
	var Table = View("table");
	var TableRow = View("tr");
	var TableCell = View("td");
	var is = {
		void: (node) => (() => {
			return (input) => "hr" === input;
		})()(node["#"]),
		valueVoid: (node) => (() => {
			return (input) => "img" === input;
		})()(node["#"]),
		view: (node) => (() => {
			const _iv1 = new Set([
				"b",
				"i",
				"u",
				"s",
				"sub",
				"sup",
				"code",
				"#spoiler",
				"li",
				"ul",
				"ol",
				"table",
				"tr",
				"td"
			]);
			return (input) => true === _iv1.has(input);
		})()(node["#"]),
		valueView: (node) => (() => {
			return (input) => "font" === input || "size" === input || "color" === input || "h" === input || "url" === input || "align" === input || "quote" === input || "pre" === input || "#collapse" === input;
		})()(node["#"])
	};
	var BBText = class {
		"#" = "#text";
		$;
		constructor(value) {
			this.$ = value;
		}
	};
	function _clamp(value, min, max) {
		return Math.min(Math.max(value, min), max);
	}
	function _wrapNewline(nodes, position) {
		if (position === 2 || position === 3) {
			let f = nodes.at(0);
			if (f instanceof BBText) f.$ = f.$.replace(/^ */, "\n");
			else nodes.unshift(new BBText("\n"));
		}
		if (position === 1 || position === 3) {
			let l = nodes.at(-1);
			if (l instanceof BBText) l.$ = l.$.replace(/ *$/, "\n");
			else nodes.push(new BBText("\n"));
		}
		return nodes;
	}
	function _fromHTML(parent, baseURL, raw = false) {
		let index = -1;
		const origin = [...parent.childNodes];
		const result = [];
		while (++index < origin.length) {
			const n = origin[index];
			if (n instanceof globalThis.Text) {
				let last = result.at(-1);
				if (raw) result.push(new BBText(n.textContent ?? ""));
				else if (last instanceof BBText) last.$ = last.$ + (last.$.match(/\s$/) ? n.textContent?.trimStart() ?? "" : n.textContent ?? "").replace(/\s+/g, " ");
				else result.push(new BBText(n.textContent?.replace(/\s+/g, " ") ?? ""));
			} else if (n instanceof HTMLBRElement) _wrapNewline(result, 1);
			else if (n instanceof HTMLUListElement) result.push(UList([...n.children].map((item) => ListItem(_fromHTML(item, baseURL)))));
			else if (n instanceof HTMLOListElement) result.push(OList([...n.children].map((item) => ListItem(_fromHTML(item, baseURL)))));
			else if (n instanceof HTMLTableElement) if (n.classList.contains("hide")) result.push(Collapse(n.tBodies.item(0)?.rows?.item(0)?.cells?.item(0)?.textContent?.trim() ?? _throw(n), _fromHTML(n.tBodies.item(0)?.rows?.item(1)?.cells?.item(0) ?? _throw(n), baseURL)));
			else {
				const caption = [...n.children].at(0);
				if (caption instanceof HTMLTableCaptionElement) result.push(Align("center", _fromHTML(caption, baseURL)));
				result.push(Table([n.tHead, ...n.tBodies].filter((sec) => sec).flatMap((sec) => [...sec.rows]).map((row) => TableRow([...row.cells].map((cell) => TableCell(_fromHTML(cell, baseURL)))))));
			}
			else if (n instanceof HTMLQuoteElement) result.push(Quote("", _fromHTML(n, baseURL)));
			else if (n instanceof HTMLPreElement) result.push(Pre("", _fromHTML(n, baseURL, true)));
			else if (n instanceof HTMLFieldSetElement) {
				const firstChild = [...n.children].at(0);
				if (firstChild instanceof HTMLLegendElement) {
					n.removeChild(firstChild);
					result.push(Quote(firstChild.textContent?.trim() ?? "", _fromHTML(n, baseURL)));
				} else result.push(Quote("", _fromHTML(n, baseURL)));
			} else if (n instanceof HTMLFontElement) {
				let outer;
				const children = _fromHTML(n, baseURL);
				if (n.face) outer = Font(n.face, children);
				if (n.size) outer = Font(n.size, outer ? [outer] : children);
				if (n.color) outer = Font(n.color, outer ? [outer] : children);
				if (outer) result.push(outer);
				else result.push(...children);
			} else if (n instanceof HTMLHeadingElement) result.push(Heading(parseInt(n.tagName.slice(1)), _fromHTML(n, baseURL)));
			else if (n instanceof HTMLAnchorElement) {
				let href = n.href;
				if (!href.match(/^[a-z+]+:\/\//)) href = new URL(href, baseURL).toString();
				if (n.attributes.getNamedItem("onclick")?.value?.startsWith("QuoteJump")) {
					let offset = 0;
					while (offset++ < origin.length) if (origin.at(index + offset) instanceof HTMLQuoteElement) break;
					if (index + offset === origin.length) throw n;
					result.push(Quote([...n.children].at(0)?.textContent?.trim() ?? "", _fromHTML(origin.at(index + offset), baseURL)));
					index += offset;
				} else result.push(Anchor(href, _fromHTML(n, baseURL)));
			} else if (n instanceof HTMLImageElement) if (n.classList.contains("listicon")) result.push(ListItem([]));
			else result.push(Image(n.src, n.alt));
			else if (n instanceof HTMLHRElement) result.push(HorizontalRule());
			else if (n instanceof HTMLElement) {
				if (n.classList.contains("mature")) continue;
				const tagName = n.tagName.toLowerCase();
				const nextElement = origin.slice(index).filter((node) => node instanceof HTMLElement && !(node instanceof HTMLBRElement)).at(1);
				if (n.classList.contains("quoteheader")) {
					let offset = 0;
					while (offset++ < origin.length) if (origin.at(index + offset) instanceof HTMLQuoteElement) break;
					if (index + offset === origin.length) throw n;
					result.push(Quote(n.textContent?.trim() ?? "", _fromHTML(origin.at(index + offset), baseURL)));
					index += offset;
				} else if (tagName === "strong" && nextElement instanceof HTMLAnchorElement && (nextElement.attributes.getNamedItem("onclick")?.value?.indexOf("spoiler") ?? NaN) >= 0) {
					let offset = 0;
					while (offset++ < origin.length) if (origin.at(index + offset) instanceof HTMLQuoteElement) break;
					if (index + offset === origin.length) throw n;
					result.push(Collapse(n.textContent?.trim() ?? "", _fromHTML(origin.at(index + offset), baseURL)));
					index += offset;
					index += 3;
				} else if (n.classList.contains("codetop")) {
					let nextElement;
					do {
						nextElement = origin[++index];
						if (nextElement === void 0) throw n;
					} while (!(nextElement instanceof HTMLElement));
					result.push(..._fromHTML(nextElement, baseURL));
					let offset = 1;
					nextElement = origin[index + offset];
					while (!(nextElement instanceof HTMLElement) && nextElement) nextElement = origin[index + ++offset];
					if (nextElement instanceof HTMLElement) {
						if (nextElement.children.item(0)?.classList?.contains("codemain")) {
							result.push(..._fromHTML(nextElement.children.item(0), baseURL));
							index += offset;
						}
					}
				} else if (tagName === "b" || tagName === "strong") result.push(Bold(_fromHTML(n, baseURL)));
				else if (tagName === "i" || tagName === "i") result.push(Italic(_fromHTML(n, baseURL)));
				else if (tagName === "u" || tagName === "ins") result.push(Underline(_fromHTML(n, baseURL)));
				else if (tagName === "s" || tagName === "strike" || tagName === "del") result.push(Strikethrough(_fromHTML(n, baseURL)));
				else if (tagName === "code" || tagName === "tt") result.push(Code(_fromHTML(n, baseURL)));
				else if (tagName === "sub") result.push(Sub(_fromHTML(n, baseURL)));
				else if (tagName === "sup") result.push(Sup(_fromHTML(n, baseURL)));
				else if (tagName === "center" || tagName === "marquee") result.push(Align("center", _fromHTML(n, baseURL)));
				else {
					let outer;
					let allowUnwrap = false;
					const children = _fromHTML(n, baseURL);
					const classes = [...n.classList];
					const fontWeight = n.style.fontWeight.toLowerCase();
					if (parseFloat(fontWeight) >= 550 || fontWeight === "bold" || fontWeight === "bolder") outer = Bold(children);
					const fontStyle = n.style.fontStyle.toLowerCase();
					if (fontStyle === "italic" || fontStyle.startsWith("oblique")) outer = Italic(outer ? [outer] : children);
					const textDecoration = n.style.textDecoration.toLowerCase().split(" ");
					const textDecorationLine = n.style.textDecorationLine.toLowerCase();
					if (textDecorationLine === "underline" || textDecoration.indexOf("underline") >= 0) outer = Underline(outer ? [outer] : children);
					else if (textDecorationLine === "line-through" || textDecoration.indexOf("line-through") >= 0) outer = Strikethrough(outer ? [outer] : children);
					const fontFamily = n.style.fontFamily.toLowerCase().split(";").at(0);
					if (fontFamily) if (n.children.item(0) instanceof HTMLPreElement) allowUnwrap = true;
					else outer = Font(fontFamily, outer ? [outer] : children);
					const fontSize = n.style.fontSize.toLowerCase();
					const sizeClasses = classes.filter((x) => x.startsWith("size"));
					if (sizeClasses.length) outer = Size(_clamp(parseInt(sizeClasses.at(0).slice(4)), 0, 7), outer ? [outer] : children);
					else if (fontSize) console.warn(fontSize);
					const color = n.style.color.toLowerCase();
					if (color) outer = Color(color, outer ? [outer] : children);
					const align = n.style.textAlign.toLowerCase();
					if ((() => {
						return (input) => "left" === input || "center" === input || "right" === input;
					})()(align)) outer = Align(align, outer ? [outer] : children);
					if (tagName === "span") {
						if (!(n.attributes.getNamedItem("class")?.value || n.attributes.getNamedItem("style")?.value)) allowUnwrap = true;
						else if (n.classList.contains("mask")) outer = Spoiler(children);
					}
					if (tagName === "p") if (n.classList.contains("sub")) result.push(Heading(2, children));
					else result.push(..._wrapNewline(outer ? [outer] : children, 3));
					else if (outer) if (tagName === "p") {} else result.push(outer);
					else if (allowUnwrap) result.push(...children);
					else {
						console.warn(n);
						console.log(n.outerHTML);
						if (tagName === "span") result.push(...children);
					}
				}
			} else throw n;
		}
		return result;
	}
	function fromHTML(parent, baseURL) {
		return _fromHTML(parent, baseURL);
	}
	var bbcode_default$2 = {
		fromHTML,
		is
	};
	var _isBigEndian = (() => {
		const u32 = new Uint32Array([1464816196]);
		const u8 = new Uint8Array(u32.buffer);
		switch (u8[0]) {
			case 87: return true;
			case 68: return false;
			default: throw u8;
		}
	})();
	var _bomUtf16LE = new Uint8Array([255, 254]);
	function toFile(logs, title) {
		if (logs.recovered) console.warn(logs);
		return logs.encoded ? logs.encoded.map((log, l) => new File([base64url.decodeBytes(log)], (0, import_sanitize_filename.default)(logs.encoded.length > 1 ? `${title}.${l + 1}.log` : `${title}.log`), { type: "text/plain" })) : logs.plain.map((log, l) => {
			log = log.trim();
			const name = (0, import_sanitize_filename.default)(logs.plain.length > 1 ? `${title}.${l + 1}.log` : `${title}.log`);
			if (log.startsWith("Exact Audio Copy")) {
				const array = new Uint16Array(log.length);
				let c = log.length;
				while (c >= 0) array[c] = log.charCodeAt(--c);
				if (_isBigEndian) {
					c = array.length;
					while (c >= 0) {
						const ch = array[--c];
						array[c] = (ch >> 8) + ((ch & 255) << 8);
					}
				}
				return new File([_bomUtf16LE, array.buffer], name, { type: "text/plain" });
			} else if (log.startsWith("X Lossless Decoder")) return new File([new TextEncoder().encode(`${log}\n`).buffer], name, { type: "text/plain" });
			else throw log;
		});
	}
	var utf8 = new TextDecoder("utf-8", {
		ignoreBOM: true,
		fatal: true
	});
	var utf16BE = new TextDecoder("utf-16be", {
		ignoreBOM: true,
		fatal: true
	});
	var utf16LE = new TextDecoder("utf-16le", {
		ignoreBOM: true,
		fatal: true
	});
	function toString(logs) {
		return logs.encoded ? logs.encoded.map((log) => {
			const array = base64url.decodeBytes(log);
			if (array[0] === 255 && array[1] === 254) return utf16LE.decode(array);
			else if (array[0] === 255 && array[1] === 254) return utf16BE.decode(array);
			else return utf8.decode(array);
		}) : logs.plain;
	}
	var log_default = {
		toFile,
		toString
	};
	function _dump$1(n, ordered = false) {
		let tag = n["#"];
		switch (n["#"]) {
			case "#text": return n.$.match(/\[(\/?(?:\w+(?:=.+?)?|\*|#))\]/g) ? `[plain]${n.$}[/plain]` : n.$;
			case "li":
				tag = ordered ? "#" : "*";
				return `[${tag}]${n.$$.map((n) => _dump$1(n)).join("")}`;
			case "img": return `[${tag}=${n.$}]${n.alt}[/${tag}]`;
			case "ul": return n.$$.map((n) => _dump$1(n)).join("\n");
			case "ol": return n.$$.map((n) => _dump$1(n, true)).join("\n");
			case "#collapse":
			case "#spoiler":
				tag = "hide";
				break;
		}
		if (bbcode_default$2.is.void(n)) return `[${tag}]`;
		else if (bbcode_default$2.is.valueVoid(n)) return n;
		else if (bbcode_default$2.is.view(n)) return `[${tag}]${n.$$.map((x) => _dump$1(x)).join("")}[/${tag}]`;
		else if (bbcode_default$2.is.valueView(n)) return n.$ ? `[${tag}=${n.$}]${n.$$.map((x) => _dump$1(x)).join("")}[/${tag}]` : `[${tag}]${n.$$.map((x) => _dump$1(x)).join("")}[/${tag}]`;
		else throw n;
	}
	function dump$1(root) {
		return root.map((node) => _dump$1(node)).join("").trim();
	}
	var bbcode_default$1 = {
		...bbcode_default$2,
		dump: dump$1
	};
	function dic_default(def) {
		def.lang = "zh";
		def.adapt = async (site, payload, callback) => {
			const record = payload.record;
			const gazelle = await getGazelle(site, payload);
			if (gazelle) {
				gazelle.group.wikiBody = "";
				gazelle.torrent.description = "";
				await adaptAuto(gazelle, payload.record, callback);
				await adaptDescriptions(record, callback);
			} else await adaptGeneric(site, payload.record, callback);
			if (record.item.logs) await adaptLogs(record.item.logs, record.group.name);
		};
	}
	function jpopsuki_default(def) {
		def.lang = "native";
		def.validate = void 0;
		def.extract = async (site, callback) => {
			$(".group_torrent:not(.edition)").each((_, header) => {
				let initialised = false;
				let busy = false;
				const details = header.nextElementSibling;
				if (details?.classList?.contains("pad") !== true) return;
				const header_buttons = $(header).find("> td > span");
				const repost_button = $("<a>RE</a>").attr("href", "#repost")[0];
				header_buttons.find("> a").last().after(document.createTextNode(" | "), repost_button);
				repost_button.onclick = async () => {
					const torrent_url = header_buttons.children().filter((_, e) => e instanceof HTMLAnchorElement).map((_, e) => new URL(e.href, location.href)).filter((_, url) => url.searchParams.get("action") === "download")[0];
					const links_container = $(details).removeClass("hide").find("blockquote + blockquote").first();
					if (!links_container.hasClass("ostrich")) links_container.addClass("ostrich").append($("<br>"), $("<br>"));
					if (initialised || busy) return;
					busy = true;
					try {
						const links = $(`<span>`).text("Repost to...").appendTo(links_container);
						const h2 = $("h2").single();
						const h3 = $("h3").get(0);
						const header_info = header_buttons[0].nextElementSibling;
						const type = h2.firstChild?.textContent?.match(/\[([^\]]+)\]/)?.[1] ?? "";
						const latin_artist = h2.querySelector("a")?.textContent?.trim() ?? "";
						const [, latin_title = "", date = ""] = h2.lastChild?.textContent?.trim()?.match(/^-\s*(.+?)\s*\[([\d.]+)\]$/) ?? [];
						let native_artist = h3.querySelector("a")?.textContent?.trim();
						let [, native_title = void 0] = h3.lastChild?.textContent?.trim().match(/^-\s*(.+?)\s*\)$/) ?? [];
						if (native_artist == latin_artist) native_artist = void 0;
						if (native_title == latin_title) native_title = void 0;
						const [, format = "", encoding = "", media = ""] = header_info?.textContent?.match(/(\w.+?)\s*\/\s*(\w.+?)\s*\/\s*(\w.+?)\s*$/) ?? [];
						const record = {
							site: site.name,
							group: {
								type,
								name: native_title ? {
									latin: latin_title,
									native: native_title
								} : latin_title,
								artists: [native_artist ? {
									latin: latin_artist,
									native: native_artist
								} : latin_artist],
								guests: $(".box:has(.head:contains(\"Contributing Artists\")) .stats.nobullet").first().find("li a:first-of-type").toArray().map((a) => a.textContent).filter((t) => t !== void 0),
								composers: [],
								conductor: [],
								producer: [],
								dj: [],
								remixer: [],
								label: "",
								catalogue: "",
								year: parseInt(date.slice(0, 4)),
								image: $(".sidebar a:has(img)").get(0)?.href ?? "",
								description_tree: bbcode_default$1.fromHTML($(".torrent_table + .box .body").single(), new URL(location.href))
							},
							item: {
								media,
								encoding,
								format,
								scene: false,
								uploaded_by: "",
								description_tree: $(details).find("blockquote + blockquote + blockquote").first().map((_, bq) => bbcode_default$1.fromHTML(bq, new URL(location.href))).toArray() ?? []
							}
						};
						await callback(links, {
							torrent: torrent_url.toString(),
							record
						});
						initialised = true;
					} finally {
						busy = false;
					}
				};
			});
		};
		def.adapt = async (site, payload, callback) => {
			const record = payload.record;
			const gazelle = await getGazelle(site, payload);
			trySelect($("#categories").single(), record.group.type);
			const artist = record.group.artists[0];
			if (typeof artist === "string") $("#artist").single().value = artist;
			else {
				$("#artist").single().value = artist.latin;
				$("#artistjp").single().value = artist.native;
			}
			if (typeof record.group.name === "string") $("#title").single().value = record.group.name;
			else {
				$("#title").single().value = record.group.name.latin;
				$("#titlejp").single().value = record.group.name.native;
			}
			$("#releasedate").single().value = record.group.year?.toString() ?? "";
			if (record.item.name || record.item.year && record.item.year !== record.group.year) {
				$("#remaster").single().click();
				await new Promise((resolve) => setTimeout(resolve, 1e3));
				$("#remaster_year").single().value = record.item.year?.toString() ?? "";
				$("#remaster_title").single().value = record.item.name ?? "";
			}
			await adaptGenericCore(record, callback);
			if (gazelle) $("#tags").single().value = gazelle.group.tags.join(",");
		};
	}
	function ops_default(def) {
		def.adapt = async (site, payload, callback) => {
			const record = payload.record;
			const gazelle = await getGazelle(site, payload);
			if (gazelle) await adaptAuto(gazelle, payload.record, callback);
			else await adaptGeneric(site, payload.record, callback);
			if (record.item.logs) await adaptLogs(record.item.logs, record.group.name);
		};
	}
	function redacted_default(def) {
		def.adapt = async (site, payload, callback) => {
			const record = payload.record;
			const gazelle = await getGazelle(site, payload);
			await adaptGeneric(site, record, callback);
			if (record.item.logs) await adaptLogs(record.item.logs, record.group.name);
			if (gazelle) adaptGazelle(site, gazelle);
		};
	}
	var encoder = new TextEncoder();
	function _toRecord(site, e, base, logs) {
		const group_bb = e.group.bbBody ?? e.group.wikiBBcode;
		return {
			site: site.name,
			group: {
				type: site.selects?.releaseType[e.group.releaseType.toString()] ?? e.group.releaseType.toString(),
				name: l10n_default.parse(unescapeHtml(e.group.name)),
				artists: e.group.musicInfo.artists.map((a) => l10n_default.parse(a.name)),
				guests: e.group.musicInfo.with.map((a) => l10n_default.parse(a.name)),
				composers: e.group.musicInfo.composers.map((a) => l10n_default.parse(a.name)),
				conductor: e.group.musicInfo.conductor.map((a) => l10n_default.parse(a.name)),
				producer: e.group.musicInfo.producer.map((a) => l10n_default.parse(a.name)),
				dj: e.group.musicInfo.dj.map((a) => l10n_default.parse(a.name)),
				remixer: e.group.musicInfo.remixedBy.map((a) => l10n_default.parse(a.name)),
				description: group_bb ? unescapeHtml(group_bb) : void 0,
				description_tree: bbcode_default$2.fromHTML(new DOMParser().parseFromString(`<html><body>${e.group.wikiBody}</body></html>`, "text/html").body, base),
				label: unescapeHtml(e.group.recordLabel),
				catalogue: unescapeHtml(e.group.catalogueNumber),
				year: e.group.year,
				image: e.group.wikiImage
			},
			item: {
				name: unescapeHtml(e.torrent.remasterTitle),
				description: unescapeHtml(e.torrent.description),
				label: unescapeHtml(e.torrent.remasterRecordLabel),
				catalogue: unescapeHtml(e.torrent.remasterCatalogueNumber),
				year: e.torrent.remasterYear,
				media: e.torrent.media,
				encoding: e.torrent.encoding,
				format: e.torrent.format,
				scene: e.torrent.scene,
				uploaded_by: e.torrent.username,
				logs
			}
		};
	}
	function _mostCommon(array, invalid) {
		let compare = 0;
		let common = invalid;
		array.reduce((acc, val) => {
			if (val in acc) acc[val]++;
			else acc[val] = 1;
			if (acc[val] > compare) {
				compare = acc[val];
				common = val;
			}
			return acc;
		}, {});
		return common;
	}
	function _recoverLog(log) {
		if (log.startsWith("Exact Audio Copy") || log.startsWith("EAC extraction logfile")) return log.replace("\r\n", "\n").replace(/^Used [Dd]rive( +: .+?)(?: \(not found in database\))?$/m, "Used drive$1").replace(/Additional command line options +: .+(\n.+)+/m, (sub) => sub.replace("\n", "")).split("\n\n").map((block) => {
			let lines = block.split("\n");
			if (lines.some((line) => line.startsWith("Delete leading and trailing silent blocks"))) {
				const common_pos = _mostCommon(lines.map((line) => line.indexOf(":")), -1);
				lines = lines.map((line) => {
					const pos = line.indexOf(":");
					return line.slice(0, pos).padEnd(common_pos) + line.slice(pos);
				});
			}
			return lines.join("\n");
		}).join("\n\n").replace("\n", "\r\n");
		else if (log.startsWith("X Lossless Decoder") || log.startsWith("XLD extraction logfile")) return log.replace("\r\n", "\n").replace(/^Used [Dd]rive( +: .+?)(?: \(not found in database\))?$/m, "Used drive$1").replace(/(Absolute +\| +Relative +\| +Confidence)$/m, "$1 ").replace(/(?<!\n)\n(\n\nAccurateRip)/, "$1");
		else {
			console.warn(log);
			return log;
		}
	}
	async function extract(site, callback) {
		$("tr.torrent_row, .group_torrent:not(.edition)").each((_, header) => {
			let initialised = false;
			let busy = false;
			const header_buttons = $(header).find(".torrent_action_buttons, .td_info > span");
			const repost_button = $("<a>RE</a>").attr("href", "#repost")[0];
			header_buttons.find("> a").last().after(document.createTextNode(" | "), repost_button);
			repost_button.onclick = async () => {
				const torrent_url = header_buttons.children().filter((_, e) => e instanceof HTMLAnchorElement).map((_, e) => new URL(e.href, location.href)).filter((_, url) => url.searchParams.get("action") === "download")[0];
				const torrent_id = torrent_url.searchParams.get("id");
				let links_container;
				if (header.id) {
					links_container = $(`#torrent_${torrent_id}`).removeClass("hidden").find("blockquote").first();
					if (!links_container.hasClass("ostrich")) links_container.addClass("ostrich").append($("<br>"), $("<br>"));
				} else {
					links_container = $(header).next();
					if (links_container.length === 0 || !links_container.hasClass("torrentdetails")) links_container = $(`<td>`).attr("colspan", 9).appendTo($(`<tr>`).addClass("torrentdetails").addClass("pad").insertAfter(header));
				}
				if (initialised || busy) return;
				busy = true;
				try {
					const links = $(`<span>`).text("Repost to...").appendTo(links_container);
					const gazelle_url = new URL(`/ajax.php?action=torrent&id=${torrent_id}`, location.href).toString();
					const record = await _GM.xmlHttpRequest({
						method: "GET",
						url: gazelle_url,
						responseType: "json"
					}).then(async (event) => {
						let r = event.response;
						if (r.status !== "success") throw r.error;
						let logs;
						if (r.response.torrent.hasLog) logs = await _GM.xmlHttpRequest({
							method: "GET",
							url: `${site.exclude.download}?action=${site.actions?.log || _throw(site)}&torrentid=${torrent_id}`,
							responseType: "document"
						}).then(async (event) => {
							const body = $(event.response?.body);
							const sections = body.find(".log_section");
							if (sections.length) return {
								encoded: await Promise.all(sections.toArray().map(async (section) => {
									const event = await _GM.xmlHttpRequest({
										method: "GET",
										url: new URL(($(section).find("a.brackets")[0] ?? _throw(section)).href, location.href).toString(),
										responseType: "arraybuffer"
									});
									return base64url.encodeBytes(new Uint8Array(event.response));
								})),
								score: r.response.torrent.logScore
							};
							else return {
								plain: body.find("pre").map((_, pre) => pre.textContent).toArray().map(_recoverLog),
								recovered: true,
								score: r.response.torrent.logScore
							};
						});
						else logs = void 0;
						return _toRecord(site, r.response, new URL(location.href), logs);
					});
					links.text("Repost to: ");
					await callback(links, {
						torrent: torrent_url.toString(),
						record,
						gazelle: gazelle_url
					});
					initialised = true;
				} finally {
					busy = false;
				}
			};
		});
	}
	async function validate(callback) {
		await callback($("#upload_logs .label"), "#file[name^=logfiles], #logfile_1[name^=logfile]");
		const form = $("#dynamic_form")[0];
		if (form) onDescendantAdded($(form).single(), false, async (node) => {
			const label = $(node).find("#upload_logs .label");
			if (label.length) await callback(label, "#file[name^=logfiles], #logfile_1[name^=logfile]");
		});
	}
	async function getJson(gazelle, type) {
		return _GM.xmlHttpRequest({
			method: "GET",
			url: gazelle,
			responseType: type
		}).then((event) => event.response);
	}
	async function getGazelle(site, payload) {
		if (payload["gazelle"]) {
			const json = await getJson(payload["gazelle"], "json");
			if (json.status === "failure") throw json;
			json.response.group.name = l10n_default.format(l10n_default.parse(json.response.group.name), site.lang);
			json.response.group.musicInfo.artists = json.response.group.musicInfo.artists.map((a) => ({
				...a,
				name: l10n_default.format(l10n_default.parse(a.name), site.lang)
			}));
			return json.response;
		}
	}
	async function adaptAuto(gazelle, record, callback) {
		if (gazelle.torrent.remasterTitle || gazelle.torrent.remasterYear || gazelle.torrent.remasterRecordLabel || gazelle.torrent.remasterCatalogueNumber) gazelle.torrent.remastered = true;
		const json_input = $("#torrent-json-file").single();
		const response = {
			status: "success",
			response: gazelle
		};
		json_input.files = toDataTransfer(new File([encoder.encode(JSON.stringify(response)).buffer], "gazelle.json", { type: "application/json" })).files;
		await nextMutation($("#dynamic_form").single(), "childList", void 0, void 0, json_input);
		await new Promise((resolve) => setTimeout(resolve, 1e3));
		await adaptDescriptions(record, callback);
	}
	function _adaptArtistRole(role) {
		switch (role) {
			case "artists": return "1";
			case "with":
			case "guests": return "2";
			case "composers": return "3";
			case "conductor": return "4";
			case "dj": return "5";
			case "remixedBy":
			case "remixer": return "6";
			case "producer": return "7";
			default: throw role;
		}
	}
	async function adaptDescriptions(record, callback) {
		await callback($("tr:has(#album_desc) > .label"), $("#album_desc"), dumpDescriptions([record.group], bbcode_default$1.dump));
		await callback($("tr:has(#release_desc) > .label"), $("#release_desc"), dumpDescriptions([record.item], bbcode_default$1.dump));
	}
	function adaptArtists(artists) {
		const [artist_add, artist_rm] = $("#artistfields .brackets").toArray();
		while ($(`#artist_1`).length > 0) artist_rm.click();
		artists.forEach(([artist, role], i) => {
			let input;
			if (i === 0) input = $("#artist").single();
			else {
				artist_add.click();
				input = $(`#artist_${i}`).single();
			}
			input.value = artist;
			input.nextElementSibling.value = _adaptArtistRole(role);
		});
	}
	async function adaptGenericCore(record, callback) {
		const format_select = $("#format").single();
		trySelect(format_select, record.item.format);
		$(format_select).trigger("change");
		const encoding_select = $("#bitrate").single();
		if (!trySelect(encoding_select, record.item.encoding)) {
			trySelect(encoding_select, "Other");
			$(encoding_select).trigger("change");
			$("#other_bitrate").single().value = record.item.encoding;
		}
		trySelect($("#media, select[name=media]").single(), record.item.media);
		$("#image").single().value = record.group.image;
		await adaptDescriptions(record, callback);
	}
	async function adaptGeneric(site, record, callback) {
		$("#title").single().value = l10n_default.format(record.group.name, site.lang);
		adaptArtists(Object.keys(record.group).filter((k) => (() => {
			return (input) => "artists" === input || "composers" === input || "conductor" === input || "dj" === input || "producer" === input || "guests" === input || "remixer" === input;
		})()(k)).flatMap((role) => record.group[role].map((artist) => [l10n_default.format(artist, site.lang), role])));
		$("#year").single().value = record.group.year.toString();
		$("#remaster_year").single().value = record.item.year?.toString() ?? "";
		$("#remaster_title").single().value = record.item.name ?? "";
		$("#remaster_record_label").single().value = record.item.label ?? "";
		$("#remaster_catalogue_number").single().value = record.item.catalogue ?? "";
		await adaptGenericCore(record, callback);
	}
	function _adaptReleaseType(select, value, source, target) {
		const name = Object.entries(data.gazelle[source].selects.releaseType).find(([k, _v]) => k === value)?.[1]?.toLowerCase();
		if (!name) return;
		const mapped = Object.entries(data.gazelle[target].selects.releaseType).find(([_, v]) => v.toLowerCase() === name)?.[0];
		if (mapped === void 0) return;
		select.value = mapped;
	}
	async function adaptGazelle(site, gazelle) {
		const group = gazelle.group;
		const release = gazelle.torrent;
		adaptArtists(Object.entries(group.musicInfo).flatMap(([role, artists]) => {
			return artists.map((artist) => [artist.name, role]);
		}));
		if ((() => {
			return (input) => "DIC" === input || "JPopsuki" === input || "OPS" === input || "Redacted" === input;
		})()(site.name)) _adaptReleaseType($("#releasetype").single(), group.releaseType.toString(), site.name, "Redacted");
		else console.warn(site.name);
		if (release.scene) $("#scene").single().click();
		$("#tags").single().value = group.tags.join(",");
	}
	async function adaptLogs(logs, name) {
		const log_input = $("#file[name^=logfiles], #logfile_1[name^=logfile]").single();
		log_input.files = toDataTransfer(log_default.toFile(logs, l10n_default.select(name, "native"))).files;
	}
	function gazelle_default(framework) {
		Object.entries(framework).forEach(([st, site]) => {
			site.extract = extract;
			site.validate = validate;
			switch (st) {
				case "DIC": return dic_default(site);
				case "JPopsuki": return jpopsuki_default(site);
				case "OPS": return ops_default(site);
				case "Redacted": return redacted_default(site);
			}
		});
	}
	var _is = {
		void: (node) => (() => {
			return (input) => "hr" === input;
		})()(node["#"]),
		valueVoid: (node) => (() => {
			return (input) => "img" === input;
		})()(node["#"]),
		view: (node) => (() => {
			const _iv1 = new Set([
				"b",
				"i",
				"u",
				"s",
				"center",
				"sup",
				"sub",
				"mask",
				"pre",
				"*",
				"table",
				"tr",
				"td"
			]);
			return (input) => true === _iv1.has(input);
		})()(node["#"]),
		valueView: (node) => (() => {
			return (input) => "color" === input || "font" === input || "url" === input || "quote" === input || "hide" === input || "code" === input || "size" === input;
		})()(node["#"])
	};
	function _dump(n, depth = -1) {
		let np = (() => {
			switch (n["#"]) {
				case "h": return ValueView("size")(8 - n.$, n.$$);
				case "code": return ValueView("font")("monospace", n.$$);
				case "#spoiler": return {
					...n,
					"#": "mask"
				};
				case "align": if (n.$ === "center") return View("center")(n.$$);
				else {
					console.warn(n);
					return n.$$.map((c) => _dump(c, depth)).join("");
				}
				case "#collapse": return {
					...n,
					"#": "hide"
				};
				case "li":
					console.warn(n);
					return {
						...n,
						"#": "*"
					};
				case "ul":
					++depth;
					return n.$$.map((li) => `${"    ".repeat(depth)}[*] ${li.$$.map((c) => _dump(c, depth)).join()}`).join("\n");
				case "ol":
					++depth;
					return n.$$.map((li, i) => `${"    ".repeat(depth)}[*] ${i + 1}. ${li.$$.map((c) => _dump(c, depth)).join()}`).join("\n");
				default: return n;
			}
		})();
		if (typeof np === "string") return np;
		switch (np["#"]) {
			case "#text": return np.$.replace(/\[(\/?(?:\w+(?:=.+?)?|\*|#))\]/g, "[​$1​]");
			case "*": return `[${np["#"]}]${np.$$.map((n) => _dump(n)).join("")}`;
		}
		if (_is.void(np)) return `[${np["#"]}]`;
		else if (_is.valueVoid(np)) return np.$ ? `[${np["#"]}=${np.$}]` : `[${np["#"]}]`;
		else if (_is.view(np)) return `[${np["#"]}]${np.$$.map((c) => _dump(c)).join("")}[/${np["#"]}]`;
		else if (_is.valueView(np)) return np.$ ? `[${np["#"]}=${np.$}]${np.$$.map((c) => _dump(c)).join("")}[/${np["#"]}]` : `[${np["#"]}]${np.$$.map((c) => _dump(c)).join("")}[/${np["#"]}]`;
		else throw n;
	}
	function dump(root) {
		return root.map((node) => _dump(node)).join("").trim();
	}
	var bbcode_default = {
		...bbcode_default$2,
		dump
	};
	function opencd_default(def) {
		def.lang = "native";
		def.validate = async (callback) => {
			await callback($(".rowhead[msg^=NFO]"), "input[name^=nfo1]");
		};
		def.adapt = async (site, payload, callback) => {
			const record = payload.record;
			const cover_task = _GM.xmlHttpRequest({
				method: "GET",
				url: record.group.image,
				responseType: "arraybuffer"
			}).then((event) => {
				const transfer = toDataTransfer(new File([event.response], new URL(event.finalUrl).pathname.split("/").filter((x) => x).at(-1)?.substring(1) ?? _throw(event), { type: parseHeaders(event.responseHeaders)["content-type"].split(";")[0] }));
				$("td:has(> #cover) iframe").single().contentDocument.querySelector("#file").files = transfer.files;
			});
			const desc_parent = $("#editer_description").single();
			if (desc_parent.children.length === 0) await nextMutation(desc_parent, "childList");
			$("#browsecat").single().value = "408";
			$("#artist").single().value = record.group.artists.map((a) => l10n_default.format(a, site.lang)).join(" / ");
			$("#resource_name").single().value = l10n_default.format(record.group.name, site.lang);
			const year = $("#year").single();
			year.value = record.group.year.toString();
			year.dispatchEvent(new Event("change"));
			trySelect($("#standard").single(), record.item.format);
			trySelect($("#medium").single(), record.item.media);
			const repost_input = $("#boardid1").single();
			repost_input.checked = true;
			$(repost_input).trigger("change");
			$("#small_descr").single().value = [
				record.item.name,
				record.group.year !== record.item.year && record.item.year,
				record.item.label ? record.item.label : record.group.label,
				record.item.catalogue ? record.item.catalogue : record.group.catalogue
			].filter((i) => i).join(" / ");
			if (record.item.logs) {
				const log_add = $("#nfoadd").single();
				log_default.toFile(record.item.logs, l10n_default.select(record.group.name, "native")).forEach(async (f, i) => {
					if (i > 0) log_add.click();
					$(`[name=nfo${"1".repeat(i + 1)}]`).single().files = toDataTransfer(f).files;
				});
			}
			await callback($("tr:has(#descr) > .rowhead"), $("#descr"), dumpDescriptions([record.group, record.item], bbcode_default.dump));
			await cover_task;
		};
	}
	function tjupt_default(def) {
		def.lang = "native";
		def.adapt = async (site, payload, callback) => {
			const record = payload.record;
			const select_cat = $("#browsecat").single();
			select_cat.value = "406";
			$(select_cat).trigger("change");
			const form_div = select_cat.nextElementSibling ?? _throw(select_cat);
			while (form_div.children.length <= 1) await nextMutation(select_cat.nextElementSibling ?? _throw(select_cat), "childList");
			$("#hqname").single().value = l10n_default.format(record.group.name, site.lang);
			$("#artist").single().value = record.group.artists.map((a) => l10n_default.format(a, site.lang)).join(" / ");
			$("#issuedate").single().value = record.group.year.toString();
			$("#specificcat").single().value = record.item.media;
			$("#format").single().value = record.item.format;
			$("#hqtone").single().value = record.item.encoding;
			$("input[name=small_descr]").single().value = [
				record.item.name,
				record.group.year !== record.item.year && record.item.year,
				record.item.label ? record.item.label : record.group.label,
				record.item.catalogue ? record.item.catalogue : record.group.catalogue,
				record.item.logs?.score && `Log (${record.item.logs.score}%)`
			].filter((i) => i).join(" / ");
			const logs = record.item.logs ? log_default.toString(record.item.logs).map((log) => `[hide=Log][code]${log}[/code][/hide]`).join("\n") : void 0;
			await callback($("tr:has(#descr) > .rowhead"), $("#descr"), dumpDescriptions([record.group, record.item], bbcode_default.dump).map((s) => [
				`[img]${record.group.image}[/img]`,
				s,
				logs
			].filter((i) => i).join("\n[hr]\n")));
		};
	}
	function nexusphp_default(framework) {
		Object.entries(framework).forEach(([st, site]) => {
			switch (st) {
				case "OpenCD": return opencd_default(site);
				case "TJUPT": return tjupt_default(site);
			}
		});
	}
	gazelle_default(data.gazelle);
	nexusphp_default(data.nexusphp);
	function parseSites(location) {
		if (location.hostname.toLowerCase() === "logs.musichoarders.xyz") return [
			"gazelle",
			{},
			"validate"
		];
		const [fw, st, site] = Object.entries(data).flatMap(([fw, framework]) => Object.entries(framework).map(([st, site]) => [
			fw,
			st,
			site
		])).find(([_f, _s, site]) => location.hostname.endsWith(site.hostname)) ?? _throw(location);
		const [cat] = Object.entries(site.include).find(([cat, fw_path]) => {
			const path = site.include?.[cat] ?? fw_path;
			return path instanceof Array ? path.filter((path) => path === location.pathname).length > 0 : path === location.pathname;
		}) ?? _throw(location);
		return [
			fw,
			{
				...site,
				name: st
			},
			cat
		];
	}
	function dumpDescriptions(descriptions, dump) {
		const array = descriptions.map((d) => [d.description, d.description_tree ? dump(d.description_tree) : void 0]);
		function* _join() {
			if (array[0][0] !== void 0) yield [array[0][0], ...array.slice(1).map((p) => p[0] ?? p[1] ?? "")].filter((d) => d).join("\n[hr]\n");
			if (array[0][1] !== void 0) yield [array[0][1], ...array.slice(1).map((p) => p[1] ?? p[0] ?? "")].filter((d) => d).join("\n[hr]\n");
		}
		return Array.from(_join());
	}
	var sites_default = data;
	var [fw, site, cat] = parseSites(location);
	if (cat === "validate") {
		const psuedo_url = new URL(new URL(location.href).hash.substring(1), location.origin);
		if (psuedo_url.pathname === "/ostrich") {
			const input = document.querySelector("#cursorfiles");
			if (input) {
				input.files = toDataTransfer(new File([base64url.decodeBytes(psuedo_url.hash.slice(1))], "text.log", { type: "text/plain" })).files;
				await(new Promise((resolve) => setTimeout(resolve, 1e3)));
				input.dispatchEvent(new Event("change"));
			}
		}
	} else {
		if ($?.fn?.jquery == void 0) $ = jQuery?.fn?.jquery ? jQuery : await(import("https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.slim.min.js"));
		$.fn.extend({ single() {
			return this.length === 1 ? this[0] : _throw(this);
		} });
		if (cat === "source") {
			if (site.extract) await(site.extract(site, async (container, payload) => {
				console.debug(payload);
				const params = new URLSearchParams();
				Object.entries(payload).forEach(([k, v]) => {
					params.set(k, marshal(v));
				});
				const p = params.toString();
				Object.entries(sites_default).flatMap(([_fw, framework]) => Object.entries(framework)).filter(([_st, site]) => site.adapt && !location.hostname.endsWith(site.hostname)).forEach(([st, site], s) => {
					if (s !== 0) container.append(document.createTextNode(" · "));
					$(`<a>`).appendTo(container).text(st).attr("target", "_blank").attr("href", `https://${site.hostname}${site.include.target}#ostrich?${p}`);
				});
			}));
		} else if (cat === "target") {
			const psuedo_url = new URL(new URL(location.href).hash.substring(1), location.origin);
			if (site.validate) await(site.validate(async (container, selector) => {
				const anchor = $("<a>").appendTo(container.append($("<br>"))).text("Validate").attr("href", "#_ostrich").single();
				anchor.onclick = async () => {
					await Promise.all($(selector).toArray().filter((input) => input.files).flatMap((input) => [...input.files]).map(async (file) => {
						window.open(`https://logs.musichoarders.xyz#ostrich#${base64url.encodeBytes(new Uint8Array(await file.arrayBuffer()))}`, "_blank");
					}));
				};
			}));
			if (psuedo_url.pathname === "/ostrich") {
				const payload = Object.fromEntries([...psuedo_url.searchParams.entries()].map(([k, v]) => [k, unmarshal(v)]));
				const record = payload.record;
				console.debug(payload);
				const torrent_task = (async () => {
					let buffer = (await _GM.xmlHttpRequest({
						method: "GET",
						url: payload.torrent,
						responseType: "arraybuffer"
					})).response;
					buffer = (await patch(new Uint8Array(buffer), site.name)).buffer;
					return toDataTransfer(new File([buffer], (0, import_sanitize_filename.default)(`${l10n_default.select(record.group.name, "native")}.torrent`), { type: "application/x-bittorrent" }));
				})();
				if (site.adapt) {
					const input = (() => {
						switch (fw) {
							case "gazelle": return $("#file[name=file_input]").single();
							case "nexusphp": return $("#torrent").single();
							default: throw new Error(`Unsupported framework: ${fw}`);
						}
					})();
					input.addEventListener("contextmenu", (event) => {
						event.preventDefault();
						for (const file of input.files ?? []) {
							const a = document.createElement("a");
							a.style.display = "none";
							a.href = URL.createObjectURL(file);
							a.download = file.name;
							input.insertAdjacentElement("afterend", a);
							a.click();
							a.remove();
							URL.revokeObjectURL(a.href);
						}
					});
					await(torrent_task.then((data) => {
						input.files = data.files;
					}));
					await(site.adapt(site, payload, async (container, input, selections) => {
						selections = selections.filter((s) => s);
						if (selections.length >= 1) {
							input.single().value = selections[0];
							if (selections.length > 1) {
								const anchor = $("<a>").appendTo(container.append($("<br>"))).text("Toggle").attr("href", "#_ostrich").single();
								anchor.onclick = () => {
									selections.push(selections.shift());
									input.single().value = selections[0];
								};
							}
						}
					}));
				}
			}
		}
	}
})();