Reposting music torrents on sites built on Gazelle and other frameworks
// ==UserScript== // @name ostrich // @namespace https://dvxg.de/ // @version 0.3.9 // @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 = (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 require_truncate = __commonJSMin(((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(((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(((exports, module) => { var truncate = require_truncate(); var getLength = require_browser$1(); module.exports = truncate.bind(null, getLength); })); var import_sanitize_filename = __toESM(__commonJSMin(((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 = (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; } async function _init() { const url = _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 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)], (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 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], (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]; }; } } })); } } } } })();