Browse Source

Add "load balancing" ;^)

pull/46/head
coomdev 2 years ago
parent
commit
ee6b0739fb
  1. 2
      main.meta.js
  2. 76
      main.user.js
  3. 57
      src/main.ts
  4. 25
      src/websites/index.ts

2
main.meta.js

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

76
main.user.js

@ -1,7 +1,7 @@
// ==UserScript==
// @name PNGExtraEmbed
// @namespace https://coom.tech/
// @version 0.205
// @version 0.206
// @description uhh
// @author You
// @match https://boards.4channel.org/*
@ -88,7 +88,7 @@ const _DOMParser = DOMParser;
var define_BUILD_VERSION_default;
var init_define_BUILD_VERSION = __esm({
"<define:BUILD_VERSION>"() {
define_BUILD_VERSION_default = [0, 205];
define_BUILD_VERSION_default = [0, 206];
}
});
@ -22180,7 +22180,9 @@ const _DOMParser = DOMParser;
postsWithFiles: (h) => [...(h || document).querySelectorAll(".file")].map((e) => e.closest(".postContainer")),
settingsHost: () => document.getElementById("navtopright"),
catalogControlHost: () => document.getElementById("settings"),
getImageLink: (post) => post.querySelector('a[target="_blank"]')?.getAttribute("href") || "",
getImageLink: async function* (post) {
yield post.querySelector('a[target="_blank"]')?.getAttribute("href") || "";
},
getFilename: (post) => {
const a = post.querySelector('a[target="_blank"]');
if (a && a.title)
@ -22199,7 +22201,9 @@ const _DOMParser = DOMParser;
postsWithFiles: (h) => [...(h || document).querySelectorAll('.postContainer:not([class*="noFile"])')],
settingsHost: () => document.getElementById("shortcuts"),
catalogControlHost: () => document.getElementById("index-options"),
getImageLink: (post) => post.querySelector('a[target="_blank"]')?.getAttribute("href") || "",
getImageLink: async function* (post) {
yield post.querySelector('a[target="_blank"]')?.getAttribute("href") || "";
},
getFilename: (post) => {
const a = post.querySelector('a[target="_blank"]');
const origlink = post.querySelector('.file-info > a[target*="_blank"]');
@ -22217,7 +22221,16 @@ const _DOMParser = DOMParser;
postsWithFiles: (h) => [...(h || document).querySelectorAll('article[class*="has_image"]')],
settingsHost: () => document.querySelector(".letters"),
catalogControlHost: () => document.getElementById("index-options"),
getImageLink: (post) => post.querySelector("a[rel]")?.getAttribute("href") || "",
getImageLink: async function* (post) {
yield post.querySelector("a[rel]")?.getAttribute("href") || "";
if (location.host == "arch.b4k.co") {
const pid = post.id.match(/\d+/)[0];
const board = location.pathname.match(/\/(..?.?)\//)[1];
const res = await GM_fetch(`https://archive.wakarimasen.moe/_/api/chan/post/?board=${board}&num=${pid}`);
const data = await res.json();
yield data.media.media_link;
}
},
getFilename: (post) => {
const opfn = post.querySelector("a.post_file_filename")?.textContent;
if (opfn)
@ -23249,7 +23262,7 @@ const _DOMParser = DOMParser;
appState.subscribe((v) => {
cappState = v;
});
var processImage = async (src, fn, hex, prevurl, onfound) => {
var processImage = async (srcs, fn, hex, prevurl, onfound) => {
return Promise.all(processors.filter((e) => e.match(fn)).map(async (proc) => {
if (proc.skip) {
const md5 = import_buffer11.Buffer.from(hex, "base64");
@ -23259,28 +23272,39 @@ const _DOMParser = DOMParser;
}
return;
}
const iter = streamRemote(src);
if (!iter)
return;
let cumul = import_buffer11.Buffer.alloc(0);
let found;
let chunk = { done: true };
let succ = false;
let cumul;
do {
const { value, done } = await iter.next(typeof found === "boolean");
if (done) {
chunk = { done: true };
} else {
chunk = { done: false, value };
cumul = import_buffer11.Buffer.concat([cumul, value]);
found = await proc.has_embed(cumul);
try {
const n = await srcs.next();
if (n.done)
return;
const iter = streamRemote(n.value);
if (!iter)
return;
cumul = import_buffer11.Buffer.alloc(0);
let found;
let chunk = { done: true };
do {
const { value, done } = await iter.next(typeof found === "boolean");
if (done) {
chunk = { done: true };
} else {
chunk = { done: false, value };
cumul = import_buffer11.Buffer.concat([cumul, value]);
found = await proc.has_embed(cumul);
}
} while (found !== false && !chunk.done);
succ = true;
await iter.next(true);
if (found === false) {
return;
}
onfound();
return [await proc.extract(cumul), false];
} catch {
}
} while (found !== false && !chunk.done);
await iter.next(true);
if (found === false) {
return;
}
onfound();
return [await proc.extract(cumul), false];
} while (!succ);
}));
};
var textToElement = (s) => document.createRange().createContextualFragment(s).children[0];

57
src/main.ts

@ -87,7 +87,7 @@ type EmbeddedFileWithoutPreview = {
export type EmbeddedFile = EmbeddedFileWithPreview | EmbeddedFileWithoutPreview;
const processImage = async (src: string, fn: string, hex: string, prevurl: string, onfound: () => void): Promise<([EmbeddedFile[], boolean] | undefined)[]> => {
const processImage = async (srcs: AsyncGenerator<string, void, void>, fn: string, hex: string, prevurl: string, onfound: () => void): 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
@ -98,30 +98,41 @@ const processImage = async (src: string, fn: string, hex: string, prevurl: strin
return [await proc.extract(md5, fn), true] as [EmbeddedFile[], boolean];
} return;
}
// TODO: Move this outside the loop?
const iter = streamRemote(src);
if (!iter)
return;
let cumul = Buffer.alloc(0);
let found: boolean | undefined;
let chunk: ReadableStreamDefaultReadResult<Buffer> = { done: true };
let succ = false;
let cumul: Buffer;
do {
const { value, done } = await iter.next(typeof found === "boolean");
if (done) {
chunk = { done: true } as ReadableStreamDefaultReadDoneResult;
} else {
chunk = { done: false, value } as ReadableStreamDefaultReadValueResult<Buffer>;
cumul = Buffer.concat([cumul, value!]);
found = await proc.has_embed(cumul);
try {
const n = await srcs.next();
if (n.done)
return; // no more links to try
const iter = streamRemote(n.value);
if (!iter)
return;
cumul = Buffer.alloc(0);
let found: boolean | undefined;
let chunk: ReadableStreamDefaultReadResult<Buffer> = { done: true };
do {
const { value, done } = await iter.next(typeof found === "boolean");
if (done) {
chunk = { done: true } as ReadableStreamDefaultReadDoneResult;
} else {
chunk = { done: false, value } as ReadableStreamDefaultReadValueResult<Buffer>;
cumul = Buffer.concat([cumul, value!]);
found = await proc.has_embed(cumul);
}
} while (found !== false && !chunk.done /* Because we only embed links now, it's safe to assume we get everything we need in the first chunk */);
succ = true;
await iter.next(true);
if (found === false) {
//console.log(`Gave up on ${src} after downloading ${cumul.byteLength} bytes...`);
return;
}
onfound();
return [await proc.extract(cumul), false] as [EmbeddedFile[], boolean];
} catch {
// ignore error and retry with another link
}
} while (found !== false && !chunk.done /* Because we only embed links now, it's safe to assume we get everything we need in the first chunk */);
await iter.next(true);
if (found === false) {
//console.log(`Gave up on ${src} after downloading ${cumul.byteLength} bytes...`);
return;
}
onfound();
return [await proc.extract(cumul), false] as [EmbeddedFile[], boolean];
} while (!succ);
}));
};

25
src/websites/index.ts

@ -1,10 +1,12 @@
import { GM_fetch } from "../requests";
export type QueryProcessor = {
getPost: (post: HTMLElement) => HTMLElement;
getFileThumbnail: (post: HTMLElement) => HTMLElement;
postsWithFiles: (host?: HTMLElement) => HTMLElement[];
settingsHost: () => HTMLSpanElement;
catalogControlHost: () => HTMLDivElement;
getImageLink: (post: HTMLElement) => string;
getImageLink:(post: HTMLElement) => AsyncGenerator<string, void, void>;
getThumbnailLink: (post: HTMLElement) => string;
getFilename: (post: HTMLElement) => string;
getMD5: (post: HTMLElement) => string;
@ -19,7 +21,11 @@ export const V4chan: QueryProcessor = {
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: (post: HTMLElement) => post.querySelector('a[target="_blank"]')?.getAttribute('href') || '',
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)
@ -39,7 +45,9 @@ export const X4chan: QueryProcessor = {
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: (post: HTMLElement) => post.querySelector('a[target="_blank"]')?.getAttribute('href') || '',
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;
@ -58,7 +66,16 @@ export const FoolFuuka: QueryProcessor = {
postsWithFiles: (h) => [...(h || document).querySelectorAll('article[class*="has_image"]')] as HTMLElement[],
settingsHost: () => document.querySelector(".letters") as any,
catalogControlHost: () => document.getElementById("index-options") as HTMLDivElement,
getImageLink: (post: HTMLElement) => post.querySelector('a[rel]')?.getAttribute('href') || '',
getImageLink: async function *(post: HTMLElement) {
yield post.querySelector('a[rel]')?.getAttribute('href') || '';
if (location.host == "arch.b4k.co") { //get fucked
const pid = post.id.match(/\d+/)![0];
const board = location.pathname.match(/\/(..?.?)\//)![1];
const res = await GM_fetch(`https://archive.wakarimasen.moe/_/api/chan/post/?board=${board}&num=${pid}`);
const data = await res.json();
yield data.media.media_link;
}
},
getFilename: (post: HTMLElement) => {
const opfn = post.querySelector('a.post_file_filename')?.textContent;
if (opfn)

Loading…
Cancel
Save