mirror of
https://git.luna-app.eu/50n50/sources
synced 2026-01-12 09:28:35 +01:00
282 lines
10 KiB
JavaScript
282 lines
10 KiB
JavaScript
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;
|
|
}
|
|
|
|
|
|
|
|
|