Can embed any file in a PNG/WebM/GIF/JPEG and upload it to a third-party host through 4chan
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

157 lines
7.5 KiB

import { ifetch } from "../platform";
export type QueryProcessor = {
getPost: (post: HTMLElement) => HTMLElement;
getFileThumbnail: (post: HTMLElement) => HTMLElement;
postsWithFiles: (host?: HTMLElement) => HTMLElement[];
settingsHost: () => HTMLSpanElement;
catalogControlHost: () => HTMLDivElement;
getImageLink: (post: HTMLElement) => AsyncGenerator<string, void, void>;
getThumbnailLink: (post: HTMLElement) => string;
getFilename: (post: HTMLElement) => string;
getMD5: (post: HTMLElement) => string;
getInfoBox: (post: HTMLElement) => HTMLElement;
getPostIdPrefix: () => string;
getTextBox: (post: HTMLElement) => HTMLElement;
getCurrentBoard: () => string;
getCurrentThread: () => number | undefined;
};
export const V4chan: QueryProcessor = {
getFileThumbnail: post => post.querySelector('div.file')!,
getPost: (post) => post.classList.contains("post") ? post : post.querySelector('.post')!,
postsWithFiles: (h) => [...(h || document).querySelectorAll('.file')].map(e => e.closest('.postContainer')) as any,
settingsHost: () => document.getElementById("navtopright") as any,
catalogControlHost: () => document.getElementById("settings") as HTMLDivElement,
getImageLink: async function*(post: HTMLElement) {
yield post.querySelector('a[target="_blank"]')?.getAttribute('href') || '';
},
//(post: HTMLElement) => post.querySelector('a[target="_blank"]')?.getAttribute('href') || '',
getFilename: (post: HTMLElement) => {
const a = post.querySelector('a[target="_blank"]') as (HTMLAnchorElement | null);
if (a && a.title)
return a.title;
return a?.textContent || '';
},
getMD5: (post: HTMLElement) => post.querySelector("img[data-md5]")?.getAttribute("data-md5") || '',
getThumbnailLink: (post: HTMLElement) => post.querySelector("img[data-md5]")?.getAttribute("src") || '',
getInfoBox: post => post.querySelector("div.fileText")!,
getPostIdPrefix: () => 'p',
getTextBox: (post) => post.querySelector('blockquote')!,
getCurrentBoard: () => location.pathname.split('/')[1],
getCurrentThread: () => +location.pathname.split('/')[3]
};
export const X4chan: QueryProcessor = {
getFileThumbnail: post => post.querySelector('div.file')!,
getPost: (post) => V4chan.getPost(post),
postsWithFiles: (h) => [...(h || document).querySelectorAll('.postContainer:not([class*="noFile"])')] as HTMLElement[],
settingsHost: () => document.getElementById("shortcuts") as any,
catalogControlHost: () => document.getElementById("index-options") as HTMLDivElement,
getImageLink: async function*(post: HTMLElement) {
yield post.querySelector('a[target="_blank"]')?.getAttribute('href') || '';
},
getFilename: (post: HTMLElement) => {
const a = post.querySelector('a[target="_blank"]') as (HTMLAnchorElement | null);
const origlink = post.querySelector('.file-info > a[target*="_blank"]') as (HTMLAnchorElement | null);
return (origlink?.querySelector('.fnfull') || origlink)?.textContent || V4chan.getFilename(post) || '';
},
getMD5: (post: HTMLElement) => post.querySelector("img[data-md5]")?.getAttribute("data-md5") || '',
getThumbnailLink: (post: HTMLElement) => post.querySelector("img[data-md5]")?.getAttribute("src") || '',
getInfoBox: post => post.querySelector("span.file-info") || V4chan.getInfoBox(post),
getPostIdPrefix: V4chan.getPostIdPrefix,
getTextBox: V4chan.getTextBox,
getCurrentBoard: V4chan.getCurrentBoard,
getCurrentThread: V4chan.getCurrentThread,
};
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') || post,
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) {
if (location.host == "arch.b4k.co") { //get hecked
return;
}
yield post.querySelector('a[rel]')?.getAttribute('href') || '';
},
getFilename: (post: HTMLElement) => {
const opfn = post.querySelector('.post_file_filename')?.textContent;
if (opfn)
return opfn;
const a = post.querySelector('a[rel]') as (HTMLAnchorElement | null);
return a?.title || '';
},
getMD5: (post: HTMLElement) => post.querySelector("img[data-md5]")?.getAttribute("data-md5") || '',
getThumbnailLink: (post: HTMLElement) => {
const e = post.querySelector("img[data-md5]");
return e?.getAttribute("src") || e?.getAttribute("data-src") || '';
},
getInfoBox: post => post.querySelector("span.post_controls")!,
getPostIdPrefix: () => '',
getTextBox: post => post.querySelector('.text')!,
getCurrentBoard: V4chan.getCurrentBoard,
getCurrentThread: V4chan.getCurrentThread,
};
export const KChan: QueryProcessor = {
getFileThumbnail: post => post.querySelector('figure.uploadCell')!,
getPost: (post) => post.querySelector('.innerPost')!,
postsWithFiles: (h) => ([...(h || document).querySelectorAll('.postCell')] as HTMLElement[]).filter(p => p.querySelector('figure')),
settingsHost: () => document.getElementById("navOptionsSpanThread") || document.getElementById("navOptionsSpan") || document.getElementById("navOptionsSpanCatalog") as any,
catalogControlHost: () => document.getElementById("divTools") as HTMLDivElement,
getImageLink: async function*(post: HTMLElement) {
yield (post.querySelector('a.imgLink[target="_blank"]') as HTMLAnchorElement)?.href || '';
},
//(post: HTMLElement) => post.querySelector('a[target="_blank"]')?.getAttribute('href') || '',
getFilename: (post: HTMLElement) => {
const a = post.querySelector('.imgLink > img') as (HTMLImageElement | null);
if (a && a.title)
return a.title;
return a?.textContent || '';
},
getMD5: (post: HTMLElement) => '', // kohlchan doesn't compute md5s, filename look like a longer hash
getThumbnailLink: (post: HTMLElement) => post.querySelector(".imgLink > img")?.getAttribute("src") || '',
getInfoBox: post => post.querySelector("div.uploadDetails")!,
getPostIdPrefix: () => '',
getTextBox: (post) => post.querySelector('.divMessage')!,
getCurrentBoard: () => location.pathname.split('/')[1],
getCurrentThread: () => +location.pathname.split('/')[3]
};
export const getQueryProcessor = (is4chanX: boolean) => {
if (['boards.4chan.org', 'boards.4channel.org'].includes(location.host))
return is4chanX ? X4chan : V4chan;
if (['kohlchan.net', 'nocsp.kohlchan.net'].includes(location.host)) {
return KChan;
}
if (document.querySelector('meta[name="generator"]')?.getAttribute("content")?.startsWith("FoolFuuka"))
return FoolFuuka;
};
const altdomains = [
"desuarchive.org",
"archived.moe",
"archive.nyafuu.org",
"arch.b4k.co",
"archive.4plebs.org",
"archive.wakarimasen.moe",
"b4k.co",
"fireden.net",
"thebarchive.com",
"archiveofsins.com",
"kohlchan.net",
"nocsp.kohlchan.net",
];
export function supportedAltDomain(s: string) {
return altdomains.includes(s);
}
export function supportedMainDomain(s: string) {
return ['boards.4channel.org', 'boards.4chan.org'].includes(s);
}