]*class="item\\s+server-item"[^>]*data-type="${esc(wantTrack)}"[^>]*data-id="(\\d+)"[^>]*>[\\s\\S]*?
]*>[\\s\\S]*?${esc(serverName)}[\\s\\S]*?<\\/a>`,
+ const escapedServer = server.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
+ const reExact = new RegExp(
+ `class="item server-item"[^>]*data-type="${subOrDub}"[^>]*data-id="([^"]+)"[^>]*>[\\s\\S]*?>\\s*${escapedServer}\\s*<`,
"i"
);
+ const mmExact = reExact.exec(html);
- let mm = strictRe.exec(serverHtml);
- let serverId = mm ? String(mm[1] || "").trim() : "";
+ let serverId = mmExact ? String(mmExact[1] || "").trim() : "";
if (!serverId) {
- const trackAnyRe = new RegExp(
- `]*class="item\\s+server-item"[^>]*data-type="${esc(wantTrack)}"[^>]*data-id="(\\d+)"`,
+ const reFirst = new RegExp(
+ `class="item server-item"[^>]*data-type="${subOrDub}"[^>]*data-id="([^"]+)"`,
"i"
);
- mm = trackAnyRe.exec(serverHtml);
- serverId = mm ? String(mm[1] || "").trim() : "";
+ const mmFirst = reFirst.exec(html);
+ if (mmFirst) serverId = String(mmFirst[1] || "").trim();
}
- if (!serverId) throw new Error(`No server id found for track=${wantTrack}`);
+ if (!serverId) throw new Error(`No server id found for track=${subOrDub}`);
const sourcesJson = this._getJson(
`${this.baseUrl}/ajax/v2/episode/sources?id=${encodeURIComponent(serverId)}`,
- { "X-Requested-With": "XMLHttpRequest" }
+ this._headersJson()
);
const embed = (sourcesJson && sourcesJson.link) ? String(sourcesJson.link) : "";
@@ -332,7 +481,7 @@ class HiAnime {
const sources = Array.isArray(decryptData.sources) ? decryptData.sources : [];
const tracks = Array.isArray(decryptData.tracks) ? decryptData.tracks : [];
- let streamSource =
+ const streamSource =
sources.find((s) => s && s.type === "hls" && s.file) ||
sources.find((s) => s && s.type === "mp4" && s.file) ||
sources.find((s) => s && s.file);
@@ -341,23 +490,27 @@ class HiAnime {
const subtitles = tracks
.filter((t) => t && String(t.kind || "").toLowerCase() === "captions" && t.file)
- .map((t, idx) => ({
- id: `sub-${idx}`,
- language: this._decodeHtml(t.label || "Unknown"),
+ .map((t, index) => ({
+ id: `sub-${index}`,
+ language: String(t.label || "Unknown"),
url: String(t.file),
isDefault: !!t.default
}));
- return JSON.stringify({
- server: serverName,
+ const out = {
+ server: server,
headers: requiredHeaders,
- videoSources: [{
- url: String(streamSource.file),
- type: (String(streamSource.type || "").toLowerCase() === "hls" || String(streamSource.file).includes(".m3u8")) ? "m3u8" : "mp4",
- quality: "auto",
- subtitles
- }]
- });
+ videoSources: [
+ {
+ url: String(streamSource.file),
+ type: String(streamSource.type || "").toLowerCase() === "hls" ? "m3u8" : "mp4",
+ quality: "auto",
+ subtitles: subtitles
+ }
+ ]
+ };
+
+ return JSON.stringify(out);
}
extractMegaCloudSync(embedUrl) {
@@ -369,10 +522,10 @@ class HiAnime {
"X-Requested-With": "XMLHttpRequest",
"Referer": baseDomain,
"Origin": `${url.protocol}//${url.host}`,
- "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"
+ "User-Agent": "Mozilla/5.0"
};
- const html = this._getText(embedUrl, headers);
+ const html = this._getText(String(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");
@@ -381,12 +534,14 @@ class HiAnime {
let nonce = null;
const match48 = html.match(/\b[a-zA-Z0-9]{48}\b/);
if (match48) nonce = match48[0];
- else {
- const match3x16 = Array.from(html.matchAll(/["']([A-Za-z0-9]{16})["']/g));
+
+ 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(
@@ -395,7 +550,7 @@ class HiAnime {
);
return {
- sources: sourcesJson.sources,
+ sources: sourcesJson.sources || [],
tracks: sourcesJson.tracks || [],
intro: sourcesJson.intro || null,
outro: sourcesJson.outro || null,
@@ -405,4 +560,4 @@ class HiAnime {
}
}
-module.exports = new HiAnime();
+module.exports = HiAnime;