mirror of
https://github.com/vega-org/vega-providers.git
synced 2026-06-17 20:28:37 +00:00
feat: update Movies4U version to 1.4 and modify catalog titles
fix: handle anti-DDoS checks in meta and posts fetching fix: improve episode extraction logic in episodes fix: enhance stream link extraction in stream Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Vendored
+1
-1
@@ -1 +1 @@
|
||||
"use strict";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,__export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&"object"==typeof from||"function"==typeof from)for(let key of __getOwnPropNames(from))__hasOwnProp.call(to,key)||key===except||__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to},__toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod),catalog_exports={};__export(catalog_exports,{catalog:()=>catalog});var catalog=[{title:"Trending",filter:""},{title:"Anime",filter:"/category/anime/"}];exports.catalog=catalog;
|
||||
"use strict";var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,__export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&"object"==typeof from||"function"==typeof from)for(let key of __getOwnPropNames(from))__hasOwnProp.call(to,key)||key===except||__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to},__toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod),catalog_exports={};__export(catalog_exports,{catalog:()=>catalog});var catalog=[{title:"Latest",filter:""},{title:"Web Series",filter:"/category/web-series/"}];exports.catalog=catalog;
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
"use strict";var __defProp=Object.defineProperty,__defProps=Object.defineProperties,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropDescs=Object.getOwnPropertyDescriptors,__getOwnPropNames=Object.getOwnPropertyNames,__getOwnPropSymbols=Object.getOwnPropertySymbols,__hasOwnProp=Object.prototype.hasOwnProperty,__propIsEnum=Object.prototype.propertyIsEnumerable,__defNormalProp=(obj,key,value)=>key in obj?__defProp(obj,key,{enumerable:!0,configurable:!0,writable:!0,value:value}):obj[key]=value,__spreadValues=(a,b)=>{for(var prop in b||(b={}))__hasOwnProp.call(b,prop)&&__defNormalProp(a,prop,b[prop]);if(__getOwnPropSymbols)for(var prop of __getOwnPropSymbols(b))__propIsEnum.call(b,prop)&&__defNormalProp(a,prop,b[prop]);return a},__spreadProps=(a,b)=>__defProps(a,__getOwnPropDescs(b)),__name=(target,value)=>__defProp(target,"name",{value:value,configurable:!0}),__export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&"object"==typeof from||"function"==typeof from)for(let key of __getOwnPropNames(from))__hasOwnProp.call(to,key)||key===except||__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to},__toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod),__async=(__this,__arguments,generator)=>new Promise((resolve,reject)=>{var fulfilled=value=>{try{step(generator.next(value))}catch(e){reject(e)}},rejected=value=>{try{step(generator.throw(value))}catch(e){reject(e)}},step=x=>x.done?resolve(x.value):Promise.resolve(x.value).then(fulfilled,rejected);step((generator=generator.apply(__this,__arguments)).next())}),episodes_exports={};__export(episodes_exports,{getEpisodes:()=>getEpisodes});var getEpisodes=__name(function(_0){return __async(this,arguments,function*({url:url,providerContext:providerContext}){const{axios:axios,cheerio:cheerio,commonHeaders:headers}=providerContext;console.log("getEpisodeLinks",url);try{const res=yield axios.get(url,{headers:__spreadProps(__spreadValues({},headers),{cookie:"ext_name=ojplmecpdpgccookcobabopnaifgidhf; cf_clearance=Zl2yiOCN3pzGUd0Bgs.VyBXniJooDbG2Tk1g7DEoRnw-1756381111-1.2.1.1-RVPZoWGCAygGNAHavrVR0YaqASWZlJyYff8A.oQfPB5qbcPrAVud42BzsSwcDgiKAP0gw5D92V3o8XWwLwDRNhyg3DuL1P8wh2K4BCVKxWvcy.iCCxczKtJ8QSUAsAQqsIzRWXk29N6X.kjxuOTYlfB2jrlq12TRDld_zTbsskNcTxaA.XQekUcpGLseYqELuvlNOQU568NZD6LiLn3ICyFThMFAx6mIcgXkxVAvnxU; xla=s4t"})}),$=cheerio.load(res.data),container=$(".entry-content,.entry-inner, .download-links-div");$(".unili-content,.code-block-1").remove();const episodes=[];return container.find("h5").each((index,element)=>{const el=$(element),title=el.text().trim(),hubCloudLink=el.next(".downloads-btns-div").find('a[style*="background: linear-gradient(135deg,#e629d0,#007bff);"]').attr("href");if(title&&hubCloudLink){const cleanedTitle=title.replace(/[-:]/g,"").trim();episodes.push({title:cleanedTitle,link:hubCloudLink})}}),episodes}catch(err){return console.log("getEpisodeLinks error: "),[]}})},"getEpisodes");exports.getEpisodes=getEpisodes;
|
||||
"use strict";var __defProp=Object.defineProperty,__defProps=Object.defineProperties,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropDescs=Object.getOwnPropertyDescriptors,__getOwnPropNames=Object.getOwnPropertyNames,__getOwnPropSymbols=Object.getOwnPropertySymbols,__hasOwnProp=Object.prototype.hasOwnProperty,__propIsEnum=Object.prototype.propertyIsEnumerable,__defNormalProp=(obj,key,value)=>key in obj?__defProp(obj,key,{enumerable:!0,configurable:!0,writable:!0,value:value}):obj[key]=value,__spreadValues=(a,b)=>{for(var prop in b||(b={}))__hasOwnProp.call(b,prop)&&__defNormalProp(a,prop,b[prop]);if(__getOwnPropSymbols)for(var prop of __getOwnPropSymbols(b))__propIsEnum.call(b,prop)&&__defNormalProp(a,prop,b[prop]);return a},__spreadProps=(a,b)=>__defProps(a,__getOwnPropDescs(b)),__name=(target,value)=>__defProp(target,"name",{value:value,configurable:!0}),__export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&"object"==typeof from||"function"==typeof from)for(let key of __getOwnPropNames(from))__hasOwnProp.call(to,key)||key===except||__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to},__toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod),__async=(__this,__arguments,generator)=>new Promise((resolve,reject)=>{var fulfilled=value=>{try{step(generator.next(value))}catch(e){reject(e)}},rejected=value=>{try{step(generator.throw(value))}catch(e){reject(e)}},step=x=>x.done?resolve(x.value):Promise.resolve(x.value).then(fulfilled,rejected);step((generator=generator.apply(__this,__arguments)).next())}),episodes_exports={};__export(episodes_exports,{getEpisodes:()=>getEpisodes});var getEpisodes=__name(function(_0){return __async(this,arguments,function*({url:url,providerContext:providerContext}){const{axios:axios,cheerio:cheerio,commonHeaders:headers}=providerContext;console.log("getEpisodeLinks",url);try{let res=yield axios.get(url,{headers:__spreadProps(__spreadValues({},headers),{cookie:"ext_name=ojplmecpdpgccookcobabopnaifgidhf; cf_clearance=Zl2yiOCN3pzGUd0Bgs.VyBXniJooDbG2Tk1g7DEoRnw-1756381111-1.2.1.1-RVPZoWGCAygGNAHavrVR0YaqASWZlJyYff8A.oQfPB5qbcPrAVud42BzsSwcDgiKAP0gw5D92V3o8XWwLwDRNhyg3DuL1P8wh2K4BCVKxWvcy.iCCxczKtJ8QSUAsAQqsIzRWXk29N6X.kjxuOTYlfB2jrlq12TRDld_zTbsskNcTxaA.XQekUcpGLseYqELuvlNOQU568NZD6LiLn3ICyFThMFAx6mIcgXkxVAvnxU; xla=s4t"})});if(res.data&&res.data.includes("Please turn JavaScript on and reload the page.")){const b1Match=res.data.match(/var b1=atob\(['"]([^'"]+)['"]\)/),a2Match=res.data.match(/_0x2aa8=\[['"]([^'"]+)['"]\]/),c3Match=res.data.match(/c3=toNumbers\(['"]([^'"]+)['"]\)/);if(b1Match&&a2Match&&c3Match){const unescapeHexStr=__name(str=>str.replace(/\\x([0-9A-Fa-f]{2})/g,(_,hex)=>String.fromCharCode(parseInt(hex,16))),"unescapeHexStr"),baseUrl=url.split("/").slice(0,3).join("/"),minJsRes=yield axios.get(`${baseUrl}/min.js`,{headers:headers}),b1Hex=atob(unescapeHexStr(b1Match[1])),a2Hex=atob(unescapeHexStr(a2Match[1])),c3Hex=unescapeHexStr(c3Match[1]),newCookie=`Antiddos-systems-DH=${new Function("c3Hex","a1Hex","b2Hex",`\n ${minJsRes.data}\n function toNumbers(d){var e=[];d.replace(/(..)/g,function(d){e.push(parseInt(d,16))});return e}\n function toHex(){for(var d=[],d=1==arguments.length&&arguments[0].constructor==Array?arguments[0]:arguments,e='',f=0;f<d.length;f++)e+=(16>d[f]?'0':'')+d[f].toString(16);return e.toLowerCase()}\n return toHex(slowAES.decrypt(toNumbers(c3Hex), 2, toNumbers(a1Hex), toNumbers(b2Hex)));\n `)(c3Hex,a2Hex,b1Hex)}`;res=yield axios.get(url,{headers:__spreadProps(__spreadValues({},headers),{Cookie:newCookie})})}}const $=cheerio.load(res.data),container=$(".entry-content,.entry-inner, .download-links-div");$(".unili-content,.code-block-1").remove();const episodes=[];return container.find("h3, h4, h5, p").each((index,element)=>{const el=$(element),title=el.text().trim(),link=el.nextAll().find("a").first().attr("href");if(title&&link&&title.match(/Episode|Ep|E\d+/i)&&title.length<150){const cleanedTitle=title.replace(/[-:]/g,"").trim();episodes.some(e=>e.link===link)||episodes.push({title:cleanedTitle,link:link})}}),0===episodes.length&&$("a").each((i,el)=>{const href=$(el).attr("href");if(href&&(href.includes("mdrive")||href.includes("fastdl")||href.includes("filebee")||href.includes("gdflix"))){const title=$(el).parent().prev().text().trim()||$(el).text().trim()||`Episode ${i+1}`;episodes.some(e=>e.link===href)||episodes.push({title:title.replace(/[-:]/g,"").trim(),link:href})}}),episodes}catch(err){return console.log("getEpisodeLinks error: "),[]}})},"getEpisodes");exports.getEpisodes=getEpisodes;
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -114,7 +114,7 @@
|
||||
{
|
||||
"display_name": "Movies4U",
|
||||
"value": "movies4u",
|
||||
"version": "1.3",
|
||||
"version": "1.4",
|
||||
"icon": "",
|
||||
"type": "global",
|
||||
"disabled": false
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
export const catalog = [
|
||||
{
|
||||
title: "Trending",
|
||||
title: "Latest",
|
||||
filter: "",
|
||||
},
|
||||
{
|
||||
title: "Anime",
|
||||
filter: "/category/anime/",
|
||||
title: "Web Series",
|
||||
filter: "/category/web-series/",
|
||||
},
|
||||
];
|
||||
@@ -14,7 +14,7 @@ export const getEpisodes = async function ({
|
||||
console.log("getEpisodeLinks", url);
|
||||
try {
|
||||
// Note: Cookies को URL के आधार पर अपडेट करने की आवश्यकता हो सकती है
|
||||
const res = await axios.get(url, {
|
||||
let res = await axios.get(url, {
|
||||
headers: {
|
||||
...headers,
|
||||
// Cloudflare/Bot protection के लिए Hardcoded cookie यहाँ आवश्यक हो सकता है
|
||||
@@ -22,6 +22,51 @@ export const getEpisodes = async function ({
|
||||
"ext_name=ojplmecpdpgccookcobabopnaifgidhf; cf_clearance=Zl2yiOCN3pzGUd0Bgs.VyBXniJooDbG2Tk1g7DEoRnw-1756381111-1.2.1.1-RVPZoWGCAygGNAHavrVR0YaqASWZlJyYff8A.oQfPB5qbcPrAVud42BzsSwcDgiKAP0gw5D92V3o8XWwLwDRNhyg3DuL1P8wh2K4BCVKxWvcy.iCCxczKtJ8QSUAsAQqsIzRWXk29N6X.kjxuOTYlfB2jrlq12TRDld_zTbsskNcTxaA.XQekUcpGLseYqELuvlNOQU568NZD6LiLn3ICyFThMFAx6mIcgXkxVAvnxU; xla=s4t",
|
||||
},
|
||||
});
|
||||
|
||||
if (
|
||||
res.data &&
|
||||
res.data.includes("Please turn JavaScript on and reload the page.")
|
||||
) {
|
||||
const b1Match = res.data.match(/var b1=atob\(['"]([^'"]+)['"]\)/);
|
||||
const a2Match = res.data.match(/_0x2aa8=\[['"]([^'"]+)['"]\]/);
|
||||
const c3Match = res.data.match(/c3=toNumbers\(['"]([^'"]+)['"]\)/);
|
||||
|
||||
if (b1Match && a2Match && c3Match) {
|
||||
const unescapeHexStr = (str: string) =>
|
||||
str.replace(/\\x([0-9A-Fa-f]{2})/g, (_, hex) =>
|
||||
String.fromCharCode(parseInt(hex, 16)),
|
||||
);
|
||||
|
||||
const baseUrl = url.split("/").slice(0, 3).join("/");
|
||||
const minJsRes = await axios.get(`${baseUrl}/min.js`, {
|
||||
headers,
|
||||
});
|
||||
|
||||
const b1Hex = atob(unescapeHexStr(b1Match[1]));
|
||||
const a2Hex = atob(unescapeHexStr(a2Match[1]));
|
||||
const c3Hex = unescapeHexStr(c3Match[1]);
|
||||
|
||||
const solver = new Function(
|
||||
"c3Hex",
|
||||
"a1Hex",
|
||||
"b2Hex",
|
||||
`
|
||||
${minJsRes.data}
|
||||
function toNumbers(d){var e=[];d.replace(/(..)/g,function(d){e.push(parseInt(d,16))});return e}
|
||||
function toHex(){for(var d=[],d=1==arguments.length&&arguments[0].constructor==Array?arguments[0]:arguments,e='',f=0;f<d.length;f++)e+=(16>d[f]?'0':'')+d[f].toString(16);return e.toLowerCase()}
|
||||
return toHex(slowAES.decrypt(toNumbers(c3Hex), 2, toNumbers(a1Hex), toNumbers(b2Hex)));
|
||||
`,
|
||||
);
|
||||
|
||||
const decrypted = solver(c3Hex, a2Hex, b1Hex);
|
||||
const newCookie = `Antiddos-systems-DH=${decrypted}`;
|
||||
|
||||
res = await axios.get(url, {
|
||||
headers: { ...headers, Cookie: newCookie },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const $ = cheerio.load(res.data);
|
||||
const container = $(".entry-content,.entry-inner, .download-links-div");
|
||||
|
||||
@@ -30,35 +75,62 @@ export const getEpisodes = async function ({
|
||||
|
||||
const episodes: EpisodeLink[] = [];
|
||||
|
||||
// HubCloud Links को लक्षित करने के लिए:
|
||||
// 1. Episode Title (h5) से शुरू करें
|
||||
// 2. उसके बाद के downloads-btns-div में HubCloud बटन खोजें
|
||||
// The site changed its layout. Links are now inside <p> tags following <h3> or <h4> tags with quality info.
|
||||
// We can also just look for the <a> tags directly and find their preceding quality headers.
|
||||
const hElements = container.find("h3, h4, h5, p");
|
||||
|
||||
container.find("h5").each((index, element) => {
|
||||
hElements.each((index, element) => {
|
||||
const el = $(element);
|
||||
const title = el.text().trim(); // e.g., "-:Episodes: 1:- (Grand Premiere)"
|
||||
const title = el.text().trim();
|
||||
|
||||
// HubCloud लिंक को विशिष्ट स्टाइल और टेक्स्ट से खोजें
|
||||
// बटन सेलेक्टर: style="background: linear-gradient(135deg,#e629d0,#007bff);color: white;"
|
||||
const hubCloudLink = el
|
||||
.next(".downloads-btns-div")
|
||||
.find(
|
||||
'a[style*="background: linear-gradient(135deg,#e629d0,#007bff);"]'
|
||||
)
|
||||
.attr("href");
|
||||
// The download buttons are usually in the next <p> tag
|
||||
const downloadButtons = el.nextAll().find("a").first();
|
||||
const link = downloadButtons.attr("href");
|
||||
|
||||
if (title && hubCloudLink) {
|
||||
// टाइटल को साफ़ करें (e.g., सिर्फ़ Episode 1: Grand Premiere रखें)
|
||||
if (
|
||||
title &&
|
||||
link &&
|
||||
title.match(/Episode|Ep|E\d+/i) &&
|
||||
title.length < 150
|
||||
) {
|
||||
// Clean up the title
|
||||
const cleanedTitle = title.replace(/[-:]/g, "").trim();
|
||||
|
||||
episodes.push({
|
||||
// Deduplicate
|
||||
if (!episodes.some((e) => e.link === link)) {
|
||||
episodes.push({
|
||||
title: cleanedTitle,
|
||||
link: hubCloudLink,
|
||||
// यदि यह HubCloud/Streaming लिंक है, तो आप 'type' को यहाँ 'stream' भी सेट कर सकते हैं
|
||||
});
|
||||
link: link,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Fallback: if no episodes found by heading, just grab all mdrive/fastdl links
|
||||
if (episodes.length === 0) {
|
||||
$("a").each((i, el) => {
|
||||
const href = $(el).attr("href");
|
||||
if (
|
||||
href &&
|
||||
(href.includes("mdrive") ||
|
||||
href.includes("fastdl") ||
|
||||
href.includes("filebee") ||
|
||||
href.includes("gdflix"))
|
||||
) {
|
||||
const title =
|
||||
$(el).parent().prev().text().trim() ||
|
||||
$(el).text().trim() ||
|
||||
`Episode ${i + 1}`;
|
||||
if (!episodes.some((e) => e.link === href)) {
|
||||
episodes.push({
|
||||
title: title.replace(/[-:]/g, "").trim(),
|
||||
link: href,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// console.log(episodes);
|
||||
return episodes;
|
||||
} catch (err) {
|
||||
|
||||
+69
-27
@@ -43,10 +43,53 @@ export const getMeta = async function ({
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await axios.get(url, {
|
||||
let response = await axios.get(url, {
|
||||
headers: { ...headers, Referer: baseUrl },
|
||||
});
|
||||
|
||||
if (
|
||||
response.data &&
|
||||
response.data.includes("Please turn JavaScript on and reload the page.")
|
||||
) {
|
||||
const b1Match = response.data.match(/var b1=atob\(['"]([^'"]+)['"]\)/);
|
||||
const a2Match = response.data.match(/_0x2aa8=\[['"]([^'"]+)['"]\]/);
|
||||
const c3Match = response.data.match(/c3=toNumbers\(['"]([^'"]+)['"]\)/);
|
||||
|
||||
if (b1Match && a2Match && c3Match) {
|
||||
const unescapeHexStr = (str: string) =>
|
||||
str.replace(/\\x([0-9A-Fa-f]{2})/g, (_, hex) =>
|
||||
String.fromCharCode(parseInt(hex, 16)),
|
||||
);
|
||||
|
||||
const minJsRes = await axios.get(`${baseUrl}/min.js`, {
|
||||
headers: { ...headers, Referer: baseUrl },
|
||||
});
|
||||
|
||||
const b1Hex = atob(unescapeHexStr(b1Match[1]));
|
||||
const a2Hex = atob(unescapeHexStr(a2Match[1]));
|
||||
const c3Hex = unescapeHexStr(c3Match[1]);
|
||||
|
||||
const solver = new Function(
|
||||
"c3Hex",
|
||||
"a1Hex",
|
||||
"b2Hex",
|
||||
`
|
||||
${minJsRes.data}
|
||||
function toNumbers(d){var e=[];d.replace(/(..)/g,function(d){e.push(parseInt(d,16))});return e}
|
||||
function toHex(){for(var d=[],d=1==arguments.length&&arguments[0].constructor==Array?arguments[0]:arguments,e='',f=0;f<d.length;f++)e+=(16>d[f]?'0':'')+d[f].toString(16);return e.toLowerCase()}
|
||||
return toHex(slowAES.decrypt(toNumbers(c3Hex), 2, toNumbers(a1Hex), toNumbers(b2Hex)));
|
||||
`,
|
||||
);
|
||||
|
||||
const decrypted = solver(c3Hex, a2Hex, b1Hex);
|
||||
const newCookie = `Antiddos-systems-DH=${decrypted}`;
|
||||
|
||||
response = await axios.get(url, {
|
||||
headers: { ...headers, Referer: baseUrl, Cookie: newCookie },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const $ = cheerio.load(response.data);
|
||||
const infoContainer = $(".entry-content, .post-inner").length
|
||||
? $(".entry-content, .post-inner")
|
||||
@@ -100,29 +143,23 @@ export const getMeta = async function ({
|
||||
image = "";
|
||||
result.image = image;
|
||||
|
||||
// --- Synopsis ---
|
||||
result.synopsis =
|
||||
$("h3.movie-title")
|
||||
.filter((i, el) => $(el).text().includes("Storyline"))
|
||||
.next("p")
|
||||
.text()
|
||||
.trim() ||
|
||||
infoContainer.find("p").first().text().trim() ||
|
||||
"";
|
||||
|
||||
// --- LinkList extraction ---
|
||||
const links: Link[] = [];
|
||||
const h4Elements = $(".download-links-div").find("> h4");
|
||||
|
||||
h4Elements.each((index, element) => {
|
||||
// The site changed its layout. Links are now inside <p> tags following <h3> or <h4> tags with quality info.
|
||||
// We can also just look for the <a> tags directly and find their preceding quality headers.
|
||||
const hElements = infoContainer.find("h3, h4, p");
|
||||
|
||||
hElements.each((index, element) => {
|
||||
const el = $(element);
|
||||
const titleText = el.text().trim();
|
||||
const qualityMatch = titleText.match(/\d+p\b/)?.[0];
|
||||
const fullTitle = titleText;
|
||||
|
||||
const downloadButtons = el.next(".downloads-btns-div").find("a");
|
||||
// The download buttons are usually in the next <p> tag
|
||||
const downloadButtons = el.nextAll().find("a").first();
|
||||
|
||||
if (downloadButtons.length && qualityMatch) {
|
||||
if (downloadButtons.length && qualityMatch && titleText.length < 350) {
|
||||
if (result.type === "series") {
|
||||
links.push({
|
||||
title: fullTitle,
|
||||
@@ -134,17 +171,14 @@ export const getMeta = async function ({
|
||||
// Movie: collect all direct download buttons
|
||||
const directLinks: Link["directLinks"] = [];
|
||||
|
||||
downloadButtons.each((i, btn) => {
|
||||
const btnEl = $(btn);
|
||||
const link = btnEl.attr("href");
|
||||
if (link) {
|
||||
directLinks.push({
|
||||
title: btnEl.text().trim() || "Download",
|
||||
link,
|
||||
type: "movie", // literal type
|
||||
});
|
||||
}
|
||||
});
|
||||
const link = downloadButtons.attr("href");
|
||||
if (link) {
|
||||
directLinks.push({
|
||||
title: downloadButtons.text().trim() || "Download",
|
||||
link,
|
||||
type: "movie", // literal type
|
||||
});
|
||||
}
|
||||
|
||||
if (directLinks.length) {
|
||||
links.push({
|
||||
@@ -158,7 +192,15 @@ export const getMeta = async function ({
|
||||
}
|
||||
});
|
||||
|
||||
result.linkList = links;
|
||||
// Deduplicate links by href
|
||||
const uniqueLinks = new Map<string, Link>();
|
||||
links.forEach((link) => {
|
||||
const href = link.episodesLink || link.directLinks?.[0]?.link;
|
||||
if (href && !uniqueLinks.has(href)) {
|
||||
uniqueLinks.set(href, link);
|
||||
}
|
||||
});
|
||||
result.linkList = Array.from(uniqueLinks.values());
|
||||
return result;
|
||||
} catch (err) {
|
||||
console.log("getMeta error:", err);
|
||||
|
||||
+80
-11
@@ -1,14 +1,23 @@
|
||||
import { Post, ProviderContext } from "../types";
|
||||
|
||||
const defaultHeaders = {
|
||||
Referer: "https://www.google.com",
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " +
|
||||
"(KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36",
|
||||
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
||||
"Accept-Language": "en-US,en;q=0.9",
|
||||
Pragma: "no-cache",
|
||||
"Cache-Control": "no-cache",
|
||||
accept:
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||
"accept-language": "en-US,en;q=0.9",
|
||||
"cache-control": "no-cache",
|
||||
pragma: "no-cache",
|
||||
priority: "u=0, i",
|
||||
"sec-ch-ua":
|
||||
'"Microsoft Edge";v="147", "Not.A/Brand";v="8", "Chromium";v="147"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"Windows"',
|
||||
"sec-fetch-dest": "document",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-user": "?1",
|
||||
"upgrade-insecure-requests": "1",
|
||||
cookie: "Antiddos-systems-DH=395a53ac840ad21dff778291a3ffae36",
|
||||
Referer: "https://movies4u.vg/category/web-series/",
|
||||
};
|
||||
|
||||
// --- Normal catalog posts ---
|
||||
@@ -81,7 +90,60 @@ async function fetchPosts({
|
||||
}
|
||||
|
||||
const { axios, cheerio } = providerContext;
|
||||
const res = await axios.get(url, { headers: defaultHeaders, signal });
|
||||
let res = await axios.get(url, {
|
||||
headers: defaultHeaders,
|
||||
signal,
|
||||
maxRedirects: 5,
|
||||
});
|
||||
|
||||
// Anti-DDoS-Guard check
|
||||
if (
|
||||
res.data &&
|
||||
res.data.includes("Please turn JavaScript on and reload the page.")
|
||||
) {
|
||||
const b1Match = res.data.match(/var b1=atob\(['"]([^'"]+)['"]\)/);
|
||||
const a2Match = res.data.match(/_0x2aa8=\[['"]([^'"]+)['"]\]/);
|
||||
const c3Match = res.data.match(/c3=toNumbers\(['"]([^'"]+)['"]\)/);
|
||||
|
||||
if (b1Match && a2Match && c3Match) {
|
||||
const unescapeHexStr = (str: string) =>
|
||||
str.replace(/\\x([0-9A-Fa-f]{2})/g, (_, hex) =>
|
||||
String.fromCharCode(parseInt(hex, 16)),
|
||||
);
|
||||
|
||||
// Fetch the min.js payload from the provider to safely execute slowAES
|
||||
const minJsRes = await axios.get(`${baseUrl}/min.js`, {
|
||||
headers: defaultHeaders,
|
||||
signal,
|
||||
});
|
||||
|
||||
const b1Hex = atob(unescapeHexStr(b1Match[1]));
|
||||
const a2Hex = atob(unescapeHexStr(a2Match[1]));
|
||||
const c3Hex = unescapeHexStr(c3Match[1]);
|
||||
|
||||
// Evaluate the decryption without needing crypto or buffers
|
||||
const solver = new Function(
|
||||
"c3Hex",
|
||||
"a1Hex",
|
||||
"b2Hex",
|
||||
`
|
||||
${minJsRes.data}
|
||||
function toNumbers(d){var e=[];d.replace(/(..)/g,function(d){e.push(parseInt(d,16))});return e}
|
||||
function toHex(){for(var d=[],d=1==arguments.length&&arguments[0].constructor==Array?arguments[0]:arguments,e='',f=0;f<d.length;f++)e+=(16>d[f]?'0':'')+d[f].toString(16);return e.toLowerCase()}
|
||||
return toHex(slowAES.decrypt(toNumbers(c3Hex), 2, toNumbers(a1Hex), toNumbers(b2Hex)));
|
||||
`,
|
||||
);
|
||||
|
||||
const decrypted = solver(c3Hex, a2Hex, b1Hex);
|
||||
const newCookie = `Antiddos-systems-DH=${decrypted}`;
|
||||
res = await axios.get(url, {
|
||||
headers: { ...defaultHeaders, Cookie: newCookie },
|
||||
signal,
|
||||
maxRedirects: 5,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const $ = cheerio.load(res.data || "");
|
||||
|
||||
const resolveUrl = (href: string) =>
|
||||
@@ -100,10 +162,13 @@ async function fetchPosts({
|
||||
".thumbnail",
|
||||
".latest-movies",
|
||||
".movie-item",
|
||||
".entry-card",
|
||||
].join(",");
|
||||
|
||||
console.log("Fetching posts from URL:", url); // Debug log
|
||||
$(POST_SELECTORS).each((_, el) => {
|
||||
const card = $(el);
|
||||
console.log("Processing card:", card.text().trim().slice(0, 50)); // Debug log
|
||||
let link = card.find("a[href]").first().attr("href") || "";
|
||||
if (!link) return;
|
||||
link = resolveUrl(link);
|
||||
@@ -114,9 +179,13 @@ async function fetchPosts({
|
||||
card.find("a[title]").first().attr("title")?.trim() ||
|
||||
card.text().trim();
|
||||
title = title
|
||||
.replace(
|
||||
/(?:480p|720p|1080p|4k|HDTC|HDRip|BluRay|LiNE|Full Movie).*$/i,
|
||||
"",
|
||||
)
|
||||
.replace(/\[.*?\]/g, "")
|
||||
.replace(/\(.+?\)/g, "")
|
||||
.replace(/\s{2,}/g, " ")
|
||||
.replace(/\s*[|\-]\s*$/, "")
|
||||
.trim();
|
||||
if (!title) return;
|
||||
|
||||
@@ -135,7 +204,7 @@ async function fetchPosts({
|
||||
} catch (err) {
|
||||
console.error(
|
||||
"HDMovie2 fetchPosts error:",
|
||||
err instanceof Error ? err.message : String(err)
|
||||
err instanceof Error ? err.message : String(err),
|
||||
);
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -44,7 +44,50 @@ export async function getStream({
|
||||
// console.log('dotlinkText', dotlinkText);
|
||||
const vlink = dotlinkText.match(/<a\s+href="([^"]*cloud\.[^"]*)"/i) || [];
|
||||
// console.log('vLink', vlink[1]);
|
||||
link = vlink[1];
|
||||
if (vlink[1]) {
|
||||
link = vlink[1];
|
||||
} else {
|
||||
// Try to find hubcloud or gdflix links directly
|
||||
const $ = cheerio.load(dotlinkText);
|
||||
const directLink = $("a")
|
||||
.filter((i, el) => {
|
||||
const href = $(el).attr("href") || "";
|
||||
return (
|
||||
href.includes("hubcloud") ||
|
||||
href.includes("gdflix") ||
|
||||
href.includes("filebee") ||
|
||||
href.includes("fastdl")
|
||||
);
|
||||
})
|
||||
.first()
|
||||
.attr("href");
|
||||
|
||||
if (directLink) {
|
||||
link = directLink;
|
||||
}
|
||||
}
|
||||
|
||||
// If it's a fastdl link, extract the redirect URL
|
||||
if (link.includes("fastdl.zip")) {
|
||||
try {
|
||||
const fastdlRes = await axios.get(link, { headers });
|
||||
const reurlMatch = fastdlRes.data.match(/var reurl = "([^"]+)";/);
|
||||
if (reurlMatch && reurlMatch[1]) {
|
||||
const actualLink = reurlMatch[1].replace(
|
||||
"https://fastdl.zip/dl.php?link=",
|
||||
"",
|
||||
);
|
||||
streamLinks.push({
|
||||
server: "fastdl",
|
||||
link: actualLink,
|
||||
type: "mkv",
|
||||
});
|
||||
return streamLinks;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("fastdl error: ", error);
|
||||
}
|
||||
}
|
||||
|
||||
// filepress link
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user