mirror of
https://git.coom.tech/fuckjannies/lolipiss.git
synced 2024-07-01 06:52:35 +00:00
Fix Regex matching and hover thing?
This commit is contained in:
parent
11047fb50a
commit
0c8dd166fa
|
@ -1,7 +1,7 @@
|
|||
// ==UserScript==
|
||||
// @name PNGExtraEmbed
|
||||
// @namespace https://coom.tech/
|
||||
// @version 0.115
|
||||
// @version 0.116
|
||||
// @description uhh
|
||||
// @author You
|
||||
// @match https://boards.4channel.org/*
|
||||
|
|
29
main.user.js
29
main.user.js
|
@ -1,7 +1,7 @@
|
|||
// ==UserScript==
|
||||
// @name PNGExtraEmbed
|
||||
// @namespace https://coom.tech/
|
||||
// @version 0.115
|
||||
// @version 0.116
|
||||
// @description uhh
|
||||
// @author You
|
||||
// @match https://boards.4channel.org/*
|
||||
|
@ -11181,7 +11181,7 @@
|
|||
const fnsize = data.readUInt32LE(0);
|
||||
const fn = data.slice(4, 4 + fnsize).toString();
|
||||
data = data.slice(4 + fnsize);
|
||||
return { filename: fn, data };
|
||||
return [{ filename: fn, data }];
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
@ -11191,7 +11191,7 @@
|
|||
};
|
||||
var buildChunk = (tag, data) => {
|
||||
const ret = import_buffer.Buffer.alloc(data.byteLength + 4);
|
||||
ret.write(tag.substr(0, 4), 0);
|
||||
ret.write(tag.slice(0, 4), 0);
|
||||
data.copy(ret, 4);
|
||||
return ret;
|
||||
};
|
||||
|
@ -11345,7 +11345,7 @@
|
|||
return;
|
||||
const chk = chunks[embed2 + 1];
|
||||
if (chk.type == "b" && chk.name == "TagBinary")
|
||||
return { filename: "string", data: chk.data };
|
||||
return [{ filename: "string", data: chk.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) => {
|
||||
|
@ -11407,7 +11407,7 @@
|
|||
ptr += sec.data.byteLength;
|
||||
end = sec.end;
|
||||
} while (sec.appname == "COOMTECH" && gif[end] == "!".charCodeAt(0));
|
||||
return { data: ret, filename: "embedded" };
|
||||
return [{ data: ret, filename: "embedded" }];
|
||||
}
|
||||
end = sec.end;
|
||||
}
|
||||
|
@ -11629,7 +11629,6 @@
|
|||
var unlockQueue = Promise.resolve();
|
||||
var queryCache = {};
|
||||
var processQueries = async () => {
|
||||
console.log("======== FIRIN =======");
|
||||
let unlock;
|
||||
unlockQueue = new Promise((_) => unlock = _);
|
||||
const md5 = reqQueue.map((e) => e[0]).filter((e) => !(e in queryCache));
|
||||
|
@ -11747,7 +11746,7 @@
|
|||
];
|
||||
var getExt = (fn) => {
|
||||
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}=)?$/);
|
||||
const isB64 = fn.match(/^((?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=))?\.(gif|jpe?g|png|webm)/);
|
||||
const isExt = fn.match(/\[.*=(.*)\]/);
|
||||
let ext;
|
||||
if (isDum) {
|
||||
|
@ -11770,7 +11769,7 @@
|
|||
} catch {
|
||||
}
|
||||
}
|
||||
return {
|
||||
return [{
|
||||
filename: ext,
|
||||
data: async (lsn) => {
|
||||
try {
|
||||
|
@ -11779,7 +11778,7 @@
|
|||
}
|
||||
},
|
||||
thumbnail: hasembed_default
|
||||
};
|
||||
}];
|
||||
};
|
||||
var has_embed5 = async (b, fn) => {
|
||||
const ext = getExt(fn);
|
||||
|
@ -11798,13 +11797,7 @@
|
|||
skip: true,
|
||||
extract: extract5,
|
||||
has_embed: has_embed5,
|
||||
match: (fn) => {
|
||||
const base = fn.split(".").slice(0, -1).join(".");
|
||||
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}=)?$/);
|
||||
const isExt = !!fn.match(/\[.*=.*\]/);
|
||||
return isB64 || isExt || isDum;
|
||||
}
|
||||
match: (fn) => !!getExt(fn)
|
||||
};
|
||||
|
||||
// src/App.svelte
|
||||
|
@ -15847,6 +15840,8 @@
|
|||
if (!contracted)
|
||||
return;
|
||||
const [sw, sh] = [visualViewport.width, visualViewport.height];
|
||||
if (dims[0] == 0 && dims[1] == 0)
|
||||
recompute();
|
||||
let width = dims[0];
|
||||
let height = dims[1] + 25;
|
||||
let { clientX, clientY } = ev || lastev;
|
||||
|
@ -16647,7 +16642,7 @@
|
|||
res2 = res2?.filter((e) => e);
|
||||
if (!res2 || res2.length == 0)
|
||||
return;
|
||||
processAttachments(post, res2?.filter((e) => e));
|
||||
processAttachments(post, res2?.filter((e) => e).flatMap((e) => e[0].map((k) => [k, e[1]])));
|
||||
};
|
||||
var startup = async () => {
|
||||
if (typeof window["FCX"] != "undefined")
|
||||
|
|
|
@ -211,6 +211,8 @@
|
|||
if (!contracted) return
|
||||
const [sw, sh] = [visualViewport.width, visualViewport.height]
|
||||
// shamelessly stolen from 4chanX
|
||||
if (dims[0] == 0 && dims[1] == 0)
|
||||
recompute();
|
||||
let width = dims[0]
|
||||
let height = dims[1] + 25
|
||||
let { clientX, clientY } = (ev || lastev!)
|
||||
|
|
|
@ -43,7 +43,7 @@ const extractBuff = (gif: Buffer) => {
|
|||
ptr += sec.data.byteLength;
|
||||
end = sec.end;
|
||||
} while (sec.appname == "COOMTECH" && gif[end] == '!'.charCodeAt(0));
|
||||
return { data: ret, filename: 'embedded' } as EmbeddedFile;
|
||||
return [{ data: ret, filename: 'embedded' }] as EmbeddedFile[];
|
||||
}
|
||||
end = sec.end;
|
||||
}
|
||||
|
|
10
src/main.ts
10
src/main.ts
|
@ -21,7 +21,7 @@ export interface ImageProcessor {
|
|||
skip?: true;
|
||||
match(fn: string): boolean;
|
||||
has_embed(b: Buffer, fn?: string): boolean | Promise<boolean>;
|
||||
extract(b: Buffer, fn?: string): EmbeddedFile | Promise<EmbeddedFile>;
|
||||
extract(b: Buffer, fn?: string): EmbeddedFile[] | Promise<EmbeddedFile[]>;
|
||||
inject?(b: File, c: File): Buffer | Promise<Buffer>;
|
||||
}
|
||||
|
||||
|
@ -86,14 +86,14 @@ type EmbeddedFileWithoutPreview = {
|
|||
|
||||
export type EmbeddedFile = EmbeddedFileWithPreview | EmbeddedFileWithoutPreview;
|
||||
|
||||
const processImage = async (src: string, fn: string, hex: string): Promise<([EmbeddedFile, boolean] | undefined)[]> => {
|
||||
const processImage = async (src: string, fn: string, hex: string): Promise<([EmbeddedFile[], boolean] | undefined)[]> => {
|
||||
return Promise.all(processors.filter(e => e.match(fn)).map(async proc => {
|
||||
if (proc.skip) {
|
||||
// skip file downloading, file is referenced from the filename
|
||||
// basically does things like filtering out blacklisted tags
|
||||
const md5 = Buffer.from(hex, 'base64');
|
||||
if (await proc.has_embed(md5, fn) === true)
|
||||
return [await proc.extract(md5, fn), true] as [EmbeddedFile, boolean];
|
||||
return [await proc.extract(md5, fn), true] as [EmbeddedFile[], boolean];
|
||||
return;
|
||||
}
|
||||
const iter = streamRemote(src);
|
||||
|
@ -118,7 +118,7 @@ const processImage = async (src: string, fn: string, hex: string): Promise<([Emb
|
|||
//console.log(`Gave up on ${src} after downloading ${cumul.byteLength} bytes...`);
|
||||
return;
|
||||
}
|
||||
return [await proc.extract(cumul), false] as [EmbeddedFile, boolean];
|
||||
return [await proc.extract(cumul), false] as [EmbeddedFile[], boolean];
|
||||
}));
|
||||
};
|
||||
|
||||
|
@ -136,7 +136,7 @@ const processPost = async (post: HTMLDivElement) => {
|
|||
res2 = res2?.filter(e => e);
|
||||
if (!res2 || res2.length == 0)
|
||||
return;
|
||||
processAttachments(post, res2?.filter(e => e) as [EmbeddedFile, boolean][]);
|
||||
processAttachments(post, res2?.filter(e => e).flatMap(e => e![0].map(k => [k, e![1]] as [EmbeddedFile, boolean])));
|
||||
};
|
||||
|
||||
const startup = async () => {
|
||||
|
|
10
src/png.ts
10
src/png.ts
|
@ -2,9 +2,9 @@ import { buf } from "crc-32";
|
|||
import { Buffer } from "buffer";
|
||||
import type { ImageProcessor } from "./main";
|
||||
|
||||
type PNGChunk = [string, Buffer, number, number];
|
||||
export type PNGChunk = [string, Buffer, number, number];
|
||||
|
||||
class PNGDecoder {
|
||||
export class PNGDecoder {
|
||||
repr: Buffer;
|
||||
|
||||
req = 8;
|
||||
|
@ -47,7 +47,7 @@ class PNGDecoder {
|
|||
}
|
||||
}
|
||||
|
||||
class PNGEncoder {
|
||||
export class PNGEncoder {
|
||||
writer: WritableStreamDefaultWriter<Buffer>;
|
||||
|
||||
constructor(bytes: WritableStream<Buffer>) {
|
||||
|
@ -118,7 +118,7 @@ const extract = async (png: Buffer) => {
|
|||
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 };
|
||||
return [{ filename: fn, data }];
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
@ -129,7 +129,7 @@ const extract = async (png: Buffer) => {
|
|||
|
||||
const buildChunk = (tag: string, data: Buffer) => {
|
||||
const ret = Buffer.alloc(data.byteLength + 4);
|
||||
ret.write(tag.substr(0, 4), 0);
|
||||
ret.write(tag.slice(0, 4), 0);
|
||||
data.copy(ret, 4);
|
||||
return ret;
|
||||
};
|
||||
|
|
149
src/pngv3.ts
Normal file
149
src/pngv3.ts
Normal file
|
@ -0,0 +1,149 @@
|
|||
import { buf } from "crc-32";
|
||||
import { Buffer } from "buffer";
|
||||
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) => {
|
||||
const ret = new ReadableStream<Buffer>({
|
||||
pull(cont) {
|
||||
cont.enqueue(b);
|
||||
cont.close();
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
};
|
||||
|
||||
const extract = async (png: Buffer) => {
|
||||
let magic = false;
|
||||
let coom3 = false;
|
||||
const reader = BufferReadStream(png).getReader();
|
||||
const sneed = new PNGDecoder(reader);
|
||||
try {
|
||||
let lastIDAT: Buffer | null = null;
|
||||
for await (const [name, chunk, crc, offset] of sneed.chunks()) {
|
||||
let buff: Buffer;
|
||||
switch (name) {
|
||||
// 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;
|
||||
magic = true;
|
||||
}
|
||||
break;
|
||||
case 'IDAT':
|
||||
if (magic) {
|
||||
lastIDAT = chunk;
|
||||
break;
|
||||
}
|
||||
// eslint-disable-next-line no-fallthrough
|
||||
case 'IEND':
|
||||
if (!magic)
|
||||
return; // Didn't find tExt Chunk;
|
||||
// eslint-disable-next-line no-fallthrough
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
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 }];
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
reader.releaseLock();
|
||||
}
|
||||
};
|
||||
|
||||
const buildChunk = (tag: string, data: Buffer) => {
|
||||
const ret = Buffer.alloc(data.byteLength + 4);
|
||||
ret.write(tag.slice(0, 4), 0);
|
||||
data.copy(ret, 4);
|
||||
return ret;
|
||||
};
|
||||
|
||||
export const BufferWriteStream = () => {
|
||||
let b = Buffer.from([]);
|
||||
const ret = new WritableStream<Buffer>({
|
||||
write(chunk) {
|
||||
b = Buffer.concat([b, chunk]);
|
||||
}
|
||||
});
|
||||
return [ret, () => b] as [WritableStream<Buffer>, () => Buffer];
|
||||
};
|
||||
|
||||
const inject = async (container: File, inj: File) => {
|
||||
const [writestream, extract] = BufferWriteStream();
|
||||
const encoder = new PNGEncoder(writestream);
|
||||
const decoder = new PNGDecoder(container.stream().getReader());
|
||||
|
||||
let magic = false;
|
||||
for await (const [name, chunk, crc, offset] of decoder.chunks()) {
|
||||
if (magic && name != "IDAT")
|
||||
break;
|
||||
if (!magic && name == "IDAT") {
|
||||
await encoder.insertchunk(["tEXt", buildChunk("tEXt", CUM0), 0, 0]);
|
||||
magic = true;
|
||||
}
|
||||
await encoder.insertchunk([name, chunk, crc, offset]);
|
||||
}
|
||||
const injb = Buffer.alloc(4 + inj.name.length + inj.size);
|
||||
injb.writeInt32LE(inj.name.length, 0);
|
||||
injb.write(inj.name, 4);
|
||||
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", Buffer.from([])), 0, 0]);
|
||||
return extract();
|
||||
};
|
||||
|
||||
const has_embed = async (png: Buffer) => {
|
||||
const reader = BufferReadStream(png).getReader();
|
||||
const sneed = new PNGDecoder(reader);
|
||||
try {
|
||||
for await (const [name, chunk, crc, offset] of sneed.chunks()) {
|
||||
let buff: Buffer;
|
||||
switch (name) {
|
||||
// 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))
|
||||
return true;
|
||||
break;
|
||||
case 'IDAT':
|
||||
// eslint-disable-next-line no-fallthrough
|
||||
case 'IEND':
|
||||
return false; // Didn't find tExt Chunk; Definite no
|
||||
// eslint-disable-next-line no-fallthrough
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// stream ended on chunk boundary, so no unexpected EOF was fired, need more data anyway
|
||||
} catch (e) {
|
||||
return; // possibly unexpected EOF, need more data to decide
|
||||
} finally {
|
||||
reader.releaseLock();
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
extract,
|
||||
has_embed,
|
||||
inject,
|
||||
match: fn => !!fn.match(/\.png$/)
|
||||
} as ImageProcessor;
|
18
src/pomf.ts
18
src/pomf.ts
|
@ -11,7 +11,7 @@ const sources = [
|
|||
|
||||
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}=)?$/);
|
||||
const isB64 = fn!.match(/^((?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=))?\.(gif|jpe?g|png|webm)/);
|
||||
const isExt = fn!.match(/\[.*=(.*)\]/);
|
||||
let ext;
|
||||
if (isDum) {
|
||||
|
@ -37,8 +37,8 @@ const extract = async (b: Buffer, fn?: string) => {
|
|||
// 404
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
return [{
|
||||
filename: ext,
|
||||
data: async (lsn) => {
|
||||
try {
|
||||
|
@ -48,7 +48,7 @@ const extract = async (b: Buffer, fn?: string) => {
|
|||
}
|
||||
},
|
||||
thumbnail
|
||||
} as EmbeddedFile;
|
||||
} as EmbeddedFile];
|
||||
};
|
||||
|
||||
const has_embed = async (b: Buffer, fn?: string) => {
|
||||
|
@ -63,7 +63,7 @@ const has_embed = async (b: Buffer, fn?: string) => {
|
|||
// 404
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
@ -71,11 +71,5 @@ export default {
|
|||
skip: true,
|
||||
extract,
|
||||
has_embed,
|
||||
match: fn => {
|
||||
const base = fn.split('.').slice(0, -1).join('.');
|
||||
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}=)?$/);
|
||||
const isExt = !!fn.match(/\[.*=.*\]/);
|
||||
return isB64 || isExt || isDum;
|
||||
}
|
||||
match: fn => !!getExt(fn)
|
||||
} as ImageProcessor;
|
|
@ -71,7 +71,6 @@ let unlockQueue = Promise.resolve();
|
|||
|
||||
const queryCache: ApiResult = {};
|
||||
const processQueries = async () => {
|
||||
console.log("======== FIRIN =======");
|
||||
let unlock!: () => void;
|
||||
unlockQueue = new Promise<void>(_ => unlock = _);
|
||||
const md5 = reqQueue.map(e => e[0]).filter(e => !(e in queryCache));
|
||||
|
|
5
src/utils.ts
Normal file
5
src/utils.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import type { Buffer } from "buffer";
|
||||
|
||||
export const decodeCoom3Payload = (buff: Buffer) => {
|
||||
//
|
||||
};
|
|
@ -120,7 +120,7 @@ const extract = (webm: Buffer) => {
|
|||
return;
|
||||
const chk = chunks[embed + 1];
|
||||
if (chk.type == "b" && chk.name == "TagBinary")
|
||||
return { filename: 'string', data: chk.data };
|
||||
return [{ filename: 'string', data: chk.data }];
|
||||
};
|
||||
|
||||
const inject = async (container: File, inj: File): Promise<Buffer> =>
|
||||
|
|
Loading…
Reference in New Issue
Block a user