diff --git a/.eslintrc.js b/.eslintrc.cjs similarity index 100% rename from .eslintrc.js rename to .eslintrc.cjs diff --git a/README.md b/README.md index 471c081..f7a6534 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ PNG Extra Embedder (PEE) ======================== -Can embed any file in a PNG/WebM and upload it through 4chanX. +Can embed any file in a PNG/WebM/GIF and upload it through 4chanX. Requires 4chanX and violentmonkey. How to Build @@ -53,4 +53,4 @@ Bugs ==== - fails to find files in new posts after a thread update -- more to come \ No newline at end of file +- more to come diff --git a/main.d.ts b/main.d.ts index 55925b9..d15de7d 100644 --- a/main.d.ts +++ b/main.d.ts @@ -1,3 +1 @@ /* eslint-disable */ - -declare const GM_fetch = fetch; \ No newline at end of file diff --git a/main.meta.js b/main.meta.js index 8306718..940a020 100644 --- a/main.meta.js +++ b/main.meta.js @@ -1,7 +1,7 @@ // ==UserScript== // @name PNGExtraEmbed // @namespace https://coom.tech/ -// @version 0.54 +// @version 0.55 // @description uhh // @author You // @match https://boards.4channel.org/* diff --git a/main.user.js b/main.user.js index 22c02f2..9c7fad4 100644 --- a/main.user.js +++ b/main.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name PNGExtraEmbed // @namespace https://coom.tech/ -// @version 0.54 +// @version 0.55 // @description uhh // @author You // @match https://boards.4channel.org/* @@ -2296,8 +2296,8 @@ } return obj; } - function _classCallCheck(instance2, Constructor) { - if (!(instance2 instanceof Constructor)) { + function _classCallCheck(instance3, Constructor) { + if (!(instance3 instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -12300,7 +12300,10 @@ var supportedExtensions = new Set(extensions); var supportedMimeTypes = new Set(mimeTypes); - // src/App.svelte + // src/stores.ts + init_esbuild_inject(); + + // node_modules/svelte/store/index.mjs init_esbuild_inject(); // node_modules/svelte/internal/index.mjs @@ -12401,6 +12404,14 @@ function set_current_component(component) { current_component = component; } + function get_current_component() { + if (!current_component) + throw new Error("Function called outside component initialization"); + return current_component; + } + function onDestroy(fn) { + get_current_component().$$.on_destroy.push(fn); + } var dirty_components = []; var binding_callbacks = []; var render_callbacks = []; @@ -12499,7 +12510,7 @@ } component.$$.dirty[i / 31 | 0] |= 1 << i % 31; } - function init(component, options, instance2, create_fragment2, not_equal, props, append_styles2, dirty = [-1]) { + function init(component, options, instance3, create_fragment3, not_equal, props, append_styles2, dirty = [-1]) { const parent_component = current_component; set_current_component(component); const $$ = component.$$ = { @@ -12522,7 +12533,7 @@ }; append_styles2 && append_styles2($$.root); let ready = false; - $$.ctx = instance2 ? instance2(component, options.props || {}, (i, ret, ...rest) => { + $$.ctx = instance3 ? instance3(component, options.props || {}, (i, ret, ...rest) => { const value = rest.length ? rest[0] : ret; if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) { if (!$$.skip_bound && $$.bound[i]) @@ -12535,7 +12546,7 @@ $$.update(); ready = true; run_all($$.before_update); - $$.fragment = create_fragment2 ? create_fragment2($$.ctx) : false; + $$.fragment = create_fragment3 ? create_fragment3($$.ctx) : false; if (options.target) { if (options.hydrate) { start_hydrating(); @@ -12618,11 +12629,7 @@ } }; - // src/stores.ts - init_esbuild_inject(); - // node_modules/svelte/store/index.mjs - init_esbuild_inject(); var subscriber_queue = []; function writable(value, start = noop) { let stop; @@ -12681,210 +12688,10 @@ localSet("settings", newVal); }); - // src/App.svelte - function add_css(target) { - append_styles(target, "svelte-6ot9e6", ".enabled.svelte-6ot9e6{display:block}.disabled.svelte-6ot9e6{display:none}.glow.svelte-6ot9e6{text-shadow:0 0 4px red}.clickable.svelte-6ot9e6{cursor:pointer}.content.svelte-6ot9e6{display:flex;flex-direction:column}hr.svelte-6ot9e6{width:100%}h1.svelte-6ot9e6{text-align:center}.backpanel.svelte-6ot9e6{position:absolute;right:32px;padding:10px;width:10%;top:32px;border:1px solid;border-radius:5px;background-color:rgba(0, 0, 0, 0.2)}.clickable.svelte-6ot9e6:hover{text-shadow:0 0 2px palevioletred}"); - } - function create_fragment(ctx) { - let span; - let t1; - let div1; - let div0; - let h1; - let t3; - let hr; - let t4; - let label0; - let input0; - let t5; - let t6; - let label1; - let input1; - let t7; - let t8; - let label2; - let input2; - let t9; - let t10; - let label3; - let input3; - let t11; - let mounted; - let dispose; - return { - c() { - span = element("span"); - span.textContent = "[PEE Settings]"; - t1 = space(); - div1 = element("div"); - div0 = element("div"); - h1 = element("h1"); - h1.textContent = "PEE Settings"; - t3 = space(); - hr = element("hr"); - t4 = space(); - label0 = element("label"); - input0 = element("input"); - t5 = text("\n Autoplay Videos"); - t6 = space(); - label1 = element("label"); - input1 = element("input"); - t7 = text("\n Autoplay Audio"); - t8 = space(); - label2 = element("label"); - input2 = element("input"); - t9 = text("\n Autoexpand Images on opening."); - t10 = space(); - label3 = element("label"); - input3 = element("input"); - t11 = text("\n Autoexpand Videos on opening."); - attr(span, "class", "clickable svelte-6ot9e6"); - toggle_class(span, "glow", ctx[0]); - attr(h1, "class", "svelte-6ot9e6"); - attr(hr, "class", "svelte-6ot9e6"); - attr(input0, "type", "checkbox"); - attr(input1, "type", "checkbox"); - attr(input2, "type", "checkbox"); - attr(input3, "type", "checkbox"); - attr(div0, "class", "content svelte-6ot9e6"); - attr(div1, "class", "backpanel svelte-6ot9e6"); - toggle_class(div1, "enabled", ctx[0]); - toggle_class(div1, "disabled", !ctx[0]); - }, - m(target, anchor) { - insert(target, span, anchor); - insert(target, t1, anchor); - insert(target, div1, anchor); - append(div1, div0); - append(div0, h1); - append(div0, t3); - append(div0, hr); - append(div0, t4); - append(div0, label0); - append(label0, input0); - input0.checked = ctx[1].apv; - append(label0, t5); - append(div0, t6); - append(div0, label1); - append(label1, input1); - input1.checked = ctx[1].apa; - append(label1, t7); - append(div0, t8); - append(div0, label2); - append(label2, input2); - input2.checked = ctx[1].xpi; - append(label2, t9); - append(div0, t10); - append(div0, label3); - append(label3, input3); - input3.checked = ctx[1].xpv; - append(label3, t11); - if (!mounted) { - dispose = [ - listen(span, "click", ctx[3]), - listen(input0, "change", ctx[4]), - listen(input1, "change", ctx[5]), - listen(input2, "change", ctx[6]), - listen(input3, "change", ctx[7]) - ]; - mounted = true; - } - }, - p(ctx2, [dirty]) { - if (dirty & 1) { - toggle_class(span, "glow", ctx2[0]); - } - if (dirty & 2) { - input0.checked = ctx2[1].apv; - } - if (dirty & 2) { - input1.checked = ctx2[1].apa; - } - if (dirty & 2) { - input2.checked = ctx2[1].xpi; - } - if (dirty & 2) { - input3.checked = ctx2[1].xpv; - } - if (dirty & 1) { - toggle_class(div1, "enabled", ctx2[0]); - } - if (dirty & 1) { - toggle_class(div1, "disabled", !ctx2[0]); - } - }, - i: noop, - o: noop, - d(detaching) { - if (detaching) - detach(span); - if (detaching) - detach(t1); - if (detaching) - detach(div1); - mounted = false; - run_all(dispose); - } - }; - } - function instance($$self, $$props, $$invalidate) { - let $settings; - component_subscribe($$self, settings, ($$value) => $$invalidate(1, $settings = $$value)); - let visible = false; - function opensettings() { - $$invalidate(0, visible = !visible); - } - console.log($settings); - const click_handler = () => opensettings(); - function input0_change_handler() { - $settings.apv = this.checked; - settings.set($settings); - } - function input1_change_handler() { - $settings.apa = this.checked; - settings.set($settings); - } - function input2_change_handler() { - $settings.xpi = this.checked; - settings.set($settings); - } - function input3_change_handler() { - $settings.xpv = this.checked; - settings.set($settings); - } - return [ - visible, - $settings, - opensettings, - click_handler, - input0_change_handler, - input1_change_handler, - input2_change_handler, - input3_change_handler - ]; - } - var App = class extends SvelteComponent { - constructor(options) { - super(); - init(this, options, instance, create_fragment, safe_not_equal, {}, add_css); - } - }; - var App_default = App; - // src/png.ts init_esbuild_inject(); var import_crc_32 = __toESM(require_crc32(), 1); var import_buffer = __toESM(require_buffer(), 1); - var concatAB = (...bufs) => { - const sz = bufs.map((e) => e.byteLength).reduce((a, b) => a + b); - const ret = import_buffer.Buffer.alloc(sz); - let ptr = 0; - for (const b of bufs) { - b.copy(ret, ptr); - ptr += b.byteLength; - } - return ret; - }; var PNGDecoder = class { constructor(reader) { this.reader = reader; @@ -12895,9 +12702,10 @@ async catchup() { while (this.repr.byteLength < this.req) { const chunk = await this.reader.read(); - if (chunk.done) - throw new Error("Unexpected EOF"); - this.repr = concatAB(this.repr, import_buffer.Buffer.from(chunk.value)); + if (chunk.done) { + throw new Error(`Unexpected EOF, got ${this.repr.byteLength}, required ${this.req}, ${chunk.value}`); + } + this.repr = import_buffer.Buffer.concat([this.repr, chunk.value]); } } async *chunks() { @@ -12908,8 +12716,14 @@ const name = this.repr.slice(this.ptr + 4, this.ptr + 8).toString(); this.ptr += 4; this.req += length + 4; - await this.catchup(); - yield [name, this.repr.slice(this.ptr, this.ptr + length + 4), this.repr.readUInt32BE(this.ptr + length + 4), this.ptr]; + const pos = this.ptr; + yield [name, async () => { + await this.catchup(); + return this.repr.slice(pos, pos + length + 4); + }, async () => { + await this.catchup(); + return this.repr.readUInt32BE(this.ptr + length + 4); + }, this.ptr]; this.ptr += length + 8; if (name == "IEND") break; @@ -12927,8 +12741,9 @@ const b = import_buffer.Buffer.alloc(4); b.writeInt32BE(chunk[1].length - 4, 0); await this.writer.write(b); - await this.writer.write(chunk[1]); - b.writeInt32BE((0, import_crc_32.buf)(chunk[1]), 0); + const buff = await chunk[1](); + await this.writer.write(buff); + b.writeInt32BE((0, import_crc_32.buf)(buff), 0); await this.writer.write(b); } async dtor() { @@ -12937,20 +12752,32 @@ } }; var CUM0 = import_buffer.Buffer.from("CUM\x000"); - var extract = async (reader) => { + var BufferReadStream = (b) => { + const ret = new ReadableStream({ + pull(cont) { + cont.enqueue(b); + cont.close(); + } + }); + return ret; + }; + var extract = async (png) => { let magic2 = false; + const reader = BufferReadStream(png).getReader(); const sneed = new PNGDecoder(reader); try { let lastIDAT = null; for await (const [name, chunk, crc, offset] of sneed.chunks()) { + let buff; switch (name) { case "tEXt": - if (chunk.slice(4, 4 + CUM0.length).equals(CUM0)) + buff = await chunk(); + if (buff.slice(4, 4 + CUM0.length).equals(CUM0)) magic2 = true; break; case "IDAT": if (magic2) { - lastIDAT = chunk; + lastIDAT = await chunk(); break; } case "IEND": @@ -12983,7 +12810,7 @@ let b = import_buffer.Buffer.from([]); const ret = new WritableStream({ write(chunk) { - b = concatAB(b, chunk); + b = import_buffer.Buffer.concat([b, chunk]); } }); return [ret, () => b]; @@ -12997,7 +12824,7 @@ if (magic2 && name != "IDAT") break; if (!magic2 && name == "IDAT") { - await encoder.insertchunk(["tEXt", buildChunk("tEXt", CUM0), 0, 0]); + await encoder.insertchunk(["tEXt", () => buildChunk("tEXt", CUM0), () => 0, 0]); magic2 = true; } await encoder.insertchunk([name, chunk, crc, offset]); @@ -13006,10 +12833,36 @@ injb.writeInt32LE(inj.name.length, 0); injb.write(inj.name, 4); import_buffer.Buffer.from(await inj.arrayBuffer()).copy(injb, 4 + inj.name.length); - await encoder.insertchunk(["IDAT", buildChunk("IDAT", injb), 0, 0]); - await encoder.insertchunk(["IEND", buildChunk("IEND", import_buffer.Buffer.from([])), 0, 0]); + await encoder.insertchunk(["IDAT", () => buildChunk("IDAT", injb), () => 0, 0]); + await encoder.insertchunk(["IEND", () => buildChunk("IEND", import_buffer.Buffer.from([])), () => 0, 0]); return extract4(); }; + var has_embed = async (png) => { + const reader = BufferReadStream(png).getReader(); + const sneed = new PNGDecoder(reader); + try { + for await (const [name, chunk, crc, offset] of sneed.chunks()) { + let buff; + switch (name) { + case "tEXt": + buff = await chunk(); + if (buff.slice(4, 4 + CUM0.length).equals(CUM0)) { + return true; + } + break; + case "IDAT": + case "IEND": + return false; + default: + break; + } + } + } catch (e) { + return; + } finally { + reader.releaseLock(); + } + }; // src/webm.ts init_esbuild_inject(); @@ -13085,7 +12938,7 @@ ]); return import_buffer2.Buffer.from(enc.encode(chunks.filter((e) => e.name != "unknown"))); }; - var extractBuff = (webm) => { + var extract2 = (webm) => { const dec = new ebml.Decoder(); const chunks = dec.decode(webm); const embed2 = chunks.findIndex((e) => e.name == "TagName" && e.type == "8" && e.value == "COOM"); @@ -13096,31 +12949,29 @@ return; const chk = chunks[embed2 + 1]; if (chk.type == "b" && chk.name == "TagBinary") - return chk.data; + return { filename: "string", data: chk.data }; }; - var extract2 = async (reader) => { - let total = import_buffer2.Buffer.from(""); - let chunk; - do { - chunk = await reader.read(); - if (chunk.value) - total = concatAB(total, import_buffer2.Buffer.from(chunk.value)); - } while (!chunk.done); - const data = extractBuff(total); - if (!data) + var inject2 = async (container, inj) => embed(import_buffer2.Buffer.from(await container.arrayBuffer()), import_buffer2.Buffer.from(await inj.arrayBuffer())); + var has_embed2 = (webm) => { + const dec = new ebml.Decoder(); + const chunks = dec.decode(webm); + const embed2 = chunks.findIndex((e) => e.name == "TagName" && e.type == "8" && e.value == "COOM"); + const cl = chunks.find((e) => e.name == "Cluster"); + if (cl && embed2 == -1) + return false; + if (embed2 == -1) return; - return { filename: "embedded", data }; + return true; }; - var inject2 = async (container, inj) => embed(import_buffer2.Buffer.from(await container.arrayBuffer()), import_buffer2.Buffer.from(await inj.arrayBuffer())); // src/gif.ts init_esbuild_inject(); var import_buffer3 = __toESM(require_buffer(), 1); - var netscape = import_buffer3.Buffer.from("!\xFF\vNETSCAPE2.0\0\0\0"); + var netscape = import_buffer3.Buffer.from("!\xFF\vNETSCAPE2.0", "ascii"); var magic = import_buffer3.Buffer.from("!\xFF\vCOOMTECH0.1", "ascii"); - var extractBuff2 = (gif) => { - let field = gif.readUInt8(10); - let gcte = !!(field & 1 << 7); + var extractBuff = (gif) => { + const field = gif.readUInt8(10); + const gcte = !!(field & 1 << 7); let end = 13; if (gcte) { end += 3 * (1 << (field & 7) + 1); @@ -13128,8 +12979,8 @@ while (gif.readUInt8(end) == "!".charCodeAt(0)) { if (magic.compare(gif, end, end + magic.byteLength) != 0) { end += 3 + gif.readUInt8(end + 2); - while (1) { - let v = gif.readUInt8(end++); + while (true) { + const v = gif.readUInt8(end++); if (!v) break; end += v; @@ -13142,7 +12993,7 @@ t += v; count += v + 1; } - let buff = import_buffer3.Buffer.alloc(t); + const buff = import_buffer3.Buffer.alloc(t); count = end + magic.byteLength; t = 0; while ((v = gif.readUInt8(count)) != 0) { @@ -13150,23 +13001,11 @@ t += v; count += v + 1; } - return buff; + return { filename: "embedded", data: buff }; } } }; - var extract3 = async (reader) => { - let total = import_buffer3.Buffer.from(""); - let chunk; - do { - chunk = await reader.read(); - if (chunk.value) - total = concatAB(total, import_buffer3.Buffer.from(chunk.value)); - } while (!chunk.done); - const data = extractBuff2(total); - if (!data) - return; - return { filename: "embedded", data }; - }; + var extract3 = extractBuff; var write_embedding = async (writer, inj) => { await writer.write(magic); const byte = import_buffer3.Buffer.from([0]); @@ -13187,9 +13026,9 @@ var inject3 = async (container, inj) => { const [writestream, extract4] = BufferWriteStream(); const writer = writestream.getWriter(); - let contbuff = import_buffer3.Buffer.from(await container.arrayBuffer()); - let field = contbuff.readUInt8(10); - let gcte = !!(field & 1 << 7); + const contbuff = import_buffer3.Buffer.from(await container.arrayBuffer()); + const field = contbuff.readUInt8(10); + const gcte = !!(field & 1 << 7); let endo = 13; if (gcte) endo += 3 * (1 << (field & 7) + 1); @@ -13200,16 +13039,39 @@ await writer.write(contbuff.slice(endo)); return extract4(); }; - - // src/main.ts - var csettings; - settings.subscribe((b) => csettings = b); - var xmlhttprequest = typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : typeof GM != "undefined" ? GM.xmlHttpRequest : GM_xmlhttpRequest; - var headerStringToObject = (s) => Object.fromEntries(s.split("\n").map((e) => { - const [name, ...rest] = e.split(":"); - return [name.toLowerCase(), rest.join(":").trim()]; - })); - function GM_head(...[url, opt]) { + var has_embed3 = (gif) => { + const field = gif.readUInt8(10); + const gcte = !!(field & 1 << 7); + let end = 13; + if (gcte) { + end += 3 * (1 << (field & 7) + 1); + } + while (end < gif.byteLength && gif.readUInt8(end) == "!".charCodeAt(0)) { + if (magic.compare(gif, end, end + magic.byteLength) != 0) { + end += 3 + gif.readUInt8(end + 2); + while (true) { + const v = gif.readUInt8(end++); + if (!v) + break; + end += v; + } + } else { + return true; + } + } + if (end >= gif.byteLength) + return; + return false; + }; + + // src/requests.ts + init_esbuild_inject(); + var xmlhttprequest = typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : typeof GM != "undefined" ? GM.xmlHttpRequest : GM_xmlhttpRequest; + var headerStringToObject = (s) => Object.fromEntries(s.split("\n").map((e) => { + const [name, ...rest] = e.split(":"); + return [name.toLowerCase(), rest.join(":").trim()]; + })); + function GM_head(...[url, opt]) { return new Promise((resolve, reject) => { const gmopt = { url: url.toString(), @@ -13272,7 +13134,268 @@ xmlhttprequest(gmopt); }); } - async function* streamRemote(url, chunkSize = 128 * 1024, fetchRestOnNonCanceled = true) { + + // src/App.svelte + init_esbuild_inject(); + + // node_modules/svelte/index.mjs + init_esbuild_inject(); + + // src/App.svelte + function add_css(target) { + append_styles(target, "svelte-6ot9e6", ".enabled.svelte-6ot9e6{display:block}.disabled.svelte-6ot9e6{display:none}.glow.svelte-6ot9e6{text-shadow:0 0 4px red}.clickable.svelte-6ot9e6{cursor:pointer}.content.svelte-6ot9e6{display:flex;flex-direction:column}hr.svelte-6ot9e6{width:100%}h1.svelte-6ot9e6{text-align:center}.backpanel.svelte-6ot9e6{position:absolute;right:32px;padding:10px;width:10%;top:32px;border:1px solid;border-radius:5px;background-color:rgba(0, 0, 0, 0.2)}.clickable.svelte-6ot9e6:hover{text-shadow:0 0 2px palevioletred}"); + } + function create_fragment(ctx) { + let span; + let t1; + let div1; + let div0; + let h1; + let t3; + let hr; + let t4; + let label0; + let input0; + let t5; + let t6; + let label1; + let input1; + let t7; + let t8; + let label2; + let input2; + let t9; + let t10; + let label3; + let input3; + let t11; + let mounted; + let dispose; + return { + c() { + span = element("span"); + span.textContent = "[PEE Settings]"; + t1 = space(); + div1 = element("div"); + div0 = element("div"); + h1 = element("h1"); + h1.textContent = "PEE Settings"; + t3 = space(); + hr = element("hr"); + t4 = space(); + label0 = element("label"); + input0 = element("input"); + t5 = text("\n Autoplay Videos"); + t6 = space(); + label1 = element("label"); + input1 = element("input"); + t7 = text("\n Autoplay Audio"); + t8 = space(); + label2 = element("label"); + input2 = element("input"); + t9 = text("\n Autoexpand Images on opening."); + t10 = space(); + label3 = element("label"); + input3 = element("input"); + t11 = text("\n Autoexpand Videos on opening."); + attr(span, "class", "clickable svelte-6ot9e6"); + toggle_class(span, "glow", ctx[0]); + attr(h1, "class", "svelte-6ot9e6"); + attr(hr, "class", "svelte-6ot9e6"); + attr(input0, "type", "checkbox"); + attr(input1, "type", "checkbox"); + attr(input2, "type", "checkbox"); + attr(input3, "type", "checkbox"); + attr(div0, "class", "content svelte-6ot9e6"); + attr(div1, "class", "backpanel svelte-6ot9e6"); + toggle_class(div1, "enabled", ctx[0]); + toggle_class(div1, "disabled", !ctx[0]); + }, + m(target, anchor) { + insert(target, span, anchor); + insert(target, t1, anchor); + insert(target, div1, anchor); + append(div1, div0); + append(div0, h1); + append(div0, t3); + append(div0, hr); + append(div0, t4); + append(div0, label0); + append(label0, input0); + input0.checked = ctx[1].apv; + append(label0, t5); + append(div0, t6); + append(div0, label1); + append(label1, input1); + input1.checked = ctx[1].apa; + append(label1, t7); + append(div0, t8); + append(div0, label2); + append(label2, input2); + input2.checked = ctx[1].xpi; + append(label2, t9); + append(div0, t10); + append(div0, label3); + append(label3, input3); + input3.checked = ctx[1].xpv; + append(label3, t11); + if (!mounted) { + dispose = [ + listen(span, "click", ctx[3]), + listen(input0, "change", ctx[4]), + listen(input1, "change", ctx[5]), + listen(input2, "change", ctx[6]), + listen(input3, "change", ctx[7]) + ]; + mounted = true; + } + }, + p(ctx2, [dirty]) { + if (dirty & 1) { + toggle_class(span, "glow", ctx2[0]); + } + if (dirty & 2) { + input0.checked = ctx2[1].apv; + } + if (dirty & 2) { + input1.checked = ctx2[1].apa; + } + if (dirty & 2) { + input2.checked = ctx2[1].xpi; + } + if (dirty & 2) { + input3.checked = ctx2[1].xpv; + } + if (dirty & 1) { + toggle_class(div1, "enabled", ctx2[0]); + } + if (dirty & 1) { + toggle_class(div1, "disabled", !ctx2[0]); + } + }, + i: noop, + o: noop, + d(detaching) { + if (detaching) + detach(span); + if (detaching) + detach(t1); + if (detaching) + detach(div1); + mounted = false; + run_all(dispose); + } + }; + } + function instance($$self, $$props, $$invalidate) { + let $settings; + component_subscribe($$self, settings, ($$value) => $$invalidate(1, $settings = $$value)); + let visible = false; + function opensettings() { + $$invalidate(0, visible = !visible); + } + let penisEvent = () => { + $$invalidate(0, visible = !visible); + }; + document.addEventListener("penis", penisEvent); + onDestroy(() => { + document.removeEventListener("penis", penisEvent); + }); + const click_handler = () => opensettings(); + function input0_change_handler() { + $settings.apv = this.checked; + settings.set($settings); + } + function input1_change_handler() { + $settings.apa = this.checked; + settings.set($settings); + } + function input2_change_handler() { + $settings.xpi = this.checked; + settings.set($settings); + } + function input3_change_handler() { + $settings.xpv = this.checked; + settings.set($settings); + } + return [ + visible, + $settings, + opensettings, + click_handler, + input0_change_handler, + input1_change_handler, + input2_change_handler, + input3_change_handler + ]; + } + var App = class extends SvelteComponent { + constructor(options) { + super(); + init(this, options, instance, create_fragment, safe_not_equal, {}, add_css); + } + }; + var App_default = App; + + // src/SettingsButton.svelte + init_esbuild_inject(); + function add_css2(target) { + append_styles(target, "svelte-101vs6b", ".glow.svelte-101vs6b{text-shadow:0 0 4px red}.clickable.svelte-101vs6b{cursor:pointer}.clickable.svelte-101vs6b:hover{text-shadow:0 0 2px palevioletred}"); + } + function create_fragment2(ctx) { + let span; + let mounted; + let dispose; + return { + c() { + span = element("span"); + span.textContent = "[PEE Settings]"; + attr(span, "class", "clickable svelte-101vs6b"); + toggle_class(span, "glow", ctx[0]); + }, + m(target, anchor) { + insert(target, span, anchor); + if (!mounted) { + dispose = listen(span, "click", ctx[2]); + mounted = true; + } + }, + p(ctx2, [dirty]) { + if (dirty & 1) { + toggle_class(span, "glow", ctx2[0]); + } + }, + i: noop, + o: noop, + d(detaching) { + if (detaching) + detach(span); + mounted = false; + dispose(); + } + }; + } + function instance2($$self, $$props, $$invalidate) { + "use strict"; + let visible = false; + function opensettings() { + $$invalidate(0, visible = !visible); + } + const click_handler = () => opensettings(); + return [visible, opensettings, click_handler]; + } + var SettingsButton = class extends SvelteComponent { + constructor(options) { + super(); + init(this, options, instance2, create_fragment2, safe_not_equal, {}, add_css2); + } + }; + var SettingsButton_default = SettingsButton; + + // src/main.ts + var csettings; + settings.subscribe((b) => csettings = b); + async function* streamRemote(url, chunkSize = 16 * 1024, fetchRestOnNonCanceled = true) { const headers = await GM_head(url); const h = headerStringToObject(headers); const size = +h["content-length"]; @@ -13281,41 +13404,52 @@ while (ptr != size) { const res = await GM_fetch(url, { headers: { range: `bytes=${ptr}-${ptr + fetchSize - 1}` } }); const obj = headerStringToObject(res.responseHeaders); - if (!("content-length" in obj)) - return; + if (!("content-length" in obj)) { + console.warn("no content lenght???", url); + break; + } const len = +obj["content-length"]; ptr += len; if (fetchRestOnNonCanceled) fetchSize = size; - yield import_buffer4.Buffer.from(await res.arrayBuffer()); - } - } - function iteratorToStream(iterator) { - return new ReadableStream({ - async pull(controller) { - const { value, done } = await iterator.next(); - if (done) { - controller.close(); - } else { - controller.enqueue(value); - } + const val = import_buffer4.Buffer.from(await res.arrayBuffer()); + const e = yield val; + if (e) { + break; } - }); + } } var processors = [ - [/\.png$/, extract, inject], - [/\.webm$/, extract2, inject2], - [/\.gif$/, extract3, inject3] + [/\.png$/, has_embed, extract, inject], + [/\.webm$/, has_embed2, extract2, inject2], + [/\.gif$/, has_embed3, extract3, inject3] ]; var processImage = async (src) => { const proc = processors.find((e) => src.match(e[0])); if (!proc) return; const iter = streamRemote(src); - const reader = iteratorToStream(iter); - if (!reader) + if (!iter) return; - return await proc[1](reader.getReader()); + let cumul = import_buffer4.Buffer.alloc(0); + let found; + let chunk = { done: true }; + do { + const { value, done } = await iter.next(found === false); + if (done) { + chunk = { done: true }; + } else { + chunk = { done: false, value }; + } + if (!done) + cumul = import_buffer4.Buffer.concat([cumul, value]); + found = await proc[1](cumul); + } while (found !== false && !chunk.done); + await iter.next(false); + if (found === false) { + return; + } + return await proc[2](cumul); }; var textToElement = (s) => document.createRange().createContextualFragment(s).children[0]; var processPost = async (post) => { @@ -13448,9 +13582,9 @@ var startup = async () => { await Promise.all([...document.querySelectorAll(".postContainer")].filter((e) => e.textContent?.includes("191 KB")).map((e) => processPost(e))); document.addEventListener("ThreadUpdate", async (e) => { - let newPosts = e.detail.newPosts; + const newPosts = e.detail.newPosts; for (const post of newPosts) { - let postContainer = document.getElementById("pc" + post.substring(post.indexOf(".") + 1)); + const postContainer = document.getElementById("pc" + post.substring(post.indexOf(".") + 1)); processPost(postContainer); } }); @@ -13473,10 +13607,13 @@ const posts = [...document.querySelectorAll(".postContainer")]; const scts = document.getElementById("shortcuts"); const button = textToElement(``); - const app = new App_default({ + const settingsButton = new SettingsButton_default({ target: button }); scts?.appendChild(button); + const appHost = textToElement(`
`); + const appInstance = new App_default({ target: appHost }); + document.body.append(appHost); await Promise.all(posts.map((e) => processPost(e))); }; var getSelectedFile = () => { @@ -13508,7 +13645,7 @@ const proc = processors.find((e3) => file.name.match(e3[0])); if (!proc) throw new Error("Container filetype not supported"); - const buff = await proc[2](file, input.files[0]); + const buff = await proc[3](file, input.files[0]); document.dispatchEvent(new CustomEvent("QRSetFile", { detail: { file: new Blob([buff], { type }), name: file.name } })); diff --git a/src/App.svelte b/src/App.svelte index 0527746..52f9df8 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -1,10 +1,20 @@ opensettings()}> diff --git a/src/SettingsButton.svelte b/src/SettingsButton.svelte new file mode 100644 index 0000000..132aa95 --- /dev/null +++ b/src/SettingsButton.svelte @@ -0,0 +1,25 @@ + + + opensettings()}> + [PEE Settings] + + + diff --git a/src/gif.ts b/src/gif.ts index 48f3e16..12fb0a3 100644 --- a/src/gif.ts +++ b/src/gif.ts @@ -1,12 +1,12 @@ import { Buffer } from "buffer"; -import { BufferWriteStream, concatAB } from "./png"; +import { BufferWriteStream } from "./png"; -const netscape = Buffer.from("!\xFF\x0BNETSCAPE2.0\x03\x01\x00\x00\x00"); +const netscape = Buffer.from("!\xFF\x0BNETSCAPE2.0", 'ascii'); const magic = Buffer.from("!\xFF\x0B" + "COOMTECH0.1", 'ascii'); const extractBuff = (gif: Buffer) => { - let field = gif.readUInt8(10); - let gcte = !!(field & (1 << 7)); + const field = gif.readUInt8(10); + const gcte = !!(field & (1 << 7)); let end = 13; if (gcte) { end += 3 * (1 << ((field & 7) + 1)); @@ -15,8 +15,9 @@ const extractBuff = (gif: Buffer) => { while (gif.readUInt8(end) == '!'.charCodeAt(0)) { if (magic.compare(gif, end, end + magic.byteLength) != 0) { end += 3 + gif.readUInt8(end + 2); - while (1) { // skip sub blocks - let v = gif.readUInt8(end++); + // eslint-disable-next-line no-constant-condition + while (true) { // skip sub blocks + const v = gif.readUInt8(end++); if (!v) break; end += v; @@ -29,34 +30,21 @@ const extractBuff = (gif: Buffer) => { t += v; count += v + 1; } - let buff = Buffer.alloc(t); + const buff = Buffer.alloc(t); count = end + magic.byteLength; t = 0; while ((v = gif.readUInt8(count)) != 0) { - gif.copy(buff, t, count + 1, count + 1 + v) + gif.copy(buff, t, count + 1, count + 1 + v); t += v; count += v + 1; } - return buff; + return {filename: 'embedded', data: buff}; } } // metadata ended, nothing... }; -export const extract = async (reader: ReadableStreamDefaultReader