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) { if (movie.has_sub) { results.push({ title: (movie.name_english || movie.name) + " [SUB]", image: getImage(movie.poster_path), href: "/watch/" + movie.slug + "." + movie.id + "?type=SUB" }); } if (movie.has_dub) { results.push({ title: (movie.name_english || movie.name) + " [DUB]", image: getImage(movie.poster_path), href: "/watch/" + movie.slug + "." + movie.id + "?type=DUB" }); } } } 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().split('?')[0]; const typeMatch = url.match(/[?&]type=([^&]+)/); const type = typeMatch ? typeMatch[1] : "SUB"; 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&type=${type}` : `?_movieId=${id}&ep=${ep.number}&type=${type}`; 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, type = "DUB") { const typeMatch = ID.match(/[?&]type=([^&]+)/); if (typeMatch) { type = typeMatch[1]; } 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(); console.log(JSON.stringify(getSourcesJson)); 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 (type === "SUB" && subServerId) serverPromises.push(processServer(subServerId, "SUB")); else if (type === "DUB" && dubServerId) serverPromises.push(processServer(dubServerId, "DUB")); else if (type === "RAW" && 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 finalStreams = streams.map(s => ({ title: s.title, streamUrl: s.streamUrl, headers: s.headers })); let subtitle = null; if (streams.length > 0 && streams[0].sourcesData.tracks) { const englishTrack = streams[0].sourcesData.tracks.find(t => t.kind === "captions" && t.label === "English"); subtitle = englishTrack ? englishTrack.file : null; } const result = { streams: finalStreams, subtitle: subtitle }; console.log(JSON.stringify(result)); return JSON.stringify(result); } 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; }