diff --git a/faselhd/faselhd.js b/faselhd/faselhd.js
index 0ac1f04..8769972 100644
--- a/faselhd/faselhd.js
+++ b/faselhd/faselhd.js
@@ -132,29 +132,101 @@ async function extractStreamUrl(url) {
const regex = /
]*>\s*(\(function\([\s\S]*?)\s*<\/script>/i;
+ const scriptMatch = html2.match(scriptRegex);
+ if (scriptMatch && scriptMatch[1]) {
+ const postData = {
+ code: scriptMatch[1].trim(),
+ options: {
+ jsx: true,
+ unpack: true,
+ unminify: true,
+ deobfuscate: true,
+ mangle: false
+ }
+ };
+ const decryptResp = await fetchv2("https://webcrack-fdpm.vercel.app/api/decrypt", { "Content-Type": "application/json" }, "POST", postData);
+ const result = await decryptResp.json();
+ const deobfuscatedCode = result.code;
+
+ const extracted = (function(code) {
+ let m = code.match(/sources:\s*\[\{\s*file:\s*"([^"]+\.m3u8)"/);
+ if (m) return m[1];
+ m = code.match(/data-url="([^"]+\.m3u8)"/);
+ if (m) return m[1];
+ m = code.match(/file:\s*"([^"]+\.m3u8)"/);
+ if (m) return m[1];
+ return null;
+ })(deobfuscatedCode);
+
+ if (extracted) {
+ const final = await a(extracted);
+ return final || "";
+ }
+ }
+
+ try {
+ const netRes = await networkFetch(primaryUrl, { timeoutSeconds: 2, returnHTML: true });
+ const netHtml = netRes.html || "";
+
+ const fm = netHtml.match(/data-url="([^"]+\.m3u8)"/)
+ || netHtml.match(/sources:\s*\[\{\s*file:\s*"([^"]+\.m3u8)"/)
+ || netHtml.match(/file:\s*"([^"]+\.m3u8)"/);
+
+ const found = fm ? fm[1] : "";
+ const final = found ? await a(found) : "";
+ return final || "";
+ } catch {
return "";
}
- const streamUrl = match[1].trim();
-
- console.log(streamUrl);
-
- const response2 = await networkFetch(streamUrl, {
- timeoutSeconds: 2,
- returnHTML: true
- });
- const html2 = response2.html;
-
- const match2 = html2.match(/data-url="([^"]+\.m3u8)"/);
- if (match2) {
- return match2[1];
- } else {
- return null;
- }
- } catch (err) {
- console.log("Error fetching stream URL content:"+ err);
+ } catch {
return "";
}
}
+
+async function a(streamUrl) {
+ try {
+ const looksLikeMaster = /master\.m3u8|\/stream\/v2\//i.test(streamUrl);
+ if (!looksLikeMaster) return streamUrl;
+
+ const res = await fetchv2(streamUrl);
+ const txt = await res.text();
+
+ const lines = txt.split(/\r?\n/);
+ const variants = [];
+ for (let i = 0; i < lines.length; i++) {
+ const line = lines[i].trim();
+ if (line.startsWith('#EXT-X-STREAM-INF:')) {
+ const info = line;
+ const urlLine = (lines[i+1] || "").trim();
+ if (!urlLine || urlLine.startsWith('#')) continue;
+
+ const resMatch = info.match(/RESOLUTION=(\d+)x(\d+)/i);
+ const bwMatch = info.match(/BANDWIDTH=(\d+)/i);
+ const labelMatch = info.match(/NAME="([^"]+)"/i);
+
+ const width = resMatch ? parseInt(resMatch[1], 10) : 0;
+ const height = resMatch ? parseInt(resMatch[2], 10) : 0;
+ const bw = bwMatch ? parseInt(bwMatch[1], 10) : 0;
+
+ variants.push({ url: urlLine, width, height, bw, label: labelMatch ? labelMatch[1] : "" });
+ }
+ }
+
+ if (variants.length === 0) return streamUrl;
+
+ const prefer1080 = variants.find(v => v.height >= 1000 || /1080/i.test(v.url) || /1080/i.test(v.label));
+ if (prefer1080) return prefer1080.url;
+
+ variants.sort((a,b) => b.bw - a.bw);
+ return variants[0].url || streamUrl;
+ } catch {
+ return streamUrl;
+ }
+}