From c686cfbab31c280e062e981c69307f2705373352 Mon Sep 17 00:00:00 2001 From: aka paul <50n50@noreply.localhost> Date: Sun, 4 Jan 2026 18:49:58 +0000 Subject: [PATCH] Add anicrush/anicrush.js --- anicrush/anicrush.js | 282 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 anicrush/anicrush.js diff --git a/anicrush/anicrush.js b/anicrush/anicrush.js new file mode 100644 index 0000000..c39fc0a --- /dev/null +++ b/anicrush/anicrush.js @@ -0,0 +1,282 @@ +async function searchResults(keyword) { + const results = []; + + const headers = { + "Host": "api.anicrush.to", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:146.0) Gecko/20100101 Firefox/146.0", + "Accept": "application/json, text/plain, */*", + "Accept-Language": "en-US,en;q=0.5", + "Accept-Encoding": "gzip, deflate, br, zstd", + "x-site": "anicrush", + "Origin": "https://anicrush.to", + "Connection": "keep-alive", + "Referer": "https://anicrush.to/", + "Sec-Fetch-Dest": "empty", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Site": "same-site", + "TE": "trailers" + }; + + try { + const response = await fetchv2("https://api.anicrush.to/shared/v2/movie/list?keyword=" + encodeURIComponent(keyword) + "&limit=24&page=1", headers); + const data = await response.json(); + + if (data.status && data.result && data.result.movies) { + for (const movie of data.result.movies) { + results.push({ + title: movie.name_english || movie.name, + image: getImage(movie.poster_path), + href: "/watch/" + movie.slug + "." + movie.id + }); + } + } + + return JSON.stringify(results); + } catch (err) { + return JSON.stringify([{ + title: "Error", + image: "Error", + href: "Error" + }]); + } +} + +async function extractDetails(url) { + const id = url.split('.').pop(); + + const headers = { + "Host": "api.anicrush.to", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:146.0) Gecko/20100101 Firefox/146.0", + "Accept": "application/json, text/plain, */*", + "Accept-Language": "en-US,en;q=0.5", + "Accept-Encoding": "gzip, deflate, br, zstd", + "x-site": "anicrush", + "Origin": "https://anicrush.to", + "Connection": "keep-alive", + "Referer": "https://anicrush.to/", + "Sec-Fetch-Dest": "empty", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Site": "same-site", + "TE": "trailers" + }; + + try { + const response = await fetchv2(`https://api.anicrush.to/shared/v2/movie/getById/${id}`, headers); + const data = await response.json(); + + if (data.status && data.result) { + const result = data.result; + const description = result.overview || "N/A"; + const aliases = result.name_synonyms || "N/A"; + const airdate = result.aired_from || "N/A"; + + return JSON.stringify([{ + description: description, + aliases: aliases, + airdate: airdate + }]); + } else { + return JSON.stringify([{ + description: "Error", + aliases: "Error", + airdate: "Error" + }]); + } + } catch (err) { + return JSON.stringify([{ + description: "Error", + aliases: "Error", + airdate: "Error" + }]); + } +} + +async function extractEpisodes(url) { + const results = []; + const id = url.split('.').pop(); + + const headers = { + "Host": "api.anicrush.to", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:146.0) Gecko/20100101 Firefox/146.0", + "Accept": "application/json, text/plain, */*", + "Accept-Language": "en-US,en;q=0.5", + "x-site": "anicrush", + "Origin": "https://anicrush.to", + "Connection": "keep-alive", + "Referer": "https://anicrush.to/", + "Sec-Fetch-Dest": "empty", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Site": "same-site", + "TE": "trailers" + }; + + try { + const url = `https://api.anicrush.to/shared/v2/episode/list?_movieId=${id}`; + + const response = await fetchv2(url, headers); + const data = await response.json(); + + if (data.status && data.result) { + const seasons = Object.keys(data.result); + for (const seasonKey of seasons) { + const season = data.result[seasonKey]; + const isMovie = seasonKey === "001 - 001"; + for (const ep of season) { + const href = isMovie ? `?_movieId=${id}&ep=1` : `?_movieId=${id}&ep=${ep.number}`; + results.push({ + href: href, + number: ep.number + }); + } + } + } + + return JSON.stringify(results); + } catch (err) { + console.error(err); + return JSON.stringify([{ id: "Error", href: "Error", number: "Error", title: "Error" }]); + } +} + +async function extractStreamUrl(ID) { + const headers = { + "Host": "api.anicrush.to", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:146.0) Gecko/20100101 Firefox/146.0", + "Accept": "application/json, text/plain, */*", + "Accept-Language": "en-US,en;q=0.5", + "x-site": "anicrush", + "Origin": "https://anicrush.to", + "Connection": "keep-alive", + "Referer": "https://anicrush.to/", + "Sec-Fetch-Dest": "empty", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Site": "same-site", + "TE": "trailers" + }; + + const headersTwo = { + "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:146.0) Gecko/20100101 Firefox/146.0", + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "Referer": "https://hianime.to/" + }; + + try { + const url = `https://api.anicrush.to/shared/v2/episode/servers${ID}`; + + const serversResp = await fetchv2(url, headers); + const serversJson = await serversResp.json(); + console.log(JSON.stringify(serversJson)); + + const subServer = serversJson.result?.sub?.[0]; + const dubServer = serversJson.result?.dub?.[0]; + const rawServer = serversJson.result?.raw?.[0]; + + const subServerId = subServer?.server; + const dubServerId = dubServer?.server; + const rawServerId = rawServer?.server; + + const processServer = async (serverId, title) => { + try { + const sourcesResp = await fetchv2(`https://api.anicrush.to/shared/v2/episode/sources${ID}&sv=${serverId}&sc=${title.toLowerCase()}`, headers); + const sourcesJson = await sourcesResp.json(); + const iframeUrl = sourcesJson.result?.link; + + if (!iframeUrl) return null; + + const iframeResp = await fetchv2(iframeUrl, headersTwo); + const iframeHtml = await iframeResp.text(); + + const videoTagMatch = iframeHtml.match(/data-id="([^"]+)"/); + if (!videoTagMatch) return null; + const fileId = videoTagMatch[1]; + + const nonceMatch = iframeHtml.match(/\b[a-zA-Z0-9]{48}\b/) || + iframeHtml.match(/\b([a-zA-Z0-9]{16})\b.*?\b([a-zA-Z0-9]{16})\b.*?\b([a-zA-Z0-9]{16})\b/); + if (!nonceMatch) return null; + + const nonce = nonceMatch.length === 4 ? + nonceMatch[1] + nonceMatch[2] + nonceMatch[3] : + nonceMatch[0]; + + const urlParts = iframeUrl.split('/'); + const protocol = iframeUrl.startsWith('https') ? 'https:' : 'http:'; + const hostname = urlParts[2]; + const defaultDomain = `${protocol}//${hostname}/`; + + const getSourcesUrl = `${defaultDomain}embed-2/v3/e-1/getSources?id=${fileId}&_k=${nonce}`; + const getSourcesResp = await fetchv2(getSourcesUrl, headersTwo); + const getSourcesJson = await getSourcesResp.json(); + const videoUrl = getSourcesJson.sources?.[0]?.file || ""; + if (!videoUrl) return null; + + const streamHeaders = { + "Referer": defaultDomain, + "User-Agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Mobile Safari/537.36" + }; + + return { + title: title, + streamUrl: videoUrl, + headers: streamHeaders, + sourcesData: getSourcesJson + }; + } catch (e) { + console.log(`${title} failed:`, e); + return null; + } + }; + + const serverPromises = []; + if (subServerId) serverPromises.push(processServer(subServerId, "SUB")); + if (dubServerId) serverPromises.push(processServer(dubServerId, "DUB")); + if (rawServerId) serverPromises.push(processServer(rawServerId, "RAW")); + + const results = await Promise.all(serverPromises); + const streams = results.filter(r => r !== null); + + if (streams.length === 0) { + return "https://error.org/"; + } + + const englishTrack = streams[0].sourcesData.tracks?.find(t => t.kind === "captions" && t.label === "English"); + const subtitle = englishTrack ? englishTrack.file : ""; + + const finalStreams = streams.map(s => ({ + title: s.title, + streamUrl: s.streamUrl, + headers: s.headers + })); + console.log(JSON.stringify({ + streams: finalStreams, + subtitle: subtitle + })); + return JSON.stringify({ + streams: finalStreams, + subtitles: subtitle + }); + } catch (err) { + console.log(err); + return "https://error.oraag/"; + } +} + +function getImage(path, type = "poster") { + const baseUrl = "https://static.gniyonna.com/media/poster"; + const hashWithExt = path.split('/')[3]; + const hash = hashWithExt.split('.')[0]; + + let reversedHash = ''; + for (let i = hash.length - 1; i >= 0; i--) { + reversedHash += hash[i]; + } + + const ext = hashWithExt.split('.').pop(); + const size = type === "poster" ? "300x400" : "900x600"; + const imageUrl = `${baseUrl}/${size}/100/${reversedHash}.${ext}`; + + return imageUrl; +} + + + +