update
This commit is contained in:
+126
-63
@@ -124,79 +124,142 @@ async function extractStreamUrl(url) {
|
||||
const responseText = await ddosInterceptor.fetchWithBypass(url);
|
||||
const dataText = await responseText.text();
|
||||
|
||||
const buttonMatches = dataText.match(/<button[^>]*data-src="([^"]*)"[^>]*>/g);
|
||||
if (!buttonMatches) {
|
||||
const buttonRegex = /<button[^>]*data-src="([^"]+)"[^>]*data-fansub="([^"]+)"[^>]*data-resolution="([^"]+)"[^>]*data-audio="([^"]+)"[^>]*>/g;
|
||||
const buttons = [];
|
||||
let match;
|
||||
while ((match = buttonRegex.exec(dataText)) !== null) {
|
||||
buttons.push({
|
||||
src: match[1],
|
||||
fansub: match[2],
|
||||
resolution: match[3],
|
||||
audio: match[4]
|
||||
});
|
||||
}
|
||||
|
||||
if (buttons.length === 0) {
|
||||
const buttonMatches = dataText.match(/<button[^>]*data-src="([^"]*)"[^>]*>/g);
|
||||
if (!buttonMatches) {
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
}
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
}
|
||||
|
||||
const streamPromises = buttonMatches.map(async (buttonHtml) => {
|
||||
const srcMatch = buttonHtml.match(/data-src="([^"]*)"/);
|
||||
const resMatch = buttonHtml.match(/data-resolution="([^"]*)"/);
|
||||
const audioMatch = buttonHtml.match(/data-audio="([^"]*)"/);
|
||||
const fansubMatch = buttonHtml.match(/data-fansub="([^"]*)"/);
|
||||
|
||||
if (!srcMatch || !srcMatch[1].includes('kwik.cx')) return null;
|
||||
|
||||
const kwikUrl = srcMatch[1];
|
||||
const resolution = resMatch ? resMatch[1] : "Unknown";
|
||||
const audio = audioMatch ? audioMatch[1] : "jpn";
|
||||
const fansub = fansubMatch ? fansubMatch[1] : "Unknown";
|
||||
|
||||
try {
|
||||
const html = await fetchv2(kwikUrl).then(r => r.text());
|
||||
const scriptMatch = html.match(/<script>(.*?)<\/script>/s);
|
||||
|
||||
if (scriptMatch) {
|
||||
const scriptContent = scriptMatch[1];
|
||||
let unpacked = null;
|
||||
|
||||
if (scriptContent.includes('));eval(')) {
|
||||
const parts = scriptContent.split('));eval(');
|
||||
if (parts.length === 2) {
|
||||
const layer2Packed = parts[1].substring(0, parts[1].length - 1);
|
||||
unpacked = unpack(layer2Packed);
|
||||
}
|
||||
} else {
|
||||
unpacked = unpack(scriptContent);
|
||||
}
|
||||
|
||||
if (unpacked) {
|
||||
const urlMatch = unpacked.match(/const source=\\?['"]([^'"]+)['"]/) ||
|
||||
unpacked.match(/https:\/\/[^\s'";]+\.m3u8/);
|
||||
|
||||
if (urlMatch) {
|
||||
let hlsUrl = (urlMatch[1] || urlMatch[0]).replace(/\\+$/, '');
|
||||
const audioType = audio === "eng" ? "Dub" : "Hardsub";
|
||||
const title = `${resolution}p • ${audioType}`;
|
||||
|
||||
hlsUrl = hlsUrl
|
||||
.replace("/stream/", "/hls/")
|
||||
.replace("uwu.m3u8", "owo.m3u8");
|
||||
|
||||
return {
|
||||
title: title,
|
||||
streamUrl: hlsUrl,
|
||||
headers: {
|
||||
"Referer": "https://kwik.cx/",
|
||||
"Origin": "https://kwik.cx"
|
||||
}
|
||||
};
|
||||
const deepUnpack = (source) => {
|
||||
let decoded = source;
|
||||
let safety = 0;
|
||||
while (/eval\(function\(p,a,c,k,e,d\)/.test(decoded) && safety < 5) {
|
||||
try {
|
||||
decoded = unpack(decoded);
|
||||
safety++;
|
||||
} catch (e) {
|
||||
console.warn("[Animepahe] Unpack error at depth " + safety + ": " + e.message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return decoded;
|
||||
};
|
||||
|
||||
const streamPromises = buttons.map(async (btn) => {
|
||||
const kwikUrl = btn.src;
|
||||
const audioType = btn.audio === "jpn" ? "Hardsub" : "Dub";
|
||||
const title = btn.resolution + "p • " + audioType;
|
||||
|
||||
try {
|
||||
const headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
|
||||
"Referer": "https://animepahe.pw/",
|
||||
"Origin": "https://kwik.cx",
|
||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
||||
};
|
||||
const resp = await fetchv2(kwikUrl, headers);
|
||||
const html = await resp.text();
|
||||
const evalRegex = /eval\(function\(p,a,c,k,e,d\)\{[^}]*\}\('[^']*',\d+,\d+,'[^']*'\.split\('\|'\)[^)]*\)/g;
|
||||
const evalBlocks = [...html.matchAll(evalRegex)].map(m => m[0]);
|
||||
|
||||
if (evalBlocks.length === 0) {
|
||||
const scriptMatch = html.match(/<script>(.*?)<\/script>/s);
|
||||
if (scriptMatch) {
|
||||
const scriptContent = scriptMatch[1];
|
||||
let unpacked = null;
|
||||
if (scriptContent.includes('));eval(')) {
|
||||
const parts = scriptContent.split('));eval(');
|
||||
if (parts.length === 2) {
|
||||
const layer2Packed = parts[1].substring(0, parts[1].length - 1);
|
||||
try { unpacked = unpack(layer2Packed); } catch(e) {}
|
||||
}
|
||||
} else {
|
||||
try { unpacked = unpack(scriptContent); } catch(e) {}
|
||||
}
|
||||
if (unpacked) {
|
||||
const urlMatch = unpacked.match(/const source=\\?['"]([^'"]+)['"]/) ||
|
||||
unpacked.match(/https:\/\/[^\s'";]+\.m3u8/);
|
||||
if (urlMatch) {
|
||||
let hlsUrl = (urlMatch[1] || urlMatch[0]).replace(/\\+$/, '');
|
||||
hlsUrl = hlsUrl.replace("/stream/", "/hls/").replace("uwu.m3u8", "owo.m3u8");
|
||||
return {
|
||||
title: title,
|
||||
streamUrl: hlsUrl,
|
||||
headers: { "Referer": "https://kwik.cx/", "Origin": "https://kwik.cx" }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
let hlsUrl = null;
|
||||
for (const block of evalBlocks) {
|
||||
try {
|
||||
const unpacked = deepUnpack(block);
|
||||
console.log("[Animepahe] Unpacked snippet: " + unpacked.substring(0, 150));
|
||||
const sourceMatch = unpacked.match(/(?:source\s*=\s*['"]([^'"]+\.m3u8)['"])/i);
|
||||
if (sourceMatch) {
|
||||
hlsUrl = sourceMatch[1];
|
||||
break;
|
||||
}
|
||||
const directMatch = unpacked.match(/https?:\/\/[^\s'"<>]+\.m3u8[^\s'"<>]*/i);
|
||||
if (directMatch) {
|
||||
hlsUrl = directMatch[0];
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!hlsUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
hlsUrl = hlsUrl.replace(/\\+$/, '');
|
||||
hlsUrl = hlsUrl.replace("/stream/", "/hls/").replace("uwu.m3u8", "owo.m3u8");
|
||||
return {
|
||||
title: title,
|
||||
streamUrl: hlsUrl,
|
||||
headers: { "Referer": "https://kwik.cx/", "Origin": "https://kwik.cx" }
|
||||
};
|
||||
} catch (e) {
|
||||
// Continue to next
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
const streamResults = await Promise.all(streamPromises);
|
||||
const streams = streamResults.filter(s => s !== null);
|
||||
|
||||
return JSON.stringify({
|
||||
streams: streams,
|
||||
subtitle: ""
|
||||
|
||||
const results = await Promise.allSettled(streamPromises);
|
||||
const streams = results
|
||||
.filter(r => r.status === "fulfilled" && r.value)
|
||||
.map(r => r.value);
|
||||
|
||||
|
||||
streams.sort((a, b) => {
|
||||
const aIsSub = a.title.includes("Hardsub") ? 0 : 1;
|
||||
const bIsSub = b.title.includes("Hardsub") ? 0 : 1;
|
||||
if (aIsSub !== bIsSub) return aIsSub - bIsSub;
|
||||
const aRes = parseInt(a.title.match(/(\d+)p/)?.[1] || 0);
|
||||
const bRes = parseInt(b.title.match(/(\d+)p/)?.[1] || 0);
|
||||
return bRes - aRes;
|
||||
});
|
||||
|
||||
const finalResult = JSON.stringify({ streams: streams, subtitle: "" });
|
||||
return finalResult;
|
||||
|
||||
} catch (err) {
|
||||
return JSON.stringify({ streams: [], subtitle: "" });
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"name": "50/50",
|
||||
"icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s"
|
||||
},
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.4",
|
||||
"language": "English",
|
||||
"streamType": "HLS",
|
||||
"quality": "1080p",
|
||||
|
||||
Reference in New Issue
Block a user