From 5bd2d259fbe911eca30e8ccbd1d3d50cd84daca5 Mon Sep 17 00:00:00 2001 From: MrGus Date: Fri, 26 Dec 2025 00:29:16 +0100 Subject: [PATCH] Update anime/anicrush/source.js --- anime/anicrush/source.js | 70 +++++++++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/anime/anicrush/source.js b/anime/anicrush/source.js index de5d46b..1f22d4d 100644 --- a/anime/anicrush/source.js +++ b/anime/anicrush/source.js @@ -16,8 +16,17 @@ class AniCrush { } _nativeFetch(url, method, headers, body) { - const raw = Native.fetch(String(url), method || "GET", JSON.stringify(headers || {}), body == null ? "" : String(body)); - try { return JSON.parse(raw || "{}"); } catch (e) { return { ok: false, status: 0, headers: {}, body: "" }; } + const raw = Native.fetch( + String(url), + method || "GET", + JSON.stringify(headers || {}), + body == null ? "" : String(body) + ); + try { + return JSON.parse(raw || "{}"); + } catch (e) { + return { ok: false, status: 0, headers: {}, body: "" }; + } } _getText(url, headers) { @@ -27,12 +36,20 @@ class AniCrush { _getJson(url, headers) { const res = this._nativeFetch(url, "GET", headers, ""); - try { return JSON.parse(String(res.body || "{}")); } catch (e) { return {}; } + try { + return JSON.parse(String(res.body || "{}")); + } catch (e) { + return {}; + } } _postJson(url, headers, obj) { const res = this._nativeFetch(url, "POST", headers, JSON.stringify(obj || {})); - try { return JSON.parse(String(res.body || "{}")); } catch (e) { return {}; } + try { + return JSON.parse(String(res.body || "{}")); + } catch (e) { + return {}; + } } _safeStr(v) { @@ -237,6 +254,18 @@ class AniCrush { return episodes; } + _getEpisodeSourcesLink(movieId, epNumber, sv, sc) { + const linkUrl = + `${this.apiBase}/shared/v2/episode/sources?_movieId=${encodeURIComponent(movieId)}` + + `&ep=${encodeURIComponent(String(epNumber))}` + + `&sv=${encodeURIComponent(String(sv))}` + + `&sc=${encodeURIComponent(String(sc))}`; + + const json = this._getJson(linkUrl, this._headers()); + const link = (((json || {}).result || {}).link) ? String(json.result.link) : ""; + return { json, link, linkUrl }; + } + findEpisodeServer(episodeOrId, _server) { let ep = episodeOrId; if (typeof ep === "string") { try { ep = JSON.parse(ep); } catch (e) {} } @@ -259,13 +288,27 @@ class AniCrush { const serverMap = { "Southcloud-1": 4, "Southcloud-2": 1, "Southcloud-3": 6 }; const sv = serverMap[server] != null ? serverMap[server] : 4; - const linkUrl = - `${this.apiBase}/shared/v2/episode/sources?_movieId=${encodeURIComponent(id)}` + - `&ep=${encodeURIComponent(String(num))}&sv=${encodeURIComponent(String(sv))}&sc=${encodeURIComponent(subOrDub)}`; + const scCandidates = + subOrDub === "dub" + ? ["dub", "dubbed", "en", "eng", "2", "1"] + : ["sub", "jp", "0", "1"]; - const json = this._getJson(linkUrl, this._headers()); - const encryptedIframe = (((json || {}).result || {}).link) ? String(json.result.link) : ""; - if (!encryptedIframe) throw new Error("Missing encrypted iframe link"); + let encryptedIframe = ""; + let usedSc = null; + + for (let i = 0; i < scCandidates.length; i++) { + const sc = scCandidates[i]; + const r = this._getEpisodeSourcesLink(id, num, sv, sc); + if (r.link) { + encryptedIframe = r.link; + usedSc = sc; + break; + } + } + + if (!encryptedIframe) { + throw new Error(`Missing encrypted iframe link (movieId=${id} ep=${num} server=${server} sv=${sv} scTried=${scCandidates.join(",")})`); + } let decryptData = null; let requiredHeaders = null; @@ -295,7 +338,9 @@ class AniCrush { sources.find((s) => s && s.type === "hls") || sources.find((s) => s && s.type === "mp4"); - if (!streamSource || !streamSource.file) throw new Error("No valid stream file found"); + if (!streamSource || !streamSource.file) { + throw new Error(`No valid stream file found (scUsed=${usedSc || "none"})`); + } const tracks = decryptData.tracks || []; const subtitles = tracks @@ -318,7 +363,8 @@ class AniCrush { type: outType, quality: "auto", subtitles: subtitles - }] + }], + _debug: { scUsed: usedSc, sv: sv } }; }