commit
6a906377a7
@ -1,10 +1,12 @@
|
||||
import { DOMWindow } from "jsdom";
|
||||
import { HandlerInput } from "./handler-input";
|
||||
import { IHandlerOutput } from "./handler.interface";
|
||||
import { EngineParseError } from "../errors/main";
|
||||
|
||||
export default async function google(
|
||||
window: DOMWindow,
|
||||
input: HandlerInput,
|
||||
): Promise<IHandlerOutput> {
|
||||
const window = input.parseDom().window;
|
||||
|
||||
const googleAnchors = [
|
||||
...window.document.querySelectorAll("a[jsname=ACyKwe]"),
|
||||
] as HTMLAnchorElement[];
|
||||
|
48
src/handlers/handler-input.ts
Normal file
48
src/handlers/handler-input.ts
Normal 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;
|
||||
}
|
||||
}
|
@ -1,25 +1,23 @@
|
||||
import { IHandlerOutput } from "./handler.interface";
|
||||
import { Engines, EngineFunction, EnginesMatch } from "../types/handlers";
|
||||
import axios from "../types/axios";
|
||||
|
||||
import { JSDOM } from "jsdom";
|
||||
import { DOMWindow } from "jsdom";
|
||||
import micromatch from "micromatch";
|
||||
|
||||
import readability from "./readability";
|
||||
import google, { GoogleDomains } from "./google";
|
||||
import stackoverflow, { StackOverflowDomains } from "./stackoverflow/main";
|
||||
|
||||
import { generateProxyUrl } from "../utils/generate";
|
||||
import isLocalResource from "../utils/islocal";
|
||||
|
||||
import micromatch from "micromatch";
|
||||
|
||||
import { LocalResourceError, NotHtmlMimetypeError } from "../errors/main";
|
||||
import { HandlerInput } from "./handler-input";
|
||||
|
||||
export default async function handlePage(
|
||||
url: string, // remote URL
|
||||
requestUrl: URL, // proxy URL
|
||||
engine?: string,
|
||||
redirect_path: string = "get",
|
||||
redirectPath: string = "get",
|
||||
): Promise<IHandlerOutput> {
|
||||
const urlObj = new URL(url);
|
||||
|
||||
@ -34,39 +32,27 @@ export default async function handlePage(
|
||||
throw new NotHtmlMimetypeError(url);
|
||||
}
|
||||
|
||||
const window = new JSDOM(response.data, { url }).window;
|
||||
|
||||
[...window.document.getElementsByTagName("a")].forEach((link) => {
|
||||
try {
|
||||
link.href = generateProxyUrl(
|
||||
requestUrl,
|
||||
link.href,
|
||||
engine,
|
||||
redirect_path,
|
||||
);
|
||||
} catch (_err) {
|
||||
// ignore TypeError: Invalid URL
|
||||
}
|
||||
});
|
||||
|
||||
if (engine) {
|
||||
return engines[engine](window);
|
||||
}
|
||||
|
||||
const title = window.document.title;
|
||||
const lang = window.document.documentElement.lang;
|
||||
|
||||
for (const match of fallback) {
|
||||
if (micromatch.isMatch(urlObj.hostname, match.pattern)) {
|
||||
return { title, lang, ...match.engine(window) };
|
||||
}
|
||||
}
|
||||
|
||||
return engines.readability(window);
|
||||
return getFallbackEngine(urlObj.hostname, engine)(
|
||||
new HandlerInput(
|
||||
response.data,
|
||||
url,
|
||||
requestUrl,
|
||||
engine,
|
||||
redirectPath,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
interface Engines {
|
||||
[key: string]: EngineFunction;
|
||||
function getFallbackEngine(host: string, specified?: string): EngineFunction {
|
||||
if (specified) {
|
||||
return engines[specified];
|
||||
}
|
||||
for (const engine of fallback) {
|
||||
if (micromatch.isMatch(host, engine.pattern)) {
|
||||
return engine.engine;
|
||||
}
|
||||
}
|
||||
return engines.readability;
|
||||
}
|
||||
|
||||
export const engines: Engines = {
|
||||
@ -75,13 +61,6 @@ export const engines: Engines = {
|
||||
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 fallback: EnginesMatch = [
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { Readability } from "@mozilla/readability";
|
||||
import { HandlerInput } from "./handler-input";
|
||||
import { IHandlerOutput } from "./handler.interface";
|
||||
import { DOMWindow } from "jsdom";
|
||||
import { EngineParseError } from "../errors/main";
|
||||
|
||||
export default async function readability(
|
||||
window: DOMWindow
|
||||
input: HandlerInput,
|
||||
): Promise<IHandlerOutput> {
|
||||
const reader = new Readability(window.document);
|
||||
const reader = new Readability(input.parseDom().window.document);
|
||||
const parsed = reader.parse();
|
||||
|
||||
if (!parsed) {
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { HandlerInput } from "../handler-input";
|
||||
import { IHandlerOutput } from "../handler.interface";
|
||||
import { DOMWindow } from "jsdom";
|
||||
import { EngineParseError } from "../../errors/main";
|
||||
import qPostsHandler from "./questions-posts";
|
||||
|
||||
export default async function stackoverflow(
|
||||
window: DOMWindow,
|
||||
input: HandlerInput,
|
||||
): 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 !== "");
|
||||
|
||||
let result: IHandlerOutput = {
|
||||
|
14
src/types/handlers.ts
Normal file
14
src/types/handlers.ts
Normal 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[];
|
Loading…
x
Reference in New Issue
Block a user