function cleanTitle(title) { return title .replace(/’/g, "'") .replace(/–/g, "-") .replace(/&#[0-9]+;/g, ""); } async function searchResults(keyword) { const url = `https://animeheaven.me/fastsearch.php?xhr=1&s=${encodeURIComponent(keyword)}`; const response = await soraFetch(url); const html = await response.text(); const results = []; const itemRegex = /[\s\S]*?[^[\s\S]*?
([^<]+)<\/div>/g; let match; while ((match = itemRegex.exec(html)) !== null) { const href = `https://animeheaven.me${match[1]}`; const image = `https://animeheaven.me${match[2]}`; const rawTitle = match[3].trim(); const title = cleanTitle(rawTitle); results.push({ title, image, href }); } console.log(results); return JSON.stringify(results); } async function extractDetails(url) { const response = await soraFetch(url); const html = await response.text(); const details = []; const descriptionMatch = html.match(/
([^<]+)<\/div>/); let description = descriptionMatch ? descriptionMatch[1] : ''; const aliasesMatch = html.match(/
([^<]+)<\/div>/); let aliases = aliasesMatch ? aliasesMatch[1] : ''; const airdateMatch = html.match(/Year:
([^<]+)<\/div>/); let airdate = airdateMatch ? airdateMatch[1] : ''; if (description && airdate) { details.push({ description: description, aliases: aliases || 'N/A', airdate: airdate }); } console.log(details); return JSON.stringify(details); } async function extractEpisodes(url) { const response = await soraFetch(url); const html = await response.text(); const episodes = []; const episodeRegex = /]+id="([^"]+)"[^>]*>[\s\S]*?
]*>(\d+)<\/div>/g; let match; while ((match = episodeRegex.exec(html)) !== null) { const id = match[1]; const number = parseInt(match[2], 10); if (!isNaN(number)) { episodes.push({ href: id, number: number }); } } episodes.reverse(); console.log(episodes); return JSON.stringify(episodes); } async function extractStreamUrl(id) { const cookieHeader = `key=${id}`; const headers = { Cookie: cookieHeader }; const response = await soraFetch(`https://animeheaven.me/gate.php`, { headers }); const html = await response.text(); const sourceRegex = /(____=typeof ___,_____=___&&___[String.fromCharCode(...[108,101,110,103,116,104])],______=[...String.fromCharCode(...[99,114,97,110,99,105])],_______=___?[...___[String.fromCharCode(...[116,111,76,111,119,101,114,67,97,115,101])]()]:[],(________=______[String.fromCharCode(...[115,108,105,99,101])]())&&_______[String.fromCharCode(...[102,111,114,69,97,99,104])]((_________,__________)=>(___________=________[String.fromCharCode(...[105,110,100,101,120,79,102])](_________))>=0&&________[String.fromCharCode(...[115,112,108,105,99,101])](___________,1)),____===String.fromCharCode(...[115,116,114,105,110,103])&&_____===16&&________[String.fromCharCode(...[108,101,110,103,116,104])]===0))(_)}