/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////// Main Functions ////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// async function searchResults(keyword) { try { const encodedKeyword = encodeURIComponent(keyword); const searchApiUrl = `https://aniworld.to/ajax/seriesSearch?keyword=${encodedKeyword}`; const responseText = await fetch(searchApiUrl); const data = await JSON.parse(responseText); const transformedResults = data.map((anime) => ({ title: anime.name, image: `https://aniworld.to${anime.cover}`, href: `https://aniworld.to/anime/stream/${anime.link}`, })); return JSON.stringify(transformedResults); } catch (error) { console.log("Fetch error:" + error); return JSON.stringify([{ title: "Error", image: "", href: "" }]); } } async function extractDetails(url) { try { const fetchUrl = `${url}`; const text = await fetch(fetchUrl); const descriptionRegex = /(.*?)<\/p>/s; const aliasesRegex = /]*\bdata-alternativetitles="([^"]+)"[^>]*>/i; const aliasesMatch = aliasesRegex.exec(text); let aliasesArray = []; if (aliasesMatch) { aliasesArray = aliasesMatch[1].split(",").map((a) => a.trim()); } const descriptionMatch = descriptionRegex.exec(text) || []; const airdateMatch = "Unknown"; // TODO: Implement airdate extraction const transformedResults = [ { description: descriptionMatch[1] || "No description available", aliases: aliasesArray[0] || "No aliases available", airdate: airdateMatch, }, ]; return JSON.stringify(transformedResults); } catch (error) { console.log("Details error:" + error); return JSON.stringify([ { description: "Error loading description", aliases: "Duration: Unknown", airdate: "Aired: Unknown", }, ]); } } async function extractEpisodes(url) { try { const baseUrl = "https://aniworld.to"; const fetchUrl = `${url}`; const html = await fetch(fetchUrl); const finishedList = []; const seasonLinks = getSeasonLinks(html); for (const seasonLink of seasonLinks) { const seasonEpisodes = await fetchSeasonEpisodes( `${baseUrl}${seasonLink}` ); finishedList.push(...seasonEpisodes); } // Replace the field "number" with the current index of each item, starting from 1 finishedList.forEach((item, index) => { item.number = index + 1; }); return JSON.stringify(finishedList); } catch (error) { console.log("Fetch error:" + error); return JSON.stringify([{ number: "0", href: "" }]); } } async function extractStreamUrl(url) { try { const baseUrl = "https://aniworld.to"; const fetchUrl = `${url}`; const text = await fetch(fetchUrl); const finishedList = []; const languageList = getAvailableLanguages(text); const videoLinks = getVideoLinks(text); for (const videoLink of videoLinks) { const language = languageList.find( (l) => l.langKey === videoLink.langKey ); if (language) { finishedList.push({ provider: videoLink.provider, href: `${baseUrl}${videoLink.href}`, language: language.title, }); } } // Select the hoster const selectedHoster = selectHoster(finishedList); const provider = selectedHoster.provider; const providerLink = selectedHoster.href; if (provider === "Error") { console.log("No video found"); return JSON.stringify([{ provider: "Error", link: "" }]); } console.log("Selected provider: " + provider); console.log("Selected link: " + providerLink); const videoPage = await fetch(providerLink); console.log("Video Page: " + videoPage.length); const winLocRegex = /window\.location\.href\s*=\s*['"]([^'"]+)['"]/; const winLocMatch = winLocRegex.exec(videoPage); let winLocUrl = null; if (!winLocMatch) { winLocUrl = providerLink; } else { winLocUrl = winLocMatch[1]; } const hlsSourceResponse = await fetch(winLocUrl); const hlsSourcePage = typeof hlsSourceResponse === "object" ? await hlsSourceResponse.text() : await hlsSourceResponse; console.log("Provider: " + provider); console.log("URL: " + winLocUrl); console.log("HLS Source Page: " + hlsSourcePage.length); switch (provider) { case "VOE": try { const voeJson = voeExtractor(hlsSourcePage); return voeJson?.source || JSON.stringify([{ provider: "Error", link: "" }]); } catch (error) { console.log("VOE extractor error: " + error); return JSON.stringify([{ provider: "Error", link: "" }]); } case "SpeedFiles": try { const speedfilesUrl = await speedfilesExtractor(hlsSourcePage); return speedfilesUrl || JSON.stringify([{ provider: "Error", link: "" }]); } catch (error) { console.log("Speedfiles extractor error: " + error); return JSON.stringify([{ provider: "Error", link: "" }]); } case "Vidmoly": try { const vidmolyUrl = vidmolyExtractor(hlsSourcePage); return vidmolyUrl || JSON.stringify([{ provider: "Error", link: "" }]); } catch (error) { console.log("Vidmoly extractor error: " + error); return JSON.stringify([{ provider: "Error", link: "" }]); } default: console.log("Unsupported provider:", provider); return JSON.stringify([{ provider: "Error", link: "" }]); } // END OF VOE EXTRACTOR // Extract the sources variable and decode the hls value from base64 const sourcesRegex = /var\s+sources\s*=\s*({[^}]+})/; const sourcesMatch = sourcesRegex.exec(hlsSourcePage); let sourcesString = sourcesMatch ? sourcesMatch[1].replace(/'/g, '"') : null; return sourcesString; } catch (error) { console.log("ExtractStreamUrl error:" + error); return JSON.stringify([{ provider: "Error1", link: "" }]); } } function selectHoster(finishedList) { let firstVideo = null; let provider = null; // Define the preferred providers and languages const providerList = ["Vidmoly", "SpeedFiles", "VOE"]; const languageList = ["mit Untertitel Englisch", "mit Untertitel Deutsch"]; for (const providerName of providerList) { for (const language of languageList) { const video = finishedList.find( (video) => video.provider === providerName && video.language === language ); if (video) { provider = providerName; firstVideo = video; break; } } if (firstVideo) break; } // Default to the first video if no match is found if (!firstVideo) { firstVideo = finishedList[0]; } if (firstVideo) { return { provider: provider, href: firstVideo.href, }; } else { console.log("No video found"); return { provider: "Error", href: "https://error.org", }; } } //Thanks to Ibro and Cufiy async function vidmolyExtractor(html) { console.log("Vidmoly extractor"); console.log(html); const regexSub = /