Browse Source

Add news system

pull/46/head
coomdev 2 years ago
parent
commit
719f143969
  1. 4
      chrome/b4k-csp.json
  2. 135
      chrome/dist/background.js
  3. 4432
      chrome/dist/main.js
  4. 2
      chrome/manifest.json
  5. 135
      firefox/dist/background.js
  6. 4432
      firefox/dist/main.js
  7. 2
      firefox/manifest.json
  8. 74
      main.d.ts
  9. 2
      main.meta.js
  10. 4393
      main.user.js
  11. 36
      src/Components/App.svelte
  12. 29
      src/gif.ts
  13. 2
      src/main.ts
  14. 41
      src/pngv3.ts
  15. 15
      src/webm.ts
  16. 2
      src/websites/index.ts

4
chrome/b4k-csp.json

@ -12,10 +12,10 @@
},
"condition": {
"requestDomains": [
"arch.b4k.co"
"arch.b4k.co", "desuarchive.org"
],
"resourceTypes": [
"main_frame"
]
}
}]
}]

135
chrome/dist/background.js

@ -1,3 +1,4 @@
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@ -1852,6 +1853,7 @@
var Buffer2;
var init_esbuild_inject = __esm({
"esbuild.inject.js"() {
"use strict";
Buffer2 = require_buffer().Buffer;
}
});
@ -1986,70 +1988,81 @@
input = "https:" + input;
if (init?.body && true)
init.body = await deserialize(init.body);
const k = await fetch(input, init);
let headersStr = "";
const headerObj = {};
k.headers.forEach((v, k2) => {
headerObj[k2] = v;
headersStr += `${k2}: ${v}
try {
const k = await fetch(input, init);
let headersStr = "";
const headerObj = {};
k.headers.forEach((v, k2) => {
headerObj[k2] = v;
headersStr += `${k2}: ${v}
`;
});
c.postMessage({
id,
setRes: true,
ok: k.ok,
headers: headerObj,
responseHeaders: headersStr,
redirected: k.redirected,
type: k.type,
url: k.url,
status: k.status,
bodyUsed: k.bodyUsed,
statusText: k.statusText
});
pendingFetches.set(c, {
[id]: {
fetchFully: false
},
...pendingFetches.get(c) || {}
});
let buff = [];
const ctotal = +headerObj["content-length"] || 0;
let ltotal = 0;
let s = 0;
const e = {
write(chunk) {
ltotal += chunk.byteLength;
c.postMessage({ id, progress: [ltotal, ctotal] });
if (!pendingFetches.get(c)[id].fetchFully) {
c.postMessage({ id, s: s++, pushData: { data: chunk } }, [chunk.buffer]);
} else {
buff.push(Buffer2.from(chunk));
}
},
close() {
if (buff.length > 0) {
const chunk = Buffer2.concat(buff);
c.postMessage({ id, s: s++, pushData: { data: chunk } }, [chunk.buffer]);
buff = [];
});
c.postMessage({
id,
setRes: true,
ok: k.ok,
headers: headerObj,
responseHeaders: headersStr,
redirected: k.redirected,
type: k.type,
url: k.url,
status: k.status,
bodyUsed: k.bodyUsed,
statusText: k.statusText
});
pendingFetches.set(c, {
[id]: {
fetchFully: false
},
...pendingFetches.get(c) || {}
});
let buff = [];
const ctotal = +headerObj["content-length"] || 0;
let ltotal = 0;
let s = 0;
const e = {
write(chunk) {
ltotal += chunk.byteLength;
c.postMessage({ id, progress: [ltotal, ctotal] });
if (!pendingFetches.get(c)[id].fetchFully) {
c.postMessage({ id, s: s++, pushData: { data: chunk } }, [chunk.buffer]);
} else {
buff.push(Buffer2.from(chunk));
}
},
close() {
if (buff.length > 0) {
const chunk = Buffer2.concat(buff);
c.postMessage({ id, s: s++, pushData: { data: chunk } }, [chunk.buffer]);
buff = [];
}
const obj2 = pendingFetches.get(c);
delete obj2[id];
if (Object.keys(obj2).length == 0)
pendingFetches.delete(c);
c.postMessage({ id, s: s++, pushData: {} });
}
const obj2 = pendingFetches.get(c);
delete obj2[id];
if (Object.keys(obj2).length == 0)
pendingFetches.delete(c);
c.postMessage({ id, s: s++, pushData: {} });
}
};
const reader = k.body?.getReader();
let res;
for (; ; ) {
res = await reader.read();
if (res.done)
break;
e.write(res.value);
};
const reader = k.body?.getReader();
let res;
for (; ; ) {
res = await reader.read();
if (res.done)
break;
e.write(res.value);
}
e.close();
reader?.releaseLock();
} catch (e) {
const err = e;
c.postMessage({
id,
setRes: true,
ok: false,
url: input,
status: err.message
});
}
e.close();
reader?.releaseLock();
};
var meself = new URL(obj.runtime.getURL("")).origin;
var waitConnect = (cb) => {

4432
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.245",
"version": "0.247",
"icons": {
"64": "1449696017588.png"
},

135
firefox/dist/background.js

@ -1,3 +1,4 @@
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@ -1852,6 +1853,7 @@
var Buffer2;
var init_esbuild_inject = __esm({
"esbuild.inject.js"() {
"use strict";
Buffer2 = require_buffer().Buffer;
}
});
@ -1953,70 +1955,81 @@
input = "https:" + input;
if (init?.body && false)
init.body = await deserialize(init.body);
const k = await fetch(input, init);
let headersStr = "";
const headerObj = {};
k.headers.forEach((v, k2) => {
headerObj[k2] = v;
headersStr += `${k2}: ${v}
try {
const k = await fetch(input, init);
let headersStr = "";
const headerObj = {};
k.headers.forEach((v, k2) => {
headerObj[k2] = v;
headersStr += `${k2}: ${v}
`;
});
c.postMessage({
id,
setRes: true,
ok: k.ok,
headers: headerObj,
responseHeaders: headersStr,
redirected: k.redirected,
type: k.type,
url: k.url,
status: k.status,
bodyUsed: k.bodyUsed,
statusText: k.statusText
});
pendingFetches.set(c, {
[id]: {
fetchFully: false
},
...pendingFetches.get(c) || {}
});
let buff = [];
const ctotal = +headerObj["content-length"] || 0;
let ltotal = 0;
let s = 0;
const e = {
write(chunk) {
ltotal += chunk.byteLength;
c.postMessage({ id, progress: [ltotal, ctotal] });
if (!pendingFetches.get(c)[id].fetchFully) {
c.postMessage({ id, s: s++, pushData: { data: chunk } }, [chunk.buffer]);
} else {
buff.push(Buffer2.from(chunk));
}
},
close() {
if (buff.length > 0) {
const chunk = Buffer2.concat(buff);
c.postMessage({ id, s: s++, pushData: { data: chunk } }, [chunk.buffer]);
buff = [];
});
c.postMessage({
id,
setRes: true,
ok: k.ok,
headers: headerObj,
responseHeaders: headersStr,
redirected: k.redirected,
type: k.type,
url: k.url,
status: k.status,
bodyUsed: k.bodyUsed,
statusText: k.statusText
});
pendingFetches.set(c, {
[id]: {
fetchFully: false
},
...pendingFetches.get(c) || {}
});
let buff = [];
const ctotal = +headerObj["content-length"] || 0;
let ltotal = 0;
let s = 0;
const e = {
write(chunk) {
ltotal += chunk.byteLength;
c.postMessage({ id, progress: [ltotal, ctotal] });
if (!pendingFetches.get(c)[id].fetchFully) {
c.postMessage({ id, s: s++, pushData: { data: chunk } }, [chunk.buffer]);
} else {
buff.push(Buffer2.from(chunk));
}
},
close() {
if (buff.length > 0) {
const chunk = Buffer2.concat(buff);
c.postMessage({ id, s: s++, pushData: { data: chunk } }, [chunk.buffer]);
buff = [];
}
const obj2 = pendingFetches.get(c);
delete obj2[id];
if (Object.keys(obj2).length == 0)
pendingFetches.delete(c);
c.postMessage({ id, s: s++, pushData: {} });
}
const obj2 = pendingFetches.get(c);
delete obj2[id];
if (Object.keys(obj2).length == 0)
pendingFetches.delete(c);
c.postMessage({ id, s: s++, pushData: {} });
}
};
const reader = k.body?.getReader();
let res;
for (; ; ) {
res = await reader.read();
if (res.done)
break;
e.write(res.value);
};
const reader = k.body?.getReader();
let res;
for (; ; ) {
res = await reader.read();
if (res.done)
break;
e.write(res.value);
}
e.close();
reader?.releaseLock();
} catch (e) {
const err = e;
c.postMessage({
id,
setRes: true,
ok: false,
url: input,
status: err.message
});
}
e.close();
reader?.releaseLock();
};
var meself = new URL(obj.runtime.getURL("")).origin;
var waitConnect = (cb) => {

4432
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.245",
"version": "0.247",
"icons": {
"64": "1449696017588.png"
},

74
main.d.ts

@ -6,6 +6,80 @@ declare module '*.png' {
export default new Uint8Array;
}
declare module 'mp4box' {
type BaseTrackInfo = {
id: number,
created: string,
modified: string,
movie_duration: number,
layer: number,
alternate_group: number,
volume: number,
track_width: number,
track_height: number,
timescale: number,
duration: number,
bitrate: number,
codec: string,
language: string,
nb_samples: number
};
type VideoTrackInfo = BaseTrackInfo & {
type: 'video';
movie_duration: number;
video: {
width: number,
height: number
},
};
type AudioTrackInfo = BaseTrackInfo & {
type: 'audio';
audio: {
sample_rate: number,
channel_count: number,
sample_size: number
},
};
type InfoType = {
duration: number,
fragment_duration: number;
timescale: number,
isFragmented: boolean,
isProgressive: boolean,
hasIOD: boolean,
brands: string[],
created: string,
modified: string,
mime?: string;
tracks: (VideoTrackInfo | AudioTrackInfo)[]
};
export function createFile(): {
onError(e: Error): void;
onReady(info: InfoType): void;
appendBuffer(a: ArrayBuffer, end?: boolean): void;
start(): void;
seek(time: number, useRap: boolean): {offset: number};
stop(): void;
flush(): void;
setSegmentOptions(id: number, user?: any, options?: {
nbSamples?: number;
rapAlignement?: boolean;
}): void;
unsetSegmentOptions(id: number): void;
onSegment(id: number, user: any, buffer: ArrayBuffer, sampleNumber: number, last: boolean): void;
initializeSegmentation(): {
id: number;
user: any;
buffer: ArrayBuffer;
}[];
releaseUsedSamples(id: number, lsampleid: number): void;
};
}
declare module 'blockhash' {
export const hammingDistance: (a: string, b: string) => number;
export const blockhash: () => void;

2
main.meta.js

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

4393
main.user.js

File diff suppressed because it is too large

36
src/Components/App.svelte

@ -19,6 +19,17 @@
let newbooru: Partial<Omit<Booru, "quirks"> & { view: string }> = {};
let dial: Dialog;
export let rev: number;
let news: {
title: string;
content: string;
}[] = [];
const updateNews = async () => {
const res = await fetch("https://shoujo.coom.tech/news");
news = await res.json();
};
function appendBooru() {
$settings.rsources = [...$settings.rsources, newbooru as any];
@ -93,7 +104,7 @@
{#if visible}
<div class="backpanel" transition:slide>
<div class="content">
<h1>PEE Settings</h1>
<h1>PEE Settings 0.{rev}</h1>
<hr />
<Tabs>
<TabList>
@ -101,6 +112,7 @@
<Tab>External</Tab>
<Tab>File Host</Tab>
<Tab on:select={() => updateThreads()}>Thread Watcher</Tab>
<Tab on:select={() => updateNews()}>Reminder</Tab>
{#if $appState.akValid}
<Tab>Hydrus</Tab>
{/if}
@ -358,6 +370,23 @@
<HydrusSearch />
</TabPanel>
{/if}
<TabPanel>
<p>
Reminder to report issues to <a
href="https://git.coom.tech/coomdev/PEE">the main repo</a
>
</p>
<div class="newsbox">
{#if news.length == 0}
<p>There are no news yet.</p>
{:else}
{#each news as anew}
<h3>{anew.title}</h3>
<p>{anew.content}</p>
{/each}
{/if}
</div>
</TabPanel>
</Tabs>
</div>
</div>
@ -414,6 +443,11 @@
gap: 10px;
}
.newsbox {
max-height: 300px;
overflow-y: scroll;
}
.backpanel {
position: absolute;
right: 32px;

29
src/gif.ts

@ -5,6 +5,7 @@ import { decodeCoom3Payload, uploadFiles } from "./utils";
const netscape = Buffer.from("!\xFF\x0BNETSCAPE2.0", 'ascii');
const magic = Buffer.from("!\xFF\x0B" + "DOOMTECH1.1", 'ascii');
const magic2 = Buffer.from("!\xFF\x0B" + "VOOMTECH1.1", 'ascii');
const read_section = (gif: Buffer, pos: number) => {
const begin = pos;
@ -25,6 +26,17 @@ const read_section = (gif: Buffer, pos: number) => {
};
};
const password = Buffer.from("NOA");
const xor = (a: Buffer, p: Buffer) => {
let n = 0;
for (let i = 0; i < a.byteLength; ++i) {
a[i] ^= p[n];
n++;
n %= p.byteLength;
}
};
const extractBuff = (gif: Buffer) => {
const field = gif.readUInt8(10);
const gcte = !!(field & (1 << 7));
@ -43,9 +55,22 @@ const extractBuff = (gif: Buffer) => {
sec.data.copy(ret, ptr);
ptr += sec.data.byteLength;
end = sec.end;
// v wtf did i mean by this
} while (sec.appname == "DOOMTECH" && gif[end] == '!'.charCodeAt(0));
return decodeCoom3Payload(ret);
}
if (sec.appname == "VOOMTECH") {
const ret = Buffer.alloc(sec.data.readInt32LE(0));
let ptr = 0;
do {
sec = read_section(gif, sec.end);
sec.data.copy(ret, ptr);
ptr += sec.data.byteLength;
end = sec.end;
} while (sec.appname == "VOOMTECH" && gif[end] == '!'.charCodeAt(0));
xor(ret, password);
return decodeCoom3Payload(ret);
}
end = sec.end;
}
throw new Error("Shouldn't happen");
@ -91,7 +116,7 @@ const inject = async (container: File, links: string[]) => {
const writer = writestream.getWriter();
const inj = Buffer.from(links.join(' '));
xor(inj, password);
const contbuff = Buffer.from(await container.arrayBuffer());
const field = contbuff.readUInt8(10);
@ -117,7 +142,7 @@ const has_embed = (gif: Buffer) => {
}
// skip beeg blocks
while (end < gif.byteLength && gif.readUInt8(end) == '!'.charCodeAt(0)) {
if (magic.compare(gif, end, end + magic.byteLength) != 0) {
if ([magic, magic2].every(m => m.compare(gif, end, end + m.byteLength) != 0)) {
end += 3 + gif.readUInt8(end + 2);
// eslint-disable-next-line no-constant-condition
while (true) { // skip sub blocks

2
src/main.ts

@ -536,7 +536,7 @@ const startup = async (is4chanX = true) => {
}
const appHost = textToElement(`<div class="peee-settings"></div>`);
const appInstance = new App({ target: appHost });
const appInstance = new App({ target: appHost, props: {rev: BUILD_VERSION[1]} });
document.body.append(appHost);
const scrollHost = textToElement(`<div></div>`);

41
src/pngv3.ts

@ -3,6 +3,7 @@ import type { EmbeddedFile, ImageProcessor } from "./main";
import { PNGDecoder, PNGEncoder } from "./png";
import { decodeCoom3Payload } from "./utils";
import { settings } from "./stores";
import { filehosts } from "./filehosts";
export let csettings: Parameters<typeof settings['set']>[0];
@ -11,6 +12,7 @@ settings.subscribe(b => {
});
const CUM3 = Buffer.from("doo\0" + "m");
const CUM4 = Buffer.from("voo\0" + "m");
const CUM5 = Buffer.from("boo\0");
const BufferReadStream = (b: Buffer) => {
const ret = new ReadableStream<Buffer>({
@ -33,6 +35,20 @@ const xor = (a: Buffer, p: Buffer) => {
}
};
const prefs: any = {
'files.catbox.moe': 'c',
'a.pomf.cat': 'p',
'take-me-to.space': 't',
'z.zz.fo': 'z'
};
const rprefs: any = {
'c': 'files.catbox.moe',
'p': 'a.pomf.cat',
't': 'take-me-to.space',
'z': 'z.zz.fo',
};
const extract = async (png: Buffer) => {
const reader = BufferReadStream(png).getReader();
const sneed = new PNGDecoder(reader);
@ -55,6 +71,14 @@ const extract = async (png: Buffer) => {
const k = await decodeCoom3Payload(passed);
ret.push(...k.filter(e => e).map(e => e as EmbeddedFile));
}
if (buff.slice(4, 4 + CUM5.length).equals(CUM5)) {
const passed = buff.slice(4 + CUM5.length);
const decoded = Buffer.from(passed.toString(), 'base64').toString().split(' ').map(e => {
return `https://${rprefs[e[0]]}/${e.slice(1)}`;
}).join(' ');
const k = await decodeCoom3Payload(Buffer.from(decoded));
ret.push(...k.filter(e => e).map(e => e as EmbeddedFile));
}
break;
case 'IDAT':
// eslint-disable-next-line no-fallthrough
@ -100,8 +124,8 @@ export const inject_data = async (container: File, injb: Buffer) => {
break;
if (!magic && name == "IDAT") {
const passed = Buffer.from(injb);
xor(passed, password);
await encoder.insertchunk(["tEXt", async () => buildChunk("tEXt", Buffer.concat([CUM4, passed])), () => Promise.resolve(0), 0]);
//xor(passed, password2);
await encoder.insertchunk(["tEXt", async () => buildChunk("tEXt", Buffer.concat([CUM5, passed])), () => Promise.resolve(0), 0]);
magic = true;
}
await encoder.insertchunk([name, chunk, crc, offset]);
@ -115,7 +139,16 @@ export const inject_data = async (container: File, injb: Buffer) => {
};
const inject = async (container: File, links: string[]) => {
const injb = Buffer.from(links.join(' '));
links = links.map(link => {
for (const h of filehosts) {
if (link.includes(h.serving)) {
const end = link.split('/').slice(-1)[0];
return `${prefs[h.serving]}${end}`;
}
}
return '';
});
const injb = Buffer.from(Buffer.from(links.join(' ')).toString("base64"));
return inject_data(container, injb);
};
@ -133,6 +166,8 @@ const has_embed = async (png: Buffer) => {
return true;
if (buff.slice(4, 4 + CUM4.length).equals(CUM4))
return true;
if (buff.slice(4, 4 + CUM5.length).equals(CUM5))
return true;
break;
case 'IDAT':
// eslint-disable-next-line no-fallthrough

15
src/webm.ts

@ -91,7 +91,7 @@ const embed = (webm: Buffer, data: Buffer) => {
type: "8",
isEnd: false,
name: 'TagName',
data: Buffer.from('DOOM')
data: Buffer.from('VOOM')
},
{
type: "8",
@ -113,19 +113,26 @@ const extract = (webm: Buffer) => {
const dec = new ebml.Decoder();
const chunks = dec.decode(webm);
const embed = chunks.findIndex(e => e.name == "TagName" && e.type == '8' && e.value == "DOOM");
const embed = chunks.findIndex(e => e.name == "TagName" && e.type == '8' && (e.value == "DOOM" || e.value == "VOOM"));
const cl = chunks.find(e => e.name == "Cluster");
if (cl && embed == -1)
return;
if (embed == -1)
return;
const echk = chunks[embed];
const chk = chunks[embed + 1];
if (chk.type == "b" && chk.name == "TagBinary")
if (chk.type == "b" && chk.name == "TagBinary") {
if (echk.type == "8" && echk.value == "VOOM") {
xor(chk.data, password);
}
return decodeCoom3Payload(chk.data);
}
};
const inject = async (container: File, links: string[]): Promise<Buffer> => {
return embed(Buffer.from(await container.arrayBuffer()), Buffer.from(links.join(' ')));
const buff = Buffer.from(links.join(' '));
xor(buff, password);
return embed(Buffer.from(await container.arrayBuffer()), buff);
};
const has_embed = (webm: Buffer) => {

2
src/websites/index.ts

@ -69,7 +69,7 @@ export const X4chan: QueryProcessor = {
export const FoolFuuka: QueryProcessor = {
getFileThumbnail: post => post.classList.contains('post_is_op') ? post.querySelector('.thread_image_link')! : post.querySelector('.thread_image_box')!,
getPost: (post) => post.querySelector('.post_wrapper')!,
postsWithFiles: (h) => [...(h || document).querySelectorAll('article[class*="has_image"]')] as HTMLElement[],
postsWithFiles: (h) => [...(h || document).querySelectorAll('article[class*="thread"], article[class*="has_image"]')] as HTMLElement[],
settingsHost: () => document.querySelector(".letters") as any,
catalogControlHost: () => document.getElementById("index-options") as HTMLDivElement,
getImageLink: async function *(post: HTMLElement) {

Loading…
Cancel
Save