// // // Main functions // // async function searchResults(query) { const encodeQuery = keyword => encodeURIComponent(keyword); const decodeHtmlEntities = (str) => { if (!str) return str; return str.replace(/&#(\d+);/g, (match, dec) => String.fromCharCode(dec)) .replace(/"/g, '"') .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>'); }; const fuzzyMatch = (query, title) => { const q = query.toLowerCase().trim(); const t = title.toLowerCase().trim(); if (t === q) return 1000; if (t.startsWith(q + ' ') || t.startsWith(q + ':') || t.startsWith(q + '-')) return 950; const wordBoundaryRegex = new RegExp(`\\b${q.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`); if (wordBoundaryRegex.test(t)) return 900; const qTokens = q.split(/\s+/).filter(token => token.length > 0); const tTokens = t.split(/[\s\-:]+/).filter(token => token.length > 0); const stopwords = new Set(['the', 'a', 'an', 'and', 'or', 'of', 'in', 'on', 'at', 'to', 'for', 'with']); let score = 0; let exactMatches = 0; let partialMatches = 0; let significantMatches = 0; qTokens.forEach(qToken => { const isStopword = stopwords.has(qToken); let bestMatch = 0; let hasExactMatch = false; tTokens.forEach(tToken => { let matchScore = 0; if (tToken === qToken) { matchScore = isStopword ? 25 : 120; hasExactMatch = true; if (!isStopword) significantMatches++; } else if (qToken.includes(tToken) && tToken.length >= 3 && qToken.length <= tToken.length + 2) { matchScore = isStopword ? 8 : 40; if (!isStopword) significantMatches++; } else if (tToken.startsWith(qToken) && qToken.length >= 3) { matchScore = isStopword ? 12 : 70; if (!isStopword) significantMatches++; } else if (qToken.length >= 4 && tToken.length >= 4) { const dist = levenshteinDistance(qToken, tToken); const maxLen = Math.max(qToken.length, tToken.length); const similarity = 1 - (dist / maxLen); if (similarity > 0.8) { matchScore = Math.floor(similarity * 60); if (!isStopword) significantMatches++; } } bestMatch = Math.max(bestMatch, matchScore); }); if (bestMatch > 0) { score += bestMatch; if (hasExactMatch) exactMatches++; else partialMatches++; } }); const significantTokens = qTokens.filter(t => !stopwords.has(t)).length; const requiredMatches = Math.max(1, Math.ceil(significantTokens * 0.8)); if (significantMatches < requiredMatches) { return 0; } if (exactMatches + partialMatches >= qTokens.length) { score += 80; } score += exactMatches * 20; const extraWords = tTokens.length - qTokens.length; if (extraWords > 2) { score -= (extraWords - 2) * 25; } let orderBonus = 0; for (let i = 0; i < qTokens.length - 1; i++) { const currentTokenIndex = tTokens.findIndex(t => t.includes(qTokens[i])); const nextTokenIndex = tTokens.findIndex(t => t.includes(qTokens[i + 1])); if (currentTokenIndex !== -1 && nextTokenIndex !== -1 && currentTokenIndex < nextTokenIndex) { orderBonus += 15; } } score += orderBonus; return Math.max(0, score); }; const levenshteinDistance = (a, b) => { const matrix = []; for (let i = 0; i <= b.length; i++) { matrix[i] = [i]; } for (let j = 0; j <= a.length; j++) { matrix[0][j] = j; } for (let i = 1; i <= b.length; i++) { for (let j = 1; j <= a.length; j++) { if (b.charAt(i - 1) === a.charAt(j - 1)) { matrix[i][j] = matrix[i - 1][j - 1]; } else { matrix[i][j] = Math.min( matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1 ); } } } return matrix[b.length][a.length]; }; const animekaiSearch = async () => { const searchBaseUrl = "https://animekai.to/browser?keyword="; const baseUrl = "https://animekai.to"; const posterHrefRegex = /href="[^"]*" class="poster"/g; const titleRegex = /class="title"[^>]*title="[^"]*"/g; const imageRegex = /data-src="[^"]*"/g; const extractHrefRegex = /href="([^"]*)"/; const extractImageRegex = /data-src="([^"]*)"/; const extractTitleRegex = /title="([^"]*)"/; const extractResultsFromHTML = (htmlText) => { const results = []; const posterMatches = htmlText.match(posterHrefRegex) || []; const titleMatches = htmlText.match(titleRegex) || []; const imageMatches = htmlText.match(imageRegex) || []; const minLength = Math.min(posterMatches.length, titleMatches.length, imageMatches.length); for (let i = 0; i < minLength; i++) { const hrefMatch = posterMatches[i].match(extractHrefRegex); const fullHref = hrefMatch ? (hrefMatch[1].startsWith("http") ? hrefMatch[1] : baseUrl + hrefMatch[1]) : null; const imageMatch = imageMatches[i].match(extractImageRegex); const imageSrc = imageMatch ? imageMatch[1] : null; const titleMatch = titleMatches[i].match(extractTitleRegex); const cleanTitle = titleMatch ? decodeHtmlEntities(titleMatch[1]) : null; if (fullHref && imageSrc && cleanTitle) { results.push({ href: `Animekai:${fullHref}`, image: imageSrc, title: cleanTitle }); } } return results; }; try { const encodedQuery = encodeQuery(query); const urls = [ `${searchBaseUrl}${encodedQuery}`, `${searchBaseUrl}${encodedQuery}&page=2`, `${searchBaseUrl}${encodedQuery}&page=3` ]; const responses = await Promise.all(urls.map(url => fetchv2(url))); const htmlTexts = await Promise.all(responses.map(res => res.text())); const allResults = []; htmlTexts.forEach(html => allResults.push(...extractResultsFromHTML(html))); return allResults; } catch (error) { console.error("Animekai search error:" + error); return []; } }; const oneMoviesSearch = async () => { const searchBaseUrl = "https://1movies.bz/browser?keyword="; const baseUrl = "https://1movies.bz"; const posterHrefRegex = /href="([^"]*)" class="poster"/g; const titleRegex = /class="title" href="[^"]*">([^<]*) { const results = []; const posterMatches = [...htmlText.matchAll(posterHrefRegex)]; const titleMatches = [...htmlText.matchAll(titleRegex)]; const imageMatches = [...htmlText.matchAll(imageRegex)]; const minLength = Math.min(posterMatches.length, titleMatches.length, imageMatches.length); for (let i = 0; i < minLength; i++) { const href = posterMatches[i][1]; const fullHref = href.startsWith("http") ? href : baseUrl + href; const imageSrc = imageMatches[i][1]; const title = decodeHtmlEntities(titleMatches[i][1]); results.push({ href: fullHref, image: imageSrc, title }); } return results; }; try { const encodedQuery = encodeQuery(query); const urls = [ `${searchBaseUrl}${encodedQuery}`, `${searchBaseUrl}${encodedQuery}&page=2`, `${searchBaseUrl}${encodedQuery}&page=3` ]; const responses = await Promise.all(urls.map(url => fetchv2(url))); const htmlTexts = await Promise.all(responses.map(res => res.text())); const allResults = []; htmlTexts.forEach(html => allResults.push(...extractResultsFromHTML(html))); return allResults; } catch (error) { console.error("1Movies search error:" + error); return []; } }; try { const [animekaiResults, oneMoviesResults] = await Promise.all([ animekaiSearch(), oneMoviesSearch() ]); const mergedResults = [...animekaiResults, ...oneMoviesResults]; const scoredResults = mergedResults.map(r => ({ ...r, score: fuzzyMatch(query, r.title) })); const filteredResults = scoredResults .filter(r => r.score > 50) .sort((a, b) => b.score - a.score) .map(({ score, ...rest }) => rest); return JSON.stringify(filteredResults.length > 0 ? filteredResults : [{ href: "", image: "", title: "No results found, please refine query." }]); } catch (error) { return JSON.stringify([{ href: "", image: "", title: "Search failed: " + error.message }]); } } async function extractDetails(url) { if (url.startsWith("Animekai:")) { const actualUrl = url.replace("Animekai:", "").trim(); try { const response = await fetchv2(actualUrl); const htmlText = await response.text(); const descriptionMatch = (/
([\s\S]*?)<\/div>/.exec(htmlText) || [])[1]; const aliasesMatch = (/([\s\S]*?)<\/small>/.exec(htmlText) || [])[1]; return JSON.stringify([{ description: descriptionMatch ? cleanHtmlSymbols(descriptionMatch) : "Not available", aliases: aliasesMatch ? cleanHtmlSymbols(aliasesMatch) : "Not available", airdate: "If stream doesn't load try later or disable VPN/DNS" }]); } catch (error) { console.error("Error fetching Animekai details:" + error); return JSON.stringify([{ description: "Error loading description", aliases: "Aliases: Unknown", airdate: "Aired: Unknown" }]); } } else { try { const response = await fetchv2(url); const htmlText = await response.text(); const descriptionMatch = (/
([\s\S]*?)<\/div>/.exec(htmlText) || [])[1]; const aliasesMatch = (/([\s\S]*?)<\/small>/.exec(htmlText) || [])[1]; const airdateMatch = (/
  • Released:\s*]*>(.*?)<\/span>/.exec(htmlText) || [])[1]; return JSON.stringify([{ description: descriptionMatch ? cleanHtmlSymbols(descriptionMatch) : "Not available", aliases: aliasesMatch ? cleanHtmlSymbols(aliasesMatch) : "Not aliases", airdate: airdateMatch ? cleanHtmlSymbols(airdateMatch) : "Not available" }]); } catch (error) { console.error("Error fetching 1Movies details:"+ error); return JSON.stringify([{ description: "Error loading description", aliases: "Not available", airdate: "Not available" }]); } } } async function extractEpisodes(url) { const sendEpisodes = async (endpoint, episodeData) => { const promises = episodeData.map(item => fetchv2(`${endpoint}=${encodeURIComponent(item.data)}`) .then(res => res.json()) .then(json => ({ name: item.name, data: json.result })) .catch(err => ({ name: item.name, error: err.toString() })) ); return Promise.all(promises); }; try { if (url.startsWith("Animekai:")) { const actualUrl = url.replace("Animekai:", "").trim(); const htmlText = await (await fetchv2(actualUrl)).text(); const animeIdMatch = (htmlText.match(/
    ]*data-id="([^"]+)"/) || [])[1]; if (!animeIdMatch) return JSON.stringify([{ error: "AniID not found" }]); const tokenResponse = await fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(animeIdMatch)}`); const tokenData = await tokenResponse.json(); const token = tokenData.result; const episodeListUrl = `https://animekai.to/ajax/episodes/list?ani_id=${animeIdMatch}&_=${token}`; const episodeListData = await (await fetchv2(episodeListUrl)).json(); const cleanedHtml = cleanJsonHtml(episodeListData.result); const episodeRegex = /]+num="([^"]+)"[^>]+token="([^"]+)"[^>]*>/g; const episodeMatches = [...cleanedHtml.matchAll(episodeRegex)]; const recentEpisodeMatches = episodeMatches.slice(-50); const episodeData = recentEpisodeMatches.map(([_, episodeNum, episodeToken]) => ({ name: `Episode ${episodeNum}`, data: episodeToken })); const batchResults = await sendEpisodes("https://enc-dec.app/api/enc-kai?text", episodeData); const episodes = batchResults.map((result, index) => ({ number: parseInt(recentEpisodeMatches[index][1], 10), href: `Animekai:https://animekai.to/ajax/links/list?token=${recentEpisodeMatches[index][2]}&_=${result.data}` })); return JSON.stringify(episodes); } else { const htmlText = await (await fetchv2(url)).text(); const movieIDMatch = (htmlText.match(/
    ]*id="movie-rating"[^>]*data-id="([^"]+)"/) || [])[1]; if (!movieIDMatch) return JSON.stringify([{ error: "MovieID not found" }]); const tokenResponse = await fetchv2("https://enc-dec.app/api/enc-movies-flix?text=" + encodeURIComponent(movieIDMatch)); const temp = await tokenResponse.json(); const token = temp.result; const episodeListUrl = `https://1movies.bz/ajax/episodes/list?id=${movieIDMatch}&_=${token}`; const episodeListData = await (await fetchv2(episodeListUrl)).json(); const cleanedHtml = cleanJsonHtml(episodeListData.result); const episodeRegex = /]+eid="([^"]+)"[^>]+num="([^"]+)"[^>]*>/g; const episodeMatches = [...cleanedHtml.matchAll(episodeRegex)]; const episodeData = episodeMatches.map(([_, episodeToken, episodeNum]) => ({ name: `Episode ${episodeNum}`, data: episodeToken })); const batchResults = await sendEpisodes("https://enc-dec.app/api/enc-movies-flix?text", episodeData); const episodes = batchResults.map((result, index) => ({ number: parseInt(episodeMatches[index][2], 10), href: `https://1movies.bz/ajax/links/list?eid=${episodeMatches[index][1]}&_=${result.data}` })); return JSON.stringify(episodes); } } catch (err) { console.error("Error fetching episodes:" + err); return JSON.stringify([{ number: 1, href: "Error fetching episodes" }]); } } async function extractStreamUrl(url) { let source, actualUrl; if (url.startsWith("Animekai:")) { source = "Animekai"; actualUrl = url.replace("Animekai:", "").trim(); } else if (url.includes("1movies.bz")) { source = "1Movies"; actualUrl = url.trim(); } else { console.log("Failed to match URL:", url); return "Invalid URL format: " + url; } if (source === "Animekai") { try { const response = await fetchv2(actualUrl); const text = await response.text(); const cleanedHtml = cleanJsonHtml(text); const subRegex = /
    ]*>([\s\S]*?)<\/div>/; const softsubRegex = /
    ]*>([\s\S]*?)<\/div>/; const dubRegex = /
    ]*>([\s\S]*?)<\/div>/; const subMatch = subRegex.exec(cleanedHtml); const softsubMatch = softsubRegex.exec(cleanedHtml); const dubMatch = dubRegex.exec(cleanedHtml); const subContent = subMatch ? subMatch[1].trim() : ""; const softsubContent = softsubMatch ? softsubMatch[1].trim() : ""; const dubContent = dubMatch ? dubMatch[1].trim() : ""; const serverSpanRegex = /]*data-lid="([^"]+)"[^>]*>Server 1<\/span>/; const serverIdDub = serverSpanRegex.exec(dubContent)?.[1]; const serverIdSoftsub = serverSpanRegex.exec(softsubContent)?.[1]; const serverIdSub = serverSpanRegex.exec(subContent)?.[1]; const tokenRequestData = [ { name: "Dub", data: serverIdDub }, { name: "Softsub", data: serverIdSoftsub }, { name: "Sub", data: serverIdSub } ].filter(item => item.data); const tokenPromises = tokenRequestData.map(item => fetchv2(`https://enc-dec.app/api/enc-kai?text=${encodeURIComponent(item.data)}`) .then(res => res.json()) .then(json => ({ name: item.name, data: json.result })) .catch(err => ({ name: item.name, error: err.toString() })) ); const tokenResults = await Promise.all(tokenPromises); const streamUrls = tokenResults.map(result => { const serverIdMap = { "Dub": serverIdDub, "Softsub": serverIdSoftsub, "Sub": serverIdSub }; return { type: result.name, url: `https://animekai.to/ajax/links/view?id=${serverIdMap[result.name]}&_=${result.data}` }; }); const processStreams = async (streamUrls) => { const streamResponses = await Promise.all( streamUrls.map(async ({ type, url }) => { try { const res = await fetchv2(url); const json = await res.json(); return { type: type, result: json.result }; } catch (error) { console.log(`Error fetching ${type} stream:` + error); return { type: type, result: null }; } }) ); const decryptRequestData = streamResponses .filter(item => item.result) .map(item => ({ name: item.type, data: item.result })); if (decryptRequestData.length === 0) { return {}; } const decryptPromises = decryptRequestData.map(item => fetchv2(`https://enc-dec.app/api/dec-kai?text=${encodeURIComponent(item.data)}`) .then(res => res.json()) .then(json => ({ name: item.name, data: JSON.stringify(json.result) })) .catch(err => ({ name: item.name, error: err.toString() })) ); const decryptResults = await Promise.all(decryptPromises); const finalResults = {}; decryptResults.forEach(result => { try { const parsed = JSON.parse(result.data); finalResults[result.name] = parsed.url; console.log(`decrypted${result.name} URL:` + parsed.url); } catch (error) { console.log(`Error parsing ${result.name} result:` + error); finalResults[result.name] = null; } }); return finalResults; }; const decryptedUrls = await processStreams(streamUrls); const decryptedSub = decryptedUrls.Sub; const decryptedDub = decryptedUrls.Dub; const decryptedRaw = decryptedUrls.Softsub; const headers = { "Referer": "https://animekai.to/", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" }; async function getStream(url) { try { const response = await fetchv2(url.replace("/e/", "/media/"), headers); const responseJson = await response.json(); const result = responseJson?.result; const postData = { "text": result, "Useragent": headers["User-Agent"] }; const finalResponse = await fetchv2( "https://ilovekai.simplepostrequest.workers.dev/ilovebush", {}, "POST", JSON.stringify(postData) ); const finalJson = await finalResponse.json(); return finalJson?.result?.sources?.[0]?.file || null; } catch { return null; } } const streams = []; const subStream = decryptedSub ? await getStream(decryptedSub) : null; if (subStream) streams.push("Hardsub English", subStream); const dubStream = decryptedDub ? await getStream(decryptedDub) : null; if (dubStream) streams.push("Dubbed English", dubStream); const rawStream = decryptedRaw ? await getStream(decryptedRaw) : null; if (rawStream) streams.push("Original audio", rawStream); const final = { streams, subtitles: "" }; console.log("RETURN: " + JSON.stringify(final)); return JSON.stringify(final); } catch (error) { console.log("Animekai fetch error:" + error); return "https://error.org"; } } else if (source === "1Movies") { try { const response = await fetchv2(actualUrl); const responseData = await response.json(); const cleanedHtml = cleanJsonHtml(responseData.result); const server1Regex = /
    ]*data-lid="([^"]+)"[^>]*>\s*Server 1<\/span>/; const server1Match = server1Regex.exec(cleanedHtml); if (!server1Match) { console.log("Server 1 not found"); return "error"; } const serverId = server1Match[1]; const tokenRequestData = [{ name: "Server1", data: serverId }]; const tokenBatchResponse = await fetchv2( "https://ilovekai.simplepostrequest.workers.dev/ilovethighs", {}, "POST", JSON.stringify(tokenRequestData) ); const tokenResults = await tokenBatchResponse.json(); const token = tokenResults[0]?.data; if (!token) { console.log("Token not found"); return "error"; } const streamUrl = `https://1movies.bz/ajax/links/view?id=${serverId}&_=${token}`; const streamResponse = await fetchv2(streamUrl); const streamData = await streamResponse.json(); if (!streamData.result) { console.log("Stream result not found"); return "error"; } const decryptRequestData = [{ name: "Server1", data: streamData.result }]; const decryptBatchResponse = await fetchv2( "https://ilovekai.simplepostrequest.workers.dev/iloveboobs", {}, "POST", JSON.stringify(decryptRequestData) ); const decryptedResponse = await decryptBatchResponse.json(); console.log("Decrypted response:" + JSON.stringify(decryptedResponse)); const decryptedUrl = decryptedResponse[0]?.data.url; const subListEncoded = decryptedUrl.split("sub.list=")[1]?.split("&")[0]; let subtitles = "N/A"; if (subListEncoded) { try { const subListUrl = decodeURIComponent(subListEncoded); const subResponse = await fetchv2(subListUrl); subtitles = await subResponse.json(); } catch { subtitles = "N/A"; } } const englishSubUrl = Array.isArray(subtitles) ? subtitles.find(sub => sub.label === "English")?.file.replace(/\\\//g, "/") : "N/A"; if (!decryptedUrl) { console.log("Decryption failed"); return "error"; } const headers = { "Referer": "https://1movies.bz/", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" }; const mediaResponse = await fetchv2(decryptedUrl.replace("/e/", "/media/"), headers); const mediaJson = await mediaResponse.json(); const result = mediaJson?.result; if (!result) { console.log("Media result not found"); return "error"; } const postData = { "text": result, "Useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36" }; const finalResponse = await fetchv2("https://ilovekai.simplepostrequest.workers.dev/iloveass", {}, "POST", JSON.stringify(postData)); const finalJson = await finalResponse.json(); const m3u8Link = finalJson?.result?.sources?.[0]?.file; const returnValue = { stream: m3u8Link, subtitles: englishSubUrl }; console.log("RETURN: " + JSON.stringify(returnValue)); return JSON.stringify(returnValue); } catch (error) { console.log("1Movies fetch error:" + error); return "https://error.org"; } } } /// /// /// Helper functions /// /// function cleanHtmlSymbols(string) { if (!string) { return ""; } return string .replace(/’/g, "'") .replace(/–/g, "-") .replace(/&#[0-9]+;/g, "") .replace(/\r?\n|\r/g, " ") .replace(/\s+/g, " ") .trim(); } function cleanJsonHtml(jsonHtml) { if (!jsonHtml) { return ""; } return jsonHtml .replace(/\\"/g, "\"") .replace(/\\'/g, "'") .replace(/\\\\/g, "\\") .replace(/\\n/g, "\n") .replace(/\\t/g, "\t") .replace(/\\r/g, "\r"); } function decodeHtmlEntities(text) { if (!text) { return ""; } return text .replace(/'/g, "'") .replace(/"/g, "\"") .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/ /g, " "); }