mirror of
https://git.luna-app.eu/50n50/sources
synced 2026-01-12 09:28:35 +01:00
Bump versions to 0.3.17 for English and German Dubs; update global extractor to version 1.2.0 with enhanced stream URL extraction and new extractor functions for oneupload, packer, and smoothpre. Refactor stream handling to support headers and improve error handling in fetch requests.
This commit is contained in:
parent
71f7d30321
commit
92f3a20556
21 changed files with 2467 additions and 1295 deletions
|
|
@ -5,7 +5,7 @@
|
|||
"name": "Cufiy",
|
||||
"icon": "https://files.catbox.moe/ttj4fc.gif"
|
||||
},
|
||||
"version": "0.3.16",
|
||||
"version": "0.3.17",
|
||||
"language": "English (DUB)",
|
||||
"streamType": "HLS",
|
||||
"quality": "720p",
|
||||
|
|
@ -17,4 +17,4 @@
|
|||
"type": "shows",
|
||||
"supportsSora": true,
|
||||
"supportsLuna": true
|
||||
}
|
||||
}
|
||||
|
|
@ -376,7 +376,7 @@ function base64Decode(str) {
|
|||
// 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
|
||||
|
|
@ -384,8 +384,8 @@ function base64Decode(str) {
|
|||
* @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
|
||||
*/
|
||||
|
|
@ -395,12 +395,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;
|
||||
}
|
||||
|
|
@ -408,7 +416,6 @@ function globalExtractor(providers) {
|
|||
// check if it's a valid stream URL
|
||||
return null;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
// Ignore the error and try the next provider
|
||||
}
|
||||
|
|
@ -420,16 +427,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"
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
|
|
@ -441,20 +462,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
|
||||
|
|
@ -471,15 +493,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" ||
|
||||
|
|
@ -493,22 +524,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
|
||||
}
|
||||
|
|
@ -519,73 +557,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(/<title>(.*?)<\/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");
|
||||
const matches = [
|
||||
/<meta http-equiv="refresh" content="0;url=(.*?)"/,
|
||||
/window\.location\.href\s*=\s*["'](.*?)["']/,
|
||||
/window\.location\.replace\s*\(\s*["'](.*?)["']\s*\)/,
|
||||
/window\.location\s*=\s*["'](.*?)["']/,
|
||||
/window\.location\.assign\s*\(\s*["'](.*?)["']\s*\)/,
|
||||
/top\.location\s*=\s*["'](.*?)["']/,
|
||||
/top\.location\.replace\s*\(\s*["'](.*?)["']\s*\)/,
|
||||
];
|
||||
for (const match of matches) {
|
||||
const redirectUrl = html.match(match);
|
||||
if (redirectUrl && redirectUrl[1] && typeof redirectUrl[1] === "string" && redirectUrl[1].startsWith("http")) {
|
||||
console.log("Redirect URL found: " + redirectUrl[1]);
|
||||
url = redirectUrl[1];
|
||||
headers['Referer'] = url;
|
||||
headers['Host'] = url.match(/https?:\/\/([^\/]+)/)[1];
|
||||
html = await soraFetch(url, {
|
||||
headers,
|
||||
}).then((res) => res.text());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// console.log("HTML: " + html);
|
||||
switch (provider) {
|
||||
case "bigwarp":
|
||||
case "bigwarp":
|
||||
try {
|
||||
return await bigwarpExtractor(html, url);
|
||||
} catch (error) {
|
||||
|
|
@ -634,6 +697,20 @@ async function extractStreamUrlByProvider(url, provider) {
|
|||
console.log("Error extracting stream URL from mp4upload:", error);
|
||||
return null;
|
||||
}
|
||||
case "oneupload":
|
||||
try {
|
||||
return await oneuploadExtractor(html, url);
|
||||
} catch (error) {
|
||||
console.log("Error extracting stream URL from oneupload:", error);
|
||||
return null;
|
||||
}
|
||||
case "packer":
|
||||
try {
|
||||
return await packerExtractor(html, url);
|
||||
} catch (error) {
|
||||
console.log("Error extracting stream URL from packer:", error);
|
||||
return null;
|
||||
}
|
||||
case "sendvid":
|
||||
try {
|
||||
return await sendvidExtractor(html, url);
|
||||
|
|
@ -648,6 +725,13 @@ async function extractStreamUrlByProvider(url, provider) {
|
|||
console.log("Error extracting stream URL from sibnet:", error);
|
||||
return null;
|
||||
}
|
||||
case "smoothpre":
|
||||
try {
|
||||
return await smoothpreExtractor(html, url);
|
||||
} catch (error) {
|
||||
console.log("Error extracting stream URL from smoothpre:", error);
|
||||
return null;
|
||||
}
|
||||
case "streamtape":
|
||||
try {
|
||||
return await streamtapeExtractor(html, url);
|
||||
|
|
@ -662,13 +746,6 @@ async function extractStreamUrlByProvider(url, provider) {
|
|||
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);
|
||||
|
|
@ -717,7 +794,6 @@ async function extractStreamUrlByProvider(url, provider) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// EXTRACTORS //
|
||||
////////////////////////////////////////////////
|
||||
|
|
@ -1204,7 +1280,6 @@ async function megacloudExtractor(html, embedUrl) {
|
|||
* @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) {
|
||||
|
|
@ -1214,6 +1289,32 @@ async function mp4uploadExtractor(html, url = null) {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
/* --- oneupload --- */
|
||||
|
||||
/**
|
||||
* @name oneuploadExtractor
|
||||
* @author 50/50
|
||||
*/
|
||||
async function oneuploadExtractor(data, url = null) {
|
||||
const match = data.match(/sources:\s*\[\{file:"([^"]+)"\}\]/);
|
||||
const fileUrl = match ? match[1] : null;
|
||||
return fileUrl;
|
||||
}
|
||||
/* --- packer --- */
|
||||
|
||||
/* {REQUIRED PLUGINS: unbaser} */
|
||||
/**
|
||||
* @name packerExtractor
|
||||
* @author 50/50
|
||||
*/
|
||||
async function packerExtractor(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 m3u8Match = unpackedScript.match(/"hls2"\s*:\s*"([^"]+)"/);
|
||||
const m3u8Url = m3u8Match[1];
|
||||
return m3u8Url;
|
||||
}
|
||||
|
||||
/* --- sendvid --- */
|
||||
|
||||
/**
|
||||
|
|
@ -1249,6 +1350,29 @@ async function sibnetExtractor(html, embedUrl) {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
/* --- smoothpre --- */
|
||||
|
||||
/* {REQUIRED PLUGINS: unbaser} */
|
||||
/**
|
||||
* @name SmoothPre Extractor
|
||||
* @author 50/50
|
||||
*/
|
||||
async function smoothpreExtractor(data, url = null) {
|
||||
console.log("Using SmoothPre Extractor");
|
||||
console.log("Data Length: " + data.length);
|
||||
const obfuscatedScript = data.match(/<script[^>]*>\s*(eval\(function\(p,a,c,k,e,d.*?\)[\s\S]*?)<\/script>/);
|
||||
if (!obfuscatedScript || !obfuscatedScript[1]) {
|
||||
console.log("No obfuscated script found");
|
||||
return null;
|
||||
}
|
||||
const unpackedScript = unpack(obfuscatedScript[1]);
|
||||
|
||||
const hls2Match = unpackedScript.match(/"hls2"\s*:\s*"([^"]+)"/);
|
||||
const hls2Url = hls2Match ? hls2Match[1] : null;
|
||||
return hls2Url;
|
||||
}
|
||||
|
||||
|
||||
/* --- streamtape --- */
|
||||
|
||||
/**
|
||||
|
|
@ -1332,26 +1456,6 @@ async function streamupExtractor(data, url = null) {
|
|||
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 --- */
|
||||
|
||||
/**
|
||||
|
|
@ -1416,7 +1520,7 @@ async function vidmolyExtractor(html, url = null) {
|
|||
const streamUrl = iframeMatch[1].startsWith("//")
|
||||
? "https:" + iframeMatch[1]
|
||||
: iframeMatch[1];
|
||||
const responseTwo = await fetchv2(streamUrl);
|
||||
const responseTwo = await soraFetch(streamUrl);
|
||||
const htmlTwo = await responseTwo.text();
|
||||
const m3u8Match = htmlTwo.match(/sources:\s*\[\{file:"([^"]+\.m3u8)"/);
|
||||
return m3u8Match ? m3u8Match[1] : null;
|
||||
|
|
@ -1542,6 +1646,7 @@ function voeShiftChars(str, shift) {
|
|||
.join("");
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// PLUGINS //
|
||||
////////////////////////////////////////////////
|
||||
|
|
@ -1559,17 +1664,25 @@ function voeShiftChars(str, shift) {
|
|||
* @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 }) {
|
||||
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 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;
|
||||
}
|
||||
return await fetch(url, options);
|
||||
} catch (error) {
|
||||
await console.log("soraFetch error: " + error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
/***********************************************************
|
||||
* UNPACKER MODULE
|
||||
|
|
@ -1673,7 +1786,6 @@ function unpack(source) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* {GE END} */
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
"name": "Hamzo & Cufiy",
|
||||
"icon": "https://cdn.discordapp.com/avatars/623644371819954226/591ecab10b0b4535e859bb0b9bbe62e5?size=1024"
|
||||
},
|
||||
"version": "0.3.16",
|
||||
"version": "0.3.17",
|
||||
"language": "German (DUB)",
|
||||
"streamType": "HLS",
|
||||
"quality": "720p",
|
||||
|
|
@ -17,4 +17,4 @@
|
|||
"type": "shows",
|
||||
"supportsSora": true,
|
||||
"supportsLuna": true
|
||||
}
|
||||
}
|
||||
|
|
@ -376,7 +376,7 @@ function base64Decode(str) {
|
|||
// 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
|
||||
|
|
@ -384,8 +384,8 @@ function base64Decode(str) {
|
|||
* @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
|
||||
*/
|
||||
|
|
@ -395,12 +395,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;
|
||||
}
|
||||
|
|
@ -408,7 +416,6 @@ function globalExtractor(providers) {
|
|||
// check if it's a valid stream URL
|
||||
return null;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
// Ignore the error and try the next provider
|
||||
}
|
||||
|
|
@ -420,16 +427,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"
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
|
|
@ -441,20 +462,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
|
||||
|
|
@ -471,15 +493,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" ||
|
||||
|
|
@ -493,22 +524,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
|
||||
}
|
||||
|
|
@ -519,73 +557,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(/<title>(.*?)<\/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");
|
||||
const matches = [
|
||||
/<meta http-equiv="refresh" content="0;url=(.*?)"/,
|
||||
/window\.location\.href\s*=\s*["'](.*?)["']/,
|
||||
/window\.location\.replace\s*\(\s*["'](.*?)["']\s*\)/,
|
||||
/window\.location\s*=\s*["'](.*?)["']/,
|
||||
/window\.location\.assign\s*\(\s*["'](.*?)["']\s*\)/,
|
||||
/top\.location\s*=\s*["'](.*?)["']/,
|
||||
/top\.location\.replace\s*\(\s*["'](.*?)["']\s*\)/,
|
||||
];
|
||||
for (const match of matches) {
|
||||
const redirectUrl = html.match(match);
|
||||
if (redirectUrl && redirectUrl[1] && typeof redirectUrl[1] === "string" && redirectUrl[1].startsWith("http")) {
|
||||
console.log("Redirect URL found: " + redirectUrl[1]);
|
||||
url = redirectUrl[1];
|
||||
headers['Referer'] = url;
|
||||
headers['Host'] = url.match(/https?:\/\/([^\/]+)/)[1];
|
||||
html = await soraFetch(url, {
|
||||
headers,
|
||||
}).then((res) => res.text());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// console.log("HTML: " + html);
|
||||
switch (provider) {
|
||||
case "bigwarp":
|
||||
case "bigwarp":
|
||||
try {
|
||||
return await bigwarpExtractor(html, url);
|
||||
} catch (error) {
|
||||
|
|
@ -634,6 +697,20 @@ async function extractStreamUrlByProvider(url, provider) {
|
|||
console.log("Error extracting stream URL from mp4upload:", error);
|
||||
return null;
|
||||
}
|
||||
case "oneupload":
|
||||
try {
|
||||
return await oneuploadExtractor(html, url);
|
||||
} catch (error) {
|
||||
console.log("Error extracting stream URL from oneupload:", error);
|
||||
return null;
|
||||
}
|
||||
case "packer":
|
||||
try {
|
||||
return await packerExtractor(html, url);
|
||||
} catch (error) {
|
||||
console.log("Error extracting stream URL from packer:", error);
|
||||
return null;
|
||||
}
|
||||
case "sendvid":
|
||||
try {
|
||||
return await sendvidExtractor(html, url);
|
||||
|
|
@ -648,6 +725,13 @@ async function extractStreamUrlByProvider(url, provider) {
|
|||
console.log("Error extracting stream URL from sibnet:", error);
|
||||
return null;
|
||||
}
|
||||
case "smoothpre":
|
||||
try {
|
||||
return await smoothpreExtractor(html, url);
|
||||
} catch (error) {
|
||||
console.log("Error extracting stream URL from smoothpre:", error);
|
||||
return null;
|
||||
}
|
||||
case "streamtape":
|
||||
try {
|
||||
return await streamtapeExtractor(html, url);
|
||||
|
|
@ -662,13 +746,6 @@ async function extractStreamUrlByProvider(url, provider) {
|
|||
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);
|
||||
|
|
@ -717,7 +794,6 @@ async function extractStreamUrlByProvider(url, provider) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// EXTRACTORS //
|
||||
////////////////////////////////////////////////
|
||||
|
|
@ -1204,7 +1280,6 @@ async function megacloudExtractor(html, embedUrl) {
|
|||
* @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) {
|
||||
|
|
@ -1214,6 +1289,32 @@ async function mp4uploadExtractor(html, url = null) {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
/* --- oneupload --- */
|
||||
|
||||
/**
|
||||
* @name oneuploadExtractor
|
||||
* @author 50/50
|
||||
*/
|
||||
async function oneuploadExtractor(data, url = null) {
|
||||
const match = data.match(/sources:\s*\[\{file:"([^"]+)"\}\]/);
|
||||
const fileUrl = match ? match[1] : null;
|
||||
return fileUrl;
|
||||
}
|
||||
/* --- packer --- */
|
||||
|
||||
/* {REQUIRED PLUGINS: unbaser} */
|
||||
/**
|
||||
* @name packerExtractor
|
||||
* @author 50/50
|
||||
*/
|
||||
async function packerExtractor(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 m3u8Match = unpackedScript.match(/"hls2"\s*:\s*"([^"]+)"/);
|
||||
const m3u8Url = m3u8Match[1];
|
||||
return m3u8Url;
|
||||
}
|
||||
|
||||
/* --- sendvid --- */
|
||||
|
||||
/**
|
||||
|
|
@ -1249,6 +1350,29 @@ async function sibnetExtractor(html, embedUrl) {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
/* --- smoothpre --- */
|
||||
|
||||
/* {REQUIRED PLUGINS: unbaser} */
|
||||
/**
|
||||
* @name SmoothPre Extractor
|
||||
* @author 50/50
|
||||
*/
|
||||
async function smoothpreExtractor(data, url = null) {
|
||||
console.log("Using SmoothPre Extractor");
|
||||
console.log("Data Length: " + data.length);
|
||||
const obfuscatedScript = data.match(/<script[^>]*>\s*(eval\(function\(p,a,c,k,e,d.*?\)[\s\S]*?)<\/script>/);
|
||||
if (!obfuscatedScript || !obfuscatedScript[1]) {
|
||||
console.log("No obfuscated script found");
|
||||
return null;
|
||||
}
|
||||
const unpackedScript = unpack(obfuscatedScript[1]);
|
||||
|
||||
const hls2Match = unpackedScript.match(/"hls2"\s*:\s*"([^"]+)"/);
|
||||
const hls2Url = hls2Match ? hls2Match[1] : null;
|
||||
return hls2Url;
|
||||
}
|
||||
|
||||
|
||||
/* --- streamtape --- */
|
||||
|
||||
/**
|
||||
|
|
@ -1332,26 +1456,6 @@ async function streamupExtractor(data, url = null) {
|
|||
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 --- */
|
||||
|
||||
/**
|
||||
|
|
@ -1416,7 +1520,7 @@ async function vidmolyExtractor(html, url = null) {
|
|||
const streamUrl = iframeMatch[1].startsWith("//")
|
||||
? "https:" + iframeMatch[1]
|
||||
: iframeMatch[1];
|
||||
const responseTwo = await fetchv2(streamUrl);
|
||||
const responseTwo = await soraFetch(streamUrl);
|
||||
const htmlTwo = await responseTwo.text();
|
||||
const m3u8Match = htmlTwo.match(/sources:\s*\[\{file:"([^"]+\.m3u8)"/);
|
||||
return m3u8Match ? m3u8Match[1] : null;
|
||||
|
|
@ -1542,6 +1646,7 @@ function voeShiftChars(str, shift) {
|
|||
.join("");
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// PLUGINS //
|
||||
////////////////////////////////////////////////
|
||||
|
|
@ -1559,17 +1664,25 @@ function voeShiftChars(str, shift) {
|
|||
* @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 }) {
|
||||
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 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;
|
||||
}
|
||||
return await fetch(url, options);
|
||||
} catch (error) {
|
||||
await console.log("soraFetch error: " + error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
/***********************************************************
|
||||
* UNPACKER MODULE
|
||||
|
|
@ -1673,7 +1786,6 @@ function unpack(source) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* {GE END} */
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue