Merge pull request #46 from TxtDot/engine-upd

Engine upd
This commit is contained in:
Artemy Egorov 2023-09-13 11:29:09 +03:00 committed by GitHub
commit 6a906377a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 96 additions and 52 deletions

View File

@ -1,10 +1,12 @@
import { DOMWindow } from "jsdom"; import { HandlerInput } from "./handler-input";
import { IHandlerOutput } from "./handler.interface"; import { IHandlerOutput } from "./handler.interface";
import { EngineParseError } from "../errors/main"; import { EngineParseError } from "../errors/main";
export default async function google( export default async function google(
window: DOMWindow, input: HandlerInput,
): Promise<IHandlerOutput> { ): Promise<IHandlerOutput> {
const window = input.parseDom().window;
const googleAnchors = [ const googleAnchors = [
...window.document.querySelectorAll("a[jsname=ACyKwe]"), ...window.document.querySelectorAll("a[jsname=ACyKwe]"),
] as HTMLAnchorElement[]; ] as HTMLAnchorElement[];

View File

@ -0,0 +1,48 @@
import { JSDOM } from "jsdom";
import { generateProxyUrl } from "../utils/generate";
export class HandlerInput {
private data: string;
private url: string;
private requestUrl: URL;
private engine?: string;
private redirectPath: string;
constructor(
data: string,
url: string,
requestUrl: URL,
engine?: string,
redirectPath: string = "get",
) {
this.data = data;
this.url = url;
this.requestUrl = requestUrl;
this.engine = engine;
this.redirectPath = redirectPath;
}
parseDom(): JSDOM {
const dom = new JSDOM(this.data, { url: this.url });
const links = dom.window.document.getElementsByTagName("a");
for (const link of links) {
try {
link.href = generateProxyUrl(
this.requestUrl,
link.href,
this.engine,
this.redirectPath,
);
} catch (_err) {
// ignore TypeError: Invalid URL
}
}
return dom;
}
getUrl(): string {
return this.url;
}
}

View File

@ -1,25 +1,23 @@
import { IHandlerOutput } from "./handler.interface"; import { IHandlerOutput } from "./handler.interface";
import { Engines, EngineFunction, EnginesMatch } from "../types/handlers";
import axios from "../types/axios"; import axios from "../types/axios";
import { JSDOM } from "jsdom"; import micromatch from "micromatch";
import { DOMWindow } from "jsdom";
import readability from "./readability"; import readability from "./readability";
import google, { GoogleDomains } from "./google"; import google, { GoogleDomains } from "./google";
import stackoverflow, { StackOverflowDomains } from "./stackoverflow/main"; import stackoverflow, { StackOverflowDomains } from "./stackoverflow/main";
import { generateProxyUrl } from "../utils/generate";
import isLocalResource from "../utils/islocal"; import isLocalResource from "../utils/islocal";
import micromatch from "micromatch";
import { LocalResourceError, NotHtmlMimetypeError } from "../errors/main"; import { LocalResourceError, NotHtmlMimetypeError } from "../errors/main";
import { HandlerInput } from "./handler-input";
export default async function handlePage( export default async function handlePage(
url: string, // remote URL url: string, // remote URL
requestUrl: URL, // proxy URL requestUrl: URL, // proxy URL
engine?: string, engine?: string,
redirect_path: string = "get", redirectPath: string = "get",
): Promise<IHandlerOutput> { ): Promise<IHandlerOutput> {
const urlObj = new URL(url); const urlObj = new URL(url);
@ -34,39 +32,27 @@ export default async function handlePage(
throw new NotHtmlMimetypeError(url); throw new NotHtmlMimetypeError(url);
} }
const window = new JSDOM(response.data, { url }).window; return getFallbackEngine(urlObj.hostname, engine)(
new HandlerInput(
[...window.document.getElementsByTagName("a")].forEach((link) => { response.data,
try { url,
link.href = generateProxyUrl(
requestUrl, requestUrl,
link.href,
engine, engine,
redirect_path, redirectPath,
)
); );
} catch (_err) {
// ignore TypeError: Invalid URL
}
});
if (engine) {
return engines[engine](window);
} }
const title = window.document.title; function getFallbackEngine(host: string, specified?: string): EngineFunction {
const lang = window.document.documentElement.lang; if (specified) {
return engines[specified];
for (const match of fallback) { }
if (micromatch.isMatch(urlObj.hostname, match.pattern)) { for (const engine of fallback) {
return { title, lang, ...match.engine(window) }; if (micromatch.isMatch(host, engine.pattern)) {
return engine.engine;
} }
} }
return engines.readability;
return engines.readability(window);
}
interface Engines {
[key: string]: EngineFunction;
} }
export const engines: Engines = { export const engines: Engines = {
@ -75,13 +61,6 @@ export const engines: Engines = {
stackoverflow, stackoverflow,
}; };
type EngineFunction = (window: DOMWindow) => Promise<IHandlerOutput>;
export type EngineMatch = {
pattern: string | string[];
engine: EngineFunction;
};
export type EnginesMatch = EngineMatch[];
export const engineList: string[] = Object.keys(engines); export const engineList: string[] = Object.keys(engines);
export const fallback: EnginesMatch = [ export const fallback: EnginesMatch = [

View File

@ -1,12 +1,12 @@
import { Readability } from "@mozilla/readability"; import { Readability } from "@mozilla/readability";
import { HandlerInput } from "./handler-input";
import { IHandlerOutput } from "./handler.interface"; import { IHandlerOutput } from "./handler.interface";
import { DOMWindow } from "jsdom";
import { EngineParseError } from "../errors/main"; import { EngineParseError } from "../errors/main";
export default async function readability( export default async function readability(
window: DOMWindow input: HandlerInput,
): Promise<IHandlerOutput> { ): Promise<IHandlerOutput> {
const reader = new Readability(window.document); const reader = new Readability(input.parseDom().window.document);
const parsed = reader.parse(); const parsed = reader.parse();
if (!parsed) { if (!parsed) {

View File

@ -1,13 +1,14 @@
import { HandlerInput } from "../handler-input";
import { IHandlerOutput } from "../handler.interface"; import { IHandlerOutput } from "../handler.interface";
import { DOMWindow } from "jsdom";
import { EngineParseError } from "../../errors/main"; import { EngineParseError } from "../../errors/main";
import qPostsHandler from "./questions-posts"; import qPostsHandler from "./questions-posts";
export default async function stackoverflow( export default async function stackoverflow(
window: DOMWindow, input: HandlerInput,
): Promise<IHandlerOutput> { ): Promise<IHandlerOutput> {
const url = new URL(window.location.href); const window = input.parseDom().window;
const url = new URL(window.location.href);
const path = url.pathname.split("/").filter((p) => p !== ""); const path = url.pathname.split("/").filter((p) => p !== "");
let result: IHandlerOutput = { let result: IHandlerOutput = {

14
src/types/handlers.ts Normal file
View File

@ -0,0 +1,14 @@
import { HandlerInput } from "../handlers/handler-input";
import { IHandlerOutput } from "../handlers/handler.interface";
export interface Engines {
[key: string]: EngineFunction;
}
export type EngineMatch = {
pattern: string | string[];
engine: EngineFunction;
};
export type EngineFunction = (input: HandlerInput) => Promise<IHandlerOutput>;
export type EnginesMatch = EngineMatch[];