Add anicrush/anicrush.js

This commit is contained in:
aka paul 2026-01-04 18:49:58 +00:00
parent a32c786156
commit c686cfbab3

282
anicrush/anicrush.js Normal file
View file

@ -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;
}