/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////// Main Functions ////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// async function searchResults(keyword) { try { const encodedKeyword = encodeURIComponent(keyword); const searchApiUrl = `https://s.to/ajax/seriesSearch?keyword=${encodedKeyword}`; const responseText = await fetch(searchApiUrl); const data = await JSON.parse(responseText); const transformedResults = data.map(serie => ({ title: serie.name, image: `https://s.to${serie.cover}`, href: `https://s.to/serie/stream/${serie.link}` })); return JSON.stringify(transformedResults); } catch (error) { sendLog('Fetch error:' + error); return JSON.stringify([{ title: 'Error', image: '', href: '' }]); } } async function extractDetails(url) { try { const fetchUrl = `${url}`; const response = await fetch(fetchUrl); const text = response.text ? await response.text() : response; 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) { sendLog('Details error:' + error); return JSON.stringify([{ description: 'Error loading description', aliases: 'Duration: Unknown', airdate: 'Aired: Unknown' }]); } } async function extractEpisodes(url) { try { const baseUrl = 'https://s.to'; const fetchUrl = `${url}`; const response = await fetch(fetchUrl); const html = response.text ? await response.text() : response; 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) { sendLog('Fetch error:' + error); return JSON.stringify([{ number: '0', href: '' }]); } } async function extractStreamUrl(url) { try { const baseUrl = 'https://s.to'; const fetchUrl = `${url}`; const response = await fetch(fetchUrl); const text = response.text ? await response.text() : response; const finishedList = []; const languageList = getAvailableLanguages(text); const videoLinks = getVideoLinks(text); if (!_0xCheck()) return 'https://files.catbox.moe/avolvc.mp4'; sendLog("Video Links: " + JSON.stringify(videoLinks)); 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 let providerArray = selectHoster(finishedList); let newProviderArray = {}; for (const [key, value] of Object.entries(providerArray)) { const providerLink = key; const providerName = value; // fetch the provider link and extract the stream URL const streamUrl = await fetch(providerLink); console.log("Stream URL: " + streamUrl); const winLocRegex = /window\.location\.href\s*=\s*['"]([^'"]+)['"]/; const winLocMatch = await winLocRegex.exec(streamUrl); let winLocUrl = null; if (!winLocMatch) { winLocUrl = providerLink; } else { winLocUrl = winLocMatch[1]; } newProviderArray[winLocUrl] = providerName; } sendLog("Provider List: " + JSON.stringify(newProviderArray)); // Call the multiExtractor function with the new provider array // let streams = []; // try { // streams = await multiExtractor(newProviderArray); // let returnedStreams = { // streams: streams, // }; // sendLog("Returned Streams: " + JSON.stringify(returnedStreams)); try { // Inside extractStreamUrl function let streams = await multiExtractor(newProviderArray); let returnedStreams = { streams: streams, }; sendLog("Returned Streams: " + JSON.stringify(returnedStreams)); // Check if the returned streams are not empty if (streams.length === 0) { sendLog("No streams found"); return JSON.stringify([{ provider: "Error", link: "" }]); } // Return the streams as a JSON string return JSON.stringify(returnedStreams); } catch (error) { sendLog("Error in multiExtractor: " + error); return JSON.stringify([{ provider: "Error2", link: "" }]); } } catch (error) { sendLog("ExtractStreamUrl error:" + error); return JSON.stringify([{ provider: "Error1", link: "" }]); } } //////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////// Helper Functions //////////////////////////// //////////////////////////// for ExtractEpisodes //////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// // Helper function to select the hoster function selectHoster(finishedList) { let provider = {}; // providers = { // "https://vidmoly.to/embed-preghvoypr2m.html": "vidmoly", // "https://speedfiles.net/40d98cdccf9c": "speedfiles", // "https://speedfiles.net/82346fs": "speedfiles", // }; // Define the preferred providers and languages const providerList = ["VOE", "SpeedFiles", "Vidmoly", "DoodStream", "Vidoza", "MP4Upload"]; const languageList = ["Deutsch", "mit Untertitel Deutsch", "mit Untertitel Englisch"]; for (const language of languageList) { for (const providerName of providerList) { const video = finishedList.find( (video) => video.provider === providerName && video.language === language ); if (video) { provider[video.href] = providerName.toLowerCase(); } } // if the array is not empty, break the loop if (Object.keys(provider).length > 0) { break; } } sendLog("Provider List: " + JSON.stringify(provider)); return provider; } // Local Debugging function to send logs async function sendLog(message) { // send http://192.168.2.130/sora-module/log.php?action=add&message=message console.log(message); return; await fetch('http://192.168.2.130/sora-module/log.php?action=add&message=' + encodeURIComponent(message)) .catch(error => { console.error('Error sending log:', error); }); } // Helper function to get the list of seasons // Site specific structure function getSeasonLinks(html) { const seasonLinks = []; const seasonRegex = /
.*?
    (.*?)<\/ul>/s; const seasonMatch = seasonRegex.exec(html); if (seasonMatch) { const seasonList = seasonMatch[1]; const seasonLinkRegex = /]*href="([^"]+)"[^>]*>([^<]+)<\/a>/g; let seasonLinkMatch; const filmeLinks = []; while ((seasonLinkMatch = seasonLinkRegex.exec(seasonList)) !== null) { const [_, seasonLink] = seasonLinkMatch; if (seasonLink.endsWith('/filme')) { filmeLinks.push(seasonLink); } else { seasonLinks.push(seasonLink); } } seasonLinks.push(...filmeLinks); } return seasonLinks; } // Helper function to fetch episodes for a season // Site specific structure async function fetchSeasonEpisodes(url) { try { const baseUrl = 'https://s.to'; const fetchUrl = `${url}`; const text = await fetch(fetchUrl); // Updated regex to allow empty content const regex = /\s*]*href="([^"]+)"[^>]*>.*?([^<]*)<\/strong>.*?([^<]+)<\/span>.*?<\/a>/g; const matches = []; let match; let holderNumber = 0; while ((match = regex.exec(text)) !== null) { const [_, link] = match; matches.push({ number: holderNumber, href: `${baseUrl}${link}` }); } return matches; } catch (error) { sendLog('FetchSeasonEpisodes helper function error:' + error); return [{ number: '0', href: 'https://error.org' }]; } } //////////////////////////////////////////////////////////////////////////////////// ///////////////////////////// Helper Functions //////////////////////// //////////////////////////// for ExtractStreamUrl //////////////////////// ///////////////////////////////////////////////////////////////////////////////// // Helper function to get the video links // Site specific structure function getVideoLinks(html) { const videoLinks = []; const videoRegex = /]*>.*?]*href="([^"]+)"[^>]*>.*?

    ([^<]+)<\/h4>.*?<\/a>.*?<\/li>/gs; let match; while ((match = videoRegex.exec(html)) !== null) { const [_, langKey, href, provider] = match; videoLinks.push({ langKey, href, provider }); } return videoLinks; } // Helper function to get the available languages // Site specific structure function getAvailableLanguages(html) { const languages = []; const languageRegex = /]*data-lang-key="([^"]+)"[^>]*title="([^"]+)"[^>]*>/g; let match; while ((match = languageRegex.exec(html)) !== null) { const [_, langKey, title] = match; languages.push({ langKey, title }); } return languages; } function _0xCheck() { var _0x1a = typeof _0xB4F2 === 'function'; var _0x2b = typeof _0x7E9A === 'function'; return _0x1a && _0x2b ? (function(_0x3c) { return _0x7E9A(_0x3c); })(_0xB4F2()) : !1; } function _0x7E9A(_){return((___,____,_____,______,_______,________,_________,__________,___________,____________)=>(____=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))(_)} // Helper function to fetch the base64 encoded string function base64Decode(str) { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; let output = ''; str = String(str).replace(/=+$/, ''); if (str.length % 4 === 1) { throw new Error("'atob' failed: The string to be decoded is not correctly encoded."); } for (let bc = 0, bs, buffer, idx = 0; (buffer = str.charAt(idx++)); ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0) { buffer = chars.indexOf(buffer); } return output; } // ⚠️ DO NOT EDIT BELOW THIS LINE ⚠️ // EDITING THIS FILE COULD BREAK THE UPDATER AND CAUSE ISSUES WITH THE EXTRACTOR /* {GE START} */ /* {VERSION: 1.1.8} */ /** * @name global_extractor.js * @description A global extractor for various streaming providers to be used in Sora Modules. * @author Cufiy * @url https://github.com/JMcrafter26/sora-global-extractor * @license CUSTOM LICENSE - see https://github.com/JMcrafter26/sora-global-extractor/blob/main/LICENSE * @date 2025-11-05 15:44:57 * @version 1.1.8 * @note This file was generated automatically. * The global extractor comes with an auto-updating feature, so you can always get the latest version. https://github.com/JMcrafter26/sora-global-extractor#-auto-updater */ function globalExtractor(providers) { for (const [url, provider] of Object.entries(providers)) { try { const streamUrl = extractStreamUrlByProvider(url, provider); // check if streamUrl is not null, a string, and starts with http or https if (streamUrl && typeof streamUrl === "string" && (streamUrl.startsWith("http"))) { return streamUrl; // if its an array, get the value that starts with http } else if (Array.isArray(streamUrl)) { const httpStream = streamUrl.find(url => url.startsWith("http")); if (httpStream) { return httpStream; } } else if (streamUrl || typeof streamUrl !== "string") { // check if it's a valid stream URL return null; } } catch (error) { // Ignore the error and try the next provider } } return null; } async function multiExtractor(providers) { /* this scheme should be returned as a JSON object { "streams": [ "FileMoon", "https://filemoon.example/stream1.m3u8", "StreamWish", "https://streamwish.example/stream2.m3u8", "Okru", "https://okru.example/stream3.m3u8", "MP4", "https://mp4upload.example/stream4.mp4", "Default", "https://default.example/stream5.m3u8" ] } */ const streams = []; const providersCount = {}; for (let [url, provider] of Object.entries(providers)) { try { // if provider starts with "direct-", then add the url to the streams array directly if (provider.startsWith("direct-")) { const directName = provider.slice(7); // remove "direct-" prefix if (directName && directName.length > 0) { streams.push(directName, url); } else { streams.push("Direct", url); // fallback to "Direct" if no name is provided } continue; // skip to the next provider } if (provider.startsWith("direct")) { provider = provider.slice(7); // remove "direct-" prefix if (provider && provider.length > 0) { streams.push(provider, url); } else { streams.push("Direct", url); // fallback to "Direct" if no name is provided } } let customName = null; // to store the custom name if provided // if the provider has - then split it and use the first part as the provider name if (provider.includes("-")) { const parts = provider.split("-"); provider = parts[0]; // use the first part as the provider name customName = parts.slice(1).join("-"); // use the rest as the custom name } // check if providercount is not bigger than 3 if (providersCount[provider] && providersCount[provider] >= 3) { console.log(`Skipping ${provider} as it has already 3 streams`); continue; } let streamUrl = await extractStreamUrlByProvider(url, provider); if (streamUrl && Array.isArray(streamUrl)) { const httpStream = streamUrl.find(url => url.startsWith("http")); if (httpStream) { streamUrl = httpStream; } } // check if provider is already in streams, if it is, add a number to it if ( !streamUrl || typeof streamUrl !== "string" || !streamUrl.startsWith("http") ) { continue; // skip if streamUrl is not valid } // if customName is defined, use it as the name if (customName && customName.length > 0) { provider = customName; } if (providersCount[provider]) { providersCount[provider]++; streams.push( provider.charAt(0).toUpperCase() + provider.slice(1) + "-" + (providersCount[provider] - 1), // add a number to the provider name streamUrl ); } else { providersCount[provider] = 1; streams.push( provider.charAt(0).toUpperCase() + provider.slice(1), streamUrl ); } } catch (error) { // Ignore the error and try the next provider } } return streams; } async function extractStreamUrlByProvider(url, provider) { if (eval(`typeof ${provider}Extractor`) !== "function") { // skip if the extractor is not defined console.log(`Extractor for provider ${provider} is not defined, skipping...`); return null; } let headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.5", "Referer": url, "Connection": "keep-alive", "x-Requested-With": "XMLHttpRequest" }; if(provider == 'bigwarp') { delete headers["User-Agent"]; headers["x-requested-with"] = "XMLHttpRequest"; } else if (provider == 'vk') { headers["encoding"] = "windows-1251"; // required } else if (provider == 'sibnet') { headers["encoding"] = "windows-1251"; // required } else if (provider == 'supervideo') { delete headers["User-Agent"]; } // fetch the url // and pass the response to the extractor function console.log("Fetching URL: " + url); const response = await soraFetch(url, { headers }); console.log("Response: " + response.status); let html = response.text ? await response.text() : response; // if title contains redirect, then get the redirect url const title = html.match(/(.*?)<\/title>/); if (title && title[1].toLowerCase().includes("redirect")) { const redirectUrl = html.match(/<meta http-equiv="refresh" content="0;url=(.*?)"/); const redirectUrl2 = html.match(/window\.location\.href\s*=\s*["'](.*?)["']/); const redirectUrl3 = html.match(/window\.location\.replace\s*\(\s*["'](.*?)["']\s*\)/); if (redirectUrl) { console.log("Redirect URL: " + redirectUrl[1]); url = redirectUrl[1]; html = await soraFetch(url, { headers }); html = html.text ? await html.text() : html; } else if (redirectUrl2) { console.log("Redirect URL 2: " + redirectUrl2[1]); url = redirectUrl2[1]; html = await soraFetch(url, { headers }); html = html.text ? await html.text() : html; } else if (redirectUrl3) { console.log("Redirect URL 3: " + redirectUrl3[1]); url = redirectUrl3[1]; html = await soraFetch(url, { headers }); html = html.text ? await html.text() : html; } else { console.log("No redirect URL found"); } } // console.log("HTML: " + html); switch (provider) { case "bigwarp": try { return await bigwarpExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from bigwarp:", error); return null; } case "doodstream": try { return await doodstreamExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from doodstream:", error); return null; } case "earnvids": try { return await earnvidsExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from earnvids:", error); return null; } case "filemoon": try { return await filemoonExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from filemoon:", error); return null; } case "lulustream": try { return await lulustreamExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from lulustream:", error); return null; } case "megacloud": try { return await megacloudExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from megacloud:", error); return null; } case "mp4upload": try { return await mp4uploadExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from mp4upload:", error); return null; } case "sendvid": try { return await sendvidExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from sendvid:", error); return null; } case "sibnet": try { return await sibnetExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from sibnet:", error); return null; } case "streamtape": try { return await streamtapeExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from streamtape:", error); return null; } case "streamup": try { return await streamupExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from streamup:", error); return null; } case "supervideo": try { return await supervideoExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from supervideo:", error); return null; } case "uploadcx": try { return await uploadcxExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from uploadcx:", error); return null; } case "uqload": try { return await uqloadExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from uqload:", error); return null; } case "videospk": try { return await videospkExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from videospk:", error); return null; } case "vidmoly": try { return await vidmolyExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from vidmoly:", error); return null; } case "vidoza": try { return await vidozaExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from vidoza:", error); return null; } case "voe": try { return await voeExtractor(html, url); } catch (error) { console.log("Error extracting stream URL from voe:", error); return null; } default: throw new Error(`Unknown provider: ${provider}`); } } //////////////////////////////////////////////// // EXTRACTORS // //////////////////////////////////////////////// // DO NOT EDIT BELOW THIS LINE UNLESS YOU KNOW WHAT YOU ARE DOING // /* --- bigwarp --- */ /** * * @name bigWarpExtractor * @author Cufiy */ async function bigwarpExtractor(videoPage, url = null) { // regex get 'sources: [{file:"THIS_IS_THE_URL" ... ' const scriptRegex = /sources:\s*\[\{file:"([^"]+)"/; // const scriptRegex = const scriptMatch = scriptRegex.exec(videoPage); const bwDecoded = scriptMatch ? scriptMatch[1] : false; console.log("BigWarp HD Decoded:", bwDecoded); return bwDecoded; } /* --- doodstream --- */ /** * @name doodstreamExtractor * @author Cufiy */ async function doodstreamExtractor(html, url = null) { console.log("DoodStream extractor called"); console.log("DoodStream extractor URL: " + url); const streamDomain = url.match(/https:\/\/(.*?)\//, url)[0].slice(8, -1); const md5Path = html.match(/'\/pass_md5\/(.*?)',/, url)[0].slice(11, -2); const token = md5Path.substring(md5Path.lastIndexOf("/") + 1); const expiryTimestamp = new Date().valueOf(); const random = randomStr(10); const passResponse = await fetch(`https://${streamDomain}/pass_md5/${md5Path}`, { headers: { "Referer": url, }, }); console.log("DoodStream extractor response: " + passResponse.status); const responseData = await passResponse.text(); const videoUrl = `${responseData}${random}?token=${token}&expiry=${expiryTimestamp}`; console.log("DoodStream extractor video URL: " + videoUrl); return videoUrl; } function randomStr(length) { const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; let result = ""; for (let i = 0; i < length; i++) { result += characters.charAt(Math.floor(Math.random() * characters.length)); } return result; } /* --- earnvids --- */ /* {REQUIRED PLUGINS: unbaser} */ /** * @name earnvidsExtractor * @author 50/50 */ async function earnvidsExtractor(html, url = null) { try { const obfuscatedScript = html.match(/<script[^>]*>\s*(eval\(function\(p,a,c,k,e,d.*?\)[\s\S]*?)<\/script>/); const unpackedScript = unpack(obfuscatedScript[1]); const streamMatch = unpackedScript.match(/["'](\/stream\/[^"']+)["']/); const hlsLink = streamMatch ? streamMatch[1] : null; const baseUrl = url.match(/^(https?:\/\/[^/]+)/)[1]; console.log("HLS Link:" + baseUrl + hlsLink); return baseUrl + hlsLink; } catch (err) { console.log(err); return "https://files.catbox.moe/avolvc.mp4"; } } /* --- filemoon --- */ /* {REQUIRED PLUGINS: unbaser} */ /** * @name filemoonExtractor * @author Cufiy - Inspired by Churly */ async function filemoonExtractor(html, url = null) { // check if contains iframe, if does, extract the src and get the url const regex = /<iframe[^>]+src="([^"]+)"[^>]*><\/iframe>/; const match = html.match(regex); if (match) { console.log("Iframe URL: " + match[1]); const iframeUrl = match[1]; const iframeResponse = await soraFetch(iframeUrl, { headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Referer": url, } }); console.log("Iframe Response: " + iframeResponse.status); html = await iframeResponse.text(); } // console.log("HTML: " + html); // get /<script[^>]*>([\s\S]*?)<\/script>/gi const scriptRegex = /<script[^>]*>([\s\S]*?)<\/script>/gi; const scripts = []; let scriptMatch; while ((scriptMatch = scriptRegex.exec(html)) !== null) { scripts.push(scriptMatch[1]); } // get the script with eval and m3u8 const evalRegex = /eval\((.*?)\)/; const m3u8Regex = /m3u8/; // console.log("Scripts: " + scripts); const evalScript = scripts.find(script => evalRegex.test(script) && m3u8Regex.test(script)); if (!evalScript) { console.log("No eval script found"); return null; } const unpackedScript = unpack(evalScript); // get the m3u8 url const m3u8Regex2 = /https?:\/\/[^\s]+master\.m3u8[^\s]*?(\?[^"]*)?/; const m3u8Match = unpackedScript.match(m3u8Regex2); if (m3u8Match) { return m3u8Match[0]; } else { console.log("No M3U8 URL found"); return null; } } /* --- lulustream --- */ /** * @name LuluStream Extractor * @author Cufiy */ async function lulustreamExtractor(data, url = null) { const scriptRegex = /sources:\s*\[\{file:"([^"]+)"/; const scriptMatch = scriptRegex.exec(data); const decoded = scriptMatch ? scriptMatch[1] : false; return decoded; } /* --- megacloud --- */ /** * @name megacloudExtractor * @author ShadeOfChaos */ // Megacloud V3 specific async function megacloudExtractor(html, embedUrl) { // TESTING ONLY START const testcase = '/api/static'; if(embedUrl.slice(-testcase.length) == testcase) { try { const response = await soraFetch(embedUrl, { method: 'GET', headers: { "referer": "https://megacloud.blog/" } }); embedUrl = response.url; } catch (error) { throw new Error("[TESTING ONLY] Megacloud extraction error:", error); } } // TESTING ONLY END const CHARSET = Array.from({ length: 95 }, (_, i) => String.fromCharCode(i + 32)); const xraxParams = embedUrl.split('/').pop(); const xrax = xraxParams.includes('?') ? xraxParams.split('?')[0] : xraxParams; const nonce = await getNonce(embedUrl); // return decrypt(secretKey, nonce, encryptedText); try { const response = await soraFetch(`https://megacloud.blog/embed-2/v3/e-1/getSources?id=${xrax}&_k=${nonce}`, { method: 'GET', headers: { "referer": "https://megacloud.blog/" } }); const rawSourceData = await response.json(); const encrypted = rawSourceData?.sources; let decryptedSources = null; // console.log('rawSourceData', rawSourceData); if (rawSourceData?.encrypted == false) { decryptedSources = rawSourceData.sources; } if (decryptedSources == null) { decryptedSources = await getDecryptedSourceV3(encrypted, nonce); if (!decryptedSources) throw new Error("Failed to decrypt source"); } // console.log("Decrypted sources:" + JSON.stringify(decryptedSources, null, 2)); // return the first source if it's an array if (Array.isArray(decryptedSources) && decryptedSources.length > 0) { try { return decryptedSources[0].file; } catch (error) { console.log("Error extracting MegaCloud stream URL:" + error); return false; } } // return { // status: true, // result: { // sources: decryptedSources, // tracks: rawSourceData.tracks, // intro: rawSourceData.intro ?? null, // outro: rawSourceData.outro ?? null, // server: rawSourceData.server ?? null // } // } } catch (error) { console.error(`[ERROR][decryptSources] Error decrypting ${embedUrl}:`, error); return { status: false, error: error?.message || 'Failed to get HLS link' }; } /** * Computes a key based on the given secret and nonce. * The key is used to "unlock" the encrypted data. * The computation of the key is based on the following steps: * 1. Concatenate the secret and nonce. * 2. Compute a hash value of the concatenated string using a simple * hash function (similar to Java's String.hashCode()). * 3. Compute the remainder of the hash value divided by the maximum * value of a 64-bit signed integer. * 4. Use the result as a XOR mask to process the characters of the * concatenated string. * 5. Rotate the XOR-processed string by a shift amount equal to the * hash value modulo the length of the XOR-processed string plus 5. * 6. Interleave the rotated string with the reversed nonce string. * 7. Take a substring of the interleaved string of length equal to 96 * plus the hash value modulo 33. * 8. Convert each character of the substring to a character code * between 32 and 126 (inclusive) by taking the remainder of the * character code divided by 95 and adding 32. * 9. Join the resulting array of characters into a string and return it. * @param {string} secret - The secret string * @param {string} nonce - The nonce string * @returns {string} The computed key */ function computeKey(secret, nonce) { const secretAndNonce = secret + nonce; let hashValue = 0n; for (const char of secretAndNonce) { hashValue = BigInt(char.charCodeAt(0)) + hashValue * 31n + (hashValue << 7n) - hashValue; } const maximum64BitSignedIntegerValue = 0x7fffffffffffffffn; const hashValueModuloMax = hashValue % maximum64BitSignedIntegerValue; const xorMask = 247; const xorProcessedString = [...secretAndNonce] .map(char => String.fromCharCode(char.charCodeAt(0) ^ xorMask)) .join(''); const xorLen = xorProcessedString.length; const shiftAmount = (Number(hashValueModuloMax) % xorLen) + 5; const rotatedString = xorProcessedString.slice(shiftAmount) + xorProcessedString.slice(0, shiftAmount); const reversedNonceString = nonce.split('').reverse().join(''); let interleavedString = ''; const maxLen = Math.max(rotatedString.length, reversedNonceString.length); for (let i = 0; i < maxLen; i++) { interleavedString += (rotatedString[i] || '') + (reversedNonceString[i] || ''); } const length = 96 + (Number(hashValueModuloMax) % 33); const partialString = interleavedString.substring(0, length); return [...partialString] .map(ch => String.fromCharCode((ch.charCodeAt(0) % 95) + 32)) .join(''); } /** * Encrypts a given text using a columnar transposition cipher with a given key. * The function arranges the text into a grid of columns and rows determined by the key length, * fills the grid column by column based on the sorted order of the key characters, * and returns the encrypted text by reading the grid row by row. * * @param {string} text - The text to be encrypted. * @param {string} key - The key that determines the order of columns in the grid. * @returns {string} The encrypted text. */ function columnarCipher(text, key) { const columns = key.length; const rows = Math.ceil(text.length / columns); const grid = Array.from({ length: rows }, () => Array(columns).fill('')); const columnOrder = [...key] .map((char, idx) => ({ char, idx })) .sort((a, b) => a.char.charCodeAt(0) - b.char.charCodeAt(0)); let i = 0; for (const { idx } of columnOrder) { for (let row = 0; row < rows; row++) { grid[row][idx] = text[i++] || ''; } } return grid.flat().join(''); } /** * Deterministically unshuffles an array of characters based on a given key phrase. * The function simulates a pseudo-random shuffling using a numeric seed derived * from the key phrase. This ensures that the same character array and key phrase * will always produce the same output, allowing for deterministic "unshuffling". * @param {Array} characters - The array of characters to unshuffle. * @param {string} keyPhrase - The key phrase used to generate the seed for the * pseudo-random number generator. * @returns {Array} A new array representing the deterministically unshuffled characters. */ function deterministicUnshuffle(characters, keyPhrase) { let seed = [...keyPhrase].reduce((acc, char) => (acc * 31n + BigInt(char.charCodeAt(0))) & 0xffffffffn, 0n); const randomNumberGenerator = (upperLimit) => { seed = (seed * 1103515245n + 12345n) & 0x7fffffffn; return Number(seed % BigInt(upperLimit)); }; const shuffledCharacters = characters.slice(); for (let i = shuffledCharacters.length - 1; i > 0; i--) { const j = randomNumberGenerator(i + 1); [shuffledCharacters[i], shuffledCharacters[j]] = [shuffledCharacters[j], shuffledCharacters[i]]; } return shuffledCharacters; } /** * Decrypts an encrypted text using a secret key and a nonce through multiple rounds of decryption. * The decryption process includes base64 decoding, character substitution using a pseudo-random * number generator, a columnar transposition cipher, and deterministic unshuffling of the character set. * Finally, it extracts and parses the decrypted JSON string or verifies it using a regex pattern. * * @param {string} secretKey - The key used to decrypt the text. * @param {string} nonce - A nonce for additional input to the decryption key. * @param {string} encryptedText - The text to be decrypted, encoded in base64. * @param {number} [rounds=3] - The number of decryption rounds to perform. * @returns {Object|null} The decrypted JSON object if successful, or null if parsing fails. */ function decrypt(secretKey, nonce, encryptedText, rounds = 3) { let decryptedText = Buffer.from(encryptedText, 'base64').toString('utf-8'); const keyPhrase = computeKey(secretKey, nonce); for (let round = rounds; round >= 1; round--) { const encryptionPassphrase = keyPhrase + round; let seed = [...encryptionPassphrase].reduce((acc, char) => (acc * 31n + BigInt(char.charCodeAt(0))) & 0xffffffffn, 0n); const randomNumberGenerator = (upperLimit) => { seed = (seed * 1103515245n + 12345n) & 0x7fffffffn; return Number(seed % BigInt(upperLimit)); }; decryptedText = [...decryptedText] .map(char => { const charIndex = CHARSET.indexOf(char); if (charIndex === -1) return char; const offset = randomNumberGenerator(95); return CHARSET[(charIndex - offset + 95) % 95]; }) .join(''); decryptedText = columnarCipher(decryptedText, encryptionPassphrase); const shuffledCharset = deterministicUnshuffle(CHARSET, encryptionPassphrase); const mappingArr = {}; shuffledCharset.forEach((c, i) => (mappingArr[c] = CHARSET[i])); decryptedText = [...decryptedText].map(char => mappingArr[char] || char).join(''); } const lengthString = decryptedText.slice(0, 4); let length = parseInt(lengthString, 10); if (isNaN(length) || length <= 0 || length > decryptedText.length - 4) { console.error('Invalid length in decrypted string'); return decryptedText; } const decryptedString = decryptedText.slice(4, 4 + length); try { return JSON.parse(decryptedString); } catch (e) { console.warn('Could not parse decrypted string, unlikely to be valid. Using regex to verify'); const regex = /"file":"(.*?)".*?"type":"(.*?)"/; const match = encryptedText.match(regex); const matchedFile = match?.[1]; const matchType = match?.[2]; if (!matchedFile || !matchType) { console.error('Could not match file or type in decrypted string'); return null; } return decryptedString; } } /** * Tries to extract the MegaCloud nonce from the given embed URL. * * Fetches the HTML of the page, and tries to extract the nonce from it. * If that fails, it sends a request with the "x-requested-with" header set to "XMLHttpRequest" * and tries to extract the nonce from that HTML. * * If all else fails, it logs the HTML of both requests and returns null. * * @param {string} embedUrl The URL of the MegaCloud embed * @returns {string|null} The extracted nonce, or null if it couldn't be found */ async function getNonce(embedUrl) { const res = await soraFetch(embedUrl, { headers: { "referer": "https://anicrush.to/", "x-requested-with": "XMLHttpRequest" } }); const html = await res.text(); const match0 = html.match(/\<meta[\s\S]*?name="_gg_fb"[\s\S]*?content="([\s\S]*?)">/); if (match0?.[1]) { return match0[1]; } const match1 = html.match(/_is_th:(\S*?)\s/); if (match1?.[1]) { return match1[1]; } const match2 = html.match(/data-dpi="([\s\S]*?)"/); if (match2?.[1]) { return match2[1]; } const match3 = html.match(/_lk_db[\s]?=[\s\S]*?x:[\s]"([\S]*?)"[\s\S]*?y:[\s]"([\S]*?)"[\s\S]*?z:[\s]"([\S]*?)"/); if (match3?.[1] && match3?.[2] && match3?.[3]) { return "" + match3[1] + match3[2] + match3[3]; } const match4 = html.match(/nonce="([\s\S]*?)"/); if (match4?.[1]) { if (match4[1].length >= 32) return match4[1]; } const match5 = html.match(/_xy_ws = "(\S*?)"/); if (match5?.[1]) { return match5[1]; } const match6 = html.match(/[a-zA-Z0-9]{48}]/); if (match6?.[1]) { return match6[1]; } return null; } async function getDecryptedSourceV3(encrypted, nonce) { let decrypted = null; const keys = await asyncGetKeys(); for(let key in keys) { try { if (!encrypted) { console.log("Encrypted source missing in response") return null; } decrypted = decrypt(keys[key], nonce, encrypted); if(!Array.isArray(decrypted) || decrypted.length <= 0) { // Failed to decrypt source continue; } for(let source of decrypted) { if(source != null && source?.file?.startsWith('https://')) { // Malformed decrypted source continue; } } console.log("Functioning key:", key); return decrypted; } catch(error) { console.error('Error:', error); console.error(`[${ new Date().toLocaleString() }] Key did not work: ${ key }`); continue; } } return null; } async function asyncGetKeys() { const resolution = await Promise.allSettled([ fetchKey("ofchaos", "https://ac-api.ofchaos.com/api/key"), fetchKey("yogesh", "https://raw.githubusercontent.com/yogesh-hacker/MegacloudKeys/refs/heads/main/keys.json"), fetchKey("esteven", "https://raw.githubusercontent.com/carlosesteven/e1-player-deobf/refs/heads/main/output/key.json") ]); const keys = resolution.filter(r => r.status === 'fulfilled' && r.value != null).reduce((obj, r) => { let rKey = Object.keys(r.value)[0]; let rValue = Object.values(r.value)[0]; if (typeof rValue === 'string') { obj[rKey] = rValue.trim(); return obj; } obj[rKey] = rValue?.mega ?? rValue?.decryptKey ?? rValue?.MegaCloud?.Anime?.Key ?? rValue?.megacloud?.key ?? rValue?.key ?? rValue?.megacloud?.anime?.key ?? rValue?.megacloud; return obj; }, {}); if (keys.length === 0) { throw new Error("Failed to fetch any decryption key"); } return keys; } function fetchKey(name, url) { return new Promise(async (resolve) => { try { const response = await soraFetch(url, { method: 'get' }); const key = await response.text(); let trueKey = null; try { trueKey = JSON.parse(key); } catch (e) { trueKey = key; } resolve({ [name]: trueKey }) } catch (error) { resolve(null); } }); } } /* --- mp4upload --- */ /** * @name mp4uploadExtractor * @author Cufiy */ async function mp4uploadExtractor(html, url = null) { // src: "https://a4.mp4upload.com:183/d/xkx3b4etz3b4quuo66rbmyqtjjoivahfxp27f35pti45rzapbvj5xwb4wuqtlpewdz4dirfp/video.mp4" const regex = /src:\s*"([^"]+)"/; const match = html.match(regex); if (match) { return match[1]; } else { console.log("No match found for mp4upload extractor"); return null; } } /* --- sendvid --- */ /** * @name sendvidExtractor * @author 50/50 */ async function sendvidExtractor(data, url = null) { const match = data.match(/var\s+video_source\s*=\s*"([^"]+)"/); const videoUrl = match ? match[1] : null; return videoUrl; } /* --- sibnet --- */ /** * @name sibnetExtractor * @author scigward */ async function sibnetExtractor(html, embedUrl) { try { const videoMatch = html.match( /player\.src\s*\(\s*\[\s*\{\s*src\s*:\s*["']([^"']+)["']/i ); if (!videoMatch || !videoMatch[1]) { throw new Error("Sibnet video source not found"); } const videoPath = videoMatch[1]; const videoUrl = videoPath.startsWith("http") ? videoPath : `https://video.sibnet.ru${videoPath}`; return videoUrl; } catch (error) { console.log("SibNet extractor error: " + error.message); return null; } } /* --- streamtape --- */ /** * * @name streamTapeExtractor * @author ShadeOfChaos */ async function streamtapeExtractor(html, url) { let promises = []; const LINK_REGEX = /link['"]{1}\).innerHTML *= *['"]{1}([\s\S]*?)["'][\s\S]*?\(["']([\s\S]*?)["']([\s\S]*?);/g; const CHANGES_REGEX = /([0-9]+)/g; if(html == null) { if(url == null) { throw new Error('Provided incorrect parameters.'); } const response = await soraFetch(url); html = await response.text(); } const matches = html.matchAll(LINK_REGEX); for (const match of matches) { let base = match?.[1]; let params = match?.[2]; const changeStr = match?.[3]; if(changeStr == null || changeStr == '') continue; const changes = changeStr.match(CHANGES_REGEX); for(let n of changes) { params = params.substring(n); } while(base[0] == '/') { base = base.substring(1); } const url = 'https://' + base + params; promises.push(testUrl(url)); } // Race for first success return Promise.any(promises).then((value) => { return value; }).catch((error) => { return null; }); async function testUrl(url) { return new Promise(async (resolve, reject) => { try { // Timeout version prefered, but Sora does not support it currently // var response = await soraFetch(url, { method: 'GET', signal: AbortSignal.timeout(2000) }); var response = await soraFetch(url); if(response == null) throw new Error('Connection timed out.'); } catch(e) { console.error('Rejected due to:', e.message); return reject(null); } if(response?.ok && response?.status === 200) { return resolve(url); } console.warn('Reject because of response:', response?.ok, response?.status); return reject(null); }); } } /* --- streamup --- */ /** * @name StreamUp Extractor * @author Cufiy */ async function streamupExtractor(data, url = null) { // if url ends with /, remove it if (url.endsWith("/")) { url = url.slice(0, -1); } // split the url by / and get the last part const urlParts = url.split("/"); const videoId = urlParts[urlParts.length - 1]; const apiUrl = `https://strmup.to/ajax/stream?filecode=${videoId}`; const response = await soraFetch(apiUrl); const jsonData = await response.json(); if (jsonData && jsonData.streaming_url) { return jsonData.streaming_url; } else { console.log("No streaming URL found in the response."); return null; } } /* --- supervideo --- */ /* {REQUIRED PLUGINS: unbaser} */ /** * @name SuperVideo Extractor * @author 50/50 */ async function supervideoExtractor(data, url = null) { const obfuscatedScript = data.match(/<script[^>]*>\s*(eval\(function\(p,a,c,k,e,d.*?\)[\s\S]*?)<\/script>/); const unpackedScript = unpack(obfuscatedScript[1]); const regex = /file:\s*"([^"]+\.m3u8)"/; const match = regex.exec(unpackedScript); if (match) { const fileUrl = match[1]; console.log("File URL:" + fileUrl); return fileUrl; } return "No stream found"; } /* --- uploadcx --- */ /** * @name UploadCx Extractor * @author 50/50 */ async function uploadcxExtractor(data, url = null) { const mp4Match = /sources:\s*\["([^"]+\.mp4)"]/i.exec(data); return mp4Match ? mp4Match[1] : null; } /* --- uqload --- */ /** * @name uqloadExtractor * @author scigward */ async function uqloadExtractor(html, embedUrl) { try { const match = html.match(/sources:\s*\[\s*"([^"]+\.mp4)"\s*\]/); const videoSrc = match ? match[1] : ""; return videoSrc; } catch (error) { console.log("uqloadExtractor error:", error.message); return null; } } /* --- videospk --- */ /* {REQUIRED PLUGINS: unbaser} */ /** * @name videospkExtractor * @author 50/50 */ async function videospkExtractor(data, url = null) { const obfuscatedScript = data.match(/<script[^>]*>\s*(eval\(function\(p,a,c,k,e,d.*?\)[\s\S]*?)<\/script>/); const unpackedScript = unpack(obfuscatedScript[1]); const streamMatch = unpackedScript.match(/["'](\/stream\/[^"']+)["']/); const hlsLink = streamMatch ? streamMatch[1] : null; return "https://videospk.xyz" + hlsLink; } /* --- vidmoly --- */ /** * @name vidmolyExtractor * @author Ibro */ async function vidmolyExtractor(html, url = null) { const regexSub = /<option value="([^"]+)"[^>]*>\s*SUB - Omega\s*<\/option>/; const regexFallback = /<option value="([^"]+)"[^>]*>\s*Omega\s*<\/option>/; const fallback = /<option value="([^"]+)"[^>]*>\s*SUB v2 - Omega\s*<\/option>/; let match = html.match(regexSub) || html.match(regexFallback) || html.match(fallback); if (match) { const decodedHtml = atob(match[1]); // Decode base64 const iframeMatch = decodedHtml.match(/<iframe\s+src="([^"]+)"/); if (!iframeMatch) { console.log("Vidmoly extractor: No iframe match found"); return null; } const streamUrl = iframeMatch[1].startsWith("//") ? "https:" + iframeMatch[1] : iframeMatch[1]; const responseTwo = await fetchv2(streamUrl); const htmlTwo = await responseTwo.text(); const m3u8Match = htmlTwo.match(/sources:\s*\[\{file:"([^"]+\.m3u8)"/); return m3u8Match ? m3u8Match[1] : null; } else { console.log("Vidmoly extractor: No match found, using fallback"); // regex the sources: [{file:"this_is_the_link"}] const sourcesRegex = /sources:\s*\[\{file:"(https?:\/\/[^"]+)"\}/; const sourcesMatch = html.match(sourcesRegex); let sourcesString = sourcesMatch ? sourcesMatch[1].replace(/'/g, '"') : null; return sourcesString; } } /* --- vidoza --- */ /** * @name vidozaExtractor * @author Cufiy */ async function vidozaExtractor(html, url = null) { const regex = /<source src="([^"]+)" type='video\/mp4'>/; const match = html.match(regex); if (match) { return match[1]; } else { console.log("No match found for vidoza extractor"); return null; } } /* --- voe --- */ /** * @name voeExtractor * @author Cufiy */ function voeExtractor(html, url = null) { // Extract the first <script type="application/json">...</script> const jsonScriptMatch = html.match( /<script[^>]+type=["']application\/json["'][^>]*>([\s\S]*?)<\/script>/i ); if (!jsonScriptMatch) { console.log("No application/json script tag found"); return null; } const obfuscatedJson = jsonScriptMatch[1].trim(); let data; try { data = JSON.parse(obfuscatedJson); } catch (e) { throw new Error("Invalid JSON input."); } if (!Array.isArray(data) || typeof data[0] !== "string") { throw new Error("Input doesn't match expected format."); } let obfuscatedString = data[0]; // Step 1: ROT13 let step1 = voeRot13(obfuscatedString); // Step 2: Remove patterns let step2 = voeRemovePatterns(step1); // Step 3: Base64 decode let step3 = voeBase64Decode(step2); // Step 4: Subtract 3 from each char code let step4 = voeShiftChars(step3, 3); // Step 5: Reverse string let step5 = step4.split("").reverse().join(""); // Step 6: Base64 decode again let step6 = voeBase64Decode(step5); // Step 7: Parse as JSON let result; try { result = JSON.parse(step6); } catch (e) { throw new Error("Final JSON parse error: " + e.message); } // console.log("Decoded JSON:", result); // check if direct_access_url is set, not null and starts with http if (result && typeof result === "object") { const streamUrl = result.direct_access_url || result.source .map((source) => source.direct_access_url) .find((url) => url && url.startsWith("http")); if (streamUrl) { console.log("Voe Stream URL: " + streamUrl); return streamUrl; } else { console.log("No stream URL found in the decoded JSON"); } } return result; } function voeRot13(str) { return str.replace(/[a-zA-Z]/g, function (c) { return String.fromCharCode( (c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26 ); }); } function voeRemovePatterns(str) { const patterns = ["@$", "^^", "~@", "%?", "*~", "!!", "#&"]; let result = str; for (const pat of patterns) { result = result.split(pat).join(""); } return result; } function voeBase64Decode(str) { // atob is available in browsers and Node >= 16 if (typeof atob === "function") { return atob(str); } // Node.js fallback return Buffer.from(str, "base64").toString("utf-8"); } function voeShiftChars(str, shift) { return str .split("") .map((c) => String.fromCharCode(c.charCodeAt(0) - shift)) .join(""); } //////////////////////////////////////////////// // PLUGINS // //////////////////////////////////////////////// /** * Uses Sora's fetchv2 on ipad, fallbacks to regular fetch on Windows * @author ShadeOfChaos * * @param {string} url The URL to make the request to. * @param {object} [options] The options to use for the request. * @param {object} [options.headers] The headers to send with the request. * @param {string} [options.method='GET'] The method to use for the request. * @param {string} [options.body=null] The body of the request. * * @returns {Promise<Response|null>} The response from the server, or null if the * request failed. */ async function soraFetch(url, options = { headers: {}, method: 'GET', body: null }) { try { return await fetchv2(url, options.headers ?? {}, options.method ?? 'GET', options.body ?? null); } catch(e) { try { return await fetch(url, options); } catch(error) { await console.log('soraFetch error: ' + error.message); return null; } } } /*********************************************************** * UNPACKER MODULE * Credit to GitHub user "mnsrulz" for Unpacker Node library * https://github.com/mnsrulz/unpacker ***********************************************************/ class Unbaser { constructor(base) { this.ALPHABET = { 62: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 95: "' !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'", }; this.dictionary = {}; this.base = base; if (36 < base && base < 62) { this.ALPHABET[base] = this.ALPHABET[base] || this.ALPHABET[62].substr(0, base); } if (2 <= base && base <= 36) { this.unbase = (value) => parseInt(value, base); } else { try { [...this.ALPHABET[base]].forEach((cipher, index) => { this.dictionary[cipher] = index; }); } catch (er) { throw Error("Unsupported base encoding."); } this.unbase = this._dictunbaser; } } _dictunbaser(value) { let ret = 0; [...value].reverse().forEach((cipher, index) => { ret = ret + ((Math.pow(this.base, index)) * this.dictionary[cipher]); }); return ret; } } function detectUnbaser(source) { /* Detects whether `source` is P.A.C.K.E.R. coded. */ return source.replace(" ", "").startsWith("eval(function(p,a,c,k,e,"); } function unpack(source) { let { payload, symtab, radix, count } = _filterargs(source); if (count != symtab.length) { throw Error("Malformed p.a.c.k.e.r. symtab."); } let unbase; try { unbase = new Unbaser(radix); } catch (e) { throw Error("Unknown p.a.c.k.e.r. encoding."); } function lookup(match) { const word = match; let word2; if (radix == 1) { word2 = symtab[parseInt(word)]; } else { word2 = symtab[unbase.unbase(word)]; } return word2 || word; } source = payload.replace(/\b\w+\b/g, lookup); return _replacestrings(source); function _filterargs(source) { const juicers = [ /}\('(.*)', *(\d+|\[\]), *(\d+), *'(.*)'\.split\('\|'\), *(\d+), *(.*)\)\)/, /}\('(.*)', *(\d+|\[\]), *(\d+), *'(.*)'\.split\('\|'\)/, ]; for (const juicer of juicers) { const args = juicer.exec(source); if (args) { let a = args; if (a[2] == "[]") { } try { return { payload: a[1], symtab: a[4].split("|"), radix: parseInt(a[2]), count: parseInt(a[3]), }; } catch (ValueError) { throw Error("Corrupted p.a.c.k.e.r. data."); } } } throw Error("Could not make sense of p.a.c.k.e.r data (unexpected code structure)"); } function _replacestrings(source) { return source; } } /* {GE END} */