mirror of
https://github.com/Radiquum/AniX.git
synced 2025-09-05 14:05:36 +05:00
271 lines
7.3 KiB
TypeScript
271 lines
7.3 KiB
TypeScript
import {
|
||
ANIXART_API,
|
||
ANIXART_HEADERS,
|
||
ANIXART_HEADERST,
|
||
asJSON,
|
||
GetHook,
|
||
LoadedHook,
|
||
logger,
|
||
PostHook,
|
||
} from "./shared";
|
||
import express from "express";
|
||
import fs from "fs/promises";
|
||
|
||
const app = express();
|
||
app.use(express.json());
|
||
app.use(express.urlencoded({ extended: true }));
|
||
|
||
const host = "0.0.0.0";
|
||
const port = 7001;
|
||
|
||
const loadedHooks: LoadedHook[] = [];
|
||
|
||
app.get("/iframe", async (req, res) => {
|
||
const url = req.query.url || null;
|
||
|
||
res.status(200);
|
||
res.set({
|
||
"Access-Control-Allow-Origin": "*",
|
||
"Access-Control-Allow-Methods": "GET,HEAD,POST,OPTIONS",
|
||
"Cache-Control": "no-cache",
|
||
"Content-Type": "text/html; charset=utf-8",
|
||
});
|
||
if (!url) {
|
||
res.send("<h1>No url query found!</h1>");
|
||
return;
|
||
}
|
||
res.send(`
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<title>Веб-плеер</title>
|
||
<meta name='viewport' content='width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=yes' />
|
||
<style>body, html {height: 100%; width: 100%; margin: 0px;padding: 0px;border: 0px;}</style>
|
||
</head>
|
||
<body>
|
||
<iframe src="${url}" width='100%' height='100%' frameborder='0' AllowFullScreen allow="autoplay"></iframe>
|
||
</body>
|
||
</html>
|
||
`);
|
||
});
|
||
|
||
app.get("/*path", async (req, res) => {
|
||
if (req.path == "/favicon.ico") return asJSON(res, {}, 404);
|
||
|
||
const url = new URL(`${ANIXART_API}${req.url}`);
|
||
logger.debug(
|
||
`[${req.method}] ${url.protocol}//${url.hostname}${url.pathname}`
|
||
);
|
||
// logger.debug(` ↳ [QUERY] ${url.searchParams.toString()}`);
|
||
|
||
if (
|
||
url.searchParams.get("API-Version") == "v2" ||
|
||
req.headers["api-version"] == "v2"
|
||
) {
|
||
// logger.debug(` ↳ Force API V2`);
|
||
ANIXART_HEADERS["Api-Version"] = "v2";
|
||
url.searchParams.delete("API-Version");
|
||
}
|
||
|
||
const apiResponse = await fetch(url.toString(), {
|
||
method: "GET",
|
||
headers: ANIXART_HEADERS,
|
||
});
|
||
|
||
if (
|
||
!apiResponse ||
|
||
!apiResponse.ok ||
|
||
apiResponse.headers.get("content-type") != "application/json"
|
||
) {
|
||
logger.error(
|
||
`Failed to fetch: '${url.protocol}//${url.hostname}${url.pathname}', Path probably doesn't exist`
|
||
);
|
||
asJSON(
|
||
res,
|
||
{
|
||
code: 99,
|
||
returned_value: {
|
||
request_status: apiResponse ? apiResponse.status : null,
|
||
request_content_type:
|
||
apiResponse ? apiResponse.headers.get("content-type") : null,
|
||
},
|
||
reason: "Path probably doesn't exist",
|
||
},
|
||
500
|
||
);
|
||
return;
|
||
}
|
||
|
||
let data = await apiResponse.json();
|
||
let hooks: string[] = [];
|
||
|
||
try {
|
||
hooks = await fs.readdir("./hooks");
|
||
} catch (err) {
|
||
logger.error("'hooks' directory not found");
|
||
}
|
||
|
||
for (let i = 0; i < hooks.length; i++) {
|
||
const name = hooks[i];
|
||
if (!name.endsWith(".ts")) continue;
|
||
if (name.includes("example")) continue;
|
||
|
||
const isHookLoaded = loadedHooks.find(
|
||
(item) => item.path == `./hooks/${name}`
|
||
);
|
||
const stat = await fs.stat(`./hooks/${name}`);
|
||
|
||
if (isHookLoaded && isHookLoaded.mtime != stat.mtime.toISOString()) {
|
||
logger.infoHook(`Updated "./hooks/${name}"`);
|
||
delete require.cache[require.resolve(`./hooks/${name}`)];
|
||
isHookLoaded.mtime = stat.mtime.toISOString();
|
||
}
|
||
|
||
const hook: GetHook = require(`./hooks/${name}`);
|
||
if (!isHookLoaded) {
|
||
logger.infoHook(`Loaded "./hooks/${name}"`);
|
||
loadedHooks.push({
|
||
path: `./hooks/${name}`,
|
||
mtime: stat.mtime.toISOString(),
|
||
});
|
||
}
|
||
|
||
if (!hook.hasOwnProperty("match") || !hook.hasOwnProperty("get")) continue;
|
||
if (!hook.match(req.path)) continue;
|
||
|
||
data = await hook.get(data, url);
|
||
}
|
||
|
||
asJSON(res, data, 200);
|
||
return;
|
||
});
|
||
|
||
app.post("/*path", async (req, res) => {
|
||
const url = new URL(`${ANIXART_API}${req.url}`);
|
||
logger.debug(
|
||
`[${req.method}] ${url.protocol}//${url.hostname}${url.pathname}`
|
||
);
|
||
// logger.debug(` ↳ [QUERY] ${url.searchParams.toString()}`);
|
||
|
||
let apiResponse: null | Response = null;
|
||
const apiHeaders: ANIXART_HEADERST = {
|
||
"User-Agent": ANIXART_HEADERS["User-Agent"],
|
||
"Content-Type": req.headers["content-type"] || "application/json",
|
||
};
|
||
|
||
if (
|
||
url.searchParams.get("API-Version") == "v2" ||
|
||
req.headers["api-version"] == "v2"
|
||
) {
|
||
// logger.debug(` ↳ Force API V2`);
|
||
apiHeaders["Api-Version"] = "v2";
|
||
url.searchParams.delete("API-Version");
|
||
}
|
||
|
||
const reqContentType =
|
||
req.headers["content-type"] ?
|
||
req.headers["content-type"].split(";")[0]
|
||
: "application/json";
|
||
switch (reqContentType) {
|
||
case "multipart/form-data":
|
||
const formData = new FormData();
|
||
for (const name in req.body) {
|
||
formData.append(name, req.body[name]);
|
||
}
|
||
apiResponse = await fetch(url.toString(), {
|
||
method: "POST",
|
||
headers: apiHeaders,
|
||
body: formData,
|
||
});
|
||
break;
|
||
case "application/x-www-form-urlencoded":
|
||
apiResponse = await fetch(url.toString(), {
|
||
method: "POST",
|
||
headers: apiHeaders,
|
||
body: new URLSearchParams(req.body),
|
||
});
|
||
break;
|
||
case "application/json":
|
||
apiResponse = await fetch(url.toString(), {
|
||
method: "POST",
|
||
headers: apiHeaders,
|
||
body: JSON.stringify(req.body),
|
||
});
|
||
break;
|
||
}
|
||
|
||
// logger.console("debug", ` ↳ [REQ BODY]`, req.body);
|
||
// logger.console("debug", ` ↳ [REQ HEADERS]`, req.headers);
|
||
// logger.console("debug", " ↳ [RES TEXT]", await apiResponse.text());
|
||
// logger.console("debug", " ↳ [RES HEADERS]", apiResponse.headers);
|
||
|
||
if (
|
||
!apiResponse ||
|
||
!apiResponse.ok ||
|
||
apiResponse.headers.get("content-type") != "application/json"
|
||
) {
|
||
logger.error(
|
||
`Failed to post: '${url.protocol}//${url.hostname}${url.pathname}', Path probably doesn't exist`
|
||
);
|
||
asJSON(
|
||
res,
|
||
{
|
||
code: 99,
|
||
returned_value: {
|
||
request_status: apiResponse ? apiResponse.status : null,
|
||
request_content_type:
|
||
apiResponse ? apiResponse.headers.get("content-type") : null,
|
||
},
|
||
reason: "Path probably doesn't exist",
|
||
},
|
||
500
|
||
);
|
||
return;
|
||
}
|
||
let data = await apiResponse.json();
|
||
let hooks: string[] = [];
|
||
|
||
try {
|
||
hooks = await fs.readdir("./hooks");
|
||
} catch (err) {
|
||
logger.error("'hooks' directory not found");
|
||
}
|
||
|
||
for (let i = 0; i < hooks.length; i++) {
|
||
const name = hooks[i];
|
||
if (!name.endsWith(".ts")) continue;
|
||
if (name.includes("example")) continue;
|
||
|
||
const isHookLoaded = loadedHooks.find(
|
||
(item) => item.path == `./hooks/${name}`
|
||
);
|
||
const stat = await fs.stat(`./hooks/${name}`);
|
||
|
||
if (isHookLoaded && isHookLoaded.mtime != stat.mtime.toISOString()) {
|
||
logger.infoHook(`Updated "./hooks/${name}"`);
|
||
delete require.cache[require.resolve(`./hooks/${name}`)];
|
||
isHookLoaded.mtime = stat.mtime.toISOString();
|
||
}
|
||
|
||
const hook: PostHook = require(`./hooks/${name}`);
|
||
if (!isHookLoaded) {
|
||
logger.infoHook(`Loaded "./hooks/${name}"`);
|
||
loadedHooks.push({
|
||
path: `./hooks/${name}`,
|
||
mtime: stat.mtime.toISOString(),
|
||
});
|
||
}
|
||
|
||
if (!hook.hasOwnProperty("match") || !hook.hasOwnProperty("post")) continue;
|
||
if (!hook.match(req.path)) continue;
|
||
|
||
data = await hook.post(data, url);
|
||
}
|
||
|
||
asJSON(res, data, 200);
|
||
return;
|
||
});
|
||
|
||
app.listen(port, host, function () {
|
||
logger.info(`Server listen: http://${host}:${port}`);
|
||
});
|