PEE/src/thirdeye.ts

152 lines
4.5 KiB
TypeScript
Raw Normal View History

import { EmbeddedFile, EMBED_STATUS, ImageProcessor } from "./main";
2022-01-05 01:14:23 +00:00
import { GM_fetch } from "./requests";
2022-01-09 15:03:53 +00:00
import { localLoad, settings } from "./stores";
2022-01-05 01:14:23 +00:00
export type Booru = {
2022-01-09 15:12:48 +00:00
disabled?: boolean;
name: string;
2022-01-05 01:14:23 +00:00
domain: string;
endpoint: string;
quirks: tran;
};
export type BooruMatch = {
2022-01-07 04:43:28 +00:00
source?: string;
page?: string;
2022-01-05 01:14:23 +00:00
tags: string[];
full_url: string;
preview_url: string;
ext: string;
};
type tran = (a: any) => BooruMatch[];
function firstThatFor<T>(promises: Promise<T>[], pred: (v: T) => boolean) {
Promise.any(promises.map(async p => {
const v = await p;
if (pred(v))
return v;
throw v;
2022-01-08 22:08:20 +00:00
}));
}
2022-01-07 04:43:28 +00:00
const gelquirk: (s: string) => tran = prefix => (a =>
2022-01-05 19:37:41 +00:00
(a.post || a).map((e: any) => ({
2022-01-05 01:14:23 +00:00
full_url: e.file_url,
2022-01-09 19:41:04 +00:00
preview_url: e.preview_url || e.preview_url,
2022-01-07 04:43:28 +00:00
source: e.source,
2022-01-09 14:29:51 +00:00
ext: e.file_ext || e.file_url.substr(e.file_url.lastIndexOf('.') + 1),
2022-01-07 04:43:28 +00:00
page: `${prefix}${e.id}`,
2022-01-09 14:29:51 +00:00
tags: (e.tag_string || e.tags || '').split(' ')
2022-01-07 04:43:28 +00:00
} as BooruMatch)) || []);
2022-01-05 01:14:23 +00:00
2022-01-09 14:29:51 +00:00
settings.subscribe(s => {
boorus = s.rsources.map(e => ({
...e,
2022-01-09 15:03:53 +00:00
quirks: gelquirk(e.view)
2022-01-09 14:29:51 +00:00
}));
});
2022-01-09 15:03:53 +00:00
export let boorus: Booru[] =
localLoad('settingsv2', { rsources: [] as (Omit<Booru, 'quirks'> & { view: string, disabled?: boolean })[] })
.rsources.map(e => ({
...e,
quirks: gelquirk(e.view)
}));
2022-01-05 01:14:23 +00:00
let black = new Set<string>();
settings.subscribe(s => {
black = new Set(s.blacklist);
});
const cache: any = {};
2022-01-08 18:01:01 +00:00
const findFileFrom = async (b: Booru, hex: string, abort?: EventTarget) => {
2022-01-05 01:14:23 +00:00
try {
2022-01-05 19:37:41 +00:00
if (b.domain in cache && hex in cache[b.domain])
return cache[b.domain][hex] as BooruMatch[];
2022-01-05 01:14:23 +00:00
const res = await GM_fetch(`https://${b.domain}${b.endpoint}${hex}`);
// might throw because some endpoint respond with invalid json when an error occurs
const pres = await res.json();
const tran = b.quirks(pres) //.filter(e => !e.tags.some(e => black.has(e)));
2022-01-05 19:37:41 +00:00
if (!(b.domain in cache))
cache[b.domain] = {};
cache[b.domain][hex] = tran;
2022-01-05 01:14:23 +00:00
return tran;
} catch {
return [];
}
};
const extract = async (b: Buffer, fn?: string) => {
2022-01-05 19:37:41 +00:00
let result!: BooruMatch[];
let booru!: string;
2022-01-11 23:32:39 +00:00
let tags: string[] = [];
2022-01-05 19:37:41 +00:00
for (const e of Object.values(boorus)) {
2022-01-09 15:12:48 +00:00
if (e.disabled)
2022-01-05 19:37:41 +00:00
continue;
result = await findFileFrom(e, fn!.substring(0, 32));
if (result.length) {
booru = e.name;
2022-01-11 23:32:39 +00:00
tags = result.flatMap(e2 => e2.tags)
2022-01-05 19:37:41 +00:00
break;
}
2022-01-05 19:37:41 +00:00
}
let cachedPrev: ArrayBuffer;
let cachedFull: ArrayBuffer;
2022-01-07 10:56:39 +00:00
const prev = result[0].preview_url;
const full = result[0].full_url;
2022-01-05 01:14:23 +00:00
return {
2022-01-11 23:32:39 +00:00
tags: tags,
2022-01-07 04:43:28 +00:00
source: result[0].source,
page: { title: booru, url: result[0].page },
2022-01-05 22:20:20 +00:00
filename: fn!.substring(0, 33) + result[0].ext,
thumbnail: async () => {
if (!cachedPrev)
cachedPrev = (await (await GM_fetch(prev || full)).arrayBuffer()); // prefer preview
return cachedPrev;
},
2022-01-05 22:20:20 +00:00
data: async (lsn) => {
if (!cachedFull)
cachedFull = (await (await GM_fetch(full || prev, undefined, lsn)).arrayBuffer()); // prefer full
return cachedFull;
2022-01-05 22:20:20 +00:00
}
2022-01-05 01:14:23 +00:00
} as EmbeddedFile;
};
const has_embed = async (b: Buffer, fn?: string) : Promise<EMBED_STATUS> => {
2022-01-05 01:14:23 +00:00
// 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_STATUS.NONE;
2022-01-05 01:14:23 +00:00
let result: BooruMatch[] | undefined = undefined;
for (const e of Object.values(boorus)) {
2022-01-09 15:12:48 +00:00
if (e.disabled)
2022-01-05 01:14:23 +00:00
continue;
result = await findFileFrom(e, fn!.substring(0, 32));
2022-01-07 10:56:39 +00:00
result = result.filter(e => e.full_url || e.preview_url); // skips possible paywalls
2022-01-05 19:37:41 +00:00
if (result.length)
break;
2022-01-05 01:14:23 +00:00
}
// return result && result.length != 0;
if(result && result.length !== 0){
const filtered = result.filter(e => !e.tags.some(e => black.has(e)))
if(filtered.length > 0)
return EMBED_STATUS.SUCCESS;
return EMBED_STATUS.TE_BLACKLISTED;
}
return EMBED_STATUS.NONE;
2022-01-05 01:14:23 +00:00
};
export default {
skip: true,
extract,
has_embed,
2022-01-08 18:01:01 +00:00
match: fn => !!fn.match(/^[0-9a-fA-F]{32}\.....?/)
2022-01-05 01:14:23 +00:00
} as ImageProcessor;