mirror of
https://github.com/Radiquum/AniX.git
synced 2025-09-06 06:23:53 +05:00
feat: rewrite player parsing to js and add it them to repo
This commit is contained in:
parent
743f756920
commit
990b3c1736
9 changed files with 1275 additions and 34 deletions
|
@ -1,5 +1,5 @@
|
||||||
# пример заполнения: example.com
|
# пример заполнения: https://example.com, http://0.0.0.0:80
|
||||||
NEXT_PUBLIC_KODIK_PARSER_DOMAIN= # Домен парсера кодика, требуется для просмотра с данного источника
|
NEXT_PUBLIC_KODIK_PARSER_URL= # Домен парсера кодика, требуется для просмотра с данного источника
|
||||||
NEXT_PUBLIC_ANILIBRIA_PARSER_DOMAIN= # Домен парсера анилибрии, если не заполнено, используется официальное апи
|
NEXT_PUBLIC_ANILIBRIA_PARSER_URL= # Домен парсера анилибрии, если не заполнено, используется официальное апи
|
||||||
NEXT_PUBLIC_SIBNET_PARSER_DOMAIN= # Домен парсера сибнет, требуется для просмотра с данного источника
|
NEXT_PUBLIC_SIBNET_PARSER_URL= # Домен парсера сибнет, требуется для просмотра с данного источника
|
||||||
# ---
|
# ---
|
|
@ -75,16 +75,16 @@ export const _fetchKodikManifest = async (
|
||||||
setPlayerError: (state) => void
|
setPlayerError: (state) => void
|
||||||
) => {
|
) => {
|
||||||
// Fetch episode links via edge function
|
// Fetch episode links via edge function
|
||||||
if (!process.env.NEXT_PUBLIC_KODIK_PARSER_DOMAIN) {
|
if (!process.env.NEXT_PUBLIC_KODIK_PARSER_URL) {
|
||||||
setPlayerError({
|
setPlayerError({
|
||||||
message: "Источник не настроен",
|
message: "Источник не настроен",
|
||||||
detail: "переменная 'NEXT_PUBLIC_KODIK_PARSER_DOMAIN' не обнаружена",
|
detail: "переменная 'NEXT_PUBLIC_KODIK_PARSER_URL' не обнаружена",
|
||||||
});
|
});
|
||||||
return { manifest: null, poster: null };
|
return { manifest: null, poster: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await _fetchPlayer(
|
const data = await _fetchPlayer(
|
||||||
`https://${process.env.NEXT_PUBLIC_KODIK_PARSER_DOMAIN}/?url=${url}&player=kodik`,
|
`${process.env.NEXT_PUBLIC_KODIK_PARSER_URL}/?url=${url}&player=kodik`,
|
||||||
setPlayerError
|
setPlayerError
|
||||||
);
|
);
|
||||||
if (data) {
|
if (data) {
|
||||||
|
@ -213,9 +213,9 @@ export const _fetchAnilibriaManifest = async (
|
||||||
const epid = url.split("?id=")[1].split("&ep=")[1];
|
const epid = url.split("?id=")[1].split("&ep=")[1];
|
||||||
const _url = `https://api.anilibria.tv/v3/title?id=${id}`;
|
const _url = `https://api.anilibria.tv/v3/title?id=${id}`;
|
||||||
let data = null;
|
let data = null;
|
||||||
if (process.env.NEXT_PUBLIC_ANILIBRIA_PARSER_DOMAIN) {
|
if (process.env.NEXT_PUBLIC_ANILIBRIA_PARSER_URL) {
|
||||||
data = await _fetchPlayer(
|
data = await _fetchPlayer(
|
||||||
`https://${process.env.NEXT_PUBLIC_ANILIBRIA_PARSER_DOMAIN}/?url=${_url}&player=libria`,
|
`${process.env.NEXT_PUBLIC_ANILIBRIA_PARSER_URL}/?url=${_url}&player=libria`,
|
||||||
setPlayerError
|
setPlayerError
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -243,15 +243,15 @@ export const _fetchSibnetManifest = async (
|
||||||
setPlayerError: (state) => void
|
setPlayerError: (state) => void
|
||||||
) => {
|
) => {
|
||||||
// Fetch data via cloud endpoint
|
// Fetch data via cloud endpoint
|
||||||
if (!process.env.NEXT_PUBLIC_SIBNET_PARSER_DOMAIN) {
|
if (!process.env.NEXT_PUBLIC_SIBNET_PARSER_URL) {
|
||||||
setPlayerError({
|
setPlayerError({
|
||||||
message: "Источник не настроен",
|
message: "Источник не настроен",
|
||||||
detail: "переменная 'NEXT_PUBLIC_SIBNET_PARSER_DOMAIN' не обнаружена",
|
detail: "переменная 'NEXT_PUBLIC_SIBNET_PARSER_URL' не обнаружена",
|
||||||
});
|
});
|
||||||
return { manifest: null, poster: null };
|
return { manifest: null, poster: null };
|
||||||
}
|
}
|
||||||
const data = await _fetchPlayer(
|
const data = await _fetchPlayer(
|
||||||
`https://${process.env.NEXT_PUBLIC_SIBNET_PARSER_DOMAIN}/?url=${url}`,
|
`${process.env.NEXT_PUBLIC_SIBNET_PARSER_URL}/?url=${url}&player=sibnet`,
|
||||||
setPlayerError
|
setPlayerError
|
||||||
);
|
);
|
||||||
if (data) {
|
if (data) {
|
||||||
|
|
1034
package-lock.json
generated
1034
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -12,6 +12,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"apexcharts": "^3.52.0",
|
"apexcharts": "^3.52.0",
|
||||||
"deepmerge-ts": "^7.1.0",
|
"deepmerge-ts": "^7.1.0",
|
||||||
|
"express": "^5.1.0",
|
||||||
"flowbite": "^2.4.1",
|
"flowbite": "^2.4.1",
|
||||||
"flowbite-react": "^0.11.7",
|
"flowbite-react": "^0.11.7",
|
||||||
"hls-video-element": "^1.5.0",
|
"hls-video-element": "^1.5.0",
|
||||||
|
@ -25,6 +26,7 @@
|
||||||
"react-toastify": "^11.0.5",
|
"react-toastify": "^11.0.5",
|
||||||
"swiper": "^11.1.4",
|
"swiper": "^11.1.4",
|
||||||
"swr": "^2.2.5",
|
"swr": "^2.2.5",
|
||||||
|
"tsx": "^4.19.4",
|
||||||
"videojs-video-element": "^1.4.1",
|
"videojs-video-element": "^1.4.1",
|
||||||
"zustand": "^4.5.4"
|
"zustand": "^4.5.4"
|
||||||
},
|
},
|
||||||
|
|
45
player-parsers/index.ts
Normal file
45
player-parsers/index.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import { asJSON } from "./shared";
|
||||||
|
import { getAnilibriaURL } from "./libria";
|
||||||
|
import { getSibnetURL } from "./sibnet";
|
||||||
|
import { getKodikURL } from "./kodik";
|
||||||
|
|
||||||
|
import express from "express";
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
const host = "0.0.0.0";
|
||||||
|
const port = 7000;
|
||||||
|
const allowedPlayers = ["kodik", "libria", "sibnet"];
|
||||||
|
|
||||||
|
app.get("/", (req, res) => {
|
||||||
|
const url = req.query.url;
|
||||||
|
const player = req.query.player;
|
||||||
|
|
||||||
|
if (!url) {
|
||||||
|
asJSON(res, { message: "no 'url' query provided" }, 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!player) {
|
||||||
|
asJSON(res, { message: "no 'player' query provided" }, 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (player) {
|
||||||
|
case "libria":
|
||||||
|
getAnilibriaURL(res, url)
|
||||||
|
return
|
||||||
|
case "sibnet":
|
||||||
|
getSibnetURL(res, url)
|
||||||
|
return
|
||||||
|
case "kodik":
|
||||||
|
getKodikURL(res, url)
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
asJSON(res, { message: `player '${player}' is not supported. choose one of: ${allowedPlayers.join(", ")}` }, 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(port, host, function () {
|
||||||
|
console.log(`Server listens http://${host}:${port}`);
|
||||||
|
});
|
95
player-parsers/kodik.ts
Normal file
95
player-parsers/kodik.ts
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
import { asJSON, randomUA } from "./shared";
|
||||||
|
const altDomains = ["kodik.info", "aniqit.com", "kodik.cc", "kodik.biz"];
|
||||||
|
|
||||||
|
export async function getKodikURL(res, url: string) {
|
||||||
|
const origDomain = url.replace("https://", "").split("/")[0];
|
||||||
|
let domain = url.replace("https://", "").split("/")[0];
|
||||||
|
|
||||||
|
if (!altDomains.includes(domain)) {
|
||||||
|
asJSON(res, { message: "Wrong url provided for player kodik" }, 400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let user_agent = randomUA();
|
||||||
|
|
||||||
|
let pageRes = await fetch(url, {
|
||||||
|
headers: {
|
||||||
|
"User-Agent": user_agent,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!pageRes.ok) {
|
||||||
|
for (let i = 0; i < altDomains.length - 1; i++) {
|
||||||
|
if (url.includes(altDomains[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
user_agent = randomUA();
|
||||||
|
const altDomain = altDomains[i];
|
||||||
|
const altUrl = url.replace(
|
||||||
|
`https://${origDomain}/`,
|
||||||
|
`https://${altDomain}/`
|
||||||
|
);
|
||||||
|
|
||||||
|
domain = altDomain;
|
||||||
|
pageRes = await fetch(altUrl, {
|
||||||
|
headers: {
|
||||||
|
"User-Agent": user_agent,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (pageRes.ok) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pageRes.ok) {
|
||||||
|
asJSON(res, { message: "KODIK: failed to load page" }, 500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageData = await pageRes.text();
|
||||||
|
const urlParamsRe = /var urlParams = .*;$/m;
|
||||||
|
const urlParamsMatch = urlParamsRe.exec(pageData);
|
||||||
|
|
||||||
|
if (!urlParamsMatch || urlParamsMatch.length == 0) {
|
||||||
|
asJSON(res, { message: `KODIK: failed to find data to parse` }, 500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const urlParamsStr = urlParamsMatch[0]
|
||||||
|
.replace("var urlParams = '", "")
|
||||||
|
.replace("';", "");
|
||||||
|
|
||||||
|
const urlStr = url.replace(`https://${origDomain}/`, "");
|
||||||
|
const type = urlStr.split("/")[0];
|
||||||
|
const id = urlStr.split("/")[1];
|
||||||
|
const hash = urlStr.split("/")[2];
|
||||||
|
|
||||||
|
const urlParams = JSON.parse(urlParamsStr);
|
||||||
|
urlParams["type"] = type;
|
||||||
|
urlParams["id"] = id;
|
||||||
|
urlParams["hash"] = hash;
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
for (const [key, value] of Object.entries(urlParams)) {
|
||||||
|
formData.append(key, value as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
const linksRes = await fetch(`https://${domain}/ftor`, {
|
||||||
|
method: "POST",
|
||||||
|
body: formData,
|
||||||
|
headers: {
|
||||||
|
"User-Agent": user_agent,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!linksRes.ok) {
|
||||||
|
asJSON(res, { message: `KODIK: failed to get links` }, 500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
asJSON(res, await linksRes.json(), 200);
|
||||||
|
return;
|
||||||
|
}
|
17
player-parsers/libria.ts
Normal file
17
player-parsers/libria.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { asJSON } from "./shared";
|
||||||
|
|
||||||
|
export async function getAnilibriaURL(res, url: string) {
|
||||||
|
|
||||||
|
if (!url.includes("anilibria")) {
|
||||||
|
asJSON(res, { message: "Wrong url provided for player libria" }, 400);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let apiRes = await fetch(url);
|
||||||
|
if (!apiRes.ok) {
|
||||||
|
asJSON(res, { message: "LIBRIA: failed to get api response" }, 500);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
asJSON(res, await apiRes.json(), 200);
|
||||||
|
return
|
||||||
|
}
|
33
player-parsers/shared.ts
Normal file
33
player-parsers/shared.ts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
export const corsHeaders = {
|
||||||
|
"Access-Control-Allow-Origin": "*",
|
||||||
|
"Access-Control-Allow-Methods": "GET,HEAD,POST,OPTIONS",
|
||||||
|
"Cache-Control": "no-cache",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const resHeaders = {
|
||||||
|
...corsHeaders,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const USERAGENTS = [
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Safari/605.1.15",
|
||||||
|
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36",
|
||||||
|
"Mozilla/5.0 (Windows NT 10.0; Windows; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36",
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8",
|
||||||
|
"Mozilla/5.0 (Windows NT 10.0; Windows; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36",
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15",
|
||||||
|
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36",
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15",
|
||||||
|
"Mozilla/5.0 (Windows NT 10.0; Windows; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36",
|
||||||
|
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36",
|
||||||
|
];
|
||||||
|
|
||||||
|
export function asJSON(res, object: any, status: number) {
|
||||||
|
res.status(status).type('application/json');
|
||||||
|
res.set(corsHeaders)
|
||||||
|
res.send(JSON.stringify(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function randomUA() {
|
||||||
|
return USERAGENTS[Math.floor(Math.random() * USERAGENTS.length - 1)]
|
||||||
|
}
|
59
player-parsers/sibnet.ts
Normal file
59
player-parsers/sibnet.ts
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import { asJSON, randomUA } from "./shared";
|
||||||
|
|
||||||
|
export async function getSibnetURL(res, url: string) {
|
||||||
|
|
||||||
|
if (!url.includes("sibnet")) {
|
||||||
|
asJSON(res, { message: "Wrong url provided for player sibnet" }, 400);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const user_agent = randomUA();
|
||||||
|
|
||||||
|
let pageRes = await fetch(url, {
|
||||||
|
headers: {
|
||||||
|
"User-Agent": user_agent,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!pageRes.ok) {
|
||||||
|
asJSON(res, { message: `SIBNET:${pageRes.status}: failed to load page` }, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const pageData = await pageRes.text();
|
||||||
|
const videoRe = /\/v\/.*?\.mp4/;
|
||||||
|
const videoMatch = videoRe.exec(pageData);
|
||||||
|
|
||||||
|
if (!videoMatch || videoMatch.length == 0) {
|
||||||
|
asJSON(res, { message: `SIBNET: failed to find data to parse` }, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const posterRe = /\/upload\/cover\/.*?\.jpg/;
|
||||||
|
const posterMatch = posterRe.exec(pageData);
|
||||||
|
|
||||||
|
const actualVideoRes = await fetch(
|
||||||
|
`https://video.sibnet.ru${videoMatch[0]}`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"User-Agent": user_agent,
|
||||||
|
Referer: url,
|
||||||
|
},
|
||||||
|
redirect: "manual",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!actualVideoRes.headers.get("location")) {
|
||||||
|
asJSON(res, { message: `SIBNET: failed to get video link` }, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const video = actualVideoRes.headers.get("location");
|
||||||
|
const poster =
|
||||||
|
posterMatch ?
|
||||||
|
posterMatch.length > 0 ?
|
||||||
|
`https://st.sibnet.ru${posterMatch[0]}`
|
||||||
|
: null
|
||||||
|
: null;
|
||||||
|
|
||||||
|
asJSON(res, { video, poster }, 200)
|
||||||
|
return
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue