ostrich

Reposting music torrents on sites built on Gazelle and other frameworks

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name               ostrich
// @namespace          https://dvxg.de/
// @version            0.3.5
// @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/brotli-wasm@3/pkg.web/brotli_wasm_bg.wasm
// @grant              GM_getResourceURL
// @grant              GM_xmlhttpRequest
// ==/UserScript==

(async function() {
	"use strict";
	var __defProp = Object.defineProperty;
	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 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 = (src, urlsafe = false) => urlsafe ? _mkUriSafe(_encode(src)) : _encode(src);
	var encodeURI = (src) => encode(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 = (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(this);
		});
		_add("toBase64", function(urlsafe) {
			return encode(this, urlsafe);
		});
		_add("toBase64URI", function() {
			return encode(this, true);
		});
		_add("toBase64URL", function() {
			return encode(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,
		toBase64: encode,
		encode,
		encodeURI,
		encodeURL: encodeURI,
		utob,
		btou,
		decode,
		isValid,
		fromUint8Array,
		toUint8Array,
		extendString,
		extendUint8Array,
		extendBuiltins
	};
	var _GM_getResourceURL = (() => typeof GM_getResourceURL != "undefined" ? GM_getResourceURL : void 0)();
	var _GM_xmlhttpRequest = (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)();
	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;
	}
	var brotli = (await(async () => {
		const url = _GM_getResourceURL("brotli_wasm_bg");
		await init(gBase64.toUint8Array(url.slice(url.indexOf(","))).buffer);
		return brotli_wasm_exports;
	}))();
	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 xmlHttpRequest(details) {
		return new Promise((resolve, reject) => {
			_GM_xmlhttpRequest({
				...details,
				onabort() {
					reject("Aborted");
				},
				onload(event) {
					if (event.status !== 200) reject(event.statusText);
					resolve(event);
				},
				onerror(event) {
					reject(event);
				},
				ontimeout() {
					reject("Timeout");
				}
			});
		});
	}
	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 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)], logs.encoded.length > 1 ? `${title}.${l + 1}.log` : `${title}.log`, { type: "text/plain" })) : logs.plain.map((log, l) => {
			log = log.trim();
			const name = 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 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 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 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 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 = 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 = xmlHttpRequest({
					method: "GET",
					url: payload.torrent,
					responseType: "arraybuffer"
				}).then((event) => {
					return toDataTransfer(new File([event.response], `${encodeURIComponent(l10n_default.select(record.group.name, "native"))}.torrent`, { type: "application/x-bittorrent" }));
				});
				if (site.adapt) {
					switch (fw) {
						case "gazelle":
							await(torrent_task.then((data) => {
								$("#file[name=file_input]").single().files = data.files;
							}));
							break;
						case "nexusphp":
							await(torrent_task.then((data) => {
								$("#torrent").single().files = data.files;
							}));
							break;
					}
					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];
								};
							}
						}
					}));
				}
			}
		}
	}
})();