mirror of
https://github.com/Radiquum/AniX.git
synced 2025-09-03 21:15:35 +05:00
feat/api-prox: add support for post requests, add 'sponsor' and 'toggles' hooks
This commit is contained in:
parent
6f45876240
commit
bfe932d86c
5 changed files with 216 additions and 15 deletions
18
api-prox/hooks/profile.ts
Normal file
18
api-prox/hooks/profile.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// хук включает "вечную" спонсорку, отключая рекламу после входа в профиль, в официальном приложении
|
||||||
|
|
||||||
|
export function match(path: string): boolean {
|
||||||
|
const pathRe = /^\/profile\/\d+/;
|
||||||
|
if (pathRe.test(path) || path == "/profile/info") return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function get(data: any, url: URL) {
|
||||||
|
if (data.hasOwnProperty("profile")) {
|
||||||
|
data["profile"]["is_sponsor"] = true;
|
||||||
|
data["profile"]["sponsorshipExpires"] = 2147483647;
|
||||||
|
} else {
|
||||||
|
data["is_sponsor"] = true;
|
||||||
|
data["sponsorship_expires"] = 2147483647;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
66
api-prox/hooks/toggles.ts
Normal file
66
api-prox/hooks/toggles.ts
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
// хук изменяет ответ config/toggles
|
||||||
|
|
||||||
|
export interface Toggles {
|
||||||
|
minVersionCode: number;
|
||||||
|
lastVersionCode: number;
|
||||||
|
whatsNew: string;
|
||||||
|
downloadLink: string;
|
||||||
|
minGPVersionCode: number;
|
||||||
|
lastGPVersionCode: number;
|
||||||
|
gpWhatsNew: string;
|
||||||
|
gpDownloadLink: string;
|
||||||
|
overrideGPVersion: boolean;
|
||||||
|
inAppUpdates: boolean;
|
||||||
|
inAppUpdatesImmediate: boolean;
|
||||||
|
inAppUpdatesFlexibleDelay: number;
|
||||||
|
impMessageEnabled: boolean;
|
||||||
|
impMessageText: string;
|
||||||
|
impMessageBackgroundColor: string;
|
||||||
|
impMessageTextColor: string;
|
||||||
|
impMessageLink: string;
|
||||||
|
adBannerBlockId: string;
|
||||||
|
adBannerSizeType: number;
|
||||||
|
adInterstitialBlockId: string;
|
||||||
|
adBannerDelay: number;
|
||||||
|
adInterstitialDelay: number;
|
||||||
|
kodikVideoLinksUrl: string;
|
||||||
|
kodikIframeAd: boolean;
|
||||||
|
sibnetRandUserAgent: boolean;
|
||||||
|
sibnetUserAgent: string;
|
||||||
|
torlookUrl: string;
|
||||||
|
baseUrl: string;
|
||||||
|
apiUrl: string;
|
||||||
|
apiAltUrl: string;
|
||||||
|
apiAltAvailable: boolean;
|
||||||
|
iframeEmbedUrl: string;
|
||||||
|
kodikAdIframeUrl: string;
|
||||||
|
sponsorshipPromotion: boolean;
|
||||||
|
sponsorshipText: string;
|
||||||
|
sponsorshipAvailable: boolean;
|
||||||
|
pageNoConnectionUrl: string;
|
||||||
|
snowfall: boolean;
|
||||||
|
searchBarIconUrl: string;
|
||||||
|
searchBarIconTint: string;
|
||||||
|
searchBarIconAction: string;
|
||||||
|
searchBarIconValue: string;
|
||||||
|
min_blog_create_rating_score: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function match(path: string): boolean {
|
||||||
|
if (path == "/config/toggles") return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function get(data: Toggles, url: URL) {
|
||||||
|
data.lastVersionCode = 25062200;
|
||||||
|
|
||||||
|
data.impMessageEnabled = true;
|
||||||
|
data.impMessageText = "разработчик AniX / Api-Prox-Svc";
|
||||||
|
data.impMessageLink = "https://bento.me/radiquum";
|
||||||
|
data.impMessageBackgroundColor = "ffb3d0"
|
||||||
|
data.impMessageTextColor = "ffffff"
|
||||||
|
|
||||||
|
data.apiAltAvailable = false;
|
||||||
|
data.apiAltUrl = "";
|
||||||
|
return data;
|
||||||
|
}
|
|
@ -3,18 +3,28 @@ import express from "express";
|
||||||
import fs from "fs/promises";
|
import fs from "fs/promises";
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
app.use(express.json());
|
||||||
|
app.use(express.urlencoded({ extended: true }));
|
||||||
|
|
||||||
const host = "0.0.0.0";
|
const host = "0.0.0.0";
|
||||||
const port = 7001;
|
const port = 7001;
|
||||||
|
|
||||||
const loadedHooks = [];
|
const loadedHooks = [];
|
||||||
|
|
||||||
app.get("/*path", async (req, res) => {
|
app.get("/*path", async (req, res) => {
|
||||||
const url = new URL(`${ANIXART_API}${req.url}`);
|
if (req.path == "/favicon.ico") return asJSON(res, {}, 404);
|
||||||
logger.debug(`Fetching ${url.protocol}//${url.hostname}${url.pathname}`);
|
|
||||||
|
|
||||||
const isApiV2 = url.searchParams.get("API-Version") == "v2" || false;
|
const url = new URL(`${ANIXART_API}${req.url}`);
|
||||||
if (isApiV2) {
|
logger.debug(
|
||||||
logger.debug(` ↳ Force API V2`);
|
`[${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";
|
ANIXART_HEADERS["API-Version"] = "v2";
|
||||||
url.searchParams.delete("API-Version");
|
url.searchParams.delete("API-Version");
|
||||||
}
|
}
|
||||||
|
@ -28,7 +38,9 @@ app.get("/*path", async (req, res) => {
|
||||||
!apiResponse.ok ||
|
!apiResponse.ok ||
|
||||||
apiResponse.headers.get("content-type") != "application/json"
|
apiResponse.headers.get("content-type") != "application/json"
|
||||||
) {
|
) {
|
||||||
logger.error(`Failed to fetch: ${url.protocol}//${url.hostname}${url.pathname}`)
|
logger.error(
|
||||||
|
`Failed to fetch: '${url.protocol}//${url.hostname}${url.pathname}', Path probably doesn't exist`
|
||||||
|
);
|
||||||
asJSON(
|
asJSON(
|
||||||
res,
|
res,
|
||||||
{
|
{
|
||||||
|
@ -37,6 +49,7 @@ app.get("/*path", async (req, res) => {
|
||||||
request_status: apiResponse.status,
|
request_status: apiResponse.status,
|
||||||
request_content_type: apiResponse.headers.get("content-type"),
|
request_content_type: apiResponse.headers.get("content-type"),
|
||||||
},
|
},
|
||||||
|
reason: "Path probably doesn't exist",
|
||||||
},
|
},
|
||||||
500
|
500
|
||||||
);
|
);
|
||||||
|
@ -87,6 +100,92 @@ app.get("/*path", async (req, res) => {
|
||||||
return;
|
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 = {
|
||||||
|
"User-Agent": ANIXART_HEADERS["User-Agent"],
|
||||||
|
"Content-Type": req.headers["content-type"],
|
||||||
|
};
|
||||||
|
|
||||||
|
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.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.status,
|
||||||
|
request_content_type: apiResponse.headers.get("content-type"),
|
||||||
|
},
|
||||||
|
reason: "Path probably doesn't exist",
|
||||||
|
},
|
||||||
|
500
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let data = await apiResponse.json();
|
||||||
|
|
||||||
|
asJSON(res, data, 200);
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
|
||||||
app.listen(port, host, function () {
|
app.listen(port, host, function () {
|
||||||
logger.info(`Server listen: http://${host}:${port}`);
|
logger.info(`Server listen: http://${host}:${port}`);
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,13 +10,13 @@ export const resHeaders = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export function asJSON(res, object: any, status: number) {
|
export function asJSON(res, object: any, status: number) {
|
||||||
res.status(status).type("application/json");
|
res.status(status);
|
||||||
res.set(corsHeaders);
|
res.set(resHeaders);
|
||||||
res.send(JSON.stringify(object));
|
res.send(JSON.stringify(object));
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ANIXART_UA =
|
export const ANIXART_UA =
|
||||||
"AnixartApp/8.2.1-23121216 (Android 9; SDK 28; arm64-v8a; samsung SM-G975N; en)";
|
"AnixartApp/9.0 BETA 5-25062213 (Android 9; SDK 28; arm64-v8a; samsung SM-G975N; en)";
|
||||||
export const ANIXART_API = "https://api.anixart.app";
|
export const ANIXART_API = "https://api.anixart.app";
|
||||||
export const ANIXART_HEADERS = {
|
export const ANIXART_HEADERS = {
|
||||||
"User-Agent": ANIXART_UA,
|
"User-Agent": ANIXART_UA,
|
||||||
|
@ -47,6 +47,10 @@ export class Log {
|
||||||
return `${datetime.getHours().toString().padStart(2, "0")}:${datetime.getMinutes().toString().padStart(2, "0")}:${datetime.getSeconds().toString().padStart(2, "0")}`;
|
return `${datetime.getHours().toString().padStart(2, "0")}:${datetime.getMinutes().toString().padStart(2, "0")}:${datetime.getSeconds().toString().padStart(2, "0")}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console(logLevel: LogLevel = "info", ...msg: any[]) {
|
||||||
|
if (this.levelInt[this.level] <= this.levelInt[logLevel])
|
||||||
|
console.log(`[${logLevel.toUpperCase()}](${this.getTime()}) -> `, ...msg);
|
||||||
|
}
|
||||||
debug(...msg: string[]) {
|
debug(...msg: string[]) {
|
||||||
if (this.levelInt[this.level] <= 0)
|
if (this.levelInt[this.level] <= 0)
|
||||||
console.log(`[DEBUG](${this.getTime()}) -> ${this.getString(...msg)}`);
|
console.log(`[DEBUG](${this.getTime()}) -> ${this.getString(...msg)}`);
|
||||||
|
@ -64,23 +68,37 @@ export class Log {
|
||||||
console.log(`[ERROR](${this.getTime()}) -> ${this.getString(...msg)}`);
|
console.log(`[ERROR](${this.getTime()}) -> ${this.getString(...msg)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
consoleHook(logLevel: LogLevel = "info", ...msg: any[]) {
|
||||||
|
if (this.levelInt[this.level] <= this.levelInt[logLevel])
|
||||||
|
console.log(
|
||||||
|
`[${logLevel.toUpperCase()}|HOOK](${this.getTime()}) -> `,
|
||||||
|
...msg
|
||||||
|
);
|
||||||
|
}
|
||||||
debugHook(...msg: string[]) {
|
debugHook(...msg: string[]) {
|
||||||
if (this.levelInt[this.level] <= 0)
|
if (this.levelInt[this.level] <= 0)
|
||||||
console.log(`[DEBUG|HOOK](${this.getTime()}) -> ${this.getString(...msg)}`);
|
console.log(
|
||||||
|
`[DEBUG|HOOK](${this.getTime()}) -> ${this.getString(...msg)}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
infoHook(...msg: string[]) {
|
infoHook(...msg: string[]) {
|
||||||
if (this.levelInt[this.level] <= 1)
|
if (this.levelInt[this.level] <= 1)
|
||||||
console.log(`[INFO|HOOK](${this.getTime()}) -> ${this.getString(...msg)}`);
|
console.log(
|
||||||
|
`[INFO|HOOK](${this.getTime()}) -> ${this.getString(...msg)}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
warnHook(...msg: string[]) {
|
warnHook(...msg: string[]) {
|
||||||
if (this.levelInt[this.level] <= 2)
|
if (this.levelInt[this.level] <= 2)
|
||||||
console.log(`[WARN|HOOK](${this.getTime()}) -> ${this.getString(...msg)}`);
|
console.log(
|
||||||
|
`[WARN|HOOK](${this.getTime()}) -> ${this.getString(...msg)}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
errorHook(...msg: string[]) {
|
errorHook(...msg: string[]) {
|
||||||
if (this.levelInt[this.level] <= 3)
|
if (this.levelInt[this.level] <= 3)
|
||||||
console.log(`[ERROR|HOOK](${this.getTime()}) -> ${this.getString(...msg)}`);
|
console.log(
|
||||||
|
`[ERROR|HOOK](${this.getTime()}) -> ${this.getString(...msg)}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const logger = new Log((process.env.LOG_LEVEL as LogLevel) || "info");
|
export const logger = new Log((process.env.LOG_LEVEL as LogLevel) || "info");
|
||||||
|
|
|
@ -33,5 +33,5 @@
|
||||||
"**/*.tsx",
|
"**/*.tsx",
|
||||||
"next.config.js"
|
"next.config.js"
|
||||||
],
|
],
|
||||||
"exclude": ["node_modules", "player-parsers"]
|
"exclude": ["node_modules", "player-parsers", "api-prox"]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue