From bc41574655d9e55dcbb4539e7206818e622e7fa3 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Tue, 11 Jan 2022 13:10:21 +0100 Subject: [PATCH] - Split the EMBED enum and rely more on EmbeddedFile Instead. - Added colors indicator to EyeButton and border of media --- extheader.js | 2 +- main.meta.js | 4 +- main.user.js | 131 ++++++++++++++++++++++++++----------------- src/Embedding.svelte | 16 +++++- src/EyeButton.svelte | 17 +++++- src/gif.ts | 10 ++-- src/global.css | 19 ++++--- src/main.ts | 54 ++++++++++-------- src/png.ts | 12 ++-- src/thirdeye.ts | 12 ++-- src/webm.ts | 10 ++-- 11 files changed, 177 insertions(+), 110 deletions(-) diff --git a/extheader.js b/extheader.js index 6668068..ee2bc47 100644 --- a/extheader.js +++ b/extheader.js @@ -4,7 +4,7 @@ let res = spawnSync("git", ["rev-list", "--count", "HEAD"]); let rev = +res.stdout; export const extheader = `// ==UserScript== -// @name PNGExtraEmbed +// @name PNGExtraEmbed2 // @namespace https://coom.tech/ // @version 0.${rev} // @description uhh diff --git a/main.meta.js b/main.meta.js index a747f95..8514ad6 100644 --- a/main.meta.js +++ b/main.meta.js @@ -1,7 +1,7 @@ // ==UserScript== -// @name PNGExtraEmbed +// @name PNGExtraEmbed2 // @namespace https://coom.tech/ -// @version 0.113 +// @version 0.114 // @description uhh // @author You // @match https://boards.4channel.org/* diff --git a/main.user.js b/main.user.js index 03f970e..05376af 100644 --- a/main.user.js +++ b/main.user.js @@ -1,7 +1,7 @@ // ==UserScript== -// @name PNGExtraEmbed +// @name PNGExtraEmbed2 // @namespace https://coom.tech/ -// @version 0.113 +// @version 0.114 // @description uhh // @author You // @match https://boards.4channel.org/* @@ -11061,7 +11061,7 @@ }); // src/global.css - var global_default = ".pee-hidden {\r\n display: none;\r\n}\r\n\r\n.extractedImg {\r\n width: auto;\r\n height: auto;\r\n max-width: 125px;\r\n max-height: 125px;\r\n cursor: pointer;\r\n}\r\n\r\n#delform .postContainer>div.hasblack {\r\n border-right: 3px dashed black !important;\r\n}\r\n.hasblack.catalog-post {\r\n border: 3px dashed black !important;\r\n}\r\n\r\n#delform .postContainer>div.hasembed {\r\n border-right: 3px dashed deeppink !important;\r\n}\r\n\r\n.hasembed.catalog-post {\r\n border: 3px dashed deeppink !important;\r\n}\r\n\r\n#delform .postContainer>div.hasext {\r\n border-right: 3px dashed goldenrod !important;\r\n}\r\n\r\n.hasext.catalog-post {\r\n border: 3px dashed goldenrod !important;\r\n}\r\n\r\n#delform .postContainer>div.hasmultiple {\r\n border-right: 3px dashed cornflowerblue !important;\r\n}\r\ndiv.hasmultiple.catalog-post {\r\n border-right: 3px dashed cornflowerblue !important;\r\n}\r\n\r\n.expanded-image>.post>.file .fileThumb>img[data-md5] {\r\n display: none;\r\n}\r\n\r\n.expanded-image>.post>.file .fileThumb .full-image {\r\n display: inline;\r\n}\r\n\r\n.pee-settings {\r\n position: fixed;\r\n top: 0;\r\n width: 100%;\r\n height: 100%;\r\n pointer-events: none;\r\n}\r\n\r\n#delform div.hasemb .catalog-host .place video,\r\n#delform div.hasemb .catalog-host .place img {\r\n border: 1px solid deeppink;\r\n}\r\n\r\n#delform div.hasext .catalog-host .place video,\r\n#delform div.hasext .catalog-host .place img {\r\n border: 1px solid goldenrod;\r\n}\r\n\r\n#delform .div.hasmultiple .catalog-host video,\r\n#delform .div.hasmultiple .catalog-host img {\r\n border: 1px solid cornflowerblue;\r\n}\r\n\r\n#delform .catalog-host .place video,\r\n#delform .catalog-host .place img {\r\n position: absolute;\r\n top: -5px;\r\n right: 0px;\r\n max-width: 80px;\r\n max-height: 80px;\r\n box-shadow: 0px 0px 4px 2px #00000090;\r\n}\r\n\r\n.fileThumb.filehost {\r\n margin-left: 0 !important;\r\n display: flex;\r\n gap: 20px;\r\n}\r\n"; + var global_default = ".pee-hidden {\r\n display: none;\r\n}\r\n\r\n.extractedImg {\r\n width: auto;\r\n height: auto;\r\n max-width: 125px;\r\n max-height: 125px;\r\n cursor: pointer;\r\n}\r\n\r\n\r\n#delform .postContainer>div.hasembed {\r\n border-right: 3px dashed deeppink !important;\r\n}\r\n\r\n.hasembed.catalog-post {\r\n border: 3px dashed deeppink !important;\r\n}\r\n\r\n#delform .postContainer>div.hasext {\r\n border-right: 3px dashed goldenrod !important;\r\n}\r\n\r\n.hasext.catalog-post {\r\n border: 3px dashed goldenrod !important;\r\n}\r\n\r\n/* .hasblack overrides the .hasembed (and .hasext) */\r\n#delform .postContainer>div.hasblack {\r\n border-right: 3px dashed black !important;\r\n}\r\n.hasblack.catalog-post {\r\n border: 3px dashed black !important;\r\n}\r\n\r\n\r\n#delform .postContainer>div.hasmultiple {\r\n border-right: 3px dashed cornflowerblue !important;\r\n}\r\ndiv.hasmultiple.catalog-post {\r\n border-right: 3px dashed cornflowerblue !important;\r\n}\r\n\r\n.expanded-image>.post>.file .fileThumb>img[data-md5] {\r\n display: none;\r\n}\r\n\r\n.expanded-image>.post>.file .fileThumb .full-image {\r\n display: inline;\r\n}\r\n\r\n.pee-settings {\r\n position: fixed;\r\n top: 0;\r\n width: 100%;\r\n height: 100%;\r\n pointer-events: none;\r\n}\r\n\r\n#delform div.hasembed .catalog-host .place video,\r\n#delform div.hasembed .catalog-host .place img {\r\n border: 1px solid deeppink;\r\n}\r\n\r\n#delform div.hasext .catalog-host .place video,\r\n#delform div.hasext .catalog-host .place img {\r\n border: 1px solid goldenrod;\r\n}\r\n\r\n#delform .div.hasmultiple .catalog-host video,\r\n#delform .div.hasmultiple .catalog-host img {\r\n border: 1px solid cornflowerblue;\r\n}\r\n\r\n#delform .catalog-host .place video,\r\n#delform .catalog-host .place img {\r\n position: absolute;\r\n top: -5px;\r\n right: 0px;\r\n max-width: 80px;\r\n max-height: 80px;\r\n box-shadow: 0px 0px 4px 2px #00000090;\r\n}\r\n\r\n.fileThumb.filehost {\r\n margin-left: 0 !important;\r\n display: flex;\r\n gap: 20px;\r\n}\r\n"; // src/png.ts init_esbuild_inject(); @@ -11217,22 +11217,22 @@ case "tEXt": buff = chunk; if (buff.slice(4, 4 + CUM0.length).equals(CUM0)) { - return 0 /* HAS_PEE */; + return 0 /* SUCCESS */; } break; case "IDAT": case "IEND": - return 4 /* NONE */; + return 3 /* NONE */; default: break; } } } catch (e) { - return 3 /* PEE_UNDEFINED */; + return 2 /* PEE_UNDEFINED */; } finally { reader.releaseLock(); } - return 3 /* PEE_UNDEFINED */; + return 2 /* PEE_UNDEFINED */; }; var png_default = { extract, @@ -11264,10 +11264,10 @@ const embed = chunks.findIndex((e) => e.name == "TagName" && e.type == "8" && e.value == "COOM"); const cl = chunks.find((e) => e.name == "Cluster"); if (cl && embed == -1) - return 4 /* NONE */; + return 3 /* NONE */; if (embed == -1) - return 3 /* PEE_UNDEFINED */; - return 0 /* HAS_PEE */; + return 2 /* PEE_UNDEFINED */; + return 0 /* SUCCESS */; }; var webm_default = { extract: extract2, @@ -11387,12 +11387,12 @@ end += v; } } else { - return 0 /* HAS_PEE */; + return 0 /* SUCCESS */; } } if (end >= gif.byteLength) - return 3 /* PEE_UNDEFINED */; - return 4 /* NONE */; + return 2 /* PEE_UNDEFINED */; + return 3 /* NONE */; }; var gif_default = { extract: extract3, @@ -11554,7 +11554,7 @@ }; var has_embed4 = async (b, fn) => { if (Buffer2.from(fn, "hex").equals(b)) - return 4 /* NONE */; + return 3 /* NONE */; let result = void 0; for (const e of Object.values(boorus)) { if (e.disabled) @@ -11567,10 +11567,10 @@ if (result && result.length !== 0) { const filtered = result.filter((e) => !e.tags.some((e2) => black.has(e2))); if (filtered.length > 0) - return 1 /* HAS_TE */; - return 2 /* TE_BLACKLISTED */; + return 0 /* SUCCESS */; + return 1 /* TE_BLACKLISTED */; } - return 4 /* NONE */; + return 3 /* NONE */; }; var thirdeye_default = { skip: true, @@ -14955,7 +14955,7 @@ // src/Embedding.svelte init_esbuild_inject(); function add_css6(target) { - append_styles(target, "svelte-yvh28x", ".place.svelte-yvh28x.svelte-yvh28x{cursor:pointer;max-width:100vw;max-height:100vh}.unzipping.svelte-yvh28x>img.svelte-yvh28x{filter:brightness(0.5) blur(10px)}.progress.svelte-yvh28x.svelte-yvh28x{color:black;-webkit-text-stroke:0.7px white;font-weight:bold;left:50%;top:50%;font-size:larger;display:inline-block;position:absolute;z-index:10}.hoverer.svelte-yvh28x.svelte-yvh28x{display:none;position:fixed;pointer-events:none}.visible.svelte-yvh28x.svelte-yvh28x{display:block;z-index:9}.contract.svelte-yvh28x img.svelte-yvh28x,.contract.svelte-yvh28x video.svelte-yvh28x{max-width:125px !important;max-height:125px !important;width:auto;height:auto}.place.svelte-yvh28x:not(.contract) video.svelte-yvh28x,.place.svelte-yvh28x:not(.contract) img.svelte-yvh28x,.hoverer.svelte-yvh28x>video.svelte-yvh28x,.hoverer.svelte-yvh28x>img.svelte-yvh28x{max-width:100vw;max-height:100vh}"); + append_styles(target, "svelte-16retph", ".place.svelte-16retph.svelte-16retph{cursor:pointer;max-width:100vw;max-height:100vh}.unzipping.svelte-16retph>img.svelte-16retph{filter:brightness(0.5) blur(10px)}.progress.svelte-16retph.svelte-16retph{color:black;-webkit-text-stroke:0.7px white;font-weight:bold;left:50%;top:50%;font-size:larger;display:inline-block;position:absolute;z-index:10}.hoverer.svelte-16retph.svelte-16retph{display:none;position:fixed;pointer-events:none}.visible.svelte-16retph.svelte-16retph{display:block;z-index:9}.contract.svelte-16retph img.svelte-16retph,.contract.svelte-16retph video.svelte-16retph{max-width:125px !important;max-height:125px !important;width:auto;height:auto}.place.svelte-16retph:not(.contract) video.svelte-16retph,.place.svelte-16retph:not(.contract) img.svelte-16retph,.hoverer.svelte-16retph>video.svelte-16retph,.hoverer.svelte-16retph>img.svelte-16retph{max-width:100vw;max-height:100vh}.place.hasembed.svelte-16retph video.svelte-16retph,.place.hasembed.svelte-16retph img.svelte-16retph{border:solid 1px deeppink\r\n }.place.hasext.svelte-16retph video.svelte-16retph,.place.hasext.svelte-16retph img.svelte-16retph{border:solid 1px goldenrod\r\n }"); } function create_if_block5(ctx) { let div0; @@ -14994,9 +14994,11 @@ t4 = space(); if (if_block5) if_block5.c(); - attr(div0, "class", "place svelte-yvh28x"); + attr(div0, "class", "place svelte-16retph"); toggle_class(div0, "contract", ctx[6]); - attr(div1, "class", "hoverer svelte-yvh28x"); + toggle_class(div0, "hasembed", ctx[0]?.embed_type === 0 /* THIRD_EYE */); + toggle_class(div0, "hasext", ctx[0]?.embed_type === 1 /* MEDIA_EMBED */); + attr(div1, "class", "hoverer svelte-16retph"); attr(div1, "id", "ihover"); toggle_class(div1, "visible", ctx[7] && ctx[6]); toggle_class(div1, "unzipping", ctx[16]); @@ -15076,6 +15078,12 @@ if (dirty[0] & 64) { toggle_class(div0, "contract", ctx2[6]); } + if (dirty[0] & 1) { + toggle_class(div0, "hasembed", ctx2[0]?.embed_type === 0 /* THIRD_EYE */); + } + if (dirty[0] & 1) { + toggle_class(div0, "hasext", ctx2[0]?.embed_type === 1 /* MEDIA_EMBED */); + } if (ctx2[16]) { if (if_block3) { if_block3.p(ctx2, dirty); @@ -15155,7 +15163,7 @@ attr(img, "alt", img_alt_value = ctx[0].filename); if (!src_url_equal(img.src, img_src_value = ctx[14] || ctx[5])) attr(img, "src", img_src_value); - attr(img, "class", "svelte-yvh28x"); + attr(img, "class", "svelte-16retph"); }, m(target, anchor) { insert(target, img, anchor); @@ -15233,7 +15241,7 @@ video.loop = video_loop_value = ctx[18].loop; if (!src_url_equal(video.src, video_src_value = ctx[14] || ctx[5])) attr(video, "src", video_src_value); - attr(video, "class", "svelte-yvh28x"); + attr(video, "class", "svelte-16retph"); }, m(target, anchor) { insert(target, video, anchor); @@ -15271,7 +15279,7 @@ t2 = text(" / "); t3 = text(t3_value); t4 = text("]"); - attr(span, "class", "progress svelte-yvh28x"); + attr(span, "class", "progress svelte-16retph"); }, m(target, anchor) { insert(target, span, anchor); @@ -15303,7 +15311,7 @@ attr(img, "alt", img_alt_value = ctx[0].filename); if (!src_url_equal(img.src, img_src_value = ctx[14] || ctx[5])) attr(img, "src", img_src_value); - attr(img, "class", "svelte-yvh28x"); + attr(img, "class", "svelte-16retph"); }, m(target, anchor) { insert(target, img, anchor); @@ -15332,7 +15340,7 @@ video.loop = video_loop_value = ctx[18].loop; if (!src_url_equal(video.src, video_src_value = ctx[14] || ctx[5])) attr(video, "src", video_src_value); - attr(video, "class", "svelte-yvh28x"); + attr(video, "class", "svelte-16retph"); }, m(target, anchor) { insert(target, video, anchor); @@ -15920,7 +15928,7 @@ // src/EyeButton.svelte init_esbuild_inject(); function add_css7(target) { - append_styles(target, "svelte-64lw6s", ".clickable.svelte-64lw6s{cursor:pointer;margin-left:5px}.clickable.svelte-64lw6s:hover{text-shadow:0 0 4px palevioletred}"); + append_styles(target, "svelte-96kv3k", ".clickable.svelte-96kv3k{cursor:pointer;margin-left:5px}.clickable.svelte-96kv3k:hover{text-shadow:0 0 4px palevioletred}.clickable.hasembed.svelte-96kv3k{color:deeppink}.clickable.hasext.svelte-96kv3k{color:goldenrod}.clickable.hasblack.svelte-96kv3k{color:black}"); } function get_each_context4(ctx, list, i) { const child_ctx = ctx.slice(); @@ -15934,7 +15942,7 @@ return { c() { span = element("span"); - attr(span, "class", "fa clickable svelte-64lw6s"); + attr(span, "class", "fa clickable svelte-96kv3k"); toggle_class(span, "fa-eye", !ctx[3]); toggle_class(span, "fa-eye-slash", ctx[3]); }, @@ -15971,7 +15979,7 @@ t = text("Source"); attr(a, "href", a_href_value = ctx[11].source); attr(a, "target", "_blank"); - attr(a, "class", "clickable svelte-64lw6s"); + attr(a, "class", "clickable svelte-96kv3k"); }, m(target, anchor) { insert(target, a, anchor); @@ -15999,7 +16007,7 @@ t = text(t_value); attr(a, "href", a_href_value = ctx[11].page.url); attr(a, "target", "_blank"); - attr(a, "class", "clickable svelte-64lw6s"); + attr(a, "class", "clickable svelte-96kv3k"); }, m(target, anchor) { insert(target, a, anchor); @@ -16027,7 +16035,7 @@ a = element("a"); a.textContent = "[PEE contract]"; attr(a, "alt", "By clicking this you agree to stay hydrated"); - attr(a, "class", "clickable svelte-64lw6s"); + attr(a, "class", "clickable svelte-96kv3k"); }, m(target, anchor) { insert(target, a, anchor); @@ -16074,7 +16082,10 @@ if_block2.c(); if_block2_anchor = empty(); attr(span, "title", span_title_value = ctx[11].filename); - attr(span, "class", "fa fa-download clickable svelte-64lw6s"); + attr(span, "class", "fa fa-download clickable svelte-96kv3k"); + toggle_class(span, "hasembed", ctx[11]?.embed_type === 0 /* THIRD_EYE */); + toggle_class(span, "hasext", ctx[11]?.embed_type === 1 /* MEDIA_EMBED */); + toggle_class(span, "hasblack", ctx[11]?.isBlacklisted === true); }, m(target, anchor) { insert(target, span, anchor); @@ -16098,6 +16109,15 @@ if (dirty & 1 && span_title_value !== (span_title_value = ctx[11].filename)) { attr(span, "title", span_title_value); } + if (dirty & 1) { + toggle_class(span, "hasembed", ctx[11]?.embed_type === 0 /* THIRD_EYE */); + } + if (dirty & 1) { + toggle_class(span, "hasext", ctx[11]?.embed_type === 1 /* MEDIA_EMBED */); + } + if (dirty & 1) { + toggle_class(span, "hasblack", ctx[11]?.isBlacklisted === true); + } if (ctx[11].source) { if (if_block0) { if_block0.p(ctx, dirty); @@ -16314,14 +16334,18 @@ var EyeButton_default = EyeButton; // src/main.ts - var EMBED_ENUM = /* @__PURE__ */ ((EMBED_ENUM2) => { - EMBED_ENUM2[EMBED_ENUM2["HAS_PEE"] = 0] = "HAS_PEE"; - EMBED_ENUM2[EMBED_ENUM2["HAS_TE"] = 1] = "HAS_TE"; - EMBED_ENUM2[EMBED_ENUM2["TE_BLACKLISTED"] = 2] = "TE_BLACKLISTED"; - EMBED_ENUM2[EMBED_ENUM2["PEE_UNDEFINED"] = 3] = "PEE_UNDEFINED"; - EMBED_ENUM2[EMBED_ENUM2["NONE"] = 4] = "NONE"; - return EMBED_ENUM2; - })(EMBED_ENUM || {}); + var EMBED_TYPES = /* @__PURE__ */ ((EMBED_TYPES2) => { + EMBED_TYPES2[EMBED_TYPES2["THIRD_EYE"] = 0] = "THIRD_EYE"; + EMBED_TYPES2[EMBED_TYPES2["MEDIA_EMBED"] = 1] = "MEDIA_EMBED"; + return EMBED_TYPES2; + })(EMBED_TYPES || {}); + var EMBED_STATUS = /* @__PURE__ */ ((EMBED_STATUS2) => { + EMBED_STATUS2[EMBED_STATUS2["SUCCESS"] = 0] = "SUCCESS"; + EMBED_STATUS2[EMBED_STATUS2["TE_BLACKLISTED"] = 1] = "TE_BLACKLISTED"; + EMBED_STATUS2[EMBED_STATUS2["PEE_UNDEFINED"] = 2] = "PEE_UNDEFINED"; + EMBED_STATUS2[EMBED_STATUS2["NONE"] = 3] = "NONE"; + return EMBED_STATUS2; + })(EMBED_STATUS || {}); var csettings; var processors = [thirdeye_default, png_default, webm_default, gif_default]; var cappState; @@ -16365,9 +16389,14 @@ return Promise.all(processors.filter((e) => e.match(fn)).map(async (proc) => { if (proc.skip) { const md5 = import_buffer4.Buffer.from(hex, "base64"); - const embed_enum2 = await proc.has_embed(md5, fn); - if (embed_enum2 === 1 /* HAS_TE */ || embed_enum2 === 2 /* TE_BLACKLISTED */) - return [await proc.extract(md5, fn), embed_enum2]; + const embed_status = await proc.has_embed(md5, fn); + if (embed_status === 0 /* SUCCESS */ || embed_status === 1 /* TE_BLACKLISTED */) { + const file2 = await proc.extract(md5, fn); + file2.embed_type = 0 /* THIRD_EYE */; + if (embed_status === 1 /* TE_BLACKLISTED */) + file2.isBlacklisted = true; + return [file2, 0 /* THIRD_EYE */]; + } return; } const iter = streamRemote(src); @@ -16376,7 +16405,6 @@ let cumul = import_buffer4.Buffer.alloc(0); let found; let chunk = { done: true }; - let embed_enum; do { const { value, done } = await iter.next(found === false); if (done) { @@ -16386,14 +16414,16 @@ } if (!done) cumul = import_buffer4.Buffer.concat([cumul, value]); - embed_enum = await proc.has_embed(cumul); - found = embed_enum === 0 /* HAS_PEE */; + const embed_status = await proc.has_embed(cumul); + found = embed_status === 0 /* SUCCESS */; } while (found !== false && !chunk.done); await iter.next(true); if (found === false) { return; } - return [await proc.extract(cumul), embed_enum]; + const file = await proc.extract(cumul); + file.embed_type = 1 /* MEDIA_EMBED */; + return [file, 1 /* MEDIA_EMBED */]; })); }; var textToElement = (s) => document.createRange().createContextualFragment(s).children[0]; @@ -16409,8 +16439,7 @@ processAttachments(post, res2?.filter((e) => { if (!e) return; - if (e[1] === 2 /* TE_BLACKLISTED */) { - e[0].isBlacklisted = true; + if (e[0]?.isBlacklisted === true) { post.querySelector(".reply")?.classList.add("hasblack"); } return e; @@ -16544,10 +16573,10 @@ document.documentElement.insertBefore(customStyles, null); function processAttachments(post, ress) { const replyBox = post.querySelector(".post"); - const embed_enum = ress[0][1]; - if (embed_enum === 1 /* HAS_TE */) + const embed_status = ress[0][1]; + if (embed_status === 0 /* THIRD_EYE */) replyBox?.classList.add("hasext"); - else if (embed_enum === 0 /* HAS_PEE */) + else if (embed_status === 1 /* MEDIA_EMBED */) replyBox?.classList.add("hasembed"); if (ress.length > 1) replyBox?.classList.add("hasmultiple"); diff --git a/src/Embedding.svelte b/src/Embedding.svelte index 632e896..c4c8862 100644 --- a/src/Embedding.svelte +++ b/src/Embedding.svelte @@ -2,7 +2,7 @@ import { fileTypeFromBuffer } from 'file-type' import { settings, appState } from './stores' import { beforeUpdate, tick } from 'svelte' - import type { EmbeddedFile } from './main.js'; + import { EmbeddedFile, EMBED_TYPES } from './main.js'; import { createEventDispatcher } from 'svelte'; export const dispatch = createEventDispatcher(); @@ -249,9 +249,12 @@ {#if !file.isBlacklisted && (!$settings.eye || visible)} -
+
e.preventDefault()} on:auxclick={e => e.preventDefault()} on:mousedown={bepis} @@ -352,4 +355,13 @@ max-width: 100vw; max-height: 100vh; } + + .place.hasembed video, + .place.hasembed img { + border: solid 1px deeppink + } + .place.hasext video, + .place.hasext img { + border: solid 1px goldenrod + } diff --git a/src/EyeButton.svelte b/src/EyeButton.svelte index e73c95d..56a6a3c 100644 --- a/src/EyeButton.svelte +++ b/src/EyeButton.svelte @@ -3,7 +3,7 @@ import { fileTypeFromBuffer } from 'file-type'; import type Embedding from './Embedding.svelte'; import type Embeddings from './Embeddings.svelte'; -import type { EmbeddedFile } from './main'; +import { EmbeddedFile, EMBED_TYPES } from './main'; import { settings } from './stores' @@ -51,7 +51,11 @@ import type { EmbeddedFile } from './main'; title={file.filename} on:click={() => downloadFile(file)} class="fa fa-download clickable" -/> + class:hasembed={file?.embed_type === EMBED_TYPES.THIRD_EYE} + class:hasext={file?.embed_type === EMBED_TYPES.MEDIA_EMBED} + class:hasblack={file?.isBlacklisted === true} +/> + {#if file.source} diff --git a/src/gif.ts b/src/gif.ts index bea6888..9aadd54 100644 --- a/src/gif.ts +++ b/src/gif.ts @@ -1,5 +1,5 @@ import { Buffer } from "buffer"; -import { EmbeddedFile, EMBED_ENUM, ImageProcessor } from "./main"; +import { EmbeddedFile, EMBED_STATUS, ImageProcessor } from "./main"; import { BufferWriteStream } from "./png"; const netscape = Buffer.from("!\xFF\x0BNETSCAPE2.0", 'ascii'); @@ -106,7 +106,7 @@ const inject = async (container: File, inj: File) => { return extract(); }; -const has_embed = (gif: Buffer) : EMBED_ENUM => { +const has_embed = (gif: Buffer) : EMBED_STATUS => { const field = gif.readUInt8(10); const gcte = !!(field & (1 << 7)); let end = 13; @@ -125,12 +125,12 @@ const has_embed = (gif: Buffer) : EMBED_ENUM => { end += v; } } else { - return EMBED_ENUM.HAS_PEE; + return EMBED_STATUS.SUCCESS; } } if (end >= gif.byteLength) - return EMBED_ENUM.PEE_UNDEFINED; // Don't know yet, need more to decide. - return EMBED_ENUM.NONE; // no more extension blocks, so definite no + return EMBED_STATUS.PEE_UNDEFINED; // Don't know yet, need more to decide. + return EMBED_STATUS.NONE; // no more extension blocks, so definite no }; export default { diff --git a/src/global.css b/src/global.css index d7fa896..83e35dc 100644 --- a/src/global.css +++ b/src/global.css @@ -10,12 +10,6 @@ cursor: pointer; } -#delform .postContainer>div.hasblack { - border-right: 3px dashed black !important; -} -.hasblack.catalog-post { - border: 3px dashed black !important; -} #delform .postContainer>div.hasembed { border-right: 3px dashed deeppink !important; @@ -33,6 +27,15 @@ border: 3px dashed goldenrod !important; } +/* .hasblack overrides the .hasembed (and .hasext) */ +#delform .postContainer>div.hasblack { + border-right: 3px dashed black !important; +} +.hasblack.catalog-post { + border: 3px dashed black !important; +} + + #delform .postContainer>div.hasmultiple { border-right: 3px dashed cornflowerblue !important; } @@ -56,8 +59,8 @@ div.hasmultiple.catalog-post { pointer-events: none; } -#delform div.hasemb .catalog-host .place video, -#delform div.hasemb .catalog-host .place img { +#delform div.hasembed .catalog-host .place video, +#delform div.hasembed .catalog-host .place img { border: 1px solid deeppink; } diff --git a/src/main.ts b/src/main.ts index 328de0a..8a570f6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -16,9 +16,12 @@ import SettingsButton from './SettingsButton.svelte'; import Embeddings from './Embeddings.svelte'; import EyeButton from './EyeButton.svelte'; -export enum EMBED_ENUM { - HAS_PEE, - HAS_TE, +export enum EMBED_TYPES { + THIRD_EYE, + MEDIA_EMBED, +} +export enum EMBED_STATUS { + SUCCESS, TE_BLACKLISTED, PEE_UNDEFINED, NONE, @@ -26,7 +29,7 @@ export enum EMBED_ENUM { export interface ImageProcessor { skip?: true; match(fn: string): boolean; - has_embed(b: Buffer, fn?: string): EMBED_ENUM | Promise; + has_embed(b: Buffer, fn?: string): EMBED_STATUS | Promise; extract(b: Buffer, fn?: string): EmbeddedFile | Promise; inject?(b: File, c: File): Buffer | Promise; } @@ -75,6 +78,7 @@ async function* streamRemote(url: string, chunkSize = 72 * 1024, fetchRestOnNonC } type EmbeddedFileWithPreview = { + embed_type: EMBED_TYPES; isBlacklisted?: boolean; // third-eye only page?: { title: string, url: string }; // can be a booru page source?: string; // can be like a twitter post this was posted in originally @@ -85,6 +89,7 @@ type EmbeddedFileWithPreview = { type EmbeddedFileWithoutPreview = { + embed_type: EMBED_TYPES; isBlacklisted: boolean; // third-eye only page: undefined; source: undefined; @@ -95,15 +100,20 @@ type EmbeddedFileWithoutPreview = { export type EmbeddedFile = EmbeddedFileWithPreview | EmbeddedFileWithoutPreview; -const processImage = async (src: string, fn: string, hex: string): Promise<([EmbeddedFile, Number] | undefined)[]> => { +const processImage = async (src: string, fn: string, hex: string): Promise<([EmbeddedFile, EMBED_TYPES] | undefined)[]> => { return Promise.all(processors.filter(e => e.match(fn)).map(async proc => { if (proc.skip) { /* third-eye */ // skip file downloading, file is referenced from the filename // basically does things like filtering out blacklisted tags const md5 = Buffer.from(hex, 'base64'); - const embed_enum = await proc.has_embed(md5, fn) - if (embed_enum === EMBED_ENUM.HAS_TE || embed_enum === EMBED_ENUM.TE_BLACKLISTED) - return [await proc.extract(md5, fn), embed_enum] as [EmbeddedFile, Number]; + const embed_status = await proc.has_embed(md5, fn) + if (embed_status === EMBED_STATUS.SUCCESS || embed_status === EMBED_STATUS.TE_BLACKLISTED){ + const file = await proc.extract(md5, fn); + file.embed_type = EMBED_TYPES.THIRD_EYE; + if(embed_status === EMBED_STATUS.TE_BLACKLISTED) + file.isBlacklisted = true + return [file, EMBED_TYPES.THIRD_EYE] as [EmbeddedFile, EMBED_TYPES]; + } return; } const iter = streamRemote(src); /* media-embed */ @@ -112,7 +122,6 @@ const processImage = async (src: string, fn: string, hex: string): Promise<([Emb let cumul = Buffer.alloc(0); let found: boolean | undefined; let chunk: ReadableStreamDefaultReadResult = { done: true }; - let embed_enum: EMBED_ENUM; do { const { value, done } = await iter.next(found === false); if (done) { @@ -122,16 +131,18 @@ const processImage = async (src: string, fn: string, hex: string): Promise<([Emb } if (!done) cumul = Buffer.concat([cumul, value!]); - embed_enum = await proc.has_embed(cumul); - found = (embed_enum === EMBED_ENUM.HAS_PEE); + const embed_status = await proc.has_embed(cumul); + found = (embed_status === EMBED_STATUS.SUCCESS); } while (found !== false && !chunk.done); await iter.next(true); if (found === false) { //console.log(`Gave up on ${src} after downloading ${cumul.byteLength} bytes...`); return; } - return [await proc.extract(cumul), embed_enum] as [EmbeddedFile, EMBED_ENUM]; - // return [await proc.extract(cumul), EMBED_ENUM.HAS_PEE] as [EmbeddedFile, EMBED_ENUM]; + const file = await proc.extract(cumul); + file.embed_type = EMBED_TYPES.MEDIA_EMBED; + return [file, EMBED_TYPES.MEDIA_EMBED] as [EmbeddedFile, EMBED_TYPES]; + // return [await proc.extract(cumul), EMBED_TYPES.HAS_PEE] as [EmbeddedFile, EMBED_TYPES]; })); }; @@ -153,12 +164,11 @@ const processPost = async (post: HTMLDivElement) => { processAttachments(post, res2?.filter(e => { if(!e) return; - if(e[1] === EMBED_ENUM.TE_BLACKLISTED){ - e[0].isBlacklisted = true; + if(e[0]?.isBlacklisted === true){ post.querySelector('.reply')?.classList.add('hasblack'); } return e; - }) as [EmbeddedFile, EMBED_ENUM][]); + }) as [EmbeddedFile, EMBED_TYPES][]); }; const startup = async () => { @@ -323,12 +333,12 @@ customStyles.appendChild(document.createTextNode(globalCss)); document.documentElement.insertBefore(customStyles, null); -function processAttachments(post: HTMLDivElement, ress: [EmbeddedFile, EMBED_ENUM][]) { +function processAttachments(post: HTMLDivElement, ress: [EmbeddedFile, EMBED_TYPES][]) { const replyBox = post.querySelector('.post'); - const embed_enum : EMBED_ENUM = ress[0][1]; - if (embed_enum === EMBED_ENUM.HAS_TE) + const embed_status = ress[0][1]; + if (embed_status === EMBED_TYPES.THIRD_EYE) replyBox?.classList.add('hasext'); - else if (embed_enum === EMBED_ENUM.HAS_PEE) + else if (embed_status === EMBED_TYPES.MEDIA_EMBED) replyBox?.classList.add('hasembed'); if (ress.length > 1) replyBox?.classList.add('hasmultiple'); @@ -366,7 +376,7 @@ function processAttachments(post: HTMLDivElement, ress: [EmbeddedFile, EMBED_ENU target: imgcont, props: { files: ress.map(e => e[0]), - // embed_enum: ress.map(e => e[1]), + // EMBED_TYPES: ress.map(e => e[1]), id: '' + id } }); @@ -390,7 +400,7 @@ function processAttachments(post: HTMLDivElement, ress: [EmbeddedFile, EMBED_ENU target: imgcont, props: { files: ress.map(e => e[0]), - // embed_enum: ress.map(e => e[1]), + // EMBED_TYPES: ress.map(e => e[1]), } }); if (!ahem) diff --git a/src/png.ts b/src/png.ts index 4cc3c45..4a39121 100644 --- a/src/png.ts +++ b/src/png.ts @@ -1,6 +1,6 @@ import { buf } from "crc-32"; import { Buffer } from "buffer"; -import { EMBED_ENUM, ImageProcessor } from "./main"; +import { EMBED_STATUS, ImageProcessor } from "./main"; type PNGChunk = [string, Buffer, number, number]; @@ -168,7 +168,7 @@ const inject = async (container: File, inj: File) => { return extract(); }; -const has_embed = async (png: Buffer) : Promise => { +const has_embed = async (png: Buffer) : Promise => { const reader = BufferReadStream(png).getReader(); const sneed = new PNGDecoder(reader); try { @@ -179,12 +179,12 @@ const has_embed = async (png: Buffer) : Promise => { case 'tEXt': buff = chunk; if (buff.slice(4, 4 + CUM0.length).equals(CUM0)) { - return EMBED_ENUM.HAS_PEE; + return EMBED_STATUS.SUCCESS; } break; case 'IDAT': // eslint-disable-next-line no-fallthrough case 'IEND': - return EMBED_ENUM.NONE; // Didn't find tExt Chunk; Definite no + return EMBED_STATUS.NONE; // Didn't find tExt Chunk; Definite no // eslint-disable-next-line no-fallthrough default: break; @@ -192,11 +192,11 @@ const has_embed = async (png: Buffer) : Promise => { } // stream ended on chunk boundary, so no unexpected EOF was fired, need more data anyway } catch (e) { - return EMBED_ENUM.PEE_UNDEFINED; // possibly unexpected EOF, need more data to decide + return EMBED_STATUS.PEE_UNDEFINED; // possibly unexpected EOF, need more data to decide } finally { reader.releaseLock(); } - return EMBED_ENUM.PEE_UNDEFINED + return EMBED_STATUS.PEE_UNDEFINED }; export default { diff --git a/src/thirdeye.ts b/src/thirdeye.ts index 1731dc1..57a247c 100644 --- a/src/thirdeye.ts +++ b/src/thirdeye.ts @@ -1,4 +1,4 @@ -import { EmbeddedFile, EMBED_ENUM, ImageProcessor } from "./main"; +import { EmbeddedFile, EMBED_STATUS, ImageProcessor } from "./main"; import { GM_fetch } from "./requests"; import { localLoad, settings } from "./stores"; @@ -113,13 +113,13 @@ const extract = async (b: Buffer, fn?: string) => { } as EmbeddedFile; }; -const has_embed = async (b: Buffer, fn?: string) : Promise => { +const has_embed = async (b: Buffer, fn?: string) : Promise => { // It's not worth to bother skipping images with filenames that match their md5 because // 4chan reencodes jpegs, which is well over half the files posted // ok fine you autists if (Buffer.from(fn!, 'hex').equals(b)) - return EMBED_ENUM.NONE; + return EMBED_STATUS.NONE; let result: BooruMatch[] | undefined = undefined; for (const e of Object.values(boorus)) { @@ -135,10 +135,10 @@ const has_embed = async (b: Buffer, fn?: string) : Promise => { if(result && result.length !== 0){ const filtered = result.filter(e => !e.tags.some(e => black.has(e))) if(filtered.length > 0) - return EMBED_ENUM.HAS_TE; - return EMBED_ENUM.TE_BLACKLISTED; + return EMBED_STATUS.SUCCESS; + return EMBED_STATUS.TE_BLACKLISTED; } - return EMBED_ENUM.NONE; + return EMBED_STATUS.NONE; }; export default { diff --git a/src/webm.ts b/src/webm.ts index 6fd6311..1798f94 100644 --- a/src/webm.ts +++ b/src/webm.ts @@ -1,6 +1,6 @@ import { Buffer } from "buffer"; import * as ebml from "ts-ebml"; -import { EMBED_ENUM, ImageProcessor } from "./main"; +import { EMBED_STATUS, ImageProcessor } from "./main"; // unused, but will in case 4chan does file sig checks //const password = Buffer.from("NOA"); @@ -126,17 +126,17 @@ const extract = (webm: Buffer) => { const inject = async (container: File, inj: File): Promise => embed(Buffer.from(await container.arrayBuffer()), Buffer.from(await inj.arrayBuffer())); -const has_embed = (webm: Buffer) : EMBED_ENUM => { +const has_embed = (webm: Buffer) : EMBED_STATUS => { const dec = new ebml.Decoder(); const chunks = dec.decode(webm); const embed = chunks.findIndex(e => e.name == "TagName" && e.type == '8' && e.value == "COOM"); const cl = chunks.find(e => e.name == "Cluster"); if (cl && embed == -1) - return EMBED_ENUM.NONE; // Tags appear before Cluster, so if we have a Cluster and no coomtag, then it's a definite no + return EMBED_STATUS.NONE; // Tags appear before Cluster, so if we have a Cluster and no coomtag, then it's a definite no if (embed == -1) // Found no coomtag, but no cluster, so it might be further - return EMBED_ENUM.PEE_UNDEFINED; - return EMBED_ENUM.HAS_PEE; + return EMBED_STATUS.PEE_UNDEFINED; + return EMBED_STATUS.SUCCESS; }; export default {