diff --git a/animetoast/animetoast.json b/animetoast/animetoast.json index f513aea..20e90eb 100644 --- a/animetoast/animetoast.json +++ b/animetoast/animetoast.json @@ -5,7 +5,7 @@ "name": "50/50 & Cufiy", "icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s" }, - "version": "1.2.13", + "version": "1.2.14", "language": "German (DUB/SUB)", "streamType": "MP4", "quality": "1080p", @@ -17,4 +17,4 @@ "supportsMojuru": true, "supportsSora": true, "supportsLuna": true -} +} \ No newline at end of file diff --git a/animetoast/animetoast_v2.js b/animetoast/animetoast_v2.js index 0cd2cc8..23d2a68 100644 --- a/animetoast/animetoast_v2.js +++ b/animetoast/animetoast_v2.js @@ -313,7 +313,7 @@ async function sendLog(message) { // EDITING THIS FILE COULD BREAK THE UPDATER AND CAUSE ISSUES WITH THE EXTRACTOR /* {GE START} */ -/* {VERSION: 1.1.8} */ +/* {VERSION: 1.2.0} */ /** * @name global_extractor.js @@ -321,8 +321,8 @@ async function sendLog(message) { * @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 + * @date 2026-01-03 19:28:28 + * @version 1.2.0 * @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 */ @@ -332,12 +332,20 @@ function globalExtractor(providers) { for (const [url, provider] of Object.entries(providers)) { try { const streamUrl = extractStreamUrlByProvider(url, provider); + // check if streamUrl is an object with streamUrl property + if (streamUrl && typeof streamUrl === "object" && !Array.isArray(streamUrl) && streamUrl.streamUrl) { + return streamUrl.streamUrl; + } // check if streamUrl is not null, a string, and starts with http or https - if (streamUrl && typeof streamUrl === "string" && (streamUrl.startsWith("http"))) { + 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")); + const httpStream = streamUrl.find((url) => url.startsWith("http")); if (httpStream) { return httpStream; } @@ -345,7 +353,6 @@ function globalExtractor(providers) { // check if it's a valid stream URL return null; } - } catch (error) { // Ignore the error and try the next provider } @@ -357,16 +364,30 @@ 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" + { + "title": "FileMoon", + "streamUrl": "https://filemoon.example/stream1.m3u8", + }, + { + "title": "StreamWish", + "streamUrl": "https://streamwish.example/stream2.m3u8", + }, + { + "title": "Okru", + "streamUrl": "https://okru.example/stream3.m3u8", + "headers": { // Optional headers for the stream + "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", + "Referer": "https://okru.example/", + }, + }, + { + "title": "MP4", + "streamUrl": "https://mp4upload.example/stream4.mp4", + }, + { + "title": "Default", + "streamUrl": "https://default.example/stream5.m3u8" + } ] } */ @@ -378,20 +399,21 @@ async function multiExtractor(providers) { // 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 - } + const title = (directName && directName.length > 0) ? directName : "Direct"; + streams.push({ + title: title, + streamUrl: url + }); 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 - } + const title = (provider && provider.length > 0) ? provider : "Direct"; + streams.push({ + title: title, + streamUrl: url + }); + continue; // skip to the next provider } let customName = null; // to store the custom name if provided @@ -408,15 +430,24 @@ async function multiExtractor(providers) { 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")); + let result = await extractStreamUrlByProvider(url, provider); + let streamUrl = null; + let headers = null; + + // Check if result is an object with streamUrl and optional headers + if (result && typeof result === "object" && !Array.isArray(result) && result.streamUrl) { + streamUrl = result.streamUrl; + headers = result.headers || null; + } else if (result && Array.isArray(result)) { + const httpStream = result.find((url) => url.startsWith("http")); if (httpStream) { streamUrl = httpStream; } + } else if (result && typeof result === "string") { + streamUrl = result; } - // check if provider is already in streams, if it is, add a number to it + + // check if streamUrl is valid if ( !streamUrl || typeof streamUrl !== "string" || @@ -430,22 +461,29 @@ async function multiExtractor(providers) { provider = customName; } + let title; if (providersCount[provider]) { providersCount[provider]++; - streams.push( - provider.charAt(0).toUpperCase() + + title = provider.charAt(0).toUpperCase() + provider.slice(1) + "-" + - (providersCount[provider] - 1), // add a number to the provider name - streamUrl - ); + (providersCount[provider] - 1); // add a number to the provider name } else { providersCount[provider] = 1; - streams.push( - provider.charAt(0).toUpperCase() + provider.slice(1), - streamUrl - ); + title = provider.charAt(0).toUpperCase() + provider.slice(1); } + + const streamObject = { + title: title, + streamUrl: streamUrl + }; + + // Add headers if they exist + if (headers && typeof headers === "object" && Object.keys(headers).length > 0) { + streamObject.headers = headers; + } + + streams.push(streamObject); } catch (error) { // Ignore the error and try the next provider } @@ -456,73 +494,98 @@ async function multiExtractor(providers) { 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...`); + console.log( + `Extractor for provider ${provider} is not defined, skipping...` + ); return null; } + let uas = [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3", + "Mozilla/5.0 (iPhone; CPU iPhone OS 18_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1.1 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Linux; Android 10; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Mobile Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Safari/605.1.15", + "Mozilla/5.0 (Linux; Android 11; Pixel 4 XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Mobile Safari/537.36", + ]; 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", + "User-Agent": uas[(url.length + provider.length) % uas.length], // use a different user agent based on the url and provider + "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" + "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"]; + + switch (provider) { + case "bigwarp": + delete headers["User-Agent"]; + break; + case "vk": + case "sibnet": + headers["encoding"] = "windows-1251"; // required + break; + case "supervideo": + case "savefiles": + headers = { + "Accept": "*/*", + "Accept-Encoding": "gzip, deflate, br", + "User-Agent": "EchoapiRuntime/1.1.0", + "Connection": "keep-alive", + "Cache-Control": "no-cache", + "Host": url.match(/https?:\/\/([^\/]+)/)[1], + }; + break; + case "streamtape": + headers = { + "User-Agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0", + "Accept": + "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + }; + break; } + // console.log("Using headers: " + JSON.stringify(headers)); // fetch the url // and pass the response to the extractor function console.log("Fetching URL: " + url); const response = await soraFetch(url, { - headers - }); + 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(/