diff --git a/src/App.svelte b/src/App.svelte index 094c76c..44cea6b 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -85,6 +85,10 @@ Preload external files when they are in view. + + + Hotlink content. + Control audio on videos with mouse wheel. diff --git a/src/Embedding.svelte b/src/Embedding.svelte index 51eccd7..c012263 100644 --- a/src/Embedding.svelte +++ b/src/Embedding.svelte @@ -1,11 +1,12 @@ @@ -249,8 +267,8 @@ e.preventDefault()} - on:auxclick={e => e.preventDefault()} + on:click={(e) => e.preventDefault()} + on:auxclick={(e) => e.preventDefault()} on:mousedown={bepis} on:mouseover={hoverStart} on:mouseout={hoverStop} @@ -260,10 +278,16 @@ > {#if isImage} - + {/if} {#if isAudio} - + {/if} @@ -289,11 +318,16 @@ >{/if} {#if isImage} - + {/if} {#if isVideo} - + {/if} diff --git a/src/main.ts b/src/main.ts index 466368b..d7810cb 100644 --- a/src/main.ts +++ b/src/main.ts @@ -73,7 +73,7 @@ type EmbeddedFileWithPreview = { source?: string; // can be like a twitter post this was posted in originally thumbnail: Buffer; filename: string; - data: (lisn?: EventTarget) => Promise; + data: string | ((lisn?: EventTarget) => Promise); }; type EmbeddedFileWithoutPreview = { @@ -81,7 +81,7 @@ type EmbeddedFileWithoutPreview = { source: undefined; thumbnail: undefined; filename: string; - data: Buffer; + data: string | Buffer; }; export type EmbeddedFile = EmbeddedFileWithPreview | EmbeddedFileWithoutPreview; diff --git a/src/pngv3.ts b/src/pngv3.ts index 735e540..9cc0723 100644 --- a/src/pngv3.ts +++ b/src/pngv3.ts @@ -4,7 +4,6 @@ import type { ImageProcessor } from "./main"; import { PNGDecoder, PNGEncoder } from "./png"; import { decodeCoom3Payload } from "./utils"; -const CUM0 = Buffer.from("CUM\0" + "0"); const CUM3 = Buffer.from("CUM\0" + "3"); const BufferReadStream = (b: Buffer) => { @@ -19,7 +18,6 @@ const BufferReadStream = (b: Buffer) => { const extract = async (png: Buffer) => { let magic = false; - let coom3 = false; const reader = BufferReadStream(png).getReader(); const sneed = new PNGDecoder(reader); try { @@ -30,10 +28,7 @@ const extract = async (png: Buffer) => { // should exist at the beginning of file to signal decoders if the file indeed has an embedded chunk case 'tEXt': buff = chunk; - if (buff.slice(4, 4 + CUM0.length).equals(CUM0)) - magic = true; - if (buff.slice(4, 4 + CUM0.length).equals(CUM3)) { - coom3 = true; + if (buff.slice(4, 4 + CUM3.length).equals(CUM3)) { magic = true; } break; @@ -52,14 +47,8 @@ const extract = async (png: Buffer) => { } } if (lastIDAT) { - let data = (lastIDAT as Buffer).slice(4); - if (coom3) - return decodeCoom3Payload(data); - const fnsize = data.readUInt32LE(0); - const fn = data.slice(4, 4 + fnsize).toString(); - // Todo: xor the buffer to prevent scanning for file signatures (4chan embedded file detection)? - data = data.slice(4 + fnsize); - return [{ filename: fn, data }]; + const data = (lastIDAT as Buffer).slice(4); + return await decodeCoom3Payload(data); } } catch (e) { console.error(e); @@ -95,7 +84,7 @@ const inject = async (container: File, inj: File) => { if (magic && name != "IDAT") break; if (!magic && name == "IDAT") { - await encoder.insertchunk(["tEXt", buildChunk("tEXt", CUM0), 0, 0]); + await encoder.insertchunk(["tEXt", buildChunk("tEXt", CUM3), 0, 0]); magic = true; } await encoder.insertchunk([name, chunk, crc, offset]); @@ -119,9 +108,7 @@ const has_embed = async (png: Buffer) => { // should exist at the beginning of file to signal decoders if the file indeed has an embedded chunk case 'tEXt': buff = chunk; - if (buff.slice(4, 4 + CUM0.length).equals(CUM0)) - return true; - if (buff.slice(4, 4 + CUM0.length).equals(CUM3)) + if (buff.slice(4, 4 + CUM3.length).equals(CUM3)) return true; break; case 'IDAT': diff --git a/src/pomf.ts b/src/pomf.ts index 562b33c..e770721 100644 --- a/src/pomf.ts +++ b/src/pomf.ts @@ -2,6 +2,7 @@ import type { EmbeddedFile, ImageProcessor } from "./main"; import { GM_fetch, GM_head } from "./requests"; import type { Buffer } from "buffer"; import thumbnail from "./assets/hasembed.png"; +import { settings } from "./stores"; const sources = [ { host: 'Catbox', prefix: 'https://files.catbox.moe/' }, @@ -9,6 +10,11 @@ const sources = [ { host: 'Pomf', prefix: 'https://a.pomf.cat/' }, ]; +export let csettings: Parameters[0]; +settings.subscribe(b => { + csettings = b; +}); + const getExt = (fn: string) => { const isDum = fn!.match(/^([a-z0-9]{6}\.(?:jpe?g|png|webm|gif))/gi); const isB64 = fn!.match(/^((?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=))?\.(gif|jpe?g|png|webm)/); @@ -40,7 +46,7 @@ const extract = async (b: Buffer, fn?: string) => { return [{ filename: ext, - data: async (lsn) => { + data: csettings.hotlink ? rsource! : async (lsn) => { try { return (await GM_fetch(rsource, undefined, lsn)).arrayBuffer(); } catch (e) { diff --git a/src/stores.ts b/src/stores.ts index 23486db..8ef5d00 100644 --- a/src/stores.ts +++ b/src/stores.ts @@ -23,6 +23,7 @@ export const settings = writable(localLoad('settingsv2', { sh: false, ep: false, expte: false, + hotlink: false, conc: 8, ho: false, blacklist: ['guro', 'scat', 'ryona', 'gore'], diff --git a/src/thirdeye.ts b/src/thirdeye.ts index 1e76f28..37b1d76 100644 --- a/src/thirdeye.ts +++ b/src/thirdeye.ts @@ -3,6 +3,11 @@ import { GM_fetch } from "./requests"; import { localLoad, settings } from "./stores"; import { Buffer } from "buffer"; +export let csettings: Parameters[0]; +settings.subscribe(b => { + csettings = b; +}); + export type Booru = { disabled?: boolean; name: string; @@ -139,7 +144,7 @@ const extract = async (b: Buffer, fn?: string) => { if (e.disabled) continue; result = await findFileFrom(e, fn!.substring(0, 32)); - + if (result.length) { booru = e.name; break; @@ -153,7 +158,7 @@ const extract = async (b: Buffer, fn?: string) => { page: { title: booru, url: result[0].page }, filename: fn!.substring(0, 33) + result[0].ext, thumbnail: (await (await GM_fetch(prev || full)).arrayBuffer()), // prefer preview - data: async (lsn) => { + data: csettings.hotlink ? (full || prev) : async (lsn) => { if (!cachedFile) cachedFile = (await (await GM_fetch(full || prev, undefined, lsn)).arrayBuffer()); // prefer full return cachedFile;