]*class="item server-item"[^>]*data-type="${subOrDub}"[^>]*data-id="(\\d+)"[^>]*>\\s*
]*class="item server-item"[^>]*data-type="${subOrDub}"[^>]*data-id="(\\\\d+)"[^>]*>\\\\s*
]*>\\\\s*${serverName}\\\\s*`,
"i"
);
-
const match = regex.exec(serverHtml);
if (!match) throw new Error(`Server "${serverName}" (${subOrDub}) not found`);
const serverId = match[1];
- const sourcesJson = this._getJson(
- `${this.baseUrl}/ajax/v2/episode/sources?id=${serverId}`,
+ const sourcesJson = await this._getJson(
+ `${this.baseUrl}/ajax/v2/episode/sources?id=${encodeURIComponent(serverId)}`,
{ "X-Requested-With": "XMLHttpRequest" }
);
+ const embed = (sourcesJson && sourcesJson.link) ? String(sourcesJson.link) : "";
+ if (!embed) throw new Error("No embed link returned");
+
let decryptData = null;
let requiredHeaders = {};
try {
- decryptData = this.extractMegaCloudSync(sourcesJson.link);
- requiredHeaders = decryptData.headersProvided || {};
- } catch (e) {}
+ decryptData = await this.extractMegaCloud(embed);
+ requiredHeaders = (decryptData && decryptData.headersProvided) ? decryptData.headersProvided : {};
+ } catch (e) {
+ decryptData = null;
+ }
if (!decryptData) {
- decryptData = this._getJson(
- `https://ac-api.ofchaos.com/api/anime/embed/convert/v2?embedUrl=${encodeURIComponent(sourcesJson.link)}`,
+ decryptData = await this._getJson(
+ `https://ac-api.ofchaos.com/api/anime/embed/convert/v2?embedUrl=${encodeURIComponent(embed)}`,
{}
);
requiredHeaders = {
@@ -169,27 +330,31 @@ class HiAnime {
};
}
- const sources = decryptData.sources || [];
+ const sources = (decryptData && decryptData.sources) ? decryptData.sources : [];
const streamSource =
- sources.find((s) => s.type === "hls") || sources.find((s) => s.type === "mp4");
+ sources.find((s) => s && s.type === "hls" && s.file) ||
+ sources.find((s) => s && s.type === "mp4" && s.file) ||
+ sources.find((s) => s && s.file);
+
if (!streamSource || !streamSource.file) throw new Error("No valid stream file found");
- const subtitles = (decryptData.tracks || [])
- .filter((t) => t.kind === "captions")
+ const tracks = (decryptData && (decryptData.tracks || decryptData.track || decryptData.subtitle)) || [];
+ const subtitles = (tracks || [])
+ .filter((t) => t && String(t.kind || "").toLowerCase() === "captions" && t.file)
.map((track, index) => ({
id: `sub-${index}`,
- language: track.label || "Unknown",
- url: track.file,
+ language: String(track.label || "Unknown"),
+ url: String(track.file),
isDefault: !!track.default
}));
return {
server: serverName,
- headers: requiredHeaders,
+ headers: requiredHeaders || {},
videoSources: [
{
- url: streamSource.file,
- type: streamSource.type === "hls" ? "m3u8" : "mp4",
+ url: String(streamSource.file),
+ type: String(streamSource.type || "").toLowerCase() === "hls" ? "m3u8" : "mp4",
quality: "auto",
subtitles
}
@@ -197,13 +362,10 @@ class HiAnime {
};
}
- extractMegaCloudSync(embedUrl) {
- const s = String(embedUrl);
- const mm = s.match(/^(https?):\/\/([^\/]+)(\/.*)?$/i);
- if (!mm) throw new Error("Invalid embedUrl: " + s);
-
- const protocol = mm[1].toLowerCase();
- const host = mm[2];
+ async extractMegaCloud(embedUrl) {
+ const u = new URL(String(embedUrl));
+ const protocol = String(u.protocol || "https:").replace(":", "");
+ const host = String(u.host || "");
const baseDomain = `${protocol}://${host}/`;
const headers = {
@@ -215,23 +377,26 @@ class HiAnime {
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36"
};
- const html = this._getText(embedUrl, headers);
+ const html = await this._getText(embedUrl, headers);
const fileIdMatch = html.match(/
\s*File\s+#([a-zA-Z0-9]+)\s*-/i);
if (!fileIdMatch) throw new Error("file_id not found in embed page");
const fileId = fileIdMatch[1];
let nonce = null;
+
const match48 = html.match(/\b[a-zA-Z0-9]{48}\b/);
if (match48) nonce = match48[0];
- else {
+
+ if (!nonce) {
const match3x16 = [...html.matchAll(/["']([A-Za-z0-9]{16})["']/g)];
if (match3x16.length >= 3) nonce = match3x16[0][1] + match3x16[1][1] + match3x16[2][1];
}
+
if (!nonce) throw new Error("nonce not found");
- const sourcesJson = this._getJson(
- `${baseDomain}embed-2/v3/e-1/getSources?id=${fileId}&_k=${nonce}`,
+ const sourcesJson = await this._getJson(
+ `${baseDomain}embed-2/v3/e-1/getSources?id=${encodeURIComponent(fileId)}&_k=${encodeURIComponent(nonce)}`,
headers
);