diff --git a/api-prox/hooks/profile.ts b/api-prox/hooks/profile.ts
new file mode 100644
index 0000000..3a25e2b
--- /dev/null
+++ b/api-prox/hooks/profile.ts
@@ -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;
+}
diff --git a/api-prox/hooks/release.ts b/api-prox/hooks/release.ts
index a6866a7..f3c2e02 100644
--- a/api-prox/hooks/release.ts
+++ b/api-prox/hooks/release.ts
@@ -31,8 +31,8 @@ export async function get(data: any, url: URL) {
// пушим строки в список, что-бы было легче их объединить
const noteBuilder = [];
- if (data["release"]["note"] != null) noteBuilder.push(`${data.note}
`); // если в поле note уже что-то есть, разделяем значение и рейтинг
- noteBuilder.push(`Рейтинг Shikimori: ${shikiAnimJson.score}★
`); // добавляем рейтинг от шикимори
+ if (data["release"]["note"] != null) noteBuilder.push(`${data.release.note}
---
`); // если в поле note уже что-то есть, разделяем значение и рейтинг
+ noteBuilder.push(`Рейтинг Shikimori: ${shikiAnimJson.score}★`); // добавляем рейтинг от шикимори
data["release"]["note"] = noteBuilder.toString(); // заменяем оригинальное поле нашей строкой
data["release"]["id_shikimori"] = shikiId; // добавляем айди шикимори в ответ, потому что почему нет
diff --git a/api-prox/hooks/toggles.ts b/api-prox/hooks/toggles.ts
new file mode 100644
index 0000000..180c63f
--- /dev/null
+++ b/api-prox/hooks/toggles.ts
@@ -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;
+}
diff --git a/api-prox/index.ts b/api-prox/index.ts
index 823f219..60f53be 100644
--- a/api-prox/index.ts
+++ b/api-prox/index.ts
@@ -3,18 +3,28 @@ 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 = [];
app.get("/*path", async (req, res) => {
- const url = new URL(`${ANIXART_API}${req.url}`);
- logger.debug(`Fetching ${url.protocol}//${url.hostname}${url.pathname}`);
+ if (req.path == "/favicon.ico") return asJSON(res, {}, 404);
- const isApiV2 = url.searchParams.get("API-Version") == "v2" || false;
- if (isApiV2) {
- logger.debug(` ↳ Force API V2`);
+ 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");
}
@@ -28,7 +38,9 @@ app.get("/*path", async (req, res) => {
!apiResponse.ok ||
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(
res,
{
@@ -37,6 +49,7 @@ app.get("/*path", async (req, res) => {
request_status: apiResponse.status,
request_content_type: apiResponse.headers.get("content-type"),
},
+ reason: "Path probably doesn't exist",
},
500
);
@@ -87,6 +100,92 @@ app.get("/*path", async (req, res) => {
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 () {
logger.info(`Server listen: http://${host}:${port}`);
});
diff --git a/api-prox/shared.ts b/api-prox/shared.ts
index 8eb810a..670f2db 100644
--- a/api-prox/shared.ts
+++ b/api-prox/shared.ts
@@ -10,13 +10,13 @@ export const resHeaders = {
};
export function asJSON(res, object: any, status: number) {
- res.status(status).type("application/json");
- res.set(corsHeaders);
+ res.status(status);
+ res.set(resHeaders);
res.send(JSON.stringify(object));
}
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_HEADERS = {
"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")}`;
}
+ console(logLevel: LogLevel = "info", ...msg: any[]) {
+ if (this.levelInt[this.level] <= this.levelInt[logLevel])
+ console.log(`[${logLevel.toUpperCase()}](${this.getTime()}) -> `, ...msg);
+ }
debug(...msg: string[]) {
if (this.levelInt[this.level] <= 0)
console.log(`[DEBUG](${this.getTime()}) -> ${this.getString(...msg)}`);
@@ -64,23 +68,37 @@ export class Log {
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[]) {
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[]) {
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[]) {
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[]) {
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");
diff --git a/tsconfig.json b/tsconfig.json
index 8fdb696..46666e4 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -33,5 +33,5 @@
"**/*.tsx",
"next.config.js"
],
- "exclude": ["node_modules", "player-parsers"]
+ "exclude": ["node_modules", "player-parsers", "api-prox"]
}