updates and new extensions
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
class HiAnime {
|
||||
constructor() {
|
||||
this.type = "anime-board";
|
||||
this.version = "1.0"
|
||||
this.version = "1.1"
|
||||
this.baseUrl = "https://hianime.to";
|
||||
}
|
||||
|
||||
@@ -91,70 +91,74 @@ class HiAnime {
|
||||
return episodes;
|
||||
}
|
||||
|
||||
async findEpisodeServer(episode, _server) {
|
||||
const [id, subOrDub] = episode.id.split("/");
|
||||
let serverName = _server !== "default" ? _server : "HD-1";
|
||||
async findEpisodeServer(episode, _server, category = "sub") {
|
||||
const id = episode.id;
|
||||
const subOrDub = category; // backend manda sub | dub
|
||||
|
||||
if (_server === "HD-1" || _server === "HD-2" || _server === "HD-3") {
|
||||
const serverJson = await fetch(`${this.baseUrl}/ajax/v2/episode/servers?episodeId=${id}`, {
|
||||
headers: { "X-Requested-With": "XMLHttpRequest" }
|
||||
}).then(res => res.json());
|
||||
const serverName = _server !== "default" ? _server : "HD-1";
|
||||
|
||||
if (serverName === "HD-1" || serverName === "HD-2" || serverName === "HD-3") {
|
||||
const serverJson = await fetch(
|
||||
`${this.baseUrl}/ajax/v2/episode/servers?episodeId=${id}`,
|
||||
{ headers: { "X-Requested-With": "XMLHttpRequest" } }
|
||||
).then(res => res.json());
|
||||
|
||||
const serverHtml = serverJson.html;
|
||||
|
||||
const regex = new RegExp(
|
||||
`<div[^>]*class="item server-item"[^>]*data-type="${subOrDub}"[^>]*data-id="(\\d+)"[^>]*>\\s*<a[^>]*>\\s*${serverName}\\s*</a>`,
|
||||
"i"
|
||||
);
|
||||
|
||||
const match = regex.exec(serverHtml);
|
||||
if (!match) throw new Error(`Server "${serverName}" (${subOrDub}) not found`);
|
||||
if (!match)
|
||||
throw new Error(`Server "${serverName}" (${subOrDub}) not found`);
|
||||
|
||||
const serverId = match[1];
|
||||
|
||||
const sourcesJson = await fetch(`${this.baseUrl}/ajax/v2/episode/sources?id=${serverId}`, {
|
||||
headers: { "X-Requested-With": "XMLHttpRequest" }
|
||||
}).then(res => res.json());
|
||||
const sourcesJson = await fetch(
|
||||
`${this.baseUrl}/ajax/v2/episode/sources?id=${serverId}`,
|
||||
{ headers: { "X-Requested-With": "XMLHttpRequest" } }
|
||||
).then(res => res.json());
|
||||
|
||||
let decryptData = null;
|
||||
let decryptData;
|
||||
let requiredHeaders = {};
|
||||
|
||||
try {
|
||||
// Pass true to get headers back
|
||||
decryptData = await this.extractMegaCloud(sourcesJson.link, true);
|
||||
if (decryptData && decryptData.headersProvided) {
|
||||
if (decryptData?.headersProvided) {
|
||||
requiredHeaders = decryptData.headersProvided;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn("Primary decrypter failed:", err);
|
||||
} catch (e) {
|
||||
console.warn("Primary decrypter failed:", e);
|
||||
}
|
||||
|
||||
if (!decryptData) {
|
||||
console.warn("Primary decrypter failed — trying ShadeOfChaos fallback...");
|
||||
const fallbackRes = await fetch(
|
||||
`https://ac-api.ofchaos.com/api/anime/embed/convert/v2?embedUrl=${encodeURIComponent(sourcesJson.link)}`
|
||||
);
|
||||
decryptData = await fallbackRes.json();
|
||||
|
||||
// CRITICAL: Fallback headers must mimic the browser behavior expected by the provider
|
||||
// These MUST be used by a server-side proxy; the browser player cannot set them.
|
||||
|
||||
requiredHeaders = {
|
||||
"Referer": "https://megacloud.club/",
|
||||
"Origin": "https://megacloud.club",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
|
||||
"X-Requested-With": "XMLHttpRequest"
|
||||
Referer: "https://megacloud.club/",
|
||||
Origin: "https://megacloud.club",
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
};
|
||||
}
|
||||
|
||||
const streamSource =
|
||||
decryptData.sources.find((s) => s.type === "hls") ||
|
||||
decryptData.sources.find((s) => s.type === "mp4");
|
||||
decryptData.sources.find(s => s.type === "hls") ||
|
||||
decryptData.sources.find(s => s.type === "mp4");
|
||||
|
||||
if (!streamSource?.file) throw new Error("No valid stream file found");
|
||||
if (!streamSource?.file)
|
||||
throw new Error("No valid stream file found");
|
||||
|
||||
const subtitles = (decryptData.tracks || [])
|
||||
.filter((t) => t.kind === "captions")
|
||||
.map((track, index) => ({
|
||||
id: `sub-${index}`,
|
||||
.filter(t => t.kind === "captions")
|
||||
.map((track, i) => ({
|
||||
id: `sub-${i}`,
|
||||
language: track.label || "Unknown",
|
||||
url: track.file,
|
||||
isDefault: !!track.default,
|
||||
@@ -163,18 +167,23 @@ class HiAnime {
|
||||
return {
|
||||
server: serverName,
|
||||
headers: requiredHeaders,
|
||||
videoSources: [{
|
||||
url: streamSource.file,
|
||||
type: streamSource.type === "hls" ? "m3u8" : "mp4",
|
||||
quality: "auto",
|
||||
subtitles
|
||||
}]
|
||||
videoSources: [
|
||||
{
|
||||
url: streamSource.file,
|
||||
type: streamSource.type === "hls" ? "m3u8" : "mp4",
|
||||
quality: "auto",
|
||||
subtitles,
|
||||
subOrDub: category,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
else if (_server === "HD-4") {
|
||||
// Implementation for HD-4 if needed
|
||||
return null;
|
||||
|
||||
if (serverName === "HD-4") {
|
||||
throw new Error("HD-4 not implemented");
|
||||
}
|
||||
|
||||
throw new Error(`Unknown server ${serverName}`);
|
||||
}
|
||||
|
||||
safeString(str) {
|
||||
|
||||
Reference in New Issue
Block a user