Browse Source

Optimize JPG load times. Give option to disable loading on catalog

pull/46/head
coomdev 2 years ago
parent
commit
aa18531282
  1. 2
      README.md
  2. 6321
      chrome/dist/main.js
  3. 2
      chrome/manifest.json
  4. 6323
      dist/main.js
  5. 6445
      firefox/dist/main.js
  6. 2
      firefox/manifest.json
  7. 2
      firefox_update.json
  8. 2
      main.meta.js
  9. 6325
      main.user.js
  10. BIN
      pngextraembedder-0.273.xpi
  11. 9
      src/Components/App.svelte
  12. 72
      src/jpg.ts
  13. 44
      src/main.ts
  14. 1
      src/stores.ts

2
README.md

@ -25,7 +25,7 @@ Please report any issue you have with those (only for mainstream browsers)
Also, use this if you plan to use b4k's archive.
- [Install 4chanX (recommended)](https://www.4chan-x.net/builds/4chan-X.user.js)
- Install the correct WebExtension for your Browser ([Firefox](https://git.coom.tech/fuckjannies/lolipiss/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/pngextraembedder-0.271.xpi) or [Chrome-based](https://chrome.google.com/webstore/detail/pngextraembedder/bfhpobiikighljcapcfmfganodihbicj))
- Install the correct WebExtension for your Browser ([Firefox](https://git.coom.tech/fuckjannies/lolipiss/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/pngextraembedder-0.273.xpi) or [Chrome-based](https://chrome.google.com/webstore/detail/pngextraembedder/bfhpobiikighljcapcfmfganodihbicj))
For FF users, the extension is signed so you can just drag and drop it on your about:addons tab.

6321
chrome/dist/main.js

File diff suppressed because it is too large

2
chrome/manifest.json

@ -2,7 +2,7 @@
"manifest_version": 3,
"name": "PngExtraEmbedder",
"description": "Discover embedded files on 4chan and archives!",
"version": "0.270",
"version": "0.273",
"icons": {
"64": "1449696017588.png"
},

6323
dist/main.js

File diff suppressed because it is too large

6445
firefox/dist/main.js

File diff suppressed because it is too large

2
firefox/manifest.json

@ -7,7 +7,7 @@
},
"name": "PngExtraEmbedder",
"description": "Discover embedded files on 4chan and archives!",
"version": "0.271",
"version": "0.273",
"icons": {
"64": "1449696017588.png"
},

2
firefox_update.json

@ -1 +1 @@
{"addons":{"{34ac4994-07f2-44d2-8599-682516a6c6a6}":{"updates":[{"version":"0.271","update_link":"https://git.coom.tech/fuckjannies/lolipiss/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/pngextraembedder-0.271.xpi"}]}}}
{"addons":{"{34ac4994-07f2-44d2-8599-682516a6c6a6}":{"updates":[{"version":"0.273","update_link":"https://git.coom.tech/fuckjannies/lolipiss/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/pngextraembedder-0.273.xpi"}]}}}

2
main.meta.js

@ -1,7 +1,7 @@
// ==UserScript==
// @name PNGExtraEmbed
// @namespace https://coom.tech/
// @version 0.270
// @version 0.273
// @description uhh
// @author You
// @match https://boards.4channel.org/*

6325
main.user.js

File diff suppressed because it is too large

BIN
pngextraembedder-0.273.xpi

Binary file not shown.

9
src/Components/App.svelte

@ -125,12 +125,8 @@
</TabList>
<TabPanel>
<label>
<input type="checkbox" bind:checked={$settings.jpeg} />
Enable JPGs support (JPG embed and extract)
<a
title="JPG embed detection is relatively slow, heavy, so you might want to also enable server cache loading"
>?</a
>
<input type="checkbox" bind:checked={$settings.notcata} />
Disable loading on catalog
</label>
<label>
<input type="checkbox" bind:checked={$cached} />
@ -446,6 +442,7 @@
}
h4 {
text-align: center;
margin: 0;
}

72
src/jpg.ts

@ -1,7 +1,6 @@
import { Buffer } from "buffer";
import type { ImageProcessor } from "./main";
import pngv3 from "./pngv3";
import f5 from 'f5stegojs';
import {f5stego} from './f5stego';
import { settings } from "./stores";
import { decodeCoom3Payload } from "./utils";
@ -11,89 +10,34 @@ settings.subscribe(b => {
csettings = b;
});
export const convertToPng = async (f: File): Promise<Blob | undefined> => {
const can = document.createElement("canvas");
const url = URL.createObjectURL(f);
try {
let dims: [number, number];
let source: CanvasImageSource;
if (f.type.startsWith("image")) {
const imgElem = document.createElement('img');
imgElem.src = url;
await new Promise(_ => imgElem.onload = _);
dims = [imgElem.naturalWidth, imgElem.naturalHeight];
source = imgElem;
} else if (f.type.startsWith("video")) {
const vidElem = document.createElement('video');
vidElem.src = url;
await new Promise(_ => vidElem.onloadedmetadata = _);
vidElem.currentTime = 0;
await new Promise(_ => vidElem.onloadeddata = _);
await new Promise(requestAnimationFrame);
await new Promise(requestAnimationFrame);
await new Promise(requestAnimationFrame);
dims = [vidElem.videoWidth, vidElem.videoHeight];
source = vidElem;
} else
return;
can.width = dims[0];
can.height = dims[1];
const ctx = can.getContext("2d");
if (!ctx)
return;
ctx.drawImage(source, 0, 0, dims[0], dims[1]);
const blob = await new Promise<Blob | null>(_ => can.toBlob(_, "image/png"));
if (!blob)
return;
return blob;
} finally {
URL.revokeObjectURL(url);
}
};
const key = Buffer.from("CUNNYCUNNYCUNNY");
const f5inst = new f5(key);
const f5inst = new f5stego(key);
const injectTrue = async (b: File, links: string[]) => {
const inject = async (b: File, links: string[]) => {
// TODO: maybe do a lossless crop/embed/concat?
if (b.size / 20 < links.join(' ').length)
throw "Image too small to embed.";
const arr = new Uint8Array(new Uint8Array(await b.arrayBuffer()));
const buff = f5inst.embed(arr, new TextEncoder().encode(links.join(' ')));
const buff = f5inst.embed(arr, new TextEncoder().encode(links.join(' ')), 1);
return Buffer.from(buff);
};
const inject = async (b: File, links: string[]) => {
if (csettings.jpeg)
return injectTrue(b, links);
const pngfile = await convertToPng(b);
if (!pngfile || pngfile.size > 3000 * 1024) {
throw new Error("Couldn't convert file to PNG: resulting filesize too big.");
}
return pngv3.inject!(new File([pngfile], b.name), links);
};
// unfortunately, because of the way f5 work, we can't determine
// if there's an embedded message until we have the complete file
// but the way PEE was designed forces us to just try to extract something until it works
const has_embed = (b: Buffer) => {
if (!csettings.jpeg)
return false;
try {
const res = f5inst.extract(b);
if (!res)
return; // unsure
return false; // unsure
if (res.length > 1024) // probably garbage, allows for ~20 links from take-me-to.space, should be enough
return; // unsure
return false; // unsure
const str = Buffer.from(res).toString();
if (!str.match(/^[a-zA-Z0-9:/.\-_ ]+$/))
return; // unsure
return false; // unsure
return str; // sure
} catch {
return; // unsure
return false; // unsure
}
};

44
src/main.ts

@ -18,7 +18,7 @@ import Embeddings from './Components/Embeddings.svelte';
import EyeButton from './Components/EyeButton.svelte';
import NotificationsHandler from './Components/NotificationsHandler.svelte';
import { decodeCoom3Payload, fireNotification, getEmbedsFromCache, getSelectedFile } from "./utils";
import { fireNotification, getEmbedsFromCache, getSelectedFile } from "./utils";
import { getQueryProcessor, QueryProcessor } from "./websites";
import { ifetch, Platform, streamRemote, supportedAltDomain, supportedMainDomain } from "./platform";
import TextEmbeddingsSvelte from "./Components/TextEmbeddings.svelte";
@ -506,25 +506,29 @@ const startup = async (is4chanX = true) => {
//await Promise.all([...document.querySelectorAll('.postContainer')].filter(e => e.textContent?.includes("191 KB")).map(e => processPost(e as any)));
// keep this to handle posts getting inlined
const mo = new MutationObserver(reco => {
for (const rec of reco)
if (rec.type == "childList")
rec.addedNodes.forEach(e => {
if (!(e instanceof HTMLElement))
return;
// apparently querySelector cannot select the root element if it matches
let el = qp.postsWithFiles(e);
if (!el && e.classList.contains('postContainer'))
el = [e];
if (el)
[...el].map(el => processPost(el as any));
});
});
document.querySelectorAll('.board').forEach(e => {
mo.observe(e!, { childList: true, subtree: true });
});
if (!cappState.isCatalog) {
const mo = new MutationObserver(reco => {
for (const rec of reco)
if (rec.type == "childList")
rec.addedNodes.forEach(e => {
if (!(e instanceof HTMLElement))
return;
if (cappState.isCatalog && csettings.notcata)
return;
// apparently querySelector cannot select the root element if it matches
let el = qp.postsWithFiles(e);
if (!el && e.classList.contains('postContainer'))
el = [e];
if (el)
[...el].map(el => processPost(el as any));
});
});
document.querySelectorAll('.board').forEach(e => {
mo.observe(e!, { childList: true, subtree: true });
});
}
if (!document.body) {
let bodyRes: any;
const bodyInit = new Promise(r => bodyRes = r);
@ -582,6 +586,8 @@ const startup = async (is4chanX = true) => {
button.onclick = () => scrapeBoard(button);
opts.insertAdjacentElement("beforebegin", button);
}
if (csettings.notcata)
return;
}
const n = 7;

1
src/stores.ts

@ -17,6 +17,7 @@ export const initial_settings = localLoad('settingsv2', {
xpv: false,
xpi: false,
hyd: false,
notcata: false,
ak: '',
auto_embed: 0,
auto_tags: '',

Loading…
Cancel
Save