mirror of
https://github.com/vega-org/vega-providers.git
synced 2026-04-17 15:41:45 +00:00
init
This commit is contained in:
20
providers/autoEmbed/allCatalog.ts
Normal file
20
providers/autoEmbed/allCatalog.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export const allCatalog = [
|
||||
{
|
||||
title: 'Popular Movies',
|
||||
filter: '/top/catalog/movie/top.json',
|
||||
},
|
||||
{
|
||||
title: 'Popular TV Shows',
|
||||
filter: '/top/catalog/series/top.json',
|
||||
},
|
||||
{
|
||||
title: 'Featured Movies',
|
||||
filter: '/imdbRating/catalog/movie/imdbRating.json',
|
||||
},
|
||||
{
|
||||
title: 'Featured TV Shows',
|
||||
filter: '/imdbRating/catalog/series/imdbRating.json',
|
||||
},
|
||||
];
|
||||
|
||||
export const allGenresList = [];
|
||||
91
providers/autoEmbed/allGetInfo.ts
Normal file
91
providers/autoEmbed/allGetInfo.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import {EpisodeLink, Info, Link, ProviderContext} from '../types';
|
||||
|
||||
export const allGetInfo = async function ({
|
||||
link,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Info> {
|
||||
const axios = providerContext.axios;
|
||||
try {
|
||||
console.log('all', link);
|
||||
const res = await axios.get(link);
|
||||
const data = res.data;
|
||||
const meta = {
|
||||
title: '',
|
||||
synopsis: '',
|
||||
image: '',
|
||||
imdbId: data?.meta?.imdb_id || '',
|
||||
type: data?.meta?.type || 'movie',
|
||||
};
|
||||
|
||||
const links: Link[] = [];
|
||||
let directLinks: EpisodeLink[] = [];
|
||||
let season = new Map();
|
||||
if (meta.type === 'series') {
|
||||
data?.meta?.videos?.map((video: any) => {
|
||||
if (video?.season <= 0) return;
|
||||
if (!season.has(video?.season)) {
|
||||
season.set(video?.season, []);
|
||||
}
|
||||
season.get(video?.season).push({
|
||||
title: 'Episode ' + video?.episode,
|
||||
type: 'series',
|
||||
link: JSON.stringify({
|
||||
title: data?.meta?.name as string,
|
||||
imdbId: data?.meta?.imdb_id,
|
||||
season: video?.id?.split(':')[1],
|
||||
episode: video?.id?.split(':')[2],
|
||||
type: data?.meta?.type,
|
||||
tmdbId: data?.meta?.moviedb_id?.toString() || '',
|
||||
year: data?.meta?.year,
|
||||
}),
|
||||
});
|
||||
});
|
||||
const keys = Array.from(season.keys());
|
||||
keys.sort();
|
||||
keys.map(key => {
|
||||
directLinks = season.get(key);
|
||||
links.push({
|
||||
title: `Season ${key}`,
|
||||
directLinks: directLinks,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
console.log('all meta Mv🔥🔥', meta);
|
||||
links.push({
|
||||
title: data?.meta?.name as string,
|
||||
directLinks: [
|
||||
{
|
||||
title: 'Movie',
|
||||
type: 'movie',
|
||||
link: JSON.stringify({
|
||||
title: data?.meta?.name as string,
|
||||
imdbId: data?.meta?.imdb_id,
|
||||
season: '',
|
||||
episode: '',
|
||||
type: data?.meta?.type,
|
||||
tmdbId: data?.meta?.moviedb_id?.toString() || '',
|
||||
year: data?.meta?.year,
|
||||
}),
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
return {
|
||||
...meta,
|
||||
linkList: links,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return {
|
||||
title: '',
|
||||
synopsis: '',
|
||||
image: '',
|
||||
imdbId: '',
|
||||
type: 'movie',
|
||||
linkList: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
109
providers/autoEmbed/allGetPost.ts
Normal file
109
providers/autoEmbed/allGetPost.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
export const allGetPost = async function ({
|
||||
filter,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
filter: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
try {
|
||||
const catalog: Post[] = [];
|
||||
const url = 'https://cinemeta-catalogs.strem.io' + filter;
|
||||
console.log('allGetPostUrl', url);
|
||||
const res = await providerContext.axios.get(url, {
|
||||
headers: providerContext.commonHeaders,
|
||||
signal,
|
||||
});
|
||||
const data = res.data;
|
||||
data?.metas.map((result: any) => {
|
||||
const title = result?.name;
|
||||
const id = result?.imdb_id || result?.id;
|
||||
const type = result?.type;
|
||||
const image = result?.poster;
|
||||
if (id) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link: `https://v3-cinemeta.strem.io/meta/${type}/${id}.json`,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
console.log('catalog', catalog.length);
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('AutoEmbed error ', err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export const allGetSearchPosts = async function ({
|
||||
searchQuery,
|
||||
page,
|
||||
// providerValue,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
try {
|
||||
if (page > 1) {
|
||||
return [];
|
||||
}
|
||||
const catalog: Post[] = [];
|
||||
const url1 = `https://v3-cinemeta.strem.io/catalog/series/top/search=${encodeURI(
|
||||
searchQuery,
|
||||
)}.json`;
|
||||
const url2 = `https://v3-cinemeta.strem.io/catalog/movie/top/search=${encodeURI(
|
||||
searchQuery,
|
||||
)}.json`;
|
||||
const res = await providerContext.axios.get(url1, {
|
||||
headers: providerContext.commonHeaders,
|
||||
signal,
|
||||
});
|
||||
const data = res.data;
|
||||
data?.metas.map((result: any) => {
|
||||
const title = result.name || '';
|
||||
const id = result?.imdb_id || result?.id;
|
||||
const image = result?.poster;
|
||||
const type = result?.type;
|
||||
if (id) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link: `https://v3-cinemeta.strem.io/meta/${type}/${id}.json`,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
const res2 = await providerContext.axios.get(url2, {
|
||||
headers: providerContext.commonHeaders,
|
||||
signal,
|
||||
});
|
||||
const data2 = res2.data;
|
||||
data2?.metas.map((result: any) => {
|
||||
const title = result?.name || '';
|
||||
const id = result?.imdb_id || result?.id;
|
||||
const image = result?.poster;
|
||||
const type = result?.type;
|
||||
if (id) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link: `https://v3-cinemeta.strem.io/meta/${type}/${id}.json`,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('AutoEmbed error ', err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
250
providers/autoEmbed/allGetStream.ts
Normal file
250
providers/autoEmbed/allGetStream.ts
Normal file
@@ -0,0 +1,250 @@
|
||||
import {Stream, ProviderContext, TextTrackType, TextTracks} from '../types';
|
||||
|
||||
export const allGetStream = async ({
|
||||
link: id,
|
||||
type,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
type: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Stream[]> => {
|
||||
try {
|
||||
const streams: Stream[] = [];
|
||||
const {imdbId, season, episode, title, tmdbId, year} = JSON.parse(id);
|
||||
await getRiveStream(
|
||||
tmdbId,
|
||||
episode,
|
||||
season,
|
||||
type,
|
||||
streams,
|
||||
providerContext,
|
||||
);
|
||||
return streams;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export async function getRiveStream(
|
||||
tmdId: string,
|
||||
episode: string,
|
||||
season: string,
|
||||
type: string,
|
||||
Streams: Stream[],
|
||||
providerContext: ProviderContext,
|
||||
) {
|
||||
const secret = generateSecretKey(Number(tmdId));
|
||||
const servers = [
|
||||
'flowcast',
|
||||
'shadow',
|
||||
'asiacloud',
|
||||
'hindicast',
|
||||
'anime',
|
||||
'animez',
|
||||
'guard',
|
||||
'curve',
|
||||
'hq',
|
||||
'ninja',
|
||||
'alpha',
|
||||
'kaze',
|
||||
'zenesis',
|
||||
'genesis',
|
||||
'zenith',
|
||||
'ghost',
|
||||
'halo',
|
||||
'kinoecho',
|
||||
'ee3',
|
||||
'volt',
|
||||
'putafilme',
|
||||
'ophim',
|
||||
'kage',
|
||||
];
|
||||
const baseUrl = await providerContext.getBaseUrl('rive');
|
||||
const cors = process.env.CORS_PRXY ? process.env.CORS_PRXY + '?url=' : '';
|
||||
console.log('CORS: ' + cors);
|
||||
const route =
|
||||
type === 'series'
|
||||
? `/api/backendfetch?requestID=tvVideoProvider&id=${tmdId}&season=${season}&episode=${episode}&secretKey=${secret}&service=`
|
||||
: `/api/backendfetch?requestID=movieVideoProvider&id=${tmdId}&secretKey=${secret}&service=`;
|
||||
const url = cors
|
||||
? cors + encodeURIComponent(baseUrl + route)
|
||||
: baseUrl + route;
|
||||
await Promise.all(
|
||||
servers.map(async server => {
|
||||
console.log('Rive: ' + url + server);
|
||||
try {
|
||||
const res = await providerContext.axios.get(url + server, {
|
||||
timeout: 4000,
|
||||
headers: providerContext.commonHeaders,
|
||||
});
|
||||
const subtitles: TextTracks = [];
|
||||
if (res.data?.data?.captions) {
|
||||
res.data?.data?.captions.forEach((sub: any) => {
|
||||
subtitles.push({
|
||||
language: sub?.label?.slice(0, 2) || 'Und',
|
||||
uri: sub?.file,
|
||||
title: sub?.label || 'Undefined',
|
||||
type: sub?.file?.endsWith('.vtt')
|
||||
? TextTrackType.VTT
|
||||
: TextTrackType.SUBRIP,
|
||||
});
|
||||
});
|
||||
}
|
||||
res.data?.data?.sources.forEach((source: any) => {
|
||||
Streams.push({
|
||||
server: source?.source + '-' + source?.quality,
|
||||
link: source?.url,
|
||||
type: source?.format === 'hls' ? 'm3u8' : 'mp4',
|
||||
quality: source?.quality,
|
||||
subtitles: subtitles,
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function generateSecretKey(id: number | string) {
|
||||
// Array of secret key fragments - updated array from the new implementation
|
||||
const c = [
|
||||
'Yhv40uKAZa',
|
||||
'nn8YU4yBA',
|
||||
'uNeH',
|
||||
'ehK',
|
||||
'jT0',
|
||||
'n5G',
|
||||
'99R',
|
||||
'MvB1M',
|
||||
'DQtPCh',
|
||||
'GBRjk4k4I',
|
||||
'CzIOoa95UT',
|
||||
'BLE8s',
|
||||
'GDZlc7',
|
||||
'Fz45T',
|
||||
'JW6lWn',
|
||||
'DE3g4uw0i',
|
||||
'18KxmYizv',
|
||||
'8ji',
|
||||
'JUDdNMnZ',
|
||||
'oGpBippPgm',
|
||||
'7De8Pg',
|
||||
'Zv6',
|
||||
'VHT9TVN',
|
||||
'bYH6m',
|
||||
'aK1',
|
||||
'WcWH6jU',
|
||||
'Q47YEMi4k',
|
||||
'vRD3A',
|
||||
'CGOsfJO',
|
||||
'BLn8',
|
||||
'RgK0drv7l',
|
||||
'oPTfGCn3a',
|
||||
'MkpMDkttW9',
|
||||
'VNI1fPM',
|
||||
'XNFi6',
|
||||
'6cq',
|
||||
'4LvTksXoEI',
|
||||
'1rRa2KOZB0',
|
||||
'zoOGRb8HT2',
|
||||
'mhcXDtvz',
|
||||
'NUmexFY2Ur',
|
||||
'6BIMdvSZ',
|
||||
'Tr0zU2vjRd',
|
||||
'QPR',
|
||||
'fhOqJR',
|
||||
'R9VnFY',
|
||||
'xkZ99D6S',
|
||||
'umY7E',
|
||||
'5Ds8qyDq',
|
||||
'Cc6jy09y3',
|
||||
'yvU3iR',
|
||||
'Bg07zY',
|
||||
'GccECglg',
|
||||
'VYd',
|
||||
'6vOiXqz',
|
||||
'7xX',
|
||||
'UdRrbEzF',
|
||||
'fE6wc',
|
||||
'BUd25Rb',
|
||||
'lxq5Zum89o',
|
||||
];
|
||||
|
||||
// Handle undefined input
|
||||
if (id === undefined) {
|
||||
return 'rive';
|
||||
}
|
||||
|
||||
try {
|
||||
let fragment, insertPos;
|
||||
// Convert input to string
|
||||
const idStr = String(id);
|
||||
|
||||
// Updated string hash function to match the new implementation
|
||||
/* eslint-disable no-bitwise */
|
||||
const generateStringHash = function (input: string) {
|
||||
input = String(input);
|
||||
let hash = 0;
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
const char = input.charCodeAt(i);
|
||||
hash =
|
||||
((char + (hash << 6) + (hash << 16) - hash) ^ (char << i % 5)) >>> 0;
|
||||
}
|
||||
hash ^= hash >>> 13;
|
||||
hash = (1540483477 * hash) >>> 0;
|
||||
return (hash ^= hash >>> 15).toString(16).padStart(8, '0');
|
||||
};
|
||||
|
||||
// Updated MurmurHash-like function to match the new implementation
|
||||
const applyMurmurHash = function (input: string) {
|
||||
const str = String(input);
|
||||
let hash = 3735928559 ^ str.length;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
let char = str.charCodeAt(i);
|
||||
char ^= ((i + 31) * 131) & 255;
|
||||
hash =
|
||||
(668265261 *
|
||||
(hash = (((hash << 7) | (hash >>> 25)) >>> 0) ^ char)) >>>
|
||||
0;
|
||||
}
|
||||
hash ^= hash >>> 16;
|
||||
hash = (2246822507 * hash) >>> 0;
|
||||
hash ^= hash >>> 13;
|
||||
hash = (3266489909 * hash) >>> 0;
|
||||
return (hash ^= hash >>> 16).toString(16).padStart(8, '0');
|
||||
};
|
||||
/* eslint-enable no-bitwise */
|
||||
|
||||
// Generate the encoded hash using the new implementation
|
||||
const encodedHash = btoa(applyMurmurHash(generateStringHash(idStr)));
|
||||
|
||||
// Different handling for non-numeric vs numeric inputs
|
||||
if (isNaN(Number(id))) {
|
||||
// For non-numeric inputs, sum the character codes
|
||||
const charSum = idStr
|
||||
.split('')
|
||||
.reduce((sum, char) => sum + char.charCodeAt(0), 0);
|
||||
// Select array element or fallback to base64 encoded input
|
||||
fragment = c[charSum % c.length] || btoa(idStr);
|
||||
// Calculate insertion position
|
||||
insertPos = Math.floor((charSum % encodedHash.length) / 2);
|
||||
} else {
|
||||
// For numeric inputs, use the number directly
|
||||
const numId = Number(id);
|
||||
fragment = c[numId % c.length] || btoa(idStr);
|
||||
// Calculate insertion position
|
||||
insertPos = Math.floor((numId % encodedHash.length) / 2);
|
||||
}
|
||||
|
||||
// Construct the final key by inserting the selected value into the base64 string
|
||||
return (
|
||||
encodedHash.slice(0, insertPos) + fragment + encodedHash.slice(insertPos)
|
||||
);
|
||||
} catch (error) {
|
||||
// Return fallback value if any errors occur
|
||||
return 'topSecret';
|
||||
}
|
||||
}
|
||||
14
providers/autoEmbed/index.ts
Normal file
14
providers/autoEmbed/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {allCatalog, allGenresList} from './allCatalog';
|
||||
import {allGetInfo} from './allGetInfo';
|
||||
import {allGetStream} from './allGetStream';
|
||||
import {allGetPost, allGetSearchPosts} from './allGetPost';
|
||||
import {ProviderType} from '../../Manifest';
|
||||
|
||||
export const autoEmbed: ProviderType = {
|
||||
catalog: allCatalog,
|
||||
genres: allGenresList,
|
||||
GetMetaData: allGetInfo,
|
||||
GetHomePosts: allGetPost,
|
||||
GetStream: allGetStream,
|
||||
GetSearchPosts: allGetSearchPosts,
|
||||
};
|
||||
20
providers/cinemaLuxe/clCatalog.ts
Normal file
20
providers/cinemaLuxe/clCatalog.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export const clCatalog = [
|
||||
{
|
||||
title: 'Trending',
|
||||
filter: '/genre/latest-trending-releases/',
|
||||
},
|
||||
{
|
||||
title: 'Netflix',
|
||||
filter: '/network/netflix/',
|
||||
},
|
||||
{
|
||||
title: 'Amazon Prime',
|
||||
filter: '/network/prime-video/',
|
||||
},
|
||||
{
|
||||
title: 'Animation',
|
||||
filter: '/genre/anime/',
|
||||
},
|
||||
];
|
||||
|
||||
export const clGenresList = [];
|
||||
73
providers/cinemaLuxe/clGetEpisodes.ts
Normal file
73
providers/cinemaLuxe/clGetEpisodes.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import {EpisodeLink, ProviderContext} from '../types';
|
||||
|
||||
export const clsEpisodeLinks = async function ({
|
||||
url,
|
||||
providerContext,
|
||||
}: {
|
||||
url: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<EpisodeLink[]> {
|
||||
try {
|
||||
if (!url.includes('luxelinks') || url.includes('luxecinema')) {
|
||||
const res = await providerContext.axios.get(url, {
|
||||
headers: providerContext.commonHeaders,
|
||||
});
|
||||
const data = res.data;
|
||||
const encodedLink = data.match(/"link":"([^"]+)"/)?.[1];
|
||||
if (encodedLink) {
|
||||
url = encodedLink ? atob(encodedLink) : url;
|
||||
} else {
|
||||
const redirectUrlRes = await fetch(
|
||||
'https://ext.8man.me/api/cinemaluxe',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({url}),
|
||||
},
|
||||
);
|
||||
const redirectUrl = await redirectUrlRes.json();
|
||||
url = redirectUrl?.redirectUrl || url;
|
||||
}
|
||||
}
|
||||
const res = await providerContext.axios.get(url, {
|
||||
headers: providerContext.commonHeaders,
|
||||
});
|
||||
const html = res.data;
|
||||
let $ = providerContext.cheerio.load(html);
|
||||
const episodeLinks: EpisodeLink[] = [];
|
||||
if (url.includes('luxedrive')) {
|
||||
episodeLinks.push({
|
||||
title: 'Movie',
|
||||
link: url,
|
||||
});
|
||||
return episodeLinks;
|
||||
}
|
||||
$('a.maxbutton-4,a.maxbutton,.maxbutton-hubcloud,.ep-simple-button').map(
|
||||
(i, element) => {
|
||||
const title = $(element).text()?.trim();
|
||||
const link = $(element).attr('href');
|
||||
if (
|
||||
title &&
|
||||
link &&
|
||||
!title.includes('Batch') &&
|
||||
!title.toLowerCase().includes('zip')
|
||||
) {
|
||||
episodeLinks.push({
|
||||
title: title
|
||||
.replace(/\(\d{4}\)/, '')
|
||||
.replace('Download', 'Movie')
|
||||
.replace('⚡', '')
|
||||
.trim(),
|
||||
link,
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
return episodeLinks;
|
||||
} catch (err) {
|
||||
console.error('cl episode links', err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
69
providers/cinemaLuxe/clGetMeta.ts
Normal file
69
providers/cinemaLuxe/clGetMeta.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import {Info, Link, ProviderContext} from '../types';
|
||||
|
||||
export const clGetInfo = async function ({
|
||||
link,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Info> {
|
||||
try {
|
||||
const url = link;
|
||||
const res = await providerContext.axios.get(url, {
|
||||
headers: providerContext.commonHeaders,
|
||||
});
|
||||
const data = res.data;
|
||||
const $ = providerContext.cheerio.load(data);
|
||||
const type = url.includes('tvshows') ? 'series' : 'movie';
|
||||
const imdbId = '';
|
||||
const title = url.split('/')[4].replace(/-/g, ' ');
|
||||
const image = $('.g-item').find('a').attr('href') || '';
|
||||
const synopsis = $('.wp-content').text().trim();
|
||||
const tags = $('.sgeneros')
|
||||
.children()
|
||||
.map((i, element) => $(element).text())
|
||||
.get()
|
||||
.slice(3);
|
||||
const rating = Number($('#repimdb').find('strong').text())
|
||||
.toFixed(1)
|
||||
.toString();
|
||||
const links: Link[] = [];
|
||||
$('.mb-center.maxbutton-5-center,.ep-button-container').map(
|
||||
(i, element) => {
|
||||
const title = $(element)
|
||||
.text()
|
||||
.replace('\u2b07Download', '')
|
||||
.replace('\u2b07 Download', '')
|
||||
.trim();
|
||||
const link = $(element).find('a').attr('href');
|
||||
if (title && link) {
|
||||
links.push({
|
||||
title,
|
||||
episodesLink: link,
|
||||
quality: title?.match(/\d+P\b/)?.[0].replace('P', 'p') || '',
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
return {
|
||||
title,
|
||||
tags,
|
||||
rating,
|
||||
synopsis,
|
||||
image,
|
||||
imdbId,
|
||||
type,
|
||||
linkList: links,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return {
|
||||
title: '',
|
||||
synopsis: '',
|
||||
image: '',
|
||||
imdbId: '',
|
||||
type: 'movie',
|
||||
linkList: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
82
providers/cinemaLuxe/clGetPosts.ts
Normal file
82
providers/cinemaLuxe/clGetPosts.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
export const clGetPosts = async function ({
|
||||
filter,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
filter: string;
|
||||
page: number;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const baseUrl = await providerContext.getBaseUrl('cinemaLuxe');
|
||||
const url = `${baseUrl + filter}page/${page}/`;
|
||||
return posts({url, signal, providerContext});
|
||||
};
|
||||
|
||||
export const clGetPostsSearch = async function ({
|
||||
searchQuery,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const baseUrl = await providerContext.getBaseUrl('cinemaLuxe');
|
||||
const url = `${baseUrl}/page/${page}/?s=${searchQuery}`;
|
||||
return posts({url, signal, providerContext});
|
||||
};
|
||||
|
||||
async function posts({
|
||||
url,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
url: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
try {
|
||||
const res = await fetch(url, {
|
||||
headers: providerContext.commonHeaders,
|
||||
signal,
|
||||
});
|
||||
const data = await res.text();
|
||||
const $ = providerContext.cheerio.load(data);
|
||||
const catalog: Post[] = [];
|
||||
$('.item.tvshows,.item.movies').map((i, element) => {
|
||||
const title = $(element).find('.poster').find('img').attr('alt');
|
||||
const link = $(element).find('.poster').find('a').attr('href');
|
||||
const image = $(element).find('.poster').find('img').attr('data-src');
|
||||
if (title && link && image) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link: link,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
$('.result-item').map((i, element) => {
|
||||
const title = $(element).find('.thumbnail').find('img').attr('alt');
|
||||
const link = $(element).find('.thumbnail').find('a').attr('href');
|
||||
const image = $(element).find('.thumbnail').find('img').attr('data-src');
|
||||
if (title && link && image) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link: link,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('cinemaluxe error ', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
47
providers/cinemaLuxe/clGetSteam.ts
Normal file
47
providers/cinemaLuxe/clGetSteam.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import {Stream, ProviderContext} from '../types';
|
||||
|
||||
export const clGetStream = async ({
|
||||
link,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
type: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Stream[]> => {
|
||||
try {
|
||||
let newLink = link;
|
||||
if (link.includes('luxedrive')) {
|
||||
const res = await providerContext.axios.get(link);
|
||||
const $ = providerContext.cheerio.load(res.data);
|
||||
const hubcloudLink = $('a.btn.hubcloud').attr('href');
|
||||
if (hubcloudLink) {
|
||||
newLink = hubcloudLink;
|
||||
} else {
|
||||
const gdFlixLink = $('a.btn.gdflix').attr('href');
|
||||
if (gdFlixLink) {
|
||||
newLink = gdFlixLink;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newLink.includes('gdflix')) {
|
||||
const sreams = await providerContext.extractors.gdFlixExtracter(
|
||||
newLink,
|
||||
signal,
|
||||
);
|
||||
return sreams;
|
||||
}
|
||||
const res2 = await providerContext.axios.get(newLink, {signal});
|
||||
const data2 = res2.data;
|
||||
const hcLink = data2.match(/location\.replace\('([^']+)'/)?.[1] || newLink;
|
||||
const hubCloudLinks = await providerContext.extractors.hubcloudExtracter(
|
||||
hcLink.includes('https://hubcloud') ? hcLink : newLink,
|
||||
signal,
|
||||
);
|
||||
return hubCloudLinks;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
16
providers/cinemaLuxe/index.ts
Normal file
16
providers/cinemaLuxe/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import {clGenresList, clCatalog} from './clCatalog';
|
||||
import {clGetInfo} from './clGetMeta';
|
||||
import {clsEpisodeLinks} from './clGetEpisodes';
|
||||
import {clGetPostsSearch, clGetPosts} from './clGetPosts';
|
||||
import {ProviderType} from '../types';
|
||||
import {clGetStream} from './clGetSteam';
|
||||
|
||||
export const cinemaLuxe: ProviderType = {
|
||||
catalog: clCatalog,
|
||||
genres: clGenresList,
|
||||
GetHomePosts: clGetPosts,
|
||||
GetMetaData: clGetInfo,
|
||||
GetSearchPosts: clGetPostsSearch,
|
||||
GetEpisodeLinks: clsEpisodeLinks,
|
||||
GetStream: clGetStream,
|
||||
};
|
||||
12
providers/dooflix/dooCatalog.ts
Normal file
12
providers/dooflix/dooCatalog.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export const dooCatalog = [
|
||||
{
|
||||
title: 'Series',
|
||||
filter: '/rest-api//v130/tvseries',
|
||||
},
|
||||
{
|
||||
title: 'Movies',
|
||||
filter: '/rest-api//v130/movies',
|
||||
},
|
||||
];
|
||||
|
||||
export const dooGenresList = [];
|
||||
83
providers/dooflix/dooGetInfo.ts
Normal file
83
providers/dooflix/dooGetInfo.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import {EpisodeLink, Info, Link, ProviderContext} from '../types';
|
||||
|
||||
const headers = {
|
||||
'Accept-Encoding': 'gzip',
|
||||
'API-KEY': '2pm95lc6prpdbk0ppji9rsqo',
|
||||
Connection: 'Keep-Alive',
|
||||
'If-Modified-Since': 'Wed, 14 Aug 2024 13:00:04 GMT',
|
||||
'User-Agent': 'okhttp/3.14.9',
|
||||
};
|
||||
|
||||
export const dooGetInfo = async function ({
|
||||
link,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Info> {
|
||||
try {
|
||||
const {axios} = providerContext;
|
||||
const res = await axios.get(link, {headers});
|
||||
const resData = res.data;
|
||||
const jsonStart = resData?.indexOf('{');
|
||||
const jsonEnd = resData?.lastIndexOf('}') + 1;
|
||||
const data = JSON?.parse(resData?.substring(jsonStart, jsonEnd))?.title
|
||||
? JSON?.parse(resData?.substring(jsonStart, jsonEnd))
|
||||
: resData;
|
||||
const title = data?.title || '';
|
||||
const synopsis = data?.description || '';
|
||||
const image = data?.poster_url || '';
|
||||
const cast = data?.cast || [];
|
||||
const rating = data?.imdb_rating || '';
|
||||
const type = Number(data?.is_tvseries) ? 'series' : 'movie';
|
||||
const tags = data?.genre?.map((genre: any) => genre?.name) || [];
|
||||
const links: Link[] = [];
|
||||
if (type === 'series') {
|
||||
data?.season?.map((season: any) => {
|
||||
const title = season?.seasons_name || '';
|
||||
const directLinks: EpisodeLink[] =
|
||||
season?.episodes?.map((episode: any) => ({
|
||||
title: episode?.episodes_name,
|
||||
link: episode?.file_url,
|
||||
})) || [];
|
||||
links.push({
|
||||
title: title,
|
||||
directLinks: directLinks,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
data?.videos?.map((video: any) => {
|
||||
links.push({
|
||||
title: title + ' ' + video?.label,
|
||||
directLinks: [
|
||||
{
|
||||
title: 'Play',
|
||||
link: video?.file_url,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
}
|
||||
return {
|
||||
image: image?.includes('https') ? image : image?.replace('http', 'https'),
|
||||
synopsis: synopsis,
|
||||
title: title,
|
||||
rating: rating,
|
||||
imdbId: '',
|
||||
cast: cast,
|
||||
tags: tags,
|
||||
type: type,
|
||||
linkList: links,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return {
|
||||
title: '',
|
||||
synopsis: '',
|
||||
image: '',
|
||||
imdbId: '',
|
||||
type: 'movie',
|
||||
linkList: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
173
providers/dooflix/dooGetPosts.ts
Normal file
173
providers/dooflix/dooGetPosts.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
const headers = {
|
||||
'Accept-Encoding': 'gzip',
|
||||
'API-KEY': '2pm95lc6prpdbk0ppji9rsqo',
|
||||
Connection: 'Keep-Alive',
|
||||
'If-Modified-Since': 'Wed, 14 Aug 2024 13:00:04 GMT',
|
||||
'User-Agent': 'okhttp/3.14.9',
|
||||
};
|
||||
|
||||
export const dooGetPost = async function ({
|
||||
filter,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
filter: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
providerContext: ProviderContext;
|
||||
signal: AbortSignal;
|
||||
}): Promise<Post[]> {
|
||||
try {
|
||||
const {axios, getBaseUrl} = providerContext;
|
||||
const baseUrl = await getBaseUrl('dooflix');
|
||||
const catalog: Post[] = [];
|
||||
const url = `${baseUrl + filter + `?page=${page}`}`;
|
||||
|
||||
const res = await axios.get(url, {headers, signal});
|
||||
const resData = res.data;
|
||||
|
||||
if (!resData || typeof resData !== 'string') {
|
||||
console.warn('Unexpected response format from dooflix API');
|
||||
return [];
|
||||
}
|
||||
|
||||
let data;
|
||||
try {
|
||||
const jsonStart = resData.indexOf('[');
|
||||
const jsonEnd = resData.lastIndexOf(']') + 1;
|
||||
|
||||
if (jsonStart === -1 || jsonEnd <= jsonStart) {
|
||||
// If we can't find valid JSON array markers, try parsing the entire response
|
||||
data = JSON.parse(resData);
|
||||
} else {
|
||||
const jsonSubstring = resData.substring(jsonStart, jsonEnd);
|
||||
const parsedArray = JSON.parse(jsonSubstring);
|
||||
data = parsedArray.length > 0 ? parsedArray : resData;
|
||||
}
|
||||
} catch (parseError) {
|
||||
console.error('Error parsing dooflix response:', parseError);
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!Array.isArray(data)) {
|
||||
console.warn('Unexpected data format from dooflix API');
|
||||
return [];
|
||||
}
|
||||
|
||||
data.forEach((result: any) => {
|
||||
const id = result?.videos_id;
|
||||
if (!id) return;
|
||||
|
||||
const type = !result?.is_tvseries ? 'tvseries' : 'movie';
|
||||
const link = `${baseUrl}/rest-api//v130/single_details?type=${type}&id=${id}`;
|
||||
|
||||
const thumbnailUrl = result?.thumbnail_url;
|
||||
const image = thumbnailUrl?.includes('https')
|
||||
? thumbnailUrl
|
||||
: thumbnailUrl?.replace('http', 'https');
|
||||
|
||||
catalog.push({
|
||||
title: result?.title || '',
|
||||
link,
|
||||
image,
|
||||
});
|
||||
});
|
||||
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('dooflix error:', err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export const dooGetSearchPost = async function ({
|
||||
searchQuery,
|
||||
page,
|
||||
providerContext,
|
||||
signal,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
try {
|
||||
if (page > 1) {
|
||||
return [];
|
||||
}
|
||||
const {axios, getBaseUrl} = providerContext;
|
||||
const catalog: Post[] = [];
|
||||
const baseUrl = await getBaseUrl('dooflix');
|
||||
const url = `${baseUrl}/rest-api//v130/search?q=${searchQuery}&type=movietvserieslive&range_to=0&range_from=0&tv_category_id=0&genre_id=0&country_id=0`;
|
||||
|
||||
const res = await axios.get(url, {headers, signal});
|
||||
const resData = res.data;
|
||||
|
||||
if (!resData || typeof resData !== 'string') {
|
||||
console.warn('Unexpected search response format from dooflix API');
|
||||
return [];
|
||||
}
|
||||
|
||||
let data;
|
||||
try {
|
||||
const jsonStart = resData.indexOf('{');
|
||||
const jsonEnd = resData.lastIndexOf('}') + 1;
|
||||
|
||||
if (jsonStart === -1 || jsonEnd <= jsonStart) {
|
||||
data = resData;
|
||||
} else {
|
||||
const jsonSubstring = resData.substring(jsonStart, jsonEnd);
|
||||
const parsedData = JSON.parse(jsonSubstring);
|
||||
data = parsedData?.movie ? parsedData : resData;
|
||||
}
|
||||
} catch (parseError) {
|
||||
console.error('Error parsing dooflix search response:', parseError);
|
||||
return [];
|
||||
}
|
||||
|
||||
// Process movies
|
||||
data?.movie?.forEach((result: any) => {
|
||||
const id = result?.videos_id;
|
||||
if (!id) return;
|
||||
|
||||
const link = `${baseUrl}/rest-api//v130/single_details?type=movie&id=${id}`;
|
||||
const thumbnailUrl = result?.thumbnail_url;
|
||||
const image = thumbnailUrl?.includes('https')
|
||||
? thumbnailUrl
|
||||
: thumbnailUrl?.replace('http', 'https');
|
||||
|
||||
catalog.push({
|
||||
title: result?.title || '',
|
||||
link,
|
||||
image,
|
||||
});
|
||||
});
|
||||
|
||||
// Process TV series
|
||||
data?.tvseries?.forEach((result: any) => {
|
||||
const id = result?.videos_id;
|
||||
if (!id) return;
|
||||
|
||||
const link = `${baseUrl}/rest-api//v130/single_details?type=tvseries&id=${id}`;
|
||||
const thumbnailUrl = result?.thumbnail_url;
|
||||
const image = thumbnailUrl?.includes('https')
|
||||
? thumbnailUrl
|
||||
: thumbnailUrl?.replace('http', 'https');
|
||||
|
||||
catalog.push({
|
||||
title: result?.title || '',
|
||||
link,
|
||||
image,
|
||||
});
|
||||
});
|
||||
|
||||
return catalog;
|
||||
} catch (error) {
|
||||
console.error('dooflix search error:', error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
29
providers/dooflix/dooGetSteam.ts
Normal file
29
providers/dooflix/dooGetSteam.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import {Stream} from '../types';
|
||||
|
||||
export const dooGetStream = async function ({
|
||||
link,
|
||||
}: {
|
||||
link: string;
|
||||
}): Promise<Stream[]> {
|
||||
try {
|
||||
const streams: Stream[] = [];
|
||||
streams.push({
|
||||
server: 'Dooflix',
|
||||
link: link,
|
||||
type: 'm3u8',
|
||||
headers: {
|
||||
Connection: 'Keep-Alive',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (WindowsNT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.37',
|
||||
Referer: 'https://molop.art/',
|
||||
Cookie:
|
||||
'cf_clearance=M2_2Hy4lKRy_ruRX3dzOgm3iho1FHe2DUC1lq28BUtI-1737377622-1.2.1.1-6R8RaH94._H2BuNuotsjTZ3fAF6cLwPII0guemu9A5Xa46lpCJPuELycojdREwoonYS2kRTYcZ9_1c4h4epi2LtDvMM9jIoOZKE9pIdWa30peM1hRMpvffTjGUCraHsJNCJez8S_QZ6XkkdP7GeQ5iwiYaI6Grp6qSJWoq0Hj8lS7EITZ1LzyrALI6iLlYjgLmgLGa1VuhORWJBN8ZxrJIZ_ba_pqbrR9fjnyToqxZ0XQaZfk1d3rZyNWoZUjI98GoAxVjnKtcBQQG6b2jYPJuMbbYraGoa54N7E7BR__7o',
|
||||
},
|
||||
});
|
||||
console.log('doo streams', streams);
|
||||
return streams;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
14
providers/dooflix/index.ts
Normal file
14
providers/dooflix/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {ProviderType} from '../types';
|
||||
import {dooCatalog, dooGenresList} from './dooCatalog';
|
||||
import {dooGetInfo} from './dooGetInfo';
|
||||
import {dooGetPost, dooGetSearchPost} from './dooGetPosts';
|
||||
import {dooGetStream} from './dooGetSteam';
|
||||
|
||||
export const dooflixProvider: ProviderType = {
|
||||
catalog: dooCatalog,
|
||||
genres: dooGenresList,
|
||||
GetMetaData: dooGetInfo,
|
||||
GetStream: dooGetStream,
|
||||
GetHomePosts: dooGetPost,
|
||||
GetSearchPosts: dooGetSearchPost,
|
||||
};
|
||||
61
providers/drive/catalog.ts
Normal file
61
providers/drive/catalog.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
export const driveCatalog = [
|
||||
{
|
||||
title: 'Latest',
|
||||
filter: '',
|
||||
},
|
||||
{
|
||||
title: 'Anime',
|
||||
filter: 'category/anime/',
|
||||
},
|
||||
{
|
||||
title: 'Netflix',
|
||||
filter: 'category/netflix/',
|
||||
},
|
||||
{
|
||||
title: '4K',
|
||||
filter: 'category/2160p-4k/',
|
||||
},
|
||||
];
|
||||
|
||||
export const driveGenresList = [
|
||||
{
|
||||
title: 'Action',
|
||||
filter: '/category/action',
|
||||
},
|
||||
{
|
||||
title: 'Crime',
|
||||
filter: '/category/crime',
|
||||
},
|
||||
{
|
||||
title: 'Comedy',
|
||||
filter: '/category/comedy',
|
||||
},
|
||||
{
|
||||
title: 'Drama',
|
||||
filter: '/category/drama',
|
||||
},
|
||||
{
|
||||
title: 'Horror',
|
||||
filter: '/category/horror',
|
||||
},
|
||||
{
|
||||
title: 'Family',
|
||||
filter: '/category/family',
|
||||
},
|
||||
{
|
||||
title: 'Sci-Fi',
|
||||
filter: '/category/sifi',
|
||||
},
|
||||
{
|
||||
title: 'Thriller',
|
||||
filter: '/category/triller',
|
||||
},
|
||||
{
|
||||
title: 'Romance',
|
||||
filter: '/category/romance',
|
||||
},
|
||||
{
|
||||
title: 'Fight',
|
||||
filter: '/category/fight',
|
||||
},
|
||||
];
|
||||
39
providers/drive/driveGetEpisodesList.ts
Normal file
39
providers/drive/driveGetEpisodesList.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import {EpisodeLink, ProviderContext} from '../types';
|
||||
|
||||
export const driveGetEpisodeLinks = async function ({
|
||||
url,
|
||||
providerContext,
|
||||
}: {
|
||||
url: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<EpisodeLink[]> {
|
||||
try {
|
||||
const {axios, cheerio} = providerContext;
|
||||
const res = await axios.get(url);
|
||||
const html = res.data;
|
||||
let $ = cheerio.load(html);
|
||||
|
||||
const episodeLinks: EpisodeLink[] = [];
|
||||
$('a:contains("HubCloud")').map((i, element) => {
|
||||
const title = $(element).parent().prev().text();
|
||||
const link = $(element).attr('href');
|
||||
if (link && (title.includes('Ep') || title.includes('Download'))) {
|
||||
episodeLinks.push({
|
||||
title: title.includes('Download') ? 'Play' : title,
|
||||
link,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// console.log(episodeLinks);
|
||||
return episodeLinks;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [
|
||||
{
|
||||
title: 'Server 1',
|
||||
link: url,
|
||||
},
|
||||
];
|
||||
}
|
||||
};
|
||||
92
providers/drive/driveGetInfo.ts
Normal file
92
providers/drive/driveGetInfo.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import {Info, Link} from '../types';
|
||||
|
||||
export const driveGetInfo = async function ({
|
||||
link,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: {
|
||||
axios: any;
|
||||
cheerio: any;
|
||||
getBaseUrl: (provider: string) => Promise<string>;
|
||||
};
|
||||
}): Promise<Info> {
|
||||
try {
|
||||
const {axios, cheerio} = providerContext;
|
||||
const url = link;
|
||||
const res = await axios.get(url);
|
||||
const data = res.data;
|
||||
const $ = cheerio.load(data);
|
||||
const type = $('.left-wrapper')
|
||||
.text()
|
||||
.toLocaleLowerCase()
|
||||
.includes('movie name')
|
||||
? 'movie'
|
||||
: 'series';
|
||||
const imdbId = $('a:contains("IMDb")').attr('href')?.split('/')[4] || '';
|
||||
const title =
|
||||
$('.left-wrapper').find('strong:contains("Name")').next().text() ||
|
||||
$('.left-wrapper')
|
||||
.find('strong:contains("Name"),h5:contains("Name")')
|
||||
.find('span:first')
|
||||
.text();
|
||||
const synopsis =
|
||||
$('.left-wrapper')
|
||||
.find(
|
||||
'h2:contains("Storyline"),h3:contains("Storyline"),h5:contains("Storyline"),h4:contains("Storyline"),h4:contains("STORYLINE")',
|
||||
)
|
||||
.next()
|
||||
.text() ||
|
||||
$('.ipc-html-content-inner-div').text() ||
|
||||
'';
|
||||
const image =
|
||||
$('img.entered.lazyloaded,img.entered,img.litespeed-loaded').attr(
|
||||
'src',
|
||||
) ||
|
||||
$('img.aligncenter').attr('src') ||
|
||||
'';
|
||||
|
||||
// Links
|
||||
const links: Link[] = [];
|
||||
|
||||
$(
|
||||
'a:contains("1080")a:not(:contains("Zip")),a:contains("720")a:not(:contains("Zip")),a:contains("480")a:not(:contains("Zip")),a:contains("2160")a:not(:contains("Zip")),a:contains("4k")a:not(:contains("Zip"))',
|
||||
).map((i: number, element: any) => {
|
||||
const title = $(element).parent('h5').prev().text();
|
||||
const episodesLink = $(element).attr('href');
|
||||
const quality = title.match(/\b(480p|720p|1080p|2160p)\b/i)?.[0] || '';
|
||||
if (episodesLink && title) {
|
||||
links.push({
|
||||
title,
|
||||
episodesLink: type === 'series' ? episodesLink : '',
|
||||
directLinks:
|
||||
type === 'movie'
|
||||
? [{title: 'Movie', link: episodesLink, type: 'movie'}]
|
||||
: [],
|
||||
quality: quality,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// console.log('drive meta', title, synopsis, image, imdbId, type, links);
|
||||
console.log('drive meta', links, type);
|
||||
return {
|
||||
title,
|
||||
synopsis,
|
||||
image,
|
||||
imdbId,
|
||||
type,
|
||||
linkList: links,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return {
|
||||
title: '',
|
||||
synopsis: '',
|
||||
image: '',
|
||||
imdbId: '',
|
||||
type: 'movie',
|
||||
linkList: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
73
providers/drive/driveGetPosts.ts
Normal file
73
providers/drive/driveGetPosts.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
export const driveGetPosts = async function ({
|
||||
filter,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
filter: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl} = providerContext;
|
||||
const baseUrl = await getBaseUrl('drive');
|
||||
const url = `${baseUrl + filter}/page/${page}/`;
|
||||
return posts({url, signal, providerContext});
|
||||
};
|
||||
|
||||
export const driveGetSearchPost = async function ({
|
||||
searchQuery,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
providerContext: ProviderContext;
|
||||
signal: AbortSignal;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl} = providerContext;
|
||||
const baseUrl = await getBaseUrl('drive');
|
||||
const url = `${baseUrl}page/${page}/?s=${searchQuery}`;
|
||||
return posts({url, signal, providerContext});
|
||||
};
|
||||
|
||||
async function posts({
|
||||
url,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
url: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
try {
|
||||
const {cheerio} = providerContext;
|
||||
const res = await fetch(url, {signal});
|
||||
const data = await res.text();
|
||||
const $ = cheerio.load(data);
|
||||
const catalog: Post[] = [];
|
||||
$('.recent-movies')
|
||||
.children()
|
||||
.map((i, element) => {
|
||||
const title = $(element).find('figure').find('img').attr('alt');
|
||||
const link = $(element).find('a').attr('href');
|
||||
const image = $(element).find('figure').find('img').attr('src');
|
||||
if (title && link && image) {
|
||||
catalog.push({
|
||||
title: title.replace('Download', '').trim(),
|
||||
link: link,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('drive error ', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
47
providers/drive/driveGetStream.ts
Normal file
47
providers/drive/driveGetStream.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import {Stream, ProviderContext} from '../types';
|
||||
|
||||
export const driveGetStream = async function ({
|
||||
link: url,
|
||||
type,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
type: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Stream[]> {
|
||||
const headers = providerContext.commonHeaders;
|
||||
try {
|
||||
if (type === 'movie') {
|
||||
const res = await providerContext.axios.get(url, {headers});
|
||||
const html = res.data;
|
||||
const $ = providerContext.cheerio.load(html);
|
||||
const link = $('a:contains("HubCloud")').attr('href');
|
||||
url = link || url;
|
||||
}
|
||||
const res = await providerContext.axios.get(url, {headers});
|
||||
let redirectUrl = res.data.match(
|
||||
/<meta\s+http-equiv="refresh"\s+content="[^"]*?;\s*url=([^"]+)"\s*\/?>/i,
|
||||
)?.[1];
|
||||
if (url.includes('/archives/')) {
|
||||
redirectUrl = res.data.match(
|
||||
/<a\s+[^>]*href="(https:\/\/hubcloud\.[^\/]+\/[^"]+)"/i,
|
||||
)?.[1];
|
||||
}
|
||||
if (!redirectUrl) {
|
||||
return await providerContext.extractors.hubcloudExtracter(url, signal);
|
||||
}
|
||||
const res2 = await providerContext.axios.get(redirectUrl, {headers});
|
||||
const data = res2.data;
|
||||
const $ = providerContext.cheerio.load(data);
|
||||
const hubcloudLink = $('.fa-file-download').parent().attr('href');
|
||||
return await providerContext.extractors.hubcloudExtracter(
|
||||
hubcloudLink?.includes('https://hubcloud') ? hubcloudLink : redirectUrl,
|
||||
signal,
|
||||
);
|
||||
} catch (err) {
|
||||
console.error('Movies Drive err', err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
16
providers/drive/index.ts
Normal file
16
providers/drive/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import {ProviderType} from '../../Manifest';
|
||||
import {driveCatalog, driveGenresList} from './catalog';
|
||||
import {driveGetEpisodeLinks} from './driveGetEpisodesList';
|
||||
import {driveGetInfo} from './driveGetInfo';
|
||||
import {driveGetPosts, driveGetSearchPost} from './driveGetPosts';
|
||||
import {driveGetStream} from './driveGetStream';
|
||||
|
||||
export const moviesDrive: ProviderType = {
|
||||
catalog: driveCatalog,
|
||||
genres: driveGenresList,
|
||||
GetMetaData: driveGetInfo,
|
||||
GetHomePosts: driveGetPosts,
|
||||
GetStream: driveGetStream,
|
||||
GetEpisodeLinks: driveGetEpisodeLinks,
|
||||
GetSearchPosts: driveGetSearchPost,
|
||||
};
|
||||
16
providers/filmyfly/ffCatalog.ts
Normal file
16
providers/filmyfly/ffCatalog.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export const ffCatalog = [
|
||||
{
|
||||
title: 'Home',
|
||||
filter: '',
|
||||
},
|
||||
{
|
||||
title: 'Web Series',
|
||||
filter: '/page-cat/42/Web-Series.html',
|
||||
},
|
||||
{
|
||||
title: 'Hollywood',
|
||||
filter: '/page-cat/9/New-Hollywood-Hindi-Dubbed-Movie-2016-2025.html',
|
||||
},
|
||||
];
|
||||
|
||||
export const ffGenresList = [];
|
||||
38
providers/filmyfly/ffGetEpisodes.ts
Normal file
38
providers/filmyfly/ffGetEpisodes.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import {EpisodeLink, ProviderContext} from '../types';
|
||||
|
||||
export const ffEpisodeLinks = async function ({
|
||||
url,
|
||||
providerContext,
|
||||
}: {
|
||||
url: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<EpisodeLink[]> {
|
||||
try {
|
||||
const headers = providerContext.commonHeaders;
|
||||
const {axios, cheerio} = providerContext;
|
||||
const res = await axios.get(url, {headers});
|
||||
const data = res.data;
|
||||
const $ = cheerio.load(data);
|
||||
const episodeLinks: EpisodeLink[] = [];
|
||||
|
||||
$('.dlink.dl').map((i, element) => {
|
||||
const title = $(element)
|
||||
.find('a')
|
||||
.text()
|
||||
?.replace('Download', '')
|
||||
?.trim();
|
||||
const link = $(element).find('a').attr('href');
|
||||
|
||||
if (title && link) {
|
||||
episodeLinks.push({
|
||||
title,
|
||||
link,
|
||||
});
|
||||
}
|
||||
});
|
||||
return episodeLinks;
|
||||
} catch (err) {
|
||||
console.error('cl episode links', err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
56
providers/filmyfly/ffGetMeta.ts
Normal file
56
providers/filmyfly/ffGetMeta.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import {Info, Link, ProviderContext} from '../types';
|
||||
|
||||
export const ffGetInfo = async function ({
|
||||
link,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Info> {
|
||||
try {
|
||||
const {axios, cheerio, commonHeaders: headers} = providerContext;
|
||||
const url = link;
|
||||
const res = await axios.get(url, {headers});
|
||||
const data = res.data;
|
||||
const $ = cheerio.load(data);
|
||||
const type = url.includes('tvshows') ? 'series' : 'movie';
|
||||
const imdbId = '';
|
||||
const title = $('.fname:contains("Name")').find('.colora').text().trim();
|
||||
const image = $('.ss').find('img').attr('src') || '';
|
||||
const synopsis = $('.fname:contains("Description")')
|
||||
.find('.colorg')
|
||||
.text()
|
||||
.trim();
|
||||
const tags =
|
||||
$('.fname:contains("Genre")').find('.colorb').text().split(',') || [];
|
||||
const rating = '';
|
||||
const links: Link[] = [];
|
||||
const downloadLink = $('.dlbtn').find('a').attr('href');
|
||||
if (downloadLink) {
|
||||
links.push({
|
||||
title: title,
|
||||
episodesLink: downloadLink,
|
||||
});
|
||||
}
|
||||
return {
|
||||
title,
|
||||
tags,
|
||||
rating,
|
||||
synopsis,
|
||||
image,
|
||||
imdbId,
|
||||
type,
|
||||
linkList: links,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return {
|
||||
title: '',
|
||||
synopsis: '',
|
||||
image: '',
|
||||
imdbId: '',
|
||||
type: 'movie',
|
||||
linkList: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
77
providers/filmyfly/ffGetPosts.ts
Normal file
77
providers/filmyfly/ffGetPosts.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
export const ffGetPosts = async function ({
|
||||
filter,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
filter: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl} = providerContext;
|
||||
const baseUrl = await getBaseUrl('filmyfly');
|
||||
const url = `${baseUrl + filter}/${page}`;
|
||||
return posts({url, signal, baseUrl, providerContext});
|
||||
};
|
||||
|
||||
export const ffGetPostsSearch = async function ({
|
||||
searchQuery,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
providerContext: ProviderContext;
|
||||
signal: AbortSignal;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl} = providerContext;
|
||||
const baseUrl = await getBaseUrl('filmyfly');
|
||||
const url = `${baseUrl}/site-1.html?to-search=${searchQuery}`;
|
||||
if (page > 1) {
|
||||
return [];
|
||||
}
|
||||
return posts({url, signal, baseUrl, providerContext});
|
||||
};
|
||||
|
||||
async function posts({
|
||||
url,
|
||||
signal,
|
||||
baseUrl,
|
||||
providerContext,
|
||||
}: {
|
||||
url: string;
|
||||
signal: AbortSignal;
|
||||
baseUrl: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
try {
|
||||
const {cheerio, commonHeaders: headers} = providerContext;
|
||||
const res = await fetch(url, {headers, signal});
|
||||
const data = await res.text();
|
||||
const $ = cheerio.load(data);
|
||||
const catalog: Post[] = [];
|
||||
$('.A2,.A10,.fl').map((i, element) => {
|
||||
const title =
|
||||
$(element).find('a').eq(1).text() || $(element).find('b').text();
|
||||
const link = $(element).find('a').attr('href');
|
||||
const image = $(element).find('img').attr('src');
|
||||
if (title && link && image) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link: baseUrl + link,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('ff error ', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
51
providers/filmyfly/ffGetStream.ts
Normal file
51
providers/filmyfly/ffGetStream.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import {Stream, ProviderContext} from '../types';
|
||||
|
||||
export const ffGetStream = async function ({
|
||||
link,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
type: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Stream[]> {
|
||||
try {
|
||||
const res = await providerContext.axios.get(link, {signal});
|
||||
const data = res.data;
|
||||
const $ = providerContext.cheerio.load(data);
|
||||
const streams: Stream[] = [];
|
||||
const elements = $('.button2,.button1,.button3,.button4,.button').toArray();
|
||||
const promises = elements.map(async element => {
|
||||
const title = $(element).text();
|
||||
let link = $(element).attr('href');
|
||||
if (title.includes('GDFLIX') && link) {
|
||||
const gdLinks = await providerContext.extractors.gdFlixExtracter(
|
||||
link,
|
||||
signal,
|
||||
);
|
||||
streams.push(...gdLinks);
|
||||
}
|
||||
const alreadyAdded = streams.find(s => s.link === link);
|
||||
if (
|
||||
title &&
|
||||
link &&
|
||||
!title.includes('Watch') &&
|
||||
!title.includes('Login') &&
|
||||
!title.includes('GoFile') &&
|
||||
!alreadyAdded
|
||||
) {
|
||||
streams.push({
|
||||
server: title,
|
||||
link: link,
|
||||
type: 'mkv',
|
||||
});
|
||||
}
|
||||
});
|
||||
await Promise.all(promises);
|
||||
return streams;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
16
providers/filmyfly/index.ts
Normal file
16
providers/filmyfly/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import {ProviderType} from '../types';
|
||||
import {ffCatalog, ffGenresList} from './ffCatalog';
|
||||
import {ffEpisodeLinks} from './ffGetEpisodes';
|
||||
import {ffGetInfo} from './ffGetMeta';
|
||||
import {ffGetPosts, ffGetPostsSearch} from './ffGetPosts';
|
||||
import {ffGetStream} from './ffGetStream';
|
||||
|
||||
export const filmyfly: ProviderType = {
|
||||
catalog: ffCatalog,
|
||||
genres: ffGenresList,
|
||||
GetHomePosts: ffGetPosts,
|
||||
GetMetaData: ffGetInfo,
|
||||
GetSearchPosts: ffGetPostsSearch,
|
||||
GetEpisodeLinks: ffEpisodeLinks,
|
||||
GetStream: ffGetStream,
|
||||
};
|
||||
16
providers/flixhq/flixhqCatalog.ts
Normal file
16
providers/flixhq/flixhqCatalog.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export const flixhqCatalog = [
|
||||
{
|
||||
title: 'Trending',
|
||||
filter: '/trending',
|
||||
},
|
||||
{
|
||||
title: 'Movies',
|
||||
filter: '/recent-movies',
|
||||
},
|
||||
{
|
||||
title: 'TV Shows',
|
||||
filter: '/recent-shows',
|
||||
},
|
||||
];
|
||||
|
||||
export const flixhqGenresList = [];
|
||||
61
providers/flixhq/flixhqGetInfo.ts
Normal file
61
providers/flixhq/flixhqGetInfo.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import {Info, Link, ProviderContext} from '../types';
|
||||
|
||||
export const flixhqGetInfo = async function ({
|
||||
link: id,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Info> {
|
||||
try {
|
||||
const {axios, getBaseUrl} = providerContext;
|
||||
const baseUrl = await getBaseUrl('consumet');
|
||||
const url = `${baseUrl}/movies/flixhq/info?id=` + id;
|
||||
const res = await axios.get(url);
|
||||
const data = res.data;
|
||||
const meta = {
|
||||
title: data.title,
|
||||
synopsis: data.description.replace(/<[^>]*>?/gm, '').trim(),
|
||||
image: data.cover,
|
||||
cast: data.casts,
|
||||
rating: data.rating,
|
||||
tags: [data?.type, data?.duration, data.releaseDate.split('-')[0]],
|
||||
imdbId: '',
|
||||
type: data.episodes.length > 1 ? 'series' : 'movie',
|
||||
};
|
||||
|
||||
const links: Link['directLinks'] = [];
|
||||
data.episodes.forEach((episode: any) => {
|
||||
const title = episode?.number
|
||||
? 'Season-' + episode?.season + ' Ep-' + episode.number
|
||||
: episode.title;
|
||||
const link = episode.id + '*' + data.id;
|
||||
if (link && title) {
|
||||
links.push({
|
||||
title,
|
||||
link,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
...meta,
|
||||
linkList: [
|
||||
{
|
||||
title: meta.title,
|
||||
directLinks: links,
|
||||
},
|
||||
],
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return {
|
||||
title: '',
|
||||
synopsis: '',
|
||||
image: '',
|
||||
imdbId: '',
|
||||
type: 'movie',
|
||||
linkList: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
71
providers/flixhq/flixhqGetPosts.ts
Normal file
71
providers/flixhq/flixhqGetPosts.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
export const flixhqGetPosts = async function ({
|
||||
filter,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
filter: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl} = providerContext;
|
||||
const urlRes = await getBaseUrl('consumet');
|
||||
const baseUrl = urlRes + '/movies/flixhq';
|
||||
const url = `${baseUrl + filter}`;
|
||||
return posts({url, signal, providerContext});
|
||||
};
|
||||
|
||||
export const flixhqGetSearchPost = async function ({
|
||||
searchQuery,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl} = providerContext;
|
||||
const urlRes = await getBaseUrl('consumet');
|
||||
const baseUrl = urlRes + '/movies/flixhq';
|
||||
const url = `${baseUrl}/${searchQuery}?page=${page}`;
|
||||
return posts({url, signal, providerContext});
|
||||
};
|
||||
|
||||
async function posts({
|
||||
url,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
url: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
try {
|
||||
const {axios} = providerContext;
|
||||
const res = await axios.get(url, {signal});
|
||||
const data = res.data?.results || res.data;
|
||||
const catalog: Post[] = [];
|
||||
data?.map((element: any) => {
|
||||
const title = element.title;
|
||||
const link = element.id;
|
||||
const image = element.image;
|
||||
if (title && link && image) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link: link,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('flixhq error ', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
59
providers/flixhq/flixhqGetStream.ts
Normal file
59
providers/flixhq/flixhqGetStream.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import {ProviderContext, Stream, TextTrackType} from '../types';
|
||||
|
||||
export const flixhqGetStream = async function ({
|
||||
link: id,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Stream[]> {
|
||||
try {
|
||||
const {getBaseUrl} = providerContext;
|
||||
const episodeId = id.split('*')[0];
|
||||
const mediaId = id.split('*')[1];
|
||||
const baseUrl = await getBaseUrl('consumet');
|
||||
const serverUrl = `${baseUrl}/movies/flixhq/servers?episodeId=${episodeId}&mediaId=${mediaId}`;
|
||||
const res = await fetch(serverUrl);
|
||||
const servers = await res.json();
|
||||
const streamLinks: Stream[] = [];
|
||||
for (const server of servers) {
|
||||
const streamUrl =
|
||||
`${baseUrl}/movies/flixhq/watch?server=` +
|
||||
server.name +
|
||||
'&episodeId=' +
|
||||
episodeId +
|
||||
'&mediaId=' +
|
||||
mediaId;
|
||||
const streamRes = await fetch(streamUrl);
|
||||
const streamData = await streamRes.json();
|
||||
const subtitles: Stream['subtitles'] = [];
|
||||
if (streamData?.sources?.length > 0) {
|
||||
if (streamData.subtitles) {
|
||||
streamData.subtitles.forEach((sub: {lang: string; url: string}) => {
|
||||
subtitles.push({
|
||||
language: sub?.lang?.slice(0, 2) as any,
|
||||
uri: sub?.url,
|
||||
type: TextTrackType.VTT,
|
||||
title: sub?.lang,
|
||||
});
|
||||
});
|
||||
}
|
||||
streamData.sources.forEach((source: any) => {
|
||||
streamLinks.push({
|
||||
server:
|
||||
server?.name +
|
||||
'-' +
|
||||
source?.quality?.replace('auto', 'MultiQuality'),
|
||||
link: source.url,
|
||||
type: source.isM3U8 ? 'm3u8' : 'mp4',
|
||||
subtitles: subtitles,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
return streamLinks;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
25
providers/flixhq/index.ts
Normal file
25
providers/flixhq/index.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import {ProviderType} from '../types';
|
||||
import {flixhqCatalog, flixhqGenresList} from './flixhqCatalog';
|
||||
import {flixhqGetInfo} from './flixhqGetInfo';
|
||||
import {flixhqGetPosts, flixhqGetSearchPost} from './flixhqGetPosts';
|
||||
import {flixhqGetStream} from './flixhqGetStream';
|
||||
|
||||
export const flixhq: ProviderType = {
|
||||
catalog: flixhqCatalog,
|
||||
genres: flixhqGenresList,
|
||||
GetMetaData: flixhqGetInfo,
|
||||
GetHomePosts: flixhqGetPosts,
|
||||
GetStream: flixhqGetStream,
|
||||
GetSearchPosts: flixhqGetSearchPost,
|
||||
nonDownloadableServer: ['upcloud-MultiQuality', 'vidcloud-MultiQuality'],
|
||||
nonStreamableServer: [
|
||||
'upcloud-1080',
|
||||
'upcloud-720',
|
||||
'upcloud-480',
|
||||
'upcloud-360',
|
||||
'vidcloud-1080',
|
||||
'vidcloud-720',
|
||||
'vidcloud-480',
|
||||
'vidcloud-360',
|
||||
],
|
||||
};
|
||||
173
providers/gdflixExtractor.ts
Normal file
173
providers/gdflixExtractor.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
import axios from 'axios';
|
||||
import * as cheerio from 'cheerio';
|
||||
import {Stream} from './types';
|
||||
import {headers} from './headers';
|
||||
|
||||
export async function gdFlixExtracter(link: string, signal: AbortSignal) {
|
||||
try {
|
||||
const streamLinks: Stream[] = [];
|
||||
const res = await axios(`${link}`, {headers, signal});
|
||||
console.log('gdFlixExtracter', link);
|
||||
const data = res.data;
|
||||
let $drive = cheerio.load(data);
|
||||
// handle if redirected to another link
|
||||
|
||||
if ($drive('body').attr('onload')?.includes('location.replace')) {
|
||||
const newLink = $drive('body')
|
||||
.attr('onload')
|
||||
?.split("location.replace('")?.[1]
|
||||
.split("'")?.[0];
|
||||
|
||||
console.log('newLink', newLink);
|
||||
if (newLink) {
|
||||
const newRes = await axios.get(newLink, {headers, signal});
|
||||
$drive = cheerio.load(newRes.data);
|
||||
}
|
||||
}
|
||||
|
||||
// try {
|
||||
// const resumeBot = $drive('.fab.fa-artstation').prev().attr('href') || '';
|
||||
// console.log('resumeBot', resumeBot);
|
||||
// const resumeBotRes = await axios.get(resumeBot, {headers});
|
||||
// const resumeBotToken = resumeBotRes.data.match(
|
||||
// /formData\.append\('token', '([a-f0-9]+)'\)/,
|
||||
// )[1];
|
||||
// const resumeBotBody = new FormData();
|
||||
// resumeBotBody.append('token', resumeBotToken);
|
||||
// const resumeBotPath = resumeBotRes.data.match(
|
||||
// /fetch\('\/download\?id=([a-zA-Z0-9\/+]+)'/,
|
||||
// )[1];
|
||||
// const resumeBotBaseUrl = resumeBot.split('/download')[0];
|
||||
// // console.log(
|
||||
// // 'resumeBotPath',
|
||||
// // resumeBotBaseUrl + '/download?id=' + resumeBotPath,
|
||||
// // );
|
||||
// // console.log('resumeBotBody', resumeBotToken);
|
||||
|
||||
// const resumeBotDownload = await fetch(
|
||||
// resumeBotBaseUrl + '/download?id=' + resumeBotPath,
|
||||
// {
|
||||
// method: 'POST',
|
||||
// body: resumeBotBody,
|
||||
// headers: {
|
||||
// Referer: resumeBot,
|
||||
// Cookie: 'PHPSESSID=7e9658ce7c805dab5bbcea9046f7f308',
|
||||
// },
|
||||
// },
|
||||
// );
|
||||
// const resumeBotDownloadData = await resumeBotDownload.json();
|
||||
// console.log('resumeBotDownloadData', resumeBotDownloadData.url);
|
||||
// streamLinks.push({
|
||||
// server: 'ResumeBot',
|
||||
// link: resumeBotDownloadData.url,
|
||||
// type: 'mkv',
|
||||
// });
|
||||
// } catch (err) {
|
||||
// console.log('ResumeBot link not found', err);
|
||||
// }
|
||||
|
||||
/// resume cloud
|
||||
try {
|
||||
const baseUrl = link.split('/').slice(0, 3).join('/');
|
||||
const resumeDrive = $drive('.btn-secondary').attr('href') || '';
|
||||
console.log('resumeDrive', resumeDrive);
|
||||
if (resumeDrive.includes('indexbot')) {
|
||||
const resumeBotRes = await axios.get(resumeDrive, {headers});
|
||||
const resumeBotToken = resumeBotRes.data.match(
|
||||
/formData\.append\('token', '([a-f0-9]+)'\)/,
|
||||
)[1];
|
||||
const resumeBotBody = new FormData();
|
||||
resumeBotBody.append('token', resumeBotToken);
|
||||
const resumeBotPath = resumeBotRes.data.match(
|
||||
/fetch\('\/download\?id=([a-zA-Z0-9\/+]+)'/,
|
||||
)[1];
|
||||
const resumeBotBaseUrl = resumeDrive.split('/download')[0];
|
||||
// console.log(
|
||||
// 'resumeBotPath',
|
||||
// resumeBotBaseUrl + '/download?id=' + resumeBotPath,
|
||||
// );
|
||||
// console.log('resumeBotBody', resumeBotToken);
|
||||
|
||||
const resumeBotDownload = await fetch(
|
||||
resumeBotBaseUrl + '/download?id=' + resumeBotPath,
|
||||
{
|
||||
method: 'POST',
|
||||
body: resumeBotBody,
|
||||
headers: {
|
||||
Referer: resumeDrive,
|
||||
Cookie: 'PHPSESSID=7e9658ce7c805dab5bbcea9046f7f308',
|
||||
},
|
||||
},
|
||||
);
|
||||
const resumeBotDownloadData = await resumeBotDownload.json();
|
||||
console.log('resumeBotDownloadData', resumeBotDownloadData.url);
|
||||
streamLinks.push({
|
||||
server: 'ResumeBot',
|
||||
link: resumeBotDownloadData.url,
|
||||
type: 'mkv',
|
||||
});
|
||||
} else {
|
||||
const url = baseUrl + resumeDrive;
|
||||
const resumeDriveRes = await axios.get(url, {headers});
|
||||
const resumeDriveHtml = resumeDriveRes.data;
|
||||
const $resumeDrive = cheerio.load(resumeDriveHtml);
|
||||
const resumeLink = $resumeDrive('.btn-success').attr('href');
|
||||
// console.log('resumeLink', resumeLink);
|
||||
if (resumeLink) {
|
||||
streamLinks.push({
|
||||
server: 'ResumeCloud',
|
||||
link: resumeLink,
|
||||
type: 'mkv',
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Resume link not found');
|
||||
}
|
||||
|
||||
//instant link
|
||||
try {
|
||||
const seed = $drive('.btn-danger').attr('href') || '';
|
||||
console.log('seed', seed);
|
||||
if (!seed.includes('?url=')) {
|
||||
const newLinkRes = await axios.head(seed, {headers, signal});
|
||||
console.log('newLinkRes', newLinkRes.request?.responseURL);
|
||||
const newLink =
|
||||
newLinkRes.request?.responseURL?.split('?url=')?.[1] || seed;
|
||||
streamLinks.push({server: 'G-Drive', link: newLink, type: 'mkv'});
|
||||
} else {
|
||||
const instantToken = seed.split('=')[1];
|
||||
// console.log('InstantToken', instantToken);
|
||||
const InstantFromData = new FormData();
|
||||
InstantFromData.append('keys', instantToken);
|
||||
const videoSeedUrl = seed.split('/').slice(0, 3).join('/') + '/api';
|
||||
// console.log('videoSeedUrl', videoSeedUrl);
|
||||
const instantLinkRes = await fetch(videoSeedUrl, {
|
||||
method: 'POST',
|
||||
body: InstantFromData,
|
||||
headers: {
|
||||
'x-token': videoSeedUrl,
|
||||
},
|
||||
});
|
||||
const instantLinkData = await instantLinkRes.json();
|
||||
// console.log('instantLinkData', instantLinkData);
|
||||
if (instantLinkData.error === false) {
|
||||
const instantLink = instantLinkData.url;
|
||||
streamLinks.push({
|
||||
server: 'Gdrive-Instant',
|
||||
link: instantLink,
|
||||
type: 'mkv',
|
||||
});
|
||||
} else {
|
||||
console.log('Instant link not found', instantLinkData);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Instant link not found', err);
|
||||
}
|
||||
return streamLinks;
|
||||
} catch (error) {
|
||||
console.log('gdflix error: ', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
35
providers/getBaseUrl.ts
Normal file
35
providers/getBaseUrl.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { cacheStorageService } from '../storage';
|
||||
|
||||
// 1 hour
|
||||
const expireTime = 60 * 60 * 1000;
|
||||
|
||||
export const getBaseUrl = async (providerValue: string) => {
|
||||
try {
|
||||
let baseUrl = '';
|
||||
const cacheKey = 'CacheBaseUrl' + providerValue;
|
||||
const timeKey = 'baseUrlTime' + providerValue;
|
||||
|
||||
const cachedUrl = cacheStorageService.getString(cacheKey);
|
||||
const cachedTime = cacheStorageService.getObject<number>(timeKey);
|
||||
|
||||
if (
|
||||
cachedUrl &&
|
||||
cachedTime &&
|
||||
Date.now() - cachedTime < expireTime
|
||||
) {
|
||||
baseUrl = cachedUrl;
|
||||
} else {
|
||||
const baseUrlRes = await fetch(
|
||||
'https://himanshu8443.github.io/providers/modflix.json',
|
||||
);
|
||||
const baseUrlData = await baseUrlRes.json();
|
||||
baseUrl = baseUrlData[providerValue].url;
|
||||
cacheStorageService.setString(cacheKey, baseUrl);
|
||||
cacheStorageService.setObject(timeKey, Date.now());
|
||||
}
|
||||
return baseUrl;
|
||||
} catch (error) {
|
||||
console.error(`Error fetching baseUrl: ${providerValue}`, error);
|
||||
return '';
|
||||
}
|
||||
};
|
||||
38
providers/gofileExtracter.ts
Normal file
38
providers/gofileExtracter.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import axios from 'axios';
|
||||
|
||||
export async function gofileExtracter(
|
||||
id: string,
|
||||
): Promise<{link: string; token: string}> {
|
||||
try {
|
||||
const gofileRes = await axios.get('https://gofile.io/d/' + id);
|
||||
const genAccountres = await axios.post('https://api.gofile.io/accounts');
|
||||
const token = genAccountres.data.data.token;
|
||||
console.log('gofile token', token);
|
||||
|
||||
const wtRes = await axios.get('https://gofile.io/dist/js/global.js');
|
||||
const wt = wtRes.data.match(/appdata\.wt\s*=\s*["']([^"']+)["']/)[1];
|
||||
console.log('gofile wt', wt);
|
||||
|
||||
const res = await axios.get(
|
||||
`https://api.gofile.io/contents/${id}?wt=${wt}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
const oId = Object.keys(res.data.data.children)[0];
|
||||
console.log('gofile extracter', res.data.data.children[oId].link);
|
||||
const link = res.data.data.children[oId].link;
|
||||
return {
|
||||
link,
|
||||
token,
|
||||
};
|
||||
} catch (e) {
|
||||
console.log('gofile extracter err', e);
|
||||
return {
|
||||
link: '',
|
||||
token: '',
|
||||
};
|
||||
}
|
||||
}
|
||||
133
providers/guardahd/GetGuardahdStream.ts
Normal file
133
providers/guardahd/GetGuardahdStream.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
import {ProviderContext, Stream} from '../types';
|
||||
|
||||
export const GuardahdGetStream = async function ({
|
||||
link: id,
|
||||
type,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
type: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Stream[]> {
|
||||
try {
|
||||
const {axios, cheerio, extractors} = providerContext;
|
||||
const {superVideoExtractor} = extractors;
|
||||
async function ExtractGuardahd({
|
||||
imdb, // type,
|
||||
// episode,
|
||||
} // season,
|
||||
: {
|
||||
imdb: string;
|
||||
type: string;
|
||||
season: string;
|
||||
episode: string;
|
||||
}) {
|
||||
try {
|
||||
const baseUrl = 'https://guardahd.stream';
|
||||
const path = '/set-movie-a/' + imdb;
|
||||
const url = baseUrl + path;
|
||||
|
||||
console.log('url:', url);
|
||||
const res = await axios.get(url, {timeout: 4000});
|
||||
const html = res.data;
|
||||
const $ = cheerio.load(html);
|
||||
const superVideoUrl = $('li:contains("supervideo")').attr('data-link');
|
||||
console.log('superVideoUrl:', superVideoUrl);
|
||||
|
||||
if (!superVideoUrl) {
|
||||
return null;
|
||||
}
|
||||
const controller2 = new AbortController();
|
||||
const signal2 = controller2.signal;
|
||||
setTimeout(() => controller2.abort(), 4000);
|
||||
const res2 = await fetch('https:' + superVideoUrl, {signal: signal2});
|
||||
const data = await res2.text();
|
||||
// console.log('mostraguarda data:', data);
|
||||
const streamUrl = await superVideoExtractor(data);
|
||||
return streamUrl;
|
||||
} catch (err) {
|
||||
console.error('Error in GetMostraguardaStram:', err);
|
||||
}
|
||||
}
|
||||
async function GetMostraguardaStream({
|
||||
imdb,
|
||||
type,
|
||||
season,
|
||||
episode,
|
||||
}: {
|
||||
imdb: string;
|
||||
type: string;
|
||||
season: string;
|
||||
episode: string;
|
||||
}) {
|
||||
try {
|
||||
const baseUrl = 'https://mostraguarda.stream';
|
||||
const path =
|
||||
type === 'tv'
|
||||
? `/serie/${imdb}/${season}/${episode}`
|
||||
: `/movie/${imdb}`;
|
||||
const url = baseUrl + path;
|
||||
|
||||
console.log('url:', url);
|
||||
|
||||
const res = await axios(url, {timeout: 4000});
|
||||
const html = res.data;
|
||||
const $ = cheerio.load(html);
|
||||
const superVideoUrl = $('li:contains("supervideo")').attr('data-link');
|
||||
console.log('superVideoUrl:', superVideoUrl);
|
||||
|
||||
if (!superVideoUrl) {
|
||||
return null;
|
||||
}
|
||||
const controller2 = new AbortController();
|
||||
const signal2 = controller2.signal;
|
||||
setTimeout(() => controller2.abort(), 4000);
|
||||
const res2 = await fetch('https:' + superVideoUrl, {signal: signal2});
|
||||
const data = await res2.text();
|
||||
// console.log('mostraguarda data:', data);
|
||||
const streamUrl = await superVideoExtractor(data);
|
||||
return streamUrl;
|
||||
} catch (err) {
|
||||
console.error('Error in GetMostraguardaStram:', err);
|
||||
}
|
||||
}
|
||||
console.log(id);
|
||||
const streams: Stream[] = [];
|
||||
const {imdbId, season, episode} = JSON.parse(id);
|
||||
|
||||
///// mostraguarda
|
||||
const mostraguardaStream = await GetMostraguardaStream({
|
||||
imdb: imdbId,
|
||||
type: type,
|
||||
season: season,
|
||||
episode: episode,
|
||||
});
|
||||
if (mostraguardaStream) {
|
||||
streams.push({
|
||||
server: 'Supervideo 1',
|
||||
link: mostraguardaStream,
|
||||
type: 'm3u8',
|
||||
});
|
||||
}
|
||||
|
||||
const guardahdStream = await ExtractGuardahd({
|
||||
imdb: imdbId,
|
||||
type: type,
|
||||
season: season,
|
||||
episode: episode,
|
||||
});
|
||||
|
||||
if (guardahdStream) {
|
||||
streams.push({
|
||||
server: 'Supervideo 2',
|
||||
link: guardahdStream,
|
||||
type: 'm3u8',
|
||||
});
|
||||
}
|
||||
|
||||
return streams;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
12
providers/guardahd/guardahdCatalog.ts
Normal file
12
providers/guardahd/guardahdCatalog.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export const guardahdCatalog = [
|
||||
{
|
||||
title: 'Popular Movies',
|
||||
filter: '/top/catalog/movie/top.json',
|
||||
},
|
||||
{
|
||||
title: 'Featured Movies',
|
||||
filter: '/imdbRating/catalog/movie/imdbRating.json',
|
||||
},
|
||||
];
|
||||
|
||||
export const guardahdGenresList = [];
|
||||
44
providers/guardahd/guardahdGetPosts.ts
Normal file
44
providers/guardahd/guardahdGetPosts.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
export const guardahdGetSearchPosts = async function ({
|
||||
searchQuery,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
providerContext: ProviderContext;
|
||||
signal: AbortSignal;
|
||||
}): Promise<Post[]> {
|
||||
try {
|
||||
const {axios, commonHeaders: headers} = providerContext;
|
||||
if (page > 1) {
|
||||
return [];
|
||||
}
|
||||
const catalog: Post[] = [];
|
||||
const url2 = `https://v3-cinemeta.strem.io/catalog/movie/top/search=${encodeURI(
|
||||
searchQuery,
|
||||
)}.json`;
|
||||
const res2 = await axios.get(url2, {headers, signal});
|
||||
const data2 = res2.data;
|
||||
data2?.metas.map((result: any) => {
|
||||
const title = result?.name || '';
|
||||
const id = result?.imdb_id || result?.id;
|
||||
const image = result?.poster;
|
||||
const type = result?.type;
|
||||
if (id) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link: `https://v3-cinemeta.strem.io/meta/${type}/${id}.json`,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('AutoEmbed error ', err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
15
providers/guardahd/index.ts
Normal file
15
providers/guardahd/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import {guardahdCatalog, guardahdGenresList} from './guardahdCatalog';
|
||||
import {allGetInfo} from '../autoEmbed/allGetInfo';
|
||||
import {allGetPost} from '../autoEmbed/allGetPost';
|
||||
import {guardahdGetSearchPosts} from './guardahdGetPosts';
|
||||
import {ProviderType} from '../types';
|
||||
import {GuardahdGetStream} from './GetGuardahdStream';
|
||||
|
||||
export const guardahd: ProviderType = {
|
||||
catalog: guardahdCatalog,
|
||||
genres: guardahdGenresList,
|
||||
GetMetaData: allGetInfo,
|
||||
GetHomePosts: allGetPost,
|
||||
GetStream: GuardahdGetStream,
|
||||
GetSearchPosts: guardahdGetSearchPosts,
|
||||
};
|
||||
183
providers/hdhub4u/hdhub4uGetSteam.ts
Normal file
183
providers/hdhub4u/hdhub4uGetSteam.ts
Normal file
@@ -0,0 +1,183 @@
|
||||
import {ProviderContext} from '../types';
|
||||
|
||||
export async function hdhub4uGetStream({
|
||||
link,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
type: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}) {
|
||||
const {axios, cheerio, extractors, commonHeaders: headers} = providerContext;
|
||||
const {hubcloudExtracter} = extractors;
|
||||
let hubdriveLink = '';
|
||||
if (link.includes('hubdrive')) {
|
||||
const hubdriveRes = await axios.get(link, {headers, signal});
|
||||
const hubdriveText = hubdriveRes.data;
|
||||
const $ = cheerio.load(hubdriveText);
|
||||
hubdriveLink =
|
||||
$('.btn.btn-primary.btn-user.btn-success1.m-1').attr('href') || link;
|
||||
} else {
|
||||
const res = await axios.get(link, {headers, signal});
|
||||
const text = res.data;
|
||||
const encryptedString = text.split("s('o','")?.[1]?.split("',180")?.[0];
|
||||
const decodedString: any = decodeString(encryptedString);
|
||||
link = atob(decodedString?.o);
|
||||
const redirectLink = await getRedirectLinks(link, signal, headers);
|
||||
const redirectLinkRes = await axios.get(redirectLink, {headers, signal});
|
||||
const redirectLinkText = redirectLinkRes.data;
|
||||
const $ = cheerio.load(redirectLinkText);
|
||||
hubdriveLink =
|
||||
$('h3:contains("1080p")').find('a').attr('href') ||
|
||||
redirectLinkText.match(
|
||||
/href="(https:\/\/hubcloud\.[^\/]+\/drive\/[^"]+)"/,
|
||||
)[1];
|
||||
if (hubdriveLink.includes('hubdrive')) {
|
||||
const hubdriveRes = await axios.get(hubdriveLink, {headers, signal});
|
||||
const hubdriveText = hubdriveRes.data;
|
||||
const $$ = cheerio.load(hubdriveText);
|
||||
hubdriveLink =
|
||||
$$('.btn.btn-primary.btn-user.btn-success1.m-1').attr('href') ||
|
||||
hubdriveLink;
|
||||
}
|
||||
}
|
||||
const hubdriveLinkRes = await axios.get(hubdriveLink, {headers, signal});
|
||||
const hubcloudText = hubdriveLinkRes.data;
|
||||
const hubcloudLink =
|
||||
hubcloudText.match(
|
||||
/<META HTTP-EQUIV="refresh" content="0; url=([^"]+)">/i,
|
||||
)?.[1] || hubdriveLink;
|
||||
try {
|
||||
return await hubcloudExtracter(hubcloudLink, signal);
|
||||
} catch (error: any) {
|
||||
console.log('hd hub 4 getStream error: ', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
const encode = function (value: string) {
|
||||
return btoa(value.toString());
|
||||
};
|
||||
const decode = function (value: string) {
|
||||
if (value === undefined) {
|
||||
return '';
|
||||
}
|
||||
return atob(value.toString());
|
||||
};
|
||||
const pen = function (value: string) {
|
||||
return value.replace(/[a-zA-Z]/g, function (_0x1a470e: any) {
|
||||
return String.fromCharCode(
|
||||
(_0x1a470e <= 'Z' ? 90 : 122) >=
|
||||
(_0x1a470e = _0x1a470e.charCodeAt(0) + 13)
|
||||
? _0x1a470e
|
||||
: _0x1a470e - 26,
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const abortableTimeout = (
|
||||
ms: number,
|
||||
{signal}: {signal?: AbortSignal} = {},
|
||||
) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (signal && signal.aborted) {
|
||||
return reject(new Error('Aborted'));
|
||||
}
|
||||
|
||||
const timer = setTimeout(resolve, ms);
|
||||
|
||||
if (signal) {
|
||||
signal.addEventListener('abort', () => {
|
||||
clearTimeout(timer);
|
||||
reject(new Error('Aborted'));
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export async function getRedirectLinks(
|
||||
link: string,
|
||||
signal: AbortSignal,
|
||||
headers: any,
|
||||
) {
|
||||
try {
|
||||
const res = await fetch(link, {headers, signal});
|
||||
const resText = await res.text();
|
||||
|
||||
var regex = /ck\('_wp_http_\d+','([^']+)'/g;
|
||||
var combinedString = '';
|
||||
|
||||
var match;
|
||||
while ((match = regex.exec(resText)) !== null) {
|
||||
// console.log(match[1]);
|
||||
combinedString += match[1];
|
||||
}
|
||||
// console.log(decode(combinedString));
|
||||
const decodedString = decode(pen(decode(decode(combinedString))));
|
||||
// console.log(decodedString);
|
||||
const data = JSON.parse(decodedString);
|
||||
console.log(data);
|
||||
const token = encode(data?.data);
|
||||
const blogLink = data?.wp_http1 + '?re=' + token;
|
||||
// abort timeout on signal
|
||||
let wait = abortableTimeout((Number(data?.total_time) + 3) * 1000, {
|
||||
signal,
|
||||
});
|
||||
|
||||
await wait;
|
||||
console.log('blogLink', blogLink);
|
||||
|
||||
let vcloudLink = 'Invalid Request';
|
||||
while (vcloudLink.includes('Invalid Request')) {
|
||||
const blogRes = await fetch(blogLink, {headers, signal});
|
||||
const blogResText = (await blogRes.text()) as any;
|
||||
if (blogResText.includes('Invalid Request')) {
|
||||
console.log(blogResText);
|
||||
} else {
|
||||
vcloudLink = blogResText.match(/var reurl = "([^"]+)"/) || '';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// console.log('vcloudLink', vcloudLink?.[1]);
|
||||
return blogLink || link;
|
||||
} catch (err) {
|
||||
console.log('Error in getRedirectLinks', err);
|
||||
return link;
|
||||
}
|
||||
}
|
||||
|
||||
function rot13(str: string) {
|
||||
return str.replace(/[a-zA-Z]/g, function (char) {
|
||||
const charCode = char.charCodeAt(0);
|
||||
const isUpperCase = char <= 'Z';
|
||||
const baseCharCode = isUpperCase ? 65 : 97;
|
||||
return String.fromCharCode(
|
||||
((charCode - baseCharCode + 13) % 26) + baseCharCode,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function decodeString(encryptedString: string) {
|
||||
try {
|
||||
// First base64 decode
|
||||
let decoded = atob(encryptedString);
|
||||
|
||||
// Second base64 decode
|
||||
decoded = atob(decoded);
|
||||
|
||||
// ROT13 decode
|
||||
decoded = rot13(decoded);
|
||||
|
||||
// Third base64 decode
|
||||
decoded = atob(decoded);
|
||||
|
||||
// Parse JSON
|
||||
return JSON.parse(decoded);
|
||||
} catch (error) {
|
||||
console.error('Error decoding string:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
61
providers/hdhub4u/hdhubCatalog.ts
Normal file
61
providers/hdhub4u/hdhubCatalog.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
export const hdhub4uCatalog = [
|
||||
{
|
||||
title: 'Latest',
|
||||
filter: '',
|
||||
},
|
||||
{
|
||||
title: 'Web Series',
|
||||
filter: '/category/web-series',
|
||||
},
|
||||
{
|
||||
title: 'Hollywood ',
|
||||
filter: '/category/hollywood-movies',
|
||||
},
|
||||
{
|
||||
title: 'South Movies',
|
||||
filter: '/category/south-hindi-movies',
|
||||
},
|
||||
];
|
||||
|
||||
export const hdhub4uGenresList = [
|
||||
{
|
||||
title: 'Action',
|
||||
filter: '/category/action',
|
||||
},
|
||||
{
|
||||
title: 'Crime',
|
||||
filter: '/category/crime',
|
||||
},
|
||||
{
|
||||
title: 'Comedy',
|
||||
filter: '/category/comedy',
|
||||
},
|
||||
{
|
||||
title: 'Drama',
|
||||
filter: '/category/drama',
|
||||
},
|
||||
{
|
||||
title: 'Horror',
|
||||
filter: '/category/horror',
|
||||
},
|
||||
{
|
||||
title: 'Family',
|
||||
filter: '/category/family',
|
||||
},
|
||||
{
|
||||
title: 'Sci-Fi',
|
||||
filter: '/category/sifi',
|
||||
},
|
||||
{
|
||||
title: 'Thriller',
|
||||
filter: '/category/triller',
|
||||
},
|
||||
{
|
||||
title: 'Romance',
|
||||
filter: '/category/romance',
|
||||
},
|
||||
{
|
||||
title: 'Fight',
|
||||
filter: '/category/fight',
|
||||
},
|
||||
];
|
||||
129
providers/hdhub4u/hdhubGetInfo.ts
Normal file
129
providers/hdhub4u/hdhubGetInfo.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import {Info, Link, ProviderContext} from '../types';
|
||||
|
||||
const hdbHeaders = {
|
||||
Cookie: 'xla=s4t',
|
||||
Referer: 'https://google.com',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0',
|
||||
};
|
||||
export const hdhub4uGetInfo = async function ({
|
||||
link,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Info> {
|
||||
try {
|
||||
const {axios, cheerio} = providerContext;
|
||||
const url = link;
|
||||
const res = await axios.get(url, {headers: hdbHeaders});
|
||||
const data = res.data;
|
||||
const $ = cheerio.load(data);
|
||||
const container = $('.page-body');
|
||||
const imdbId =
|
||||
container
|
||||
.find('a[href*="imdb.com/title/tt"]:not([href*="imdb.com/title/tt/"])')
|
||||
.attr('href')
|
||||
?.split('/')[4] || '';
|
||||
const title = container
|
||||
.find(
|
||||
'h2[data-ved="2ahUKEwjL0NrBk4vnAhWlH7cAHRCeAlwQ3B0oATAfegQIFBAM"],h2[data-ved="2ahUKEwiP0pGdlermAhUFYVAKHV8tAmgQ3B0oATAZegQIDhAM"]',
|
||||
)
|
||||
.text();
|
||||
const type = title.toLocaleLowerCase().includes('season')
|
||||
? 'series'
|
||||
: 'movie';
|
||||
const synopsis = container
|
||||
.find('strong:contains("DESCRIPTION")')
|
||||
.parent()
|
||||
.text()
|
||||
.replace('DESCRIPTION:', '');
|
||||
const image = container.find('img[decoding="async"]').attr('src') || '';
|
||||
|
||||
// Links
|
||||
const links: Link[] = [];
|
||||
const directLink: Link['directLinks'] = [];
|
||||
|
||||
// direct link type
|
||||
$('strong:contains("EPiSODE")').map((i, element) => {
|
||||
const epTitle = $(element).parent().parent().text();
|
||||
const episodesLink =
|
||||
$(element)
|
||||
.parent()
|
||||
.parent()
|
||||
.parent()
|
||||
.next()
|
||||
.next()
|
||||
.find('a')
|
||||
.attr('href') ||
|
||||
$(element).parent().parent().parent().next().find('a').attr('href');
|
||||
|
||||
if (episodesLink && episodesLink) {
|
||||
directLink.push({
|
||||
title: epTitle,
|
||||
link: episodesLink,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (directLink.length === 0) {
|
||||
container.find('a:contains("EPiSODE")').map((i, element) => {
|
||||
const epTitle = $(element).text();
|
||||
const episodesLink = $(element).attr('href');
|
||||
if (episodesLink) {
|
||||
directLink.push({
|
||||
title: epTitle.toLocaleUpperCase(),
|
||||
link: episodesLink,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (directLink.length > 0) {
|
||||
links.push({
|
||||
title: title,
|
||||
directLinks: directLink,
|
||||
});
|
||||
}
|
||||
if (directLink.length === 0) {
|
||||
container
|
||||
.find(
|
||||
'a:contains("480"),a:contains("720"),a:contains("1080"),a:contains("2160"),a:contains("4K")',
|
||||
)
|
||||
.map((i, element) => {
|
||||
const quality =
|
||||
$(element)
|
||||
.text()
|
||||
.match(/\b(480p|720p|1080p|2160p)\b/i)?.[0] || '';
|
||||
const movieLinks = $(element).attr('href');
|
||||
const title = $(element).text();
|
||||
if (movieLinks) {
|
||||
links.push({
|
||||
directLinks: [{link: movieLinks, title: 'Movie', type: 'movie'}],
|
||||
quality: quality,
|
||||
title: title,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// console.log('drive meta', title, synopsis, image, imdbId, type, links);
|
||||
return {
|
||||
title,
|
||||
synopsis,
|
||||
image,
|
||||
imdbId,
|
||||
type,
|
||||
linkList: links,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return {
|
||||
title: '',
|
||||
synopsis: '',
|
||||
image: '',
|
||||
imdbId: '',
|
||||
type: 'movie',
|
||||
linkList: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
84
providers/hdhub4u/hdhubGetPosts.ts
Normal file
84
providers/hdhub4u/hdhubGetPosts.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
const hdbHeaders = {
|
||||
Cookie: 'xla=s4t',
|
||||
Referer: 'https://google.com',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0',
|
||||
};
|
||||
|
||||
export const hdhubGetPosts = async function ({
|
||||
filter,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
filter: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
providerContext: ProviderContext;
|
||||
signal: AbortSignal;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl} = providerContext;
|
||||
const baseUrl = await getBaseUrl('hdhub');
|
||||
const url = `${baseUrl + filter}/page/${page}/`;
|
||||
return posts({url, signal, providerContext});
|
||||
};
|
||||
|
||||
export const hdhubGetPostsSearch = async function ({
|
||||
searchQuery,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
providerContext: ProviderContext;
|
||||
signal: AbortSignal;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl} = providerContext;
|
||||
const baseUrl = await getBaseUrl('hdhub');
|
||||
const url = `${baseUrl}/page/${page}/?s=${searchQuery}`;
|
||||
return posts({url, signal, providerContext});
|
||||
};
|
||||
|
||||
async function posts({
|
||||
url,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
url: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {cheerio} = providerContext;
|
||||
try {
|
||||
const res = await fetch(url, {
|
||||
headers: hdbHeaders,
|
||||
signal,
|
||||
});
|
||||
const data = await res.text();
|
||||
const $ = cheerio.load(data);
|
||||
const catalog: Post[] = [];
|
||||
$('.recent-movies')
|
||||
.children()
|
||||
.map((i, element) => {
|
||||
const title = $(element).find('figure').find('img').attr('alt');
|
||||
const link = $(element).find('a').attr('href');
|
||||
const image = $(element).find('figure').find('img').attr('src');
|
||||
|
||||
if (title && link && image) {
|
||||
catalog.push({
|
||||
title: title.replace('Download', '').trim(),
|
||||
link: link,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('hdhubGetPosts error ', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
14
providers/hdhub4u/index.ts
Normal file
14
providers/hdhub4u/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {hdhub4uCatalog, hdhub4uGenresList} from './hdhubCatalog';
|
||||
import {hdhub4uGetInfo} from './hdhubGetInfo';
|
||||
import {hdhub4uGetStream} from './hdhub4uGetSteam';
|
||||
import {hdhubGetPosts, hdhubGetPostsSearch} from './hdhubGetPosts';
|
||||
import {ProviderType} from '../types';
|
||||
|
||||
export const hdhub4uProvider: ProviderType = {
|
||||
catalog: hdhub4uCatalog,
|
||||
genres: hdhub4uGenresList,
|
||||
GetMetaData: hdhub4uGetInfo,
|
||||
GetStream: hdhub4uGetStream,
|
||||
GetHomePosts: hdhubGetPosts,
|
||||
GetSearchPosts: hdhubGetPostsSearch,
|
||||
};
|
||||
10
providers/headers.ts
Normal file
10
providers/headers.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export const headers = {
|
||||
'sec-ch-ua':
|
||||
'"Not_A Brand";v="8", "Chromium";v="120", "Microsoft Edge";v="120"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
// 'Sec-Fetch-Site': 'none',
|
||||
// 'Sec-Fetch-User': '?1',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0',
|
||||
};
|
||||
56
providers/hiAnime/HiGetSteam.ts
Normal file
56
providers/hiAnime/HiGetSteam.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import {Stream, ProviderContext, TextTracks, TextTrackType} from '../types';
|
||||
|
||||
export const hiGetStream = async function ({
|
||||
link: id,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Stream[]> {
|
||||
try {
|
||||
const {getBaseUrl, axios} = providerContext;
|
||||
const baseUrl = await getBaseUrl('consumet');
|
||||
const servers = ['vidcloud', 'vidstreaming'];
|
||||
const url = `${baseUrl}/anime/zoro/watch?episodeId=${id}&server=`;
|
||||
const streamLinks: Stream[] = [];
|
||||
await Promise.all(
|
||||
servers.map(async server => {
|
||||
try {
|
||||
const res = await axios.get(url + server);
|
||||
if (res.data) {
|
||||
const subtitles: TextTracks = [];
|
||||
res.data?.subtitles.forEach((sub: any) => {
|
||||
if (sub?.lang === 'Thumbnails') return;
|
||||
subtitles.push({
|
||||
language: sub?.lang?.slice(0, 2) || 'Und',
|
||||
uri: sub?.url,
|
||||
title: sub?.lang || 'Undefined',
|
||||
type: sub?.url?.endsWith('.vtt')
|
||||
? TextTrackType.VTT
|
||||
: TextTrackType.SUBRIP,
|
||||
});
|
||||
});
|
||||
res.data?.sources.forEach((source: any) => {
|
||||
streamLinks.push({
|
||||
server: server,
|
||||
link: source?.url,
|
||||
type: source?.isM3U8 ? 'm3u8' : 'mp4',
|
||||
headers: {
|
||||
Referer: 'https://megacloud.club/',
|
||||
Origin: 'https://megacloud.club',
|
||||
},
|
||||
subtitles: subtitles,
|
||||
});
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}),
|
||||
);
|
||||
return streamLinks;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
20
providers/hiAnime/hiCatalog.ts
Normal file
20
providers/hiAnime/hiCatalog.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export const hiCatalog = [
|
||||
{
|
||||
title: 'Recent',
|
||||
filter: '/anime/zoro/recent-episodes',
|
||||
},
|
||||
{
|
||||
title: 'Top Airing',
|
||||
filter: '/anime/zoro/top-airing',
|
||||
},
|
||||
{
|
||||
title: 'Most Popular',
|
||||
filter: '/anime/zoro/most-popular',
|
||||
},
|
||||
{
|
||||
title: 'Most Favorited',
|
||||
filter: '/anime/zoro/most-favorite',
|
||||
},
|
||||
];
|
||||
|
||||
export const hiGenresList = [];
|
||||
83
providers/hiAnime/hiGetInfo.ts
Normal file
83
providers/hiAnime/hiGetInfo.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import {Info, Link, ProviderContext} from '../types';
|
||||
|
||||
export const hiGetInfo = async function ({
|
||||
link,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Info> {
|
||||
try {
|
||||
const {getBaseUrl, axios} = providerContext;
|
||||
const baseUrl = await getBaseUrl('consumet');
|
||||
const url = `${baseUrl}/anime/zoro/info?id=` + link;
|
||||
const res = await axios.get(url);
|
||||
const data = res.data;
|
||||
const meta = {
|
||||
title: data.title,
|
||||
synopsis: data.description,
|
||||
image: data.image,
|
||||
tags: [
|
||||
data?.type,
|
||||
data?.subOrDub === 'both' ? 'Sub And Dub' : data?.subOrDub,
|
||||
],
|
||||
imdbId: '',
|
||||
type: data.episodes.length > 0 ? 'series' : 'movie',
|
||||
};
|
||||
const linkList: Link[] = [];
|
||||
const subLinks: Link['directLinks'] = [];
|
||||
data.episodes.forEach((episode: any) => {
|
||||
if (!episode?.isSubbed) {
|
||||
return;
|
||||
}
|
||||
const title =
|
||||
'Episode ' + episode.number + (episode?.isFiller ? ' (Filler)' : '');
|
||||
const link = episode.id + '$sub';
|
||||
if (link && title) {
|
||||
subLinks.push({
|
||||
title,
|
||||
link,
|
||||
});
|
||||
}
|
||||
});
|
||||
linkList.push({
|
||||
title: meta.title + ' (Sub)',
|
||||
directLinks: subLinks,
|
||||
});
|
||||
if (data?.subOrDub === 'both') {
|
||||
const dubLinks: Link['directLinks'] = [];
|
||||
data.episodes.forEach((episode: any) => {
|
||||
if (!episode?.isDubbed) {
|
||||
return;
|
||||
}
|
||||
const title =
|
||||
'Episode ' + episode.number + (episode?.isFiller ? ' (Filler)' : '');
|
||||
const link = episode.id + '$dub';
|
||||
if (link && title) {
|
||||
dubLinks.push({
|
||||
title,
|
||||
link,
|
||||
});
|
||||
}
|
||||
});
|
||||
linkList.push({
|
||||
title: meta.title + ' (Dub)',
|
||||
directLinks: dubLinks,
|
||||
});
|
||||
}
|
||||
return {
|
||||
...meta,
|
||||
linkList: linkList,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return {
|
||||
title: '',
|
||||
synopsis: '',
|
||||
image: '',
|
||||
imdbId: '',
|
||||
type: 'movie',
|
||||
linkList: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
69
providers/hiAnime/hiGetPosts.ts
Normal file
69
providers/hiAnime/hiGetPosts.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
export const hiGetPosts = async function ({
|
||||
filter,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
filter: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl, axios} = providerContext;
|
||||
const baseUrl = await getBaseUrl('consumet');
|
||||
const url = `${baseUrl + filter}?page=${page}`;
|
||||
return posts({url, signal, axios});
|
||||
};
|
||||
|
||||
export const hiGetPostsSearch = async function ({
|
||||
searchQuery,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl, axios} = providerContext;
|
||||
const baseUrl = await getBaseUrl('consumet');
|
||||
const url = `${baseUrl}/anime/zoro/${searchQuery}?page=${page}`;
|
||||
return posts({url, signal, axios});
|
||||
};
|
||||
|
||||
async function posts({
|
||||
url,
|
||||
signal,
|
||||
axios,
|
||||
}: {
|
||||
url: string;
|
||||
signal: AbortSignal;
|
||||
axios: ProviderContext['axios'];
|
||||
}): Promise<Post[]> {
|
||||
try {
|
||||
const res = await axios.get(url, {signal});
|
||||
const data = res.data?.results;
|
||||
const catalog: Post[] = [];
|
||||
data?.map((element: any) => {
|
||||
const title = element.title;
|
||||
const link = element.id;
|
||||
const image = element.image;
|
||||
if (title && link && image) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link: link,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('zoro error ', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
14
providers/hiAnime/index.ts
Normal file
14
providers/hiAnime/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {hiGetInfo} from './hiGetInfo';
|
||||
import {hiCatalog, hiGenresList} from './hiCatalog';
|
||||
import {hiGetStream} from './HiGetSteam';
|
||||
import {hiGetPosts, hiGetPostsSearch} from './hiGetPosts';
|
||||
import {ProviderType} from '../types';
|
||||
|
||||
export const HiAnime: ProviderType = {
|
||||
catalog: hiCatalog,
|
||||
genres: hiGenresList,
|
||||
GetMetaData: hiGetInfo,
|
||||
GetHomePosts: hiGetPosts,
|
||||
GetStream: hiGetStream,
|
||||
GetSearchPosts: hiGetPostsSearch,
|
||||
};
|
||||
85
providers/hubcloudExtractor.ts
Normal file
85
providers/hubcloudExtractor.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import axios from 'axios';
|
||||
import * as cheerio from 'cheerio';
|
||||
import {Stream} from './types';
|
||||
import {headers} from './headers';
|
||||
|
||||
const decode = function (value: string) {
|
||||
if (value === undefined) {
|
||||
return '';
|
||||
}
|
||||
return atob(value.toString());
|
||||
};
|
||||
|
||||
export async function hubcloudExtracter(link: string, signal: AbortSignal) {
|
||||
try {
|
||||
console.log('hubcloudExtracter', link);
|
||||
const baseUrl = link.split('/').slice(0, 3).join('/');
|
||||
const streamLinks: Stream[] = [];
|
||||
const vLinkRes = await axios(`${link}`, {headers, signal});
|
||||
const vLinkText = vLinkRes.data;
|
||||
const $vLink = cheerio.load(vLinkText);
|
||||
const vLinkRedirect = vLinkText.match(/var\s+url\s*=\s*'([^']+)';/) || [];
|
||||
let vcloudLink =
|
||||
decode(vLinkRedirect[1]?.split('r=')?.[1]) ||
|
||||
vLinkRedirect[1] ||
|
||||
$vLink('.fa-file-download.fa-lg').parent().attr('href') ||
|
||||
link;
|
||||
console.log('vcloudLink', vcloudLink);
|
||||
if (vcloudLink?.startsWith('/')) {
|
||||
vcloudLink = `${baseUrl}${vcloudLink}`;
|
||||
console.log('New vcloudLink', vcloudLink);
|
||||
}
|
||||
const vcloudRes = await fetch(vcloudLink, {
|
||||
headers,
|
||||
signal,
|
||||
redirect: 'follow',
|
||||
});
|
||||
const $ = cheerio.load(await vcloudRes.text());
|
||||
// console.log('vcloudRes', $.text());
|
||||
|
||||
const linkClass = $('.btn-success.btn-lg.h6,.btn-danger,.btn-secondary');
|
||||
for (const element of linkClass) {
|
||||
const itm = $(element);
|
||||
let link = itm.attr('href') || '';
|
||||
if (link?.includes('.dev') && !link?.includes('/?id=')) {
|
||||
streamLinks.push({server: 'Cf Worker', link: link, type: 'mkv'});
|
||||
}
|
||||
if (link?.includes('pixeld')) {
|
||||
if (!link?.includes('api')) {
|
||||
const token = link.split('/').pop();
|
||||
const baseUrl = link.split('/').slice(0, -2).join('/');
|
||||
link = `${baseUrl}/api/file/${token}?download`;
|
||||
}
|
||||
streamLinks.push({server: 'Pixeldrain', link: link, type: 'mkv'});
|
||||
}
|
||||
if (link?.includes('hubcloud') || link?.includes('/?id=')) {
|
||||
try {
|
||||
const newLinkRes = await axios.head(link, {headers, signal});
|
||||
const newLink =
|
||||
newLinkRes.request?.responseURL?.split('link=')?.[1] || link;
|
||||
streamLinks.push({server: 'hubcloud', link: newLink, type: 'mkv'});
|
||||
} catch (error) {
|
||||
console.log('hubcloudExtracter error in hubcloud link: ', error);
|
||||
}
|
||||
}
|
||||
if (link?.includes('cloudflarestorage')) {
|
||||
streamLinks.push({server: 'CfStorage', link: link, type: 'mkv'});
|
||||
}
|
||||
if (link?.includes('fastdl')) {
|
||||
streamLinks.push({server: 'FastDl', link: link, type: 'mkv'});
|
||||
}
|
||||
if (link.includes('hubcdn')) {
|
||||
streamLinks.push({
|
||||
server: 'HubCdn',
|
||||
link: link,
|
||||
type: 'mkv',
|
||||
});
|
||||
}
|
||||
}
|
||||
console.log('streamLinks', streamLinks);
|
||||
return streamLinks;
|
||||
} catch (error) {
|
||||
console.log('hubcloudExtracter error: ', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
16
providers/katmovies/index.ts
Normal file
16
providers/katmovies/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import {katCatalog, katGenresList} from './katCatalog';
|
||||
import {katEpisodeLinks} from './katGetEpsodes';
|
||||
import {katGetInfo} from './katGetInfo';
|
||||
import {katGetPosts, katGetPostsSearch} from './katGetPosts';
|
||||
import {katGetStream} from './katGetSteam';
|
||||
import {ProviderType} from '../types';
|
||||
|
||||
export const katMoviesHd: ProviderType = {
|
||||
catalog: katCatalog,
|
||||
genres: katGenresList,
|
||||
GetMetaData: katGetInfo,
|
||||
GetHomePosts: katGetPosts,
|
||||
GetStream: katGetStream,
|
||||
GetEpisodeLinks: katEpisodeLinks,
|
||||
GetSearchPosts: katGetPostsSearch,
|
||||
};
|
||||
61
providers/katmovies/katCatalog.ts
Normal file
61
providers/katmovies/katCatalog.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
export const katCatalog = [
|
||||
{
|
||||
title: 'Latest',
|
||||
filter: '',
|
||||
},
|
||||
{
|
||||
title: 'Netflix',
|
||||
filter: '/category/netflix',
|
||||
},
|
||||
{
|
||||
title: 'Animated',
|
||||
filter: '/category/animated',
|
||||
},
|
||||
{
|
||||
title: 'Amazon Prime',
|
||||
filter: '/category/amazon-prime',
|
||||
},
|
||||
];
|
||||
|
||||
export const katGenresList = [
|
||||
{
|
||||
title: 'Action',
|
||||
filter: '/category/action',
|
||||
},
|
||||
{
|
||||
title: 'Crime',
|
||||
filter: '/category/crime',
|
||||
},
|
||||
{
|
||||
title: 'Comedy',
|
||||
filter: '/category/comedy',
|
||||
},
|
||||
{
|
||||
title: 'Drama',
|
||||
filter: '/category/drama',
|
||||
},
|
||||
{
|
||||
title: 'Horror',
|
||||
filter: '/category/horror',
|
||||
},
|
||||
{
|
||||
title: 'Family',
|
||||
filter: '/category/family',
|
||||
},
|
||||
{
|
||||
title: 'Sci-Fi',
|
||||
filter: '/category/sifi',
|
||||
},
|
||||
{
|
||||
title: 'Thriller',
|
||||
filter: '/category/triller',
|
||||
},
|
||||
{
|
||||
title: 'Romance',
|
||||
filter: '/category/romance',
|
||||
},
|
||||
{
|
||||
title: 'Fight',
|
||||
filter: '/category/fight',
|
||||
},
|
||||
];
|
||||
84
providers/katmovies/katGetEpsodes.ts
Normal file
84
providers/katmovies/katGetEpsodes.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import {EpisodeLink, ProviderContext} from '../types';
|
||||
|
||||
export const katEpisodeLinks = async function ({
|
||||
url,
|
||||
providerContext,
|
||||
}: {
|
||||
url: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<EpisodeLink[]> {
|
||||
const {axios, cheerio} = providerContext;
|
||||
const episodesLink: EpisodeLink[] = [];
|
||||
try {
|
||||
if (url.includes('gdflix')) {
|
||||
const baseUrl = url.split('/pack')?.[0];
|
||||
const res = await axios.get(url);
|
||||
const data = res.data;
|
||||
const $ = cheerio.load(data);
|
||||
const links = $('.list-group-item');
|
||||
links?.map((i, link) => {
|
||||
episodesLink.push({
|
||||
title: $(link).text() || '',
|
||||
link: baseUrl + $(link).find('a').attr('href') || '',
|
||||
});
|
||||
});
|
||||
if (episodesLink.length > 0) {
|
||||
return episodesLink;
|
||||
}
|
||||
}
|
||||
if (url.includes('/pack')) {
|
||||
const epIds = await extractKmhdEpisodes(url, providerContext);
|
||||
epIds?.forEach((id: string, index: number) => {
|
||||
episodesLink.push({
|
||||
title: `Episode ${index + 1}`,
|
||||
link: url.split('/pack')[0] + '/file/' + id,
|
||||
});
|
||||
});
|
||||
}
|
||||
const res = await axios.get(url, {
|
||||
headers: {
|
||||
Cookie:
|
||||
'_ga_GNR438JY8N=GS1.1.1722240350.5.0.1722240350.0.0.0; _ga=GA1.1.372196696.1722150754; unlocked=true',
|
||||
},
|
||||
});
|
||||
const episodeData = res.data;
|
||||
const $ = cheerio.load(episodeData);
|
||||
const links = $('.autohyperlink');
|
||||
links?.map((i, link) => {
|
||||
episodesLink.push({
|
||||
title: $(link).parent().children().remove().end().text() || '',
|
||||
link: $(link).attr('href') || '',
|
||||
});
|
||||
});
|
||||
|
||||
return episodesLink;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export async function extractKmhdLink(
|
||||
katlink: string,
|
||||
providerContext: ProviderContext,
|
||||
) {
|
||||
const {axios} = providerContext;
|
||||
const res = await axios.get(katlink);
|
||||
const data = res.data;
|
||||
const hubDriveRes = data.match(/hubdrive_res:\s*"([^"]+)"/)[1];
|
||||
const hubDriveLink = data.match(
|
||||
/hubdrive_res\s*:\s*{[^}]*?link\s*:\s*"([^"]+)"/,
|
||||
)[1];
|
||||
return hubDriveLink + hubDriveRes;
|
||||
}
|
||||
|
||||
async function extractKmhdEpisodes(
|
||||
katlink: string,
|
||||
providerContext: ProviderContext,
|
||||
) {
|
||||
const {axios} = providerContext;
|
||||
const res = await axios.get(katlink);
|
||||
const data = res.data;
|
||||
const ids = data.match(/[\w]+_[a-f0-9]{8}/g);
|
||||
return ids;
|
||||
}
|
||||
131
providers/katmovies/katGetInfo.ts
Normal file
131
providers/katmovies/katGetInfo.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import {Info, Link, ProviderContext} from '../types';
|
||||
|
||||
export const katGetInfo = async function ({
|
||||
link,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Info> {
|
||||
try {
|
||||
const {axios, cheerio} = providerContext;
|
||||
const url = link;
|
||||
const res = await axios.get(url);
|
||||
const data = res.data;
|
||||
const $ = cheerio.load(data);
|
||||
const container = $('.yQ8hqd.ksSzJd.LoQAYe').html()
|
||||
? $('.yQ8hqd.ksSzJd.LoQAYe')
|
||||
: $('.FxvUNb');
|
||||
const imdbId =
|
||||
container
|
||||
.find('a[href*="imdb.com/title/tt"]:not([href*="imdb.com/title/tt/"])')
|
||||
.attr('href')
|
||||
?.split('/')[4] || '';
|
||||
const title = container
|
||||
.find('li:contains("Name")')
|
||||
.children()
|
||||
.remove()
|
||||
.end()
|
||||
.text();
|
||||
const type = $('.yQ8hqd.ksSzJd.LoQAYe').html() ? 'series' : 'movie';
|
||||
const synopsis = container.find('li:contains("Stars")').text();
|
||||
const image =
|
||||
$('h4:contains("SCREENSHOTS")').next().find('img').attr('src') || '';
|
||||
|
||||
console.log('katGetInfo', title, synopsis, image, imdbId, type);
|
||||
|
||||
// Links
|
||||
const links: Link[] = [];
|
||||
const directLink: Link['directLinks'] = [];
|
||||
|
||||
// direct links
|
||||
$('.entry-content')
|
||||
.find('p:contains("Episode")')
|
||||
.each((i, element) => {
|
||||
const dlLink =
|
||||
$(element)
|
||||
.nextAll('h3,h2')
|
||||
.first()
|
||||
.find('a:contains("1080"),a:contains("720"),a:contains("480")')
|
||||
.attr('href') || '';
|
||||
const dlTitle = $(element).find('span').text();
|
||||
|
||||
if (link.trim().length > 0 && dlTitle.includes('Episode ')) {
|
||||
directLink.push({
|
||||
title: dlTitle,
|
||||
link: dlLink,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (directLink.length > 0) {
|
||||
links.push({
|
||||
quality: '',
|
||||
title: title,
|
||||
directLinks: directLink,
|
||||
});
|
||||
}
|
||||
|
||||
$('.entry-content')
|
||||
.find('pre')
|
||||
.nextUntil('div')
|
||||
.filter('h2')
|
||||
.each((i, element) => {
|
||||
const link = $(element).find('a').attr('href');
|
||||
const quality =
|
||||
$(element)
|
||||
.text()
|
||||
.match(/\b(480p|720p|1080p|2160p)\b/i)?.[0] || '';
|
||||
const title = $(element).text();
|
||||
if (link && title.includes('')) {
|
||||
links.push({
|
||||
quality,
|
||||
title,
|
||||
episodesLink: link,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (links.length === 0 && type === 'movie') {
|
||||
$('.entry-content')
|
||||
.find('h2:contains("DOWNLOAD"),h3:contains("DOWNLOAD")')
|
||||
.nextUntil('pre,div')
|
||||
.filter('h2')
|
||||
.each((i, element) => {
|
||||
const link = $(element).find('a').attr('href');
|
||||
const quality =
|
||||
$(element)
|
||||
.text()
|
||||
.match(/\b(480p|720p|1080p|2160p)\b/i)?.[0] || '';
|
||||
const title = $(element).text();
|
||||
if (link && !title.includes('Online')) {
|
||||
links.push({
|
||||
quality,
|
||||
title,
|
||||
directLinks: [{link, title, type: 'movie'}],
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// console.log('drive meta', title, synopsis, image, imdbId, type, links);
|
||||
return {
|
||||
title,
|
||||
synopsis,
|
||||
image,
|
||||
imdbId,
|
||||
type,
|
||||
linkList: links,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return {
|
||||
title: '',
|
||||
synopsis: '',
|
||||
image: '',
|
||||
imdbId: '',
|
||||
type: 'movie',
|
||||
linkList: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
72
providers/katmovies/katGetPosts.ts
Normal file
72
providers/katmovies/katGetPosts.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
export const katGetPosts = async function ({
|
||||
filter,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
filter: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl, cheerio} = providerContext;
|
||||
const baseUrl = await getBaseUrl('kat');
|
||||
const url = `${baseUrl + filter}/page/${page}/`;
|
||||
return posts({url, signal, cheerio});
|
||||
};
|
||||
|
||||
export const katGetPostsSearch = async function ({
|
||||
searchQuery,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl, cheerio} = providerContext;
|
||||
const baseUrl = await getBaseUrl('kat');
|
||||
const url = `${baseUrl}/page/${page}/?s=${searchQuery}`;
|
||||
return posts({url, signal, cheerio});
|
||||
};
|
||||
|
||||
async function posts({
|
||||
url,
|
||||
signal,
|
||||
cheerio,
|
||||
}: {
|
||||
url: string;
|
||||
signal: AbortSignal;
|
||||
cheerio: ProviderContext['cheerio'];
|
||||
}): Promise<Post[]> {
|
||||
try {
|
||||
const res = await fetch(url, {signal});
|
||||
const data = await res.text();
|
||||
const $ = cheerio.load(data);
|
||||
const catalog: Post[] = [];
|
||||
$('.recent-posts')
|
||||
.children()
|
||||
.map((i, element) => {
|
||||
const title = $(element).find('img').attr('alt');
|
||||
const link = $(element).find('a').attr('href');
|
||||
const image = $(element).find('img').attr('src');
|
||||
if (title && link && image) {
|
||||
catalog.push({
|
||||
title: title.replace('Download', '').trim(),
|
||||
link: link,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('katmovies error ', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
99
providers/katmovies/katGetSteam.ts
Normal file
99
providers/katmovies/katGetSteam.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import {Stream, ProviderContext} from '../types';
|
||||
|
||||
async function extractKmhdLink(
|
||||
katlink: string,
|
||||
providerContext: ProviderContext,
|
||||
) {
|
||||
const {axios} = providerContext;
|
||||
const res = await axios.get(katlink);
|
||||
const data = res.data;
|
||||
const hubDriveRes = data.match(/hubdrive_res:\s*"([^"]+)"/)[1];
|
||||
const hubDriveLink = data.match(
|
||||
/hubdrive_res\s*:\s*{[^}]*?link\s*:\s*"([^"]+)"/,
|
||||
)[1];
|
||||
return hubDriveLink + hubDriveRes;
|
||||
}
|
||||
export async function katGetStream({
|
||||
link,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
type: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Stream[]> {
|
||||
const {axios, cheerio, extractors} = providerContext;
|
||||
const {hubcloudExtracter, gdFlixExtracter} = extractors;
|
||||
const streamLinks: Stream[] = [];
|
||||
console.log('katGetStream', link);
|
||||
try {
|
||||
if (link.includes('gdflix')) {
|
||||
return await gdFlixExtracter(link, signal);
|
||||
}
|
||||
if (link.includes('kmhd')) {
|
||||
const hubcloudLink = await extractKmhdLink(link, providerContext);
|
||||
return await hubcloudExtracter(hubcloudLink, signal);
|
||||
}
|
||||
if (link.includes('gdflix')) {
|
||||
// resume link
|
||||
try {
|
||||
const resumeDrive = link.replace('/file', '/zfile');
|
||||
// console.log('resumeDrive', resumeDrive);
|
||||
const resumeDriveRes = await axios.get(resumeDrive);
|
||||
const resumeDriveHtml = resumeDriveRes.data;
|
||||
const $resumeDrive = cheerio.load(resumeDriveHtml);
|
||||
const resumeLink = $resumeDrive('.btn-success').attr('href');
|
||||
console.log('resumeLink', resumeLink);
|
||||
if (resumeLink) {
|
||||
streamLinks.push({
|
||||
server: 'ResumeCloud',
|
||||
link: resumeLink,
|
||||
type: 'mkv',
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Resume link not found');
|
||||
}
|
||||
//instant link
|
||||
try {
|
||||
const driveres = await axios.get(link, {timeout: 10000});
|
||||
const $drive = cheerio.load(driveres.data);
|
||||
const seed = $drive('.btn-danger').attr('href') || '';
|
||||
const instantToken = seed.split('=')[1];
|
||||
// console.log('InstantToken', instantToken);
|
||||
const InstantFromData = new FormData();
|
||||
InstantFromData.append('keys', instantToken);
|
||||
const videoSeedUrl = seed.split('/').slice(0, 3).join('/') + '/api';
|
||||
// console.log('videoSeedUrl', videoSeedUrl);
|
||||
const instantLinkRes = await fetch(videoSeedUrl, {
|
||||
method: 'POST',
|
||||
body: InstantFromData,
|
||||
headers: {
|
||||
'x-token': videoSeedUrl,
|
||||
},
|
||||
});
|
||||
const instantLinkData = await instantLinkRes.json();
|
||||
console.log('instantLinkData', instantLinkData);
|
||||
if (instantLinkData.error === false) {
|
||||
const instantLink = instantLinkData.url;
|
||||
streamLinks.push({
|
||||
server: 'Gdrive-Instant',
|
||||
link: instantLink,
|
||||
type: 'mkv',
|
||||
});
|
||||
} else {
|
||||
console.log('Instant link not found', instantLinkData);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Instant link not found', err);
|
||||
}
|
||||
return streamLinks;
|
||||
}
|
||||
const stereams = await hubcloudExtracter(link, signal);
|
||||
return stereams;
|
||||
} catch (error: any) {
|
||||
console.log('katgetStream error: ', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
14
providers/kissKh/index.ts
Normal file
14
providers/kissKh/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {kisskhCatalog, kisskhGenresList} from './kissKhCatalog';
|
||||
import {kissKhGetInfo} from './kissKhGetInfo';
|
||||
import {kissKhGetPosts, kissKhGetPostsSearch} from './kissKhGetPosts';
|
||||
import {kissKhGetStream} from './kissKhGetStream';
|
||||
import {ProviderType} from '../types';
|
||||
|
||||
export const kissKhProvider: ProviderType = {
|
||||
catalog: kisskhCatalog,
|
||||
genres: kisskhGenresList,
|
||||
GetHomePosts: kissKhGetPosts,
|
||||
GetMetaData: kissKhGetInfo,
|
||||
GetStream: kissKhGetStream,
|
||||
GetSearchPosts: kissKhGetPostsSearch,
|
||||
};
|
||||
20
providers/kissKh/kissKhCatalog.ts
Normal file
20
providers/kissKh/kissKhCatalog.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export const kisskhCatalog = [
|
||||
{
|
||||
title: 'Latest',
|
||||
filter: '/api/DramaList/List?type=0&sub=0&country=0&status=0&order=2',
|
||||
},
|
||||
{
|
||||
title: 'Hollywood',
|
||||
filter: '/api/DramaList/List?type=4&sub=0&country=0&status=0&order=2',
|
||||
},
|
||||
{
|
||||
title: 'Anime',
|
||||
filter: '/api/DramaList/List?type=3&sub=0&country=0&status=0&order=2',
|
||||
},
|
||||
{
|
||||
title: 'K Drama',
|
||||
filter: '/api/DramaList/List?type=0&sub=0&country=0&status=0&order=2',
|
||||
},
|
||||
];
|
||||
|
||||
export const kisskhGenresList = [];
|
||||
57
providers/kissKh/kissKhGetInfo.ts
Normal file
57
providers/kissKh/kissKhGetInfo.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import {Info, Link, ProviderContext} from '../types';
|
||||
|
||||
export const kissKhGetInfo = async function ({
|
||||
link,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Info> {
|
||||
try {
|
||||
const {axios} = providerContext;
|
||||
const res = await axios.get(link);
|
||||
const data = res.data;
|
||||
const meta = {
|
||||
title: data.title,
|
||||
synopsis: data.description,
|
||||
image: data.thumbnail,
|
||||
tags: [data?.releaseDate?.split('-')[0], data?.status, data?.type],
|
||||
imdbId: '',
|
||||
type: data.episodesCount > 1 ? 'series' : 'movie',
|
||||
};
|
||||
|
||||
const linkList: Link[] = [];
|
||||
const subLinks: Link['directLinks'] = [];
|
||||
|
||||
data?.episodes?.reverse().map((episode: any) => {
|
||||
const title = 'Episode ' + episode?.number;
|
||||
const link = episode?.id?.toString();
|
||||
if (link && title) {
|
||||
subLinks.push({
|
||||
title,
|
||||
link,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
linkList.push({
|
||||
title: meta.title,
|
||||
directLinks: subLinks,
|
||||
});
|
||||
|
||||
return {
|
||||
...meta,
|
||||
linkList: linkList,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return {
|
||||
title: '',
|
||||
synopsis: '',
|
||||
image: '',
|
||||
imdbId: '',
|
||||
type: 'movie',
|
||||
linkList: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
75
providers/kissKh/kissKhGetPosts.ts
Normal file
75
providers/kissKh/kissKhGetPosts.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
export const kissKhGetPosts = async function ({
|
||||
filter,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
filter: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl, axios} = providerContext;
|
||||
const baseUrl = await getBaseUrl('kissKh');
|
||||
const url = `${baseUrl + filter}&type=0`;
|
||||
try {
|
||||
const res = await axios.get(url, {signal});
|
||||
const data = res.data?.data;
|
||||
const catalog: Post[] = [];
|
||||
data?.map((element: any) => {
|
||||
const title = element.title;
|
||||
const link = baseUrl + `/api/DramaList/Drama/${element?.id}?isq=false`;
|
||||
const image = element.thumbnail;
|
||||
if (title && link && image) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link: link,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('kiss error ', err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export const kissKhGetPostsSearch = async function ({
|
||||
searchQuery,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl, axios} = providerContext;
|
||||
const baseUrl = await getBaseUrl('kissKh');
|
||||
const url = `${baseUrl}/api/DramaList/Search?q=${searchQuery}&type=0`;
|
||||
try {
|
||||
const res = await axios.get(url, {signal});
|
||||
const data = res.data;
|
||||
const catalog: Post[] = [];
|
||||
data?.map((element: any) => {
|
||||
const title = element.title;
|
||||
const link = baseUrl + `/api/DramaList/Drama/${element?.id}?isq=false`;
|
||||
const image = element.thumbnail;
|
||||
if (title && link && image) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link: link,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('kiss error ', err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
45
providers/kissKh/kissKhGetStream.ts
Normal file
45
providers/kissKh/kissKhGetStream.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import {Stream, ProviderContext, TextTrackType, TextTracks} from '../types';
|
||||
|
||||
export const kissKhGetStream = async function ({
|
||||
link: id,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Stream[]> {
|
||||
try {
|
||||
const {axios, getBaseUrl} = providerContext;
|
||||
const streamLinks: Stream[] = [];
|
||||
const subtitles: TextTracks = [];
|
||||
const baseUrl = await getBaseUrl('kissKh');
|
||||
const streamUrl =
|
||||
'https://adorable-salamander-ecbb21.netlify.app/api/kisskh/video?id=' +
|
||||
id;
|
||||
const res = await axios.get(streamUrl);
|
||||
const stream = res.data?.source?.Video;
|
||||
const subData = res.data?.subtitles;
|
||||
subData?.map((sub: any) => {
|
||||
subtitles.push({
|
||||
title: sub?.label,
|
||||
language: sub?.land,
|
||||
type: sub?.src?.includes('.vtt')
|
||||
? TextTrackType.VTT
|
||||
: TextTrackType.SUBRIP,
|
||||
uri: sub?.src,
|
||||
});
|
||||
});
|
||||
streamLinks.push({
|
||||
server: 'kissKh',
|
||||
link: stream,
|
||||
type: 'm3u8',
|
||||
subtitles,
|
||||
headers: {
|
||||
referer: baseUrl,
|
||||
},
|
||||
});
|
||||
return streamLinks;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
17
providers/luxMovies/index.ts
Normal file
17
providers/luxMovies/index.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import {luxGetPosts, luxGetPostsSearch} from './luxGetPosts';
|
||||
import {vegaGetInfo} from '../vega/getInfo';
|
||||
import {vegaGetStream} from '../vega/getStream';
|
||||
import {vegaGetEpisodeLinks} from '../vega/getEpisodesLink';
|
||||
import {homeList, genresList} from './luxCatalog';
|
||||
import {ProviderType} from '../types';
|
||||
|
||||
export const luxMovies: ProviderType = {
|
||||
catalog: homeList,
|
||||
genres: genresList,
|
||||
GetMetaData: vegaGetInfo,
|
||||
GetHomePosts: luxGetPosts,
|
||||
GetStream: vegaGetStream,
|
||||
nonStreamableServer: ['filepress'],
|
||||
GetEpisodeLinks: vegaGetEpisodeLinks,
|
||||
GetSearchPosts: luxGetPostsSearch,
|
||||
};
|
||||
101
providers/luxMovies/luxCatalog.ts
Normal file
101
providers/luxMovies/luxCatalog.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
export const homeList = [
|
||||
{
|
||||
title: 'New',
|
||||
filter: '',
|
||||
},
|
||||
{
|
||||
title: 'Netflix',
|
||||
filter: 'category/web-series/netflix',
|
||||
},
|
||||
{
|
||||
title: 'Amazon Prime',
|
||||
filter: 'category/web-series/amazon-prime-video',
|
||||
},
|
||||
{
|
||||
title: '4K Movies',
|
||||
filter: 'category/movies-by-quality/2160p',
|
||||
},
|
||||
];
|
||||
|
||||
export const genresList = [
|
||||
{
|
||||
title: 'Action',
|
||||
filter: 'category/movies-by-genres/action/',
|
||||
},
|
||||
{
|
||||
title: 'Adventure',
|
||||
filter: 'category/movies-by-genres/adventure/',
|
||||
},
|
||||
{
|
||||
title: 'Animation',
|
||||
filter: 'category/movies-by-genres/animation/',
|
||||
},
|
||||
{
|
||||
title: 'Biography',
|
||||
filter: 'category/movies-by-genres/biography/',
|
||||
},
|
||||
{
|
||||
title: 'Comedy',
|
||||
filter: 'category/movies-by-genres/comedy/',
|
||||
},
|
||||
{
|
||||
title: 'Crime',
|
||||
filter: 'category/movies-by-genres/crime/',
|
||||
},
|
||||
{
|
||||
title: 'Documentary',
|
||||
filter: 'category/movies-by-genres/documentary/',
|
||||
},
|
||||
{
|
||||
title: 'Drama',
|
||||
filter: 'category/movies-by-genres/drama/',
|
||||
},
|
||||
{
|
||||
title: 'Family',
|
||||
filter: 'category/movies-by-genres/family/',
|
||||
},
|
||||
{
|
||||
title: 'Fantasy',
|
||||
filter: 'category/movies-by-genres/fantasy/',
|
||||
},
|
||||
{
|
||||
title: 'History',
|
||||
filter: 'category/movies-by-genres/history/',
|
||||
},
|
||||
{
|
||||
title: 'Horror',
|
||||
filter: 'category/movies-by-genres/horror/',
|
||||
},
|
||||
{
|
||||
title: 'Music',
|
||||
filter: 'category/movies-by-genres/music/',
|
||||
},
|
||||
{
|
||||
title: 'Mystery',
|
||||
filter: 'category/movies-by-genres/mystery/',
|
||||
},
|
||||
{
|
||||
title: 'Romance',
|
||||
filter: 'category/movies-by-genres/romance/',
|
||||
},
|
||||
{
|
||||
title: 'Sci-Fi',
|
||||
filter: 'category/movies-by-genres/sci-fi/',
|
||||
},
|
||||
{
|
||||
title: 'Sport',
|
||||
filter: 'category/movies-by-genres/sport/',
|
||||
},
|
||||
{
|
||||
title: 'Thriller',
|
||||
filter: 'category/movies-by-genres/thriller/',
|
||||
},
|
||||
{
|
||||
title: 'War',
|
||||
filter: 'category/movies-by-genres/war/',
|
||||
},
|
||||
{
|
||||
title: 'Western',
|
||||
filter: 'category/movies-by-genres/western/',
|
||||
},
|
||||
];
|
||||
111
providers/luxMovies/luxGetPosts.ts
Normal file
111
providers/luxMovies/luxGetPosts.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
const headers = {
|
||||
Accept:
|
||||
'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
||||
'Cache-Control': 'no-store',
|
||||
'Accept-Language': 'en-US,en;q=0.9',
|
||||
DNT: '1',
|
||||
'sec-ch-ua':
|
||||
'"Not_A Brand";v="8", "Chromium";v="120", "Microsoft Edge";v="120"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
'Sec-Fetch-Dest': 'document',
|
||||
'Sec-Fetch-Mode': 'navigate',
|
||||
'Sec-Fetch-Site': 'none',
|
||||
'Sec-Fetch-User': '?1',
|
||||
Cookie:
|
||||
'ext_name=ojplmecpdpgccookcobabopnaifgidhf; cf_clearance=gaIhTNzqSvp27JCVf7qiEUfYRfwyj0Jx9rcsn774BbE-1732694853-1.2.1.1-QKgYJvmrEz08gM9qbAp70diztE2.hseO2NNi.0imIUk_gkuWUcr7U8t5Zn_z4Ov30sIGPBES1PBgMUEa.s8e8QTkQoZjgziFmoC7YdX7s2Jnt.tYCxE_s5mMLQQBYbz_94A89IYe93Y6kyLQm_L.dvUKPPiGjn_sH3qRD0g4p9oOl0SPvH0T2W_EaD0r6mVBasbgro9dAROt_6CxshXOEGeMOnoWR.ID699FKldjMUhbXJbATAffdOY6kf2sD_iwrSl4bcetTlDHd4gusTVfxSS1pL5qNjyTU9wa38soPl1wZoqFHkEGOPWz6S7FD5ikHxX0bArFem9hiDeJXctYfWz5e_Lkc6lH7nW0Rm2XS3gxCadQSg21RkSReN6kDAEecqjgJSE4zUomkWAxFZ98TSShgGWC0ridPTpdQizPDZQ; _lscache_vary=c1d682536aea2d88fbb2574666e1f0aa',
|
||||
'Upgrade-Insecure-Requests': '1',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0',
|
||||
};
|
||||
|
||||
export const luxGetPosts = async ({
|
||||
filter,
|
||||
page,
|
||||
providerValue,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
filter: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> => {
|
||||
const {getBaseUrl} = providerContext;
|
||||
const baseUrl = await getBaseUrl('lux');
|
||||
|
||||
console.log('vegaGetPosts baseUrl:', providerValue, baseUrl);
|
||||
const url = `${baseUrl}/${filter}/page/${page}/`;
|
||||
console.log('lux url:', url);
|
||||
return posts(url, signal, providerContext);
|
||||
};
|
||||
|
||||
export const luxGetPostsSearch = async ({
|
||||
searchQuery,
|
||||
page,
|
||||
providerValue,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> => {
|
||||
const {getBaseUrl} = providerContext;
|
||||
const baseUrl = await getBaseUrl('lux');
|
||||
|
||||
console.log('vegaGetPosts baseUrl:', providerValue, baseUrl);
|
||||
const url = `${baseUrl}/page/${page}/?s=${searchQuery}`;
|
||||
console.log('lux url:', url);
|
||||
|
||||
return posts(url, signal, providerContext);
|
||||
};
|
||||
|
||||
async function posts(
|
||||
url: string,
|
||||
signal: AbortSignal,
|
||||
providerContext: ProviderContext,
|
||||
): Promise<Post[]> {
|
||||
try {
|
||||
const {axios, cheerio} = providerContext;
|
||||
const urlRes = await axios.get(url, {headers, signal});
|
||||
const $ = cheerio.load(urlRes.data);
|
||||
const posts: Post[] = [];
|
||||
$('.blog-items')
|
||||
?.children('article')
|
||||
?.each((index, element) => {
|
||||
const post = {
|
||||
title:
|
||||
$(element)
|
||||
?.find('a')
|
||||
?.attr('title')
|
||||
?.replace('Download', '')
|
||||
?.match(/^(.*?)\s*\((\d{4})\)|^(.*?)\s*\((Season \d+)\)/)?.[0] ||
|
||||
$(element)?.find('a')?.attr('title')?.replace('Download', '') ||
|
||||
'',
|
||||
|
||||
link: $(element)?.find('a')?.attr('href') || '',
|
||||
image:
|
||||
$(element).find('a').find('img').attr('data-lazy-src') ||
|
||||
$(element).find('a').find('img').attr('data-src') ||
|
||||
$(element).find('a').find('img').attr('src') ||
|
||||
'',
|
||||
};
|
||||
if (post.image.startsWith('//')) {
|
||||
post.image = 'https:' + post.image;
|
||||
}
|
||||
posts.push(post);
|
||||
});
|
||||
|
||||
// console.log(posts);
|
||||
return posts;
|
||||
} catch (error) {
|
||||
console.error('vegaGetPosts error:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
85
providers/mod/catalog.ts
Normal file
85
providers/mod/catalog.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
export const catalogList = [
|
||||
{
|
||||
title: 'Latest',
|
||||
filter: '',
|
||||
},
|
||||
{
|
||||
title: 'Netflix',
|
||||
filter: '/ott/netflix',
|
||||
},
|
||||
{
|
||||
title: 'HBO Max',
|
||||
filter: '/ott/hbo-max',
|
||||
},
|
||||
{
|
||||
title: 'Amazon Prime',
|
||||
filter: '/ott/amazon-prime-video',
|
||||
},
|
||||
];
|
||||
|
||||
export const modGenresList = [
|
||||
{
|
||||
title: 'Apple TV+',
|
||||
filter: '/ott/apple-tv',
|
||||
},
|
||||
{
|
||||
title: 'Disney+',
|
||||
filter: '/ott/disney-plus',
|
||||
},
|
||||
{
|
||||
title: 'Hulu',
|
||||
filter: '/ott/hulu',
|
||||
},
|
||||
{
|
||||
title: 'Crunchyroll',
|
||||
filter: '/ott/crunchyroll',
|
||||
},
|
||||
{
|
||||
title: 'Action',
|
||||
filter: '/movies-by-genre/action/',
|
||||
},
|
||||
{
|
||||
title: 'Adventure',
|
||||
filter: '/movies-by-genre/adventure/',
|
||||
},
|
||||
{
|
||||
title: 'Animation',
|
||||
filter: '/movies-by-genre/animated/',
|
||||
},
|
||||
{
|
||||
title: 'Comedy',
|
||||
filter: '/movies-by-genre/comedy/',
|
||||
},
|
||||
{
|
||||
title: 'Crime',
|
||||
filter: '/movies-by-genre/crime/',
|
||||
},
|
||||
{
|
||||
title: 'Documentary',
|
||||
filter: '/movies-by-genre/documentary/',
|
||||
},
|
||||
{
|
||||
title: 'Fantasy',
|
||||
filter: '/movies-by-genre/fantasy/',
|
||||
},
|
||||
{
|
||||
title: 'Horror',
|
||||
filter: '/movies-by-genre/horror/',
|
||||
},
|
||||
{
|
||||
title: 'Mystery',
|
||||
filter: '/movies-by-genre/mystery/',
|
||||
},
|
||||
{
|
||||
title: 'Romance',
|
||||
filter: '/movies-by-genre/romance/',
|
||||
},
|
||||
{
|
||||
title: 'Thriller',
|
||||
filter: '/movies-by-genre/thriller/',
|
||||
},
|
||||
{
|
||||
title: 'Sci-Fi',
|
||||
filter: '/movies-by-genre/sci-fi/',
|
||||
},
|
||||
];
|
||||
17
providers/mod/index.ts
Normal file
17
providers/mod/index.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import {modGenresList, catalogList} from './catalog';
|
||||
import {modGetInfo} from './modGetInfo';
|
||||
import {modGetEpisodeLinks} from './modGetEpisodesList';
|
||||
import {modGetPosts, modGetPostsSearch} from './modGetPosts';
|
||||
import {modGetStream} from './modGetStream';
|
||||
import {ProviderType} from '../types';
|
||||
|
||||
export const modMovies: ProviderType = {
|
||||
catalog: catalogList,
|
||||
genres: modGenresList,
|
||||
GetMetaData: modGetInfo,
|
||||
GetHomePosts: modGetPosts,
|
||||
GetStream: modGetStream,
|
||||
GetEpisodeLinks: modGetEpisodeLinks,
|
||||
// nonStreamableServer: ['Gdrive-Instant'],
|
||||
GetSearchPosts: modGetPostsSearch,
|
||||
};
|
||||
52
providers/mod/modGetEpisodesList.ts
Normal file
52
providers/mod/modGetEpisodesList.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import {EpisodeLink, ProviderContext} from '../types';
|
||||
|
||||
export const modGetEpisodeLinks = async function ({
|
||||
url,
|
||||
providerContext,
|
||||
}: {
|
||||
url: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<EpisodeLink[]> {
|
||||
const {axios, cheerio} = providerContext;
|
||||
try {
|
||||
if (url.includes('url=')) {
|
||||
url = atob(url.split('url=')[1]);
|
||||
}
|
||||
const res = await axios.get(url);
|
||||
const html = res.data;
|
||||
let $ = cheerio.load(html);
|
||||
if (url.includes('url=')) {
|
||||
const newUrl = $("meta[http-equiv='refresh']")
|
||||
.attr('content')
|
||||
?.split('url=')[1];
|
||||
const res2 = await axios.get(newUrl || url);
|
||||
const html2 = res2.data;
|
||||
$ = cheerio.load(html2);
|
||||
}
|
||||
const episodeLinks: EpisodeLink[] = [];
|
||||
$('h3,h4').map((i, element) => {
|
||||
const seriesTitle = $(element).text();
|
||||
const episodesLink = $(element).find('a').attr('href');
|
||||
if (episodesLink && episodesLink !== '#') {
|
||||
episodeLinks.push({
|
||||
title: seriesTitle.trim() || 'No title found',
|
||||
link: episodesLink || '',
|
||||
});
|
||||
}
|
||||
});
|
||||
$('a.maxbutton').map((i, element) => {
|
||||
const seriesTitle = $(element).children('span').text();
|
||||
const episodesLink = $(element).attr('href');
|
||||
if (episodesLink && episodesLink !== '#') {
|
||||
episodeLinks.push({
|
||||
title: seriesTitle.trim() || 'No title found',
|
||||
link: episodesLink || '',
|
||||
});
|
||||
}
|
||||
});
|
||||
return episodeLinks;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
71
providers/mod/modGetInfo.ts
Normal file
71
providers/mod/modGetInfo.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import {Info, Link, ProviderContext} from '../types';
|
||||
|
||||
export const modGetInfo = async function ({
|
||||
link,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Info> {
|
||||
try {
|
||||
const {axios, cheerio} = providerContext;
|
||||
const url = link;
|
||||
const res = await axios.get(url);
|
||||
const data = res.data;
|
||||
const $ = cheerio.load(data);
|
||||
const meta = {
|
||||
title: $('.imdbwp__title').text(),
|
||||
synopsis: $('.imdbwp__teaser').text(),
|
||||
image: $('.imdbwp__thumb').find('img').attr('src') || '',
|
||||
imdbId: $('.imdbwp__link').attr('href')?.split('/')[4] || '',
|
||||
type: $('.thecontent').text().toLocaleLowerCase().includes('season')
|
||||
? 'series'
|
||||
: 'movie',
|
||||
};
|
||||
const links: Link[] = [];
|
||||
|
||||
$('h3,h4').map((i, element) => {
|
||||
const seriesTitle = $(element).text();
|
||||
// const batchZipLink = $(element)
|
||||
// .next("p")
|
||||
// .find(".maxbutton-batch-zip,.maxbutton-zip-download")
|
||||
// .attr("href");
|
||||
const episodesLink = $(element)
|
||||
.next('p')
|
||||
.find(
|
||||
'.maxbutton-episode-links,.maxbutton-g-drive,.maxbutton-af-download',
|
||||
)
|
||||
.attr('href');
|
||||
const movieLink = $(element)
|
||||
.next('p')
|
||||
.find('.maxbutton-download-links')
|
||||
.attr('href');
|
||||
|
||||
if (
|
||||
movieLink ||
|
||||
(episodesLink && episodesLink !== 'javascript:void(0);')
|
||||
) {
|
||||
links.push({
|
||||
title: seriesTitle.replace('Download ', '').trim() || 'Download',
|
||||
episodesLink: episodesLink || '',
|
||||
directLinks: movieLink
|
||||
? [{link: movieLink, title: 'Movie', type: 'movie'}]
|
||||
: [],
|
||||
quality: seriesTitle?.match(/\d+p\b/)?.[0] || '',
|
||||
});
|
||||
}
|
||||
});
|
||||
// console.log('mod meta', links);
|
||||
return {...meta, linkList: links};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return {
|
||||
title: '',
|
||||
synopsis: '',
|
||||
image: '',
|
||||
imdbId: '',
|
||||
type: 'movie',
|
||||
linkList: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
74
providers/mod/modGetPosts.ts
Normal file
74
providers/mod/modGetPosts.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
export const modGetPosts = async function ({
|
||||
filter,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
filter: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl, axios, cheerio} = providerContext;
|
||||
const baseUrl = await getBaseUrl('Moviesmod');
|
||||
const url = `${baseUrl + filter}/page/${page}/`;
|
||||
return posts({url, signal, axios, cheerio});
|
||||
};
|
||||
|
||||
export const modGetPostsSearch = async function ({
|
||||
searchQuery,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl, axios, cheerio} = providerContext;
|
||||
const baseUrl = await getBaseUrl('Moviesmod');
|
||||
const url = `${baseUrl}/search/${searchQuery}/page/${page}/`;
|
||||
return posts({url, signal, axios, cheerio});
|
||||
};
|
||||
|
||||
async function posts({
|
||||
url,
|
||||
signal,
|
||||
axios,
|
||||
cheerio,
|
||||
}: {
|
||||
url: string;
|
||||
signal: AbortSignal;
|
||||
axios: ProviderContext['axios'];
|
||||
cheerio: ProviderContext['cheerio'];
|
||||
}): Promise<Post[]> {
|
||||
try {
|
||||
const res = await axios.get(url, {signal});
|
||||
const data = res.data;
|
||||
const $ = cheerio.load(data);
|
||||
const catalog: Post[] = [];
|
||||
$('.post-cards')
|
||||
.find('article')
|
||||
.map((i, element) => {
|
||||
const title = $(element).find('a').attr('title');
|
||||
const link = $(element).find('a').attr('href');
|
||||
const image = $(element).find('img').attr('src');
|
||||
if (title && link && image) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link: link,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('modGetPosts error ', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
288
providers/mod/modGetStream.ts
Normal file
288
providers/mod/modGetStream.ts
Normal file
@@ -0,0 +1,288 @@
|
||||
import {Stream, ProviderContext, EpisodeLink} from '../types';
|
||||
|
||||
const headers = {
|
||||
Accept:
|
||||
'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
||||
'Cache-Control': 'no-store',
|
||||
'Accept-Language': 'en-US,en;q=0.9',
|
||||
DNT: '1',
|
||||
'sec-ch-ua':
|
||||
'"Not_A Brand";v="8", "Chromium";v="120", "Microsoft Edge";v="120"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
'Sec-Fetch-Dest': 'document',
|
||||
'Sec-Fetch-Mode': 'navigate',
|
||||
Cookie: 'popads_user_id=6ba8fe60a481387a3249f05aa058822d',
|
||||
'Sec-Fetch-Site': 'none',
|
||||
'Sec-Fetch-User': '?1',
|
||||
'Upgrade-Insecure-Requests': '1',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0',
|
||||
};
|
||||
|
||||
export const modGetStream = async function ({
|
||||
link: url,
|
||||
type,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
type: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Stream[]> {
|
||||
const {axios, cheerio} = providerContext;
|
||||
try {
|
||||
const modGetEpisodeLinks = async function ({
|
||||
url,
|
||||
providerContext,
|
||||
}: {
|
||||
url: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<EpisodeLink[]> {
|
||||
const {axios, cheerio} = providerContext;
|
||||
try {
|
||||
if (url.includes('url=')) {
|
||||
url = atob(url.split('url=')[1]);
|
||||
}
|
||||
const res = await axios.get(url);
|
||||
const html = res.data;
|
||||
let $ = cheerio.load(html);
|
||||
if (url.includes('url=')) {
|
||||
const newUrl = $("meta[http-equiv='refresh']")
|
||||
.attr('content')
|
||||
?.split('url=')[1];
|
||||
const res2 = await axios.get(newUrl || url);
|
||||
const html2 = res2.data;
|
||||
$ = cheerio.load(html2);
|
||||
}
|
||||
const episodeLinks: EpisodeLink[] = [];
|
||||
$('h3,h4').map((i, element) => {
|
||||
const seriesTitle = $(element).text();
|
||||
const episodesLink = $(element).find('a').attr('href');
|
||||
if (episodesLink && episodesLink !== '#') {
|
||||
episodeLinks.push({
|
||||
title: seriesTitle.trim() || 'No title found',
|
||||
link: episodesLink || '',
|
||||
});
|
||||
}
|
||||
});
|
||||
$('a.maxbutton').map((i, element) => {
|
||||
const seriesTitle = $(element).children('span').text();
|
||||
const episodesLink = $(element).attr('href');
|
||||
if (episodesLink && episodesLink !== '#') {
|
||||
episodeLinks.push({
|
||||
title: seriesTitle.trim() || 'No title found',
|
||||
link: episodesLink || '',
|
||||
});
|
||||
}
|
||||
});
|
||||
return episodeLinks;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
console.log('modGetStream', type, url);
|
||||
if (type === 'movie') {
|
||||
const servers = await modGetEpisodeLinks({url, providerContext});
|
||||
url = servers[0].link || url;
|
||||
}
|
||||
|
||||
let downloadLink = await modExtractor(url, providerContext);
|
||||
|
||||
// console.log(downloadLink.data);
|
||||
|
||||
const ddl = downloadLink?.data?.match(/content="0;url=(.*?)"/)?.[1] || url;
|
||||
// console.log('ddl', url);
|
||||
|
||||
// console.log(ddl);
|
||||
// console.log(ddl);
|
||||
const servers: Stream[] = [];
|
||||
const driveLink = await isDriveLink(ddl);
|
||||
const driveRes = await axios.get(driveLink, {headers});
|
||||
const driveHtml = driveRes.data;
|
||||
const $drive = cheerio.load(driveHtml);
|
||||
|
||||
try {
|
||||
const resumeBot = $drive('.btn.btn-light').attr('href') || '';
|
||||
const resumeBotRes = await axios.get(resumeBot, {headers});
|
||||
const resumeBotToken = resumeBotRes.data.match(
|
||||
/formData\.append\('token', '([a-f0-9]+)'\)/,
|
||||
)[1];
|
||||
const resumeBotBody = new FormData();
|
||||
resumeBotBody.append('token', resumeBotToken);
|
||||
const resumeBotPath = resumeBotRes.data.match(
|
||||
/fetch\('\/download\?id=([a-zA-Z0-9\/+]+)'/,
|
||||
)[1];
|
||||
const resumeBotBaseUrl = resumeBot.split('/download')[0];
|
||||
// console.log(
|
||||
// 'resumeBotPath',
|
||||
// resumeBotBaseUrl + '/download?id=' + resumeBotPath,
|
||||
// );
|
||||
// console.log('resumeBotBody', resumeBotToken);
|
||||
|
||||
const resumeBotDownload = await fetch(
|
||||
resumeBotBaseUrl + '/download?id=' + resumeBotPath,
|
||||
{
|
||||
method: 'POST',
|
||||
body: resumeBotBody,
|
||||
headers: {
|
||||
Referer: resumeBot,
|
||||
Cookie: 'PHPSESSID=7e9658ce7c805dab5bbcea9046f7f308',
|
||||
},
|
||||
},
|
||||
);
|
||||
const resumeBotDownloadData = await resumeBotDownload.json();
|
||||
console.log('resumeBotDownloadData', resumeBotDownloadData.url);
|
||||
servers.push({
|
||||
server: 'ResumeBot',
|
||||
link: resumeBotDownloadData.url,
|
||||
type: 'mkv',
|
||||
});
|
||||
} catch (err) {
|
||||
console.log('ResumeBot link not found', err);
|
||||
}
|
||||
// CF workers type 1
|
||||
try {
|
||||
const cfWorkersLink = driveLink.replace('/file', '/wfile') + '?type=1';
|
||||
const cfWorkersRes = await axios.get(cfWorkersLink, {headers});
|
||||
const cfWorkersHtml = cfWorkersRes.data;
|
||||
const $cfWorkers = cheerio.load(cfWorkersHtml);
|
||||
const cfWorkersStream = $cfWorkers('.btn-success');
|
||||
cfWorkersStream.each((i, el) => {
|
||||
const link = el.attribs.href;
|
||||
if (link) {
|
||||
servers.push({
|
||||
server: 'Cf Worker 1.' + i,
|
||||
link: link,
|
||||
type: 'mkv',
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.log('CF workers link not found', err);
|
||||
}
|
||||
|
||||
// CF workers type 2
|
||||
try {
|
||||
const cfWorkersLink = driveLink.replace('/file', '/wfile') + '?type=2';
|
||||
const cfWorkersRes = await axios.get(cfWorkersLink, {headers});
|
||||
const cfWorkersHtml = cfWorkersRes.data;
|
||||
const $cfWorkers = cheerio.load(cfWorkersHtml);
|
||||
const cfWorkersStream = $cfWorkers('.btn-success');
|
||||
cfWorkersStream.each((i, el) => {
|
||||
const link = el.attribs.href;
|
||||
if (link) {
|
||||
servers.push({
|
||||
server: 'Cf Worker 2.' + i,
|
||||
link: link,
|
||||
type: 'mkv',
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.log('CF workers link not found', err);
|
||||
}
|
||||
|
||||
// gdrive
|
||||
|
||||
//instant link
|
||||
try {
|
||||
const seed = $drive('.btn-danger').attr('href') || '';
|
||||
const instantToken = seed.split('=')[1];
|
||||
// console.log('InstantToken', instantToken);
|
||||
const InstantFromData = new FormData();
|
||||
InstantFromData.append('keys', instantToken);
|
||||
const videoSeedUrl = seed.split('/').slice(0, 3).join('/') + '/api';
|
||||
// console.log('videoSeedUrl', videoSeedUrl);
|
||||
const instantLinkRes = await fetch(videoSeedUrl, {
|
||||
method: 'POST',
|
||||
body: InstantFromData,
|
||||
headers: {
|
||||
'x-token': videoSeedUrl,
|
||||
},
|
||||
});
|
||||
const instantLinkData = await instantLinkRes.json();
|
||||
// console.log('instantLinkData', instantLinkData);
|
||||
if (instantLinkData.error === false) {
|
||||
const instantLink = instantLinkData.url;
|
||||
servers.push({
|
||||
server: 'Gdrive-Instant',
|
||||
link: instantLink,
|
||||
type: 'mkv',
|
||||
});
|
||||
} else {
|
||||
console.log('Instant link not found', instantLinkData);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Instant link not found', err);
|
||||
}
|
||||
return servers;
|
||||
} catch (err) {
|
||||
console.log('getStream error', err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const isDriveLink = async (ddl: string) => {
|
||||
if (ddl.includes('drive')) {
|
||||
const driveLeach = await fetch(ddl);
|
||||
const driveLeachData = await driveLeach.text();
|
||||
const pathMatch = driveLeachData.match(
|
||||
/window\.location\.replace\("([^"]+)"\)/,
|
||||
);
|
||||
const path = pathMatch?.[1];
|
||||
const mainUrl = ddl.split('/')[2];
|
||||
console.log(`driveUrl = https://${mainUrl}${path}`);
|
||||
return `https://${mainUrl}${path}`;
|
||||
} else {
|
||||
return ddl;
|
||||
}
|
||||
};
|
||||
|
||||
async function modExtractor(url: string, providerContext: ProviderContext) {
|
||||
const {axios, cheerio} = providerContext;
|
||||
try {
|
||||
const wpHttp = url.split('sid=')[1];
|
||||
var bodyFormData0 = new FormData();
|
||||
bodyFormData0.append('_wp_http', wpHttp);
|
||||
const res = await fetch(url.split('?')[0], {
|
||||
method: 'POST',
|
||||
body: bodyFormData0,
|
||||
});
|
||||
const data = await res.text();
|
||||
// console.log('', data);
|
||||
const html = data;
|
||||
const $ = cheerio.load(html);
|
||||
|
||||
// find input with name="_wp_http2"
|
||||
const wpHttp2 = $('input').attr('name', '_wp_http2').val();
|
||||
|
||||
// console.log('wpHttp2', wpHttp2);
|
||||
|
||||
// form data
|
||||
var bodyFormData = new FormData();
|
||||
bodyFormData.append('_wp_http2', wpHttp2);
|
||||
const formUrl1 = $('form').attr('action');
|
||||
const formUrl = formUrl1 || url.split('?')[0];
|
||||
|
||||
const res2 = await fetch(formUrl, {
|
||||
method: 'POST',
|
||||
body: bodyFormData,
|
||||
});
|
||||
const html2: any = await res2.text();
|
||||
const link = html2.match(/setAttribute\("href",\s*"(.*?)"/)[1];
|
||||
console.log(link);
|
||||
const cookie = link.split('=')[1];
|
||||
console.log('cookie', cookie);
|
||||
|
||||
const downloadLink = await axios.get(link, {
|
||||
headers: {
|
||||
Referer: formUrl,
|
||||
Cookie: `${cookie}=${wpHttp2}`,
|
||||
},
|
||||
});
|
||||
return downloadLink;
|
||||
} catch (err) {
|
||||
console.log('modGetStream error', err);
|
||||
}
|
||||
}
|
||||
14
providers/moviesApi/index.ts
Normal file
14
providers/moviesApi/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {allCatalog, allGenresList} from '../autoEmbed/allCatalog';
|
||||
import {allGetInfo} from '../autoEmbed/allGetInfo';
|
||||
import {allGetPost, allGetSearchPosts} from '../autoEmbed/allGetPost';
|
||||
import {ProviderType} from '../types';
|
||||
import {mpGetStream} from './mpGetStream';
|
||||
|
||||
export const moviesApi: ProviderType = {
|
||||
catalog: allCatalog,
|
||||
genres: allGenresList,
|
||||
GetMetaData: allGetInfo,
|
||||
GetHomePosts: allGetPost,
|
||||
GetStream: mpGetStream,
|
||||
GetSearchPosts: allGetSearchPosts,
|
||||
};
|
||||
100
providers/moviesApi/mpGetStream.ts
Normal file
100
providers/moviesApi/mpGetStream.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import {Stream, ProviderContext, TextTrackType, TextTracks} from '../types';
|
||||
|
||||
export const mpGetStream = async function ({
|
||||
link: id,
|
||||
type,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
type: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Stream[]> {
|
||||
try {
|
||||
const {getBaseUrl, cheerio} = providerContext;
|
||||
const streams: Stream[] = [];
|
||||
const {season, episode, tmdbId} = JSON.parse(id);
|
||||
const baseUrl = await getBaseUrl('moviesapi');
|
||||
const link =
|
||||
type === 'movie'
|
||||
? `${baseUrl}/movie/${tmdbId}`
|
||||
: `${baseUrl}/tv/${tmdbId}-${season}-${episode}`;
|
||||
const res = await fetch(link, {
|
||||
headers: {
|
||||
referer: baseUrl,
|
||||
},
|
||||
});
|
||||
const baseData = await res.text();
|
||||
const $ = cheerio.load(baseData);
|
||||
const embededUrl = $('iframe').attr('src') || '';
|
||||
const response = await fetch(embededUrl, {
|
||||
credentials: 'omit',
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0',
|
||||
Accept:
|
||||
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
|
||||
'Accept-Language': 'en-US,en;q=0.5',
|
||||
'Alt-Used': 'w1.moviesapi.club',
|
||||
'Upgrade-Insecure-Requests': '1',
|
||||
'Sec-Fetch-Dest': 'document',
|
||||
'Sec-Fetch-Mode': 'navigate',
|
||||
'Sec-Fetch-Site': 'none',
|
||||
'Sec-Fetch-User': '?1',
|
||||
Pragma: 'no-cache',
|
||||
'Cache-Control': 'no-cache',
|
||||
referer: baseUrl,
|
||||
},
|
||||
referrer: baseUrl,
|
||||
method: 'GET',
|
||||
mode: 'cors',
|
||||
});
|
||||
const data2 = await response.text();
|
||||
|
||||
// Extract the encrypted content
|
||||
const contents =
|
||||
data2.match(/const\s+Encrypted\s*=\s*['"]({.*})['"]/)?.[1] || '';
|
||||
if (embededUrl) {
|
||||
const res2 = await fetch(
|
||||
'https://ext.8man.me/api/decrypt?passphrase==JV[t}{trEV=Ilh5',
|
||||
{
|
||||
method: 'POST',
|
||||
body: contents,
|
||||
},
|
||||
);
|
||||
const finalData = await res2.json();
|
||||
const subtitle: TextTracks = finalData?.subtitles?.map((sub: any) => ({
|
||||
title: sub?.label || 'Unknown',
|
||||
language: sub?.label as string,
|
||||
type: sub?.file?.includes('.vtt')
|
||||
? TextTrackType.VTT
|
||||
: TextTrackType.SUBRIP,
|
||||
uri: sub?.file,
|
||||
}));
|
||||
|
||||
streams.push({
|
||||
server: 'vidstreaming ',
|
||||
type: 'm3u8',
|
||||
subtitles: subtitle,
|
||||
link: finalData?.videoUrl,
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0',
|
||||
Referer: baseUrl,
|
||||
Origin: baseUrl,
|
||||
Accept: '*/*',
|
||||
'Accept-Language': 'en-US,en;q=0.5',
|
||||
'Sec-Fetch-Dest': 'empty',
|
||||
'Sec-Fetch-Mode': 'cors',
|
||||
'Sec-Fetch-Site': 'cross-site',
|
||||
Pragma: 'no-cache',
|
||||
'Cache-Control': 'no-cache',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return streams;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
14
providers/multi/index.ts
Normal file
14
providers/multi/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {multiGenresList, multiCatalog} from './multiCatalog';
|
||||
import {multiGetInfo} from './multiGetInfo';
|
||||
import {multiGetPosts, multiGetPostsSearch} from './multiPosts';
|
||||
import {multiGetStream} from './multiGetStream';
|
||||
import {ProviderType} from '../types';
|
||||
|
||||
export const multiMovies: ProviderType = {
|
||||
catalog: multiCatalog,
|
||||
genres: multiGenresList,
|
||||
GetMetaData: multiGetInfo,
|
||||
GetHomePosts: multiGetPosts,
|
||||
GetStream: multiGetStream,
|
||||
GetSearchPosts: multiGetPostsSearch,
|
||||
};
|
||||
77
providers/multi/multiCatalog.ts
Normal file
77
providers/multi/multiCatalog.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
export const multiCatalog = [
|
||||
{
|
||||
title: 'Trending',
|
||||
filter: '/trending/',
|
||||
},
|
||||
{
|
||||
title: 'Netflix',
|
||||
filter: '/genre/netflix/',
|
||||
},
|
||||
{
|
||||
title: 'Amazon Prime',
|
||||
filter: '/genre/amazon-prime/',
|
||||
},
|
||||
{
|
||||
title: 'Disney Hotstar',
|
||||
filter: '/genre/disney-hotstar/',
|
||||
},
|
||||
];
|
||||
|
||||
export const multiGenresList = [
|
||||
{
|
||||
title: 'Action',
|
||||
filter: '/genre/action/',
|
||||
},
|
||||
{
|
||||
title: 'Adventure',
|
||||
filter: '/genre/adventure/',
|
||||
},
|
||||
{
|
||||
title: 'Animation',
|
||||
filter: '/genre/animation/',
|
||||
},
|
||||
{
|
||||
title: 'Comedy',
|
||||
filter: '/genre/comedy/',
|
||||
},
|
||||
{
|
||||
title: 'Crime',
|
||||
filter: '/genre/crime/',
|
||||
},
|
||||
{
|
||||
title: 'Drama',
|
||||
filter: '/genre/drama/',
|
||||
},
|
||||
{
|
||||
title: 'Family',
|
||||
filter: '/genre/family/',
|
||||
},
|
||||
{
|
||||
title: 'Fantasy',
|
||||
filter: '/genre/fantasy/',
|
||||
},
|
||||
{
|
||||
title: 'History',
|
||||
filter: '/genre/history/',
|
||||
},
|
||||
{
|
||||
title: 'Horror',
|
||||
filter: '/genre/horror/',
|
||||
},
|
||||
{
|
||||
title: 'Mystery',
|
||||
filter: '/genre/mystery/',
|
||||
},
|
||||
{
|
||||
title: 'Romance',
|
||||
filter: '/genre/romance/',
|
||||
},
|
||||
{
|
||||
title: 'Science Fiction',
|
||||
filter: '/genre/science-fiction/',
|
||||
},
|
||||
{
|
||||
title: 'Thriller',
|
||||
filter: '/genre/thriller/',
|
||||
},
|
||||
];
|
||||
82
providers/multi/multiGetInfo.ts
Normal file
82
providers/multi/multiGetInfo.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import {Info, Link, ProviderContext} from '../types';
|
||||
|
||||
export const multiGetInfo = async function ({
|
||||
link,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Info> {
|
||||
try {
|
||||
const {axios, cheerio} = providerContext;
|
||||
const url = link;
|
||||
const res = await axios.get(url);
|
||||
const data = res.data;
|
||||
const $ = cheerio.load(data);
|
||||
const type = url.includes('tvshows') ? 'series' : 'movie';
|
||||
const imdbId = '';
|
||||
const title = url.split('/')[4].replace(/-/g, ' ');
|
||||
const image = $('.g-item').find('a').attr('href') || '';
|
||||
const synopsis = $('.wp-content').find('p').text() || '';
|
||||
|
||||
// Links
|
||||
const links: Link[] = [];
|
||||
|
||||
if (type === 'series') {
|
||||
$('#seasons')
|
||||
.children()
|
||||
.map((i, element) => {
|
||||
const title = $(element)
|
||||
.find('.title')
|
||||
.children()
|
||||
.remove()
|
||||
.end()
|
||||
.text();
|
||||
let episodesList: {title: string; link: string}[] = [];
|
||||
$(element)
|
||||
.find('.episodios')
|
||||
.children()
|
||||
.map((i, element) => {
|
||||
const title =
|
||||
'Episode' +
|
||||
$(element).find('.numerando').text().trim().split('-')[1];
|
||||
const link = $(element).find('a').attr('href');
|
||||
if (title && link) {
|
||||
episodesList.push({title, link});
|
||||
}
|
||||
});
|
||||
if (title && episodesList.length > 0) {
|
||||
links.push({
|
||||
title,
|
||||
directLinks: episodesList,
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
links.push({
|
||||
title: title,
|
||||
directLinks: [{title: title, link: url.slice(0, -1), type: 'movie'}],
|
||||
});
|
||||
}
|
||||
// console.log('multi meta', links);
|
||||
|
||||
return {
|
||||
title,
|
||||
synopsis,
|
||||
image,
|
||||
imdbId,
|
||||
type,
|
||||
linkList: links,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return {
|
||||
title: '',
|
||||
synopsis: '',
|
||||
image: '',
|
||||
imdbId: '',
|
||||
type: 'movie',
|
||||
linkList: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
157
providers/multi/multiGetStream.ts
Normal file
157
providers/multi/multiGetStream.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import {Stream, ProviderContext, TextTracks, TextTrackType} from '../types';
|
||||
|
||||
export const multiGetStream = async function ({
|
||||
link: url,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
type: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Stream[]> {
|
||||
const {axios, cheerio} = providerContext;
|
||||
const headers = {
|
||||
'sec-ch-ua':
|
||||
'"Not_A Brand";v="8", "Chromium";v="120", "Microsoft Edge";v="120"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
Referer: 'https://multimovies.online/',
|
||||
'Sec-Fetch-User': '?1',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0',
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await axios.get(url, {headers});
|
||||
const html = res.data;
|
||||
const $ = cheerio.load(html);
|
||||
const streamLinks: Stream[] = [];
|
||||
const postId = $('#player-option-1').attr('data-post');
|
||||
const nume = $('#player-option-1').attr('data-nume');
|
||||
const typeValue = $('#player-option-1').attr('data-type');
|
||||
|
||||
const baseUrl = url.split('/').slice(0, 3).join('/');
|
||||
console.log('baseUrl', baseUrl);
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('action', 'doo_player_ajax');
|
||||
formData.append('post', postId);
|
||||
formData.append('nume', nume);
|
||||
formData.append('type', typeValue);
|
||||
|
||||
console.log('formData', formData);
|
||||
|
||||
const playerRes = await fetch(`${baseUrl}/wp-admin/admin-ajax.php`, {
|
||||
headers: headers,
|
||||
body: formData,
|
||||
method: 'POST',
|
||||
});
|
||||
const playerData = await playerRes.json();
|
||||
console.log('playerData', playerData);
|
||||
let ifameUrl =
|
||||
playerData?.embed_url?.match(/<iframe[^>]+src="([^"]+)"[^>]*>/i)?.[1] ||
|
||||
playerData?.embed_url;
|
||||
console.log('ifameUrl', ifameUrl);
|
||||
if (!ifameUrl.includes('multimovies')) {
|
||||
let playerBaseUrl = ifameUrl.split('/').slice(0, 3).join('/');
|
||||
const newPlayerBaseUrl = await axios.head(playerBaseUrl, {headers});
|
||||
if (newPlayerBaseUrl) {
|
||||
playerBaseUrl = newPlayerBaseUrl.request?.responseURL
|
||||
?.split('/')
|
||||
.slice(0, 3)
|
||||
.join('/');
|
||||
}
|
||||
const playerId = ifameUrl.split('/').pop();
|
||||
const NewformData = new FormData();
|
||||
NewformData.append('sid', playerId);
|
||||
console.log(
|
||||
'NewformData',
|
||||
playerBaseUrl + '/embedhelper.php',
|
||||
NewformData,
|
||||
);
|
||||
const playerRes = await fetch(`${playerBaseUrl}/embedhelper.php`, {
|
||||
headers: headers,
|
||||
body: NewformData,
|
||||
method: 'POST',
|
||||
});
|
||||
const playerData = await playerRes.json();
|
||||
// console.log('playerData', playerData);
|
||||
const siteUrl = playerData?.siteUrls?.smwh;
|
||||
const siteId =
|
||||
JSON.parse(atob(playerData?.mresult))?.smwh ||
|
||||
playerData?.mresult?.smwh;
|
||||
const newIframeUrl = siteUrl + siteId;
|
||||
console.log('newIframeUrl', newIframeUrl);
|
||||
if (newIframeUrl) {
|
||||
ifameUrl = newIframeUrl;
|
||||
}
|
||||
}
|
||||
const iframeRes = await axios.get(ifameUrl, {
|
||||
headers: {
|
||||
...headers,
|
||||
Referer: url,
|
||||
},
|
||||
});
|
||||
const iframeData = iframeRes.data;
|
||||
|
||||
// Step 1: Extract the function parameters and the encoded string
|
||||
var functionRegex =
|
||||
/eval\(function\((.*?)\)\{.*?return p\}.*?\('(.*?)'\.split/;
|
||||
var match = functionRegex.exec(iframeData);
|
||||
let p = '';
|
||||
if (match) {
|
||||
// var params = match[1].split(',').map(param => param.trim());
|
||||
var encodedString = match[2];
|
||||
|
||||
// console.log('Parameters:', params);
|
||||
// console.log('Encoded String:', encodedString.split("',36,")[0], '🔥🔥');
|
||||
|
||||
p = encodedString.split("',36,")?.[0].trim();
|
||||
let a = 36;
|
||||
let c = encodedString.split("',36,")[1].slice(2).split('|').length;
|
||||
let k = encodedString.split("',36,")[1].slice(2).split('|');
|
||||
|
||||
while (c--) {
|
||||
if (k[c]) {
|
||||
var regex = new RegExp('\\b' + c.toString(a) + '\\b', 'g');
|
||||
p = p.replace(regex, k[c]);
|
||||
}
|
||||
}
|
||||
|
||||
// console.log('Decoded String:', p);
|
||||
} else {
|
||||
console.log('No match found');
|
||||
}
|
||||
|
||||
const streamUrl = p?.match(/https?:\/\/[^"]+?\.m3u8[^"]*/)?.[0];
|
||||
const subtitles: TextTracks = [];
|
||||
const subtitleMatch = p?.match(/https:\/\/[^\s"]+\.vtt/g);
|
||||
// console.log('subtitleMatch', subtitleMatch);
|
||||
// console.log('streamUrl', streamUrl);
|
||||
if (subtitleMatch?.length) {
|
||||
subtitleMatch.forEach((sub: any) => {
|
||||
const lang = sub.match(/_([a-zA-Z]{3})\.vtt$/)[1];
|
||||
subtitles.push({
|
||||
language: lang,
|
||||
uri: sub,
|
||||
type: TextTrackType.VTT,
|
||||
title: lang,
|
||||
});
|
||||
});
|
||||
}
|
||||
console.log('streamUrl', streamUrl);
|
||||
console.log('newUrl', streamUrl?.replace(/&i=\d+,'\.4&/, '&i=0.4&'));
|
||||
if (streamUrl) {
|
||||
streamLinks.push({
|
||||
server: 'Multi',
|
||||
link: streamUrl.replace(/&i=\d+,'\.4&/, '&i=0.4&'),
|
||||
type: 'm3u8',
|
||||
subtitles: subtitles,
|
||||
});
|
||||
}
|
||||
|
||||
return streamLinks;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
74
providers/multi/multiPosts.ts
Normal file
74
providers/multi/multiPosts.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
export const multiGetPosts = async function ({
|
||||
filter,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
filter: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl, cheerio} = providerContext;
|
||||
const baseUrl = await getBaseUrl('multi');
|
||||
const url = `${baseUrl + filter}page/${page}/`;
|
||||
return posts({url, signal, cheerio});
|
||||
};
|
||||
|
||||
export const multiGetPostsSearch = async function ({
|
||||
searchQuery,
|
||||
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl, cheerio} = providerContext;
|
||||
const baseUrl = await getBaseUrl('multi');
|
||||
const url = `${baseUrl}/?s=${searchQuery}`;
|
||||
return posts({url, signal, cheerio});
|
||||
};
|
||||
|
||||
async function posts({
|
||||
url,
|
||||
signal,
|
||||
cheerio,
|
||||
}: {
|
||||
url: string;
|
||||
signal: AbortSignal;
|
||||
cheerio: ProviderContext['cheerio'];
|
||||
}): Promise<Post[]> {
|
||||
try {
|
||||
const res = await fetch(url, {signal});
|
||||
const data = await res.text();
|
||||
const $ = cheerio.load(data);
|
||||
const catalog: Post[] = [];
|
||||
$('.items.full')
|
||||
.children()
|
||||
.map((i, element) => {
|
||||
const title = $(element).find('.poster').find('img').attr('alt');
|
||||
const link = $(element).find('.poster').find('a').attr('href');
|
||||
const image =
|
||||
$(element).find('.poster').find('img').attr('data-src') ||
|
||||
$(element).find('.poster').find('img').attr('src');
|
||||
if (title && link && image) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link: link,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('multiGetPosts error ', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
16
providers/netflixMirror/index.ts
Normal file
16
providers/netflixMirror/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import {nfCatalog, nfGenresList} from './nfCatalog';
|
||||
import {nfGetInfo} from './nfGetInfo';
|
||||
import {nfGetPost, nfGetPostsSearch} from './nfGetPost';
|
||||
import {nfGetEpisodes} from './nfGetEpisodes';
|
||||
import {nfGetStream} from './nfGetSteam';
|
||||
import {ProviderType} from '../types';
|
||||
|
||||
export const netflixMirror: ProviderType = {
|
||||
catalog: nfCatalog,
|
||||
genres: nfGenresList,
|
||||
GetMetaData: nfGetInfo,
|
||||
GetHomePosts: nfGetPost,
|
||||
GetStream: nfGetStream,
|
||||
GetEpisodeLinks: nfGetEpisodes,
|
||||
GetSearchPosts: nfGetPostsSearch,
|
||||
};
|
||||
16
providers/netflixMirror/nfCatalog.ts
Normal file
16
providers/netflixMirror/nfCatalog.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export const nfCatalog = [
|
||||
{
|
||||
title: 'Home',
|
||||
filter: '/mobile/home?app=1',
|
||||
},
|
||||
{
|
||||
title: 'Series',
|
||||
filter: '/mobile/series',
|
||||
},
|
||||
{
|
||||
title: 'Movies',
|
||||
filter: '/mobile/movies',
|
||||
},
|
||||
];
|
||||
|
||||
export const nfGenresList = [];
|
||||
49
providers/netflixMirror/nfGetEpisodes.ts
Normal file
49
providers/netflixMirror/nfGetEpisodes.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import {EpisodeLink, ProviderContext} from '../types';
|
||||
|
||||
export const nfGetEpisodes = async function ({
|
||||
url: link,
|
||||
providerContext,
|
||||
}: {
|
||||
url: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<EpisodeLink[]> {
|
||||
const {getBaseUrl, axios} = providerContext;
|
||||
let providerValue = 'netflixMirror';
|
||||
try {
|
||||
const baseUrl = await getBaseUrl('nfMirror');
|
||||
const url =
|
||||
`${baseUrl}${
|
||||
providerValue === 'netflixMirror'
|
||||
? '/episodes.php?s='
|
||||
: '/pv/episodes.php?s='
|
||||
}` +
|
||||
link +
|
||||
'&t=' +
|
||||
Math.round(new Date().getTime() / 1000);
|
||||
console.log('nfEpisodesUrl', url);
|
||||
const res = await axios.get(url, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36',
|
||||
'Accept-Language': 'en-US,en;q=0.9',
|
||||
},
|
||||
});
|
||||
const data = res.data;
|
||||
console.log('nfEpisodes', data);
|
||||
|
||||
const episodeList: EpisodeLink[] = [];
|
||||
|
||||
data?.episodes?.map((episode: any) => {
|
||||
episodeList.push({
|
||||
title: 'Episode ' + episode?.ep.replace('E', ''),
|
||||
link: episode?.id,
|
||||
});
|
||||
});
|
||||
|
||||
return episodeList;
|
||||
} catch (err) {
|
||||
console.error('nfGetEpisodes error', err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
63
providers/netflixMirror/nfGetInfo.ts
Normal file
63
providers/netflixMirror/nfGetInfo.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import {Info, Link} from '../types';
|
||||
|
||||
export const nfGetInfo = async function ({
|
||||
link,
|
||||
}: {
|
||||
link: string;
|
||||
}): Promise<Info> {
|
||||
let providerValue = 'netflixMirror';
|
||||
try {
|
||||
const isPrime =
|
||||
providerValue === 'primeMirror' ? 'isPrime=true' : 'isPrime=false';
|
||||
const url = `https://netmirror.8man.me/api/net-proxy?${isPrime}&url=${encodeURIComponent(
|
||||
link,
|
||||
)}`;
|
||||
console.log('nfifo', url);
|
||||
const res = await fetch(url, {
|
||||
credentials: 'omit',
|
||||
});
|
||||
const data = await res.json();
|
||||
const id = link.split('id=')[1]?.split('&')[0];
|
||||
const meta = {
|
||||
title: data.title,
|
||||
synopsis: data.desc,
|
||||
image: `https://img.nfmirrorcdn.top/poster/h/${id}.jpg`,
|
||||
cast: data?.short_cast?.split(','),
|
||||
tags: [data?.year, data?.hdsd, ...data?.thismovieis?.split(',')],
|
||||
imdbId: '',
|
||||
type: 'series',
|
||||
};
|
||||
console.log('nfinfo', meta);
|
||||
|
||||
const linkList: Link[] = [];
|
||||
if (data?.season?.length > 0) {
|
||||
data.season.map((season: any) => {
|
||||
linkList.push({
|
||||
title: 'Season ' + season?.s,
|
||||
episodesLink: season?.id,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
linkList.push({
|
||||
title: meta.title,
|
||||
directLinks: [{link: id, title: 'Movie', type: 'movie'}],
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
...meta,
|
||||
|
||||
linkList: linkList,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return {
|
||||
title: '',
|
||||
synopsis: '',
|
||||
image: '',
|
||||
imdbId: '',
|
||||
type: '',
|
||||
linkList: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
135
providers/netflixMirror/nfGetPost.ts
Normal file
135
providers/netflixMirror/nfGetPost.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
export const nfGetPost = async function ({
|
||||
filter,
|
||||
page,
|
||||
providerValue,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
filter: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
try {
|
||||
const {getBaseUrl, cheerio} = providerContext;
|
||||
const baseUrl = await getBaseUrl('nfMirror');
|
||||
const catalog: Post[] = [];
|
||||
if (page > 1) {
|
||||
return [];
|
||||
}
|
||||
// console.log(filter);
|
||||
const isPrime =
|
||||
providerValue === 'primeMirror' ? 'isPrime=true' : 'isPrime=false';
|
||||
|
||||
const url = `https://netmirror.8man.me/api/net-proxy?${isPrime}&url=${
|
||||
baseUrl + filter
|
||||
}`;
|
||||
|
||||
const res = await fetch(url, {
|
||||
signal: signal,
|
||||
method: 'GET',
|
||||
credentials: 'omit',
|
||||
});
|
||||
const data = await res.text();
|
||||
// console.log('nfPost', data);
|
||||
const $ = cheerio.load(data);
|
||||
$('a.post-data').map((i, element) => {
|
||||
const title = '';
|
||||
const id = $(element).attr('data-post');
|
||||
// console.log('id', id);
|
||||
const image = $(element).find('img').attr('data-src') || '';
|
||||
if (id) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link:
|
||||
baseUrl +
|
||||
`${
|
||||
providerValue === 'netflixMirror'
|
||||
? '/post.php?id='
|
||||
: '/pv/post.php?id='
|
||||
}` +
|
||||
id +
|
||||
'&t=' +
|
||||
Math.round(new Date().getTime() / 1000),
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
// console.log(catalog);
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('nf error ', err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export const nfGetPostsSearch = async function ({
|
||||
searchQuery,
|
||||
page,
|
||||
providerValue,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl} = providerContext;
|
||||
try {
|
||||
if (page > 1) {
|
||||
return [];
|
||||
}
|
||||
const catalog: Post[] = [];
|
||||
const baseUrl = await getBaseUrl('nfMirror');
|
||||
const isPrime =
|
||||
providerValue === 'primeMirror' ? 'isPrime=true' : 'isPrime=false';
|
||||
|
||||
const url = `https://netmirror.8man.me/api/net-proxy?${isPrime}&url=${baseUrl}${
|
||||
providerValue === 'netflixMirror' ? '' : '/pv'
|
||||
}/search.php?s=${encodeURI(searchQuery)}`;
|
||||
|
||||
const res = await fetch(url, {
|
||||
signal: signal,
|
||||
method: 'GET',
|
||||
credentials: 'omit',
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
data?.searchResult?.forEach((result: any) => {
|
||||
const title = result?.t || '';
|
||||
const id = result?.id;
|
||||
const image =
|
||||
providerValue === 'netflixMirror'
|
||||
? `https://imgcdn.media/poster/v/${id}.jpg`
|
||||
: '';
|
||||
|
||||
if (id) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link:
|
||||
baseUrl +
|
||||
`${
|
||||
providerValue === 'netflixMirror'
|
||||
? '/mobile/post.php?id='
|
||||
: '/mobile/pv/post.php?id='
|
||||
}` +
|
||||
id +
|
||||
'&t=' +
|
||||
Math.round(new Date().getTime() / 1000),
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('Search error:', err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
44
providers/netflixMirror/nfGetSteam.ts
Normal file
44
providers/netflixMirror/nfGetSteam.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import {ProviderContext, Stream} from '../types';
|
||||
|
||||
export const nfGetStream = async ({
|
||||
link: id,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Stream[]> => {
|
||||
const {getBaseUrl} = providerContext;
|
||||
try {
|
||||
let providerValue = 'netflixMirror';
|
||||
const baseUrl = await getBaseUrl('nfMirror');
|
||||
const url = `https://netmirror.8man.me/api/net-proxy?url=${baseUrl}${
|
||||
providerValue === 'netflixMirror'
|
||||
? '/mobile/playlist.php?id='
|
||||
: '/pv/playlist.php?id='
|
||||
}${id}&t=${Math.round(new Date().getTime() / 1000)}`;
|
||||
console.log('nfGetStream, url:', url);
|
||||
const res = await fetch(url, {
|
||||
credentials: 'omit',
|
||||
});
|
||||
const resJson = await res.json();
|
||||
const data = resJson?.[0];
|
||||
const streamLinks: Stream[] = [];
|
||||
data?.sources.forEach((source: any) => {
|
||||
streamLinks.push({
|
||||
server: source.label,
|
||||
link: (baseUrl + source.file)?.replace(':su', ':ni'),
|
||||
type: 'm3u8',
|
||||
headers: {
|
||||
Referer: baseUrl,
|
||||
origin: baseUrl,
|
||||
Cookie: 'hd=on',
|
||||
},
|
||||
});
|
||||
});
|
||||
console.log(streamLinks);
|
||||
return streamLinks;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
16
providers/primeMirror/index.ts
Normal file
16
providers/primeMirror/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import {nfCatalog, nfGenresList} from '../netflixMirror/nfCatalog';
|
||||
import {nfGetPost, nfGetPostsSearch} from '../netflixMirror/nfGetPost';
|
||||
import {ProviderType} from '../types';
|
||||
import {pmGetInfo} from './pmGetInfo';
|
||||
import {pmGetStream} from './pmGetStream';
|
||||
import {pmGetEpisodes} from './pmGetEpisodes';
|
||||
|
||||
export const primeMirror: ProviderType = {
|
||||
catalog: nfCatalog,
|
||||
genres: nfGenresList,
|
||||
GetMetaData: pmGetInfo,
|
||||
GetHomePosts: nfGetPost,
|
||||
GetStream: pmGetStream,
|
||||
GetEpisodeLinks: pmGetEpisodes,
|
||||
GetSearchPosts: nfGetPostsSearch,
|
||||
};
|
||||
49
providers/primeMirror/pmGetEpisodes.ts
Normal file
49
providers/primeMirror/pmGetEpisodes.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import {EpisodeLink, ProviderContext} from '../types';
|
||||
|
||||
export const pmGetEpisodes = async function ({
|
||||
url: link,
|
||||
providerContext,
|
||||
}: {
|
||||
url: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<EpisodeLink[]> {
|
||||
const {getBaseUrl, axios} = providerContext;
|
||||
let providerValue = 'primeMirror';
|
||||
try {
|
||||
const baseUrl = await getBaseUrl('nfMirror');
|
||||
const url =
|
||||
`${baseUrl}${
|
||||
providerValue === 'netflixMirror'
|
||||
? '/episodes.php?s='
|
||||
: '/pv/episodes.php?s='
|
||||
}` +
|
||||
link +
|
||||
'&t=' +
|
||||
Math.round(new Date().getTime() / 1000);
|
||||
console.log('nfEpisodesUrl', url);
|
||||
const res = await axios.get(url, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36',
|
||||
'Accept-Language': 'en-US,en;q=0.9',
|
||||
},
|
||||
});
|
||||
const data = res.data;
|
||||
console.log('nfEpisodes', data);
|
||||
|
||||
const episodeList: EpisodeLink[] = [];
|
||||
|
||||
data?.episodes?.map((episode: any) => {
|
||||
episodeList.push({
|
||||
title: 'Episode ' + episode?.ep.replace('E', ''),
|
||||
link: episode?.id,
|
||||
});
|
||||
});
|
||||
|
||||
return episodeList;
|
||||
} catch (err) {
|
||||
console.error('nfGetEpisodes error', err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
63
providers/primeMirror/pmGetInfo.ts
Normal file
63
providers/primeMirror/pmGetInfo.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import {Info, Link} from '../types';
|
||||
|
||||
export const pmGetInfo = async function ({
|
||||
link,
|
||||
}: {
|
||||
link: string;
|
||||
}): Promise<Info> {
|
||||
let providerValue = 'primeMirror';
|
||||
try {
|
||||
const isPrime =
|
||||
providerValue === 'primeMirror' ? 'isPrime=true' : 'isPrime=false';
|
||||
const url = `https://netmirror.8man.me/api/net-proxy?${isPrime}&url=${encodeURIComponent(
|
||||
link,
|
||||
)}`;
|
||||
console.log('nfifo', url);
|
||||
const res = await fetch(url, {
|
||||
credentials: 'omit',
|
||||
});
|
||||
const data = await res.json();
|
||||
const id = link.split('id=')[1]?.split('&')[0];
|
||||
const meta = {
|
||||
title: data.title,
|
||||
synopsis: data.desc,
|
||||
image: `https://img.nfmirrorcdn.top/poster/h/${id}.jpg`,
|
||||
cast: data?.short_cast?.split(','),
|
||||
tags: [data?.year, data?.hdsd, ...data?.thismovieis?.split(',')],
|
||||
imdbId: '',
|
||||
type: 'series',
|
||||
};
|
||||
console.log('nfinfo', meta);
|
||||
|
||||
const linkList: Link[] = [];
|
||||
if (data?.season?.length > 0) {
|
||||
data.season.map((season: any) => {
|
||||
linkList.push({
|
||||
title: 'Season ' + season?.s,
|
||||
episodesLink: season?.id,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
linkList.push({
|
||||
title: meta.title,
|
||||
directLinks: [{link: id, title: 'Movie', type: 'movie'}],
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
...meta,
|
||||
|
||||
linkList: linkList,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return {
|
||||
title: '',
|
||||
synopsis: '',
|
||||
image: '',
|
||||
imdbId: '',
|
||||
type: '',
|
||||
linkList: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
44
providers/primeMirror/pmGetStream.ts
Normal file
44
providers/primeMirror/pmGetStream.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import {ProviderContext, Stream} from '../types';
|
||||
|
||||
export const pmGetStream = async ({
|
||||
link: id,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Stream[]> => {
|
||||
const {getBaseUrl} = providerContext;
|
||||
try {
|
||||
let providerValue = 'primeMirror';
|
||||
const baseUrl = await getBaseUrl('nfMirror');
|
||||
const url = `https://netmirror.8man.me/api/net-proxy?url=${baseUrl}${
|
||||
providerValue === 'netflixMirror'
|
||||
? '/mobile/playlist.php?id='
|
||||
: '/pv/playlist.php?id='
|
||||
}${id}&t=${Math.round(new Date().getTime() / 1000)}`;
|
||||
console.log('nfGetStream, url:', url);
|
||||
const res = await fetch(url, {
|
||||
credentials: 'omit',
|
||||
});
|
||||
const resJson = await res.json();
|
||||
const data = resJson?.[0];
|
||||
const streamLinks: Stream[] = [];
|
||||
data?.sources.forEach((source: any) => {
|
||||
streamLinks.push({
|
||||
server: source.label,
|
||||
link: (baseUrl + source.file)?.replace(':su', ':ni'),
|
||||
type: 'm3u8',
|
||||
headers: {
|
||||
Referer: baseUrl,
|
||||
origin: baseUrl,
|
||||
Cookie: 'hd=on',
|
||||
},
|
||||
});
|
||||
});
|
||||
console.log(streamLinks);
|
||||
return streamLinks;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
14
providers/primewire/index.ts
Normal file
14
providers/primewire/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {pwCatalogList, pwGenresList} from './pwCatalogl';
|
||||
import {pwGetPosts, pwGetPostsSearch} from './pwGetPosts';
|
||||
import {pwGetInfo} from './pwGetInfo';
|
||||
import {pwGetStream} from './pwGetStream';
|
||||
import {ProviderType} from '../types';
|
||||
|
||||
export const primewire: ProviderType = {
|
||||
catalog: pwCatalogList,
|
||||
genres: pwGenresList,
|
||||
GetMetaData: pwGetInfo,
|
||||
GetHomePosts: pwGetPosts,
|
||||
GetStream: pwGetStream,
|
||||
GetSearchPosts: pwGetPostsSearch,
|
||||
};
|
||||
16
providers/primewire/pwCatalogl.ts
Normal file
16
providers/primewire/pwCatalogl.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export const pwCatalogList = [
|
||||
{
|
||||
title: 'Recently Added',
|
||||
filter: '/filter?sort=Just+Added&free_links=true',
|
||||
},
|
||||
{
|
||||
title: 'TV Shows',
|
||||
filter: '/filter?sort=Trending+Today&type=tv',
|
||||
},
|
||||
{
|
||||
title: 'Movies',
|
||||
filter: '/filter?sort=Trending+Today&type=movie',
|
||||
},
|
||||
];
|
||||
|
||||
export const pwGenresList = [];
|
||||
82
providers/primewire/pwGetInfo.ts
Normal file
82
providers/primewire/pwGetInfo.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import {Info, Link, ProviderContext} from '../types';
|
||||
|
||||
export const pwGetInfo = async function ({
|
||||
link,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Info> {
|
||||
try {
|
||||
const {axios, cheerio} = providerContext;
|
||||
const url = link;
|
||||
const baseUrl = link.split('/').slice(0, 3).join('/');
|
||||
const res = await axios.get(url);
|
||||
const html = await res.data;
|
||||
const $ = cheerio.load(html);
|
||||
const imdbId =
|
||||
$('.movie_info')
|
||||
.find('a[href*="imdb.com/title/tt"]:not([href*="imdb.com/title/tt/"])')
|
||||
.attr('href')
|
||||
?.split('/')[4] || '';
|
||||
const type = $('.show_season').html() ? 'series' : 'movie';
|
||||
const linkList: Link[] = [];
|
||||
$('.show_season').each((i, element) => {
|
||||
const seasonTitle = 'Season ' + $(element).attr('data-id');
|
||||
const episodes: Link['directLinks'] = [];
|
||||
$(element)
|
||||
.children()
|
||||
.each((i, element2) => {
|
||||
const episodeTitle = $(element2)
|
||||
.find('a')
|
||||
.children()
|
||||
.remove()
|
||||
.end()
|
||||
.text()
|
||||
.trim()
|
||||
.replace('E', 'Epiosode ');
|
||||
const episodeLink = baseUrl + $(element2).find('a').attr('href');
|
||||
if (episodeTitle && episodeLink) {
|
||||
episodes.push({
|
||||
title: episodeTitle,
|
||||
link: episodeLink,
|
||||
});
|
||||
}
|
||||
});
|
||||
linkList.push({
|
||||
title: seasonTitle,
|
||||
directLinks: episodes,
|
||||
});
|
||||
});
|
||||
if (type === 'movie') {
|
||||
linkList.push({
|
||||
title: 'Movie',
|
||||
directLinks: [
|
||||
{
|
||||
link: link,
|
||||
title: 'Movie',
|
||||
type: 'movie',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
return {
|
||||
title: '',
|
||||
image: '',
|
||||
imdbId: imdbId,
|
||||
synopsis: '',
|
||||
type: type,
|
||||
linkList: linkList,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return {
|
||||
title: '',
|
||||
image: '',
|
||||
imdbId: '',
|
||||
synopsis: '',
|
||||
linkList: [],
|
||||
type: 'uhd',
|
||||
};
|
||||
}
|
||||
};
|
||||
82
providers/primewire/pwGetPosts.ts
Normal file
82
providers/primewire/pwGetPosts.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
export const pwGetPosts = async function ({
|
||||
filter,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
filter: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl, axios, cheerio} = providerContext;
|
||||
|
||||
const baseUrl = await getBaseUrl('primewire');
|
||||
const url = `${baseUrl + filter}&page=${page}`;
|
||||
return posts({baseUrl, url, signal, axios, cheerio});
|
||||
};
|
||||
|
||||
export const pwGetPostsSearch = async function ({
|
||||
searchQuery,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl, axios, cheerio, Aes} = providerContext;
|
||||
const getSHA256ofJSON = async function (input: any) {
|
||||
return await Aes.sha1(input);
|
||||
};
|
||||
const baseUrl = await getBaseUrl('primewire');
|
||||
const hash = await getSHA256ofJSON(searchQuery + 'JyjId97F9PVqUPuMO0');
|
||||
const url = `${baseUrl}/filter?s=${searchQuery}&page=${page}&ds=${hash.slice(
|
||||
0,
|
||||
10,
|
||||
)}`;
|
||||
return posts({baseUrl, url, signal, axios, cheerio});
|
||||
};
|
||||
|
||||
async function posts({
|
||||
baseUrl,
|
||||
url,
|
||||
signal,
|
||||
axios,
|
||||
cheerio,
|
||||
}: {
|
||||
baseUrl: string;
|
||||
url: string;
|
||||
signal: AbortSignal;
|
||||
axios: ProviderContext['axios'];
|
||||
cheerio: ProviderContext['cheerio'];
|
||||
}): Promise<Post[]> {
|
||||
try {
|
||||
const res = await axios.get(url, {signal});
|
||||
const data = res.data;
|
||||
const $ = cheerio.load(data);
|
||||
const catalog: Post[] = [];
|
||||
$('.index_item.index_item_ie').map((i, element) => {
|
||||
const title = $(element).find('a').attr('title');
|
||||
const link = $(element).find('a').attr('href');
|
||||
const image = $(element).find('img').attr('src') || '';
|
||||
if (title && link) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link: baseUrl + link,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('primewire error ', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
155
providers/primewire/pwGetStream.ts
Normal file
155
providers/primewire/pwGetStream.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
import {Stream, ProviderContext} from '../types';
|
||||
|
||||
export const pwGetStream = async function ({
|
||||
link: url,
|
||||
type,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
type: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Stream[]> {
|
||||
const {axios, cheerio} = providerContext;
|
||||
try {
|
||||
console.log('pwGetStream', type, url);
|
||||
const baseUrl = url.split('/').slice(0, 3).join('/');
|
||||
const streamLinks: Stream[] = [];
|
||||
const urls: {id: string; size: string}[] = [];
|
||||
const res = await axios.get(url);
|
||||
const data = res.data;
|
||||
const $ = cheerio.load(data);
|
||||
$('tr:contains("mixdrop")').map((i, element) => {
|
||||
const id = $(element).find('.wp-menu-btn').attr('data-wp-menu');
|
||||
const size = $(element).find('.wp-menu-btn').next().text();
|
||||
if (id) {
|
||||
urls.push({id: baseUrl + '/links/go/' + id, size});
|
||||
}
|
||||
});
|
||||
|
||||
console.log('urls', urls);
|
||||
|
||||
for (const url of urls) {
|
||||
const res2 = await axios.head(url.id);
|
||||
const location = res2.request?.responseURL.replace('/f/', '/e/');
|
||||
|
||||
const res3 = await fetch(location, {
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0',
|
||||
Accept:
|
||||
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
|
||||
'Accept-Language': 'en-US,en;q=0.5',
|
||||
'Upgrade-Insecure-Requests': '1',
|
||||
'Sec-Fetch-Dest': 'iframe',
|
||||
'Sec-Fetch-Mode': 'navigate',
|
||||
'Sec-Fetch-Site': 'same-origin',
|
||||
Pragma: 'no-cache',
|
||||
'Cache-Control': 'no-cache',
|
||||
referer: res2.request?.responseURL,
|
||||
},
|
||||
referrer: res2.request?.responseURL,
|
||||
method: 'GET',
|
||||
mode: 'cors',
|
||||
});
|
||||
const data3 = await res3.text();
|
||||
|
||||
// let MDCore: any = {};
|
||||
// Step 1: Extract the function parameters and the encoded string
|
||||
var functionRegex =
|
||||
/eval\(function\((.*?)\)\{.*?return p\}.*?\('(.*?)'\.split/;
|
||||
var match = functionRegex.exec(data3);
|
||||
let p = '';
|
||||
if (match) {
|
||||
// var params = match[1].split(',').map(param => param.trim());
|
||||
var encodedString = match[2];
|
||||
console.log('Encoded String:', encodedString);
|
||||
|
||||
// console.log('Parameters:', params);
|
||||
// console.log('Encoded String:', encodedString.split("',36,")[0], '🔥🔥');
|
||||
|
||||
const base = Number(
|
||||
encodedString.split(",'|MDCore|")[0].split(',')[
|
||||
encodedString.split(",'|MDCore|")[0].split(',').length - 1
|
||||
],
|
||||
);
|
||||
console.log('Base:', base);
|
||||
|
||||
p = encodedString.split(`',${base},`)?.[0].trim();
|
||||
let a = base;
|
||||
let c = encodedString.split(`',${base},`)[1].slice(2).split('|').length;
|
||||
let k = encodedString.split(`',${base},`)[1].slice(2).split('|');
|
||||
|
||||
// console.log('p:', p);
|
||||
// console.log('a:', a);
|
||||
// console.log('c:', c);
|
||||
// console.log('k:', k);
|
||||
|
||||
const decode = function (
|
||||
p: any,
|
||||
a: any,
|
||||
c: any,
|
||||
k: any,
|
||||
e: any,
|
||||
d: any,
|
||||
) {
|
||||
e = function (c: any) {
|
||||
return c.toString(36);
|
||||
};
|
||||
if (!''.replace(/^/, String)) {
|
||||
while (c--) {
|
||||
d[c.toString(a)] = k[c] || c.toString(a);
|
||||
}
|
||||
k = [
|
||||
function (e: any) {
|
||||
return d[e];
|
||||
},
|
||||
];
|
||||
e = function () {
|
||||
return '\\w+';
|
||||
};
|
||||
c = 1;
|
||||
}
|
||||
while (c--) {
|
||||
if (k[c]) {
|
||||
p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
};
|
||||
|
||||
const decoded = decode(p, a, c, k, 0, {});
|
||||
// get MDCore.wurl=
|
||||
const wurl = decoded.match(/MDCore\.wurl="([^"]+)"/)?.[1];
|
||||
console.log('wurl:', wurl);
|
||||
const streamUrl = 'https:' + wurl;
|
||||
console.log('streamUrl:', streamUrl);
|
||||
streamLinks.push({
|
||||
server: 'Mixdrop ' + url.size,
|
||||
link: streamUrl,
|
||||
type: 'mp4',
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0',
|
||||
Accept:
|
||||
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
|
||||
'Accept-Language': 'en-US,en;q=0.5',
|
||||
'Upgrade-Insecure-Requests': '1',
|
||||
'Sec-Fetch-Dest': 'iframe',
|
||||
'Sec-Fetch-Mode': 'navigate',
|
||||
'Sec-Fetch-Site': 'same-origin',
|
||||
Pragma: 'no-cache',
|
||||
'Cache-Control': 'no-cache',
|
||||
referer: res2.request?.responseURL,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
console.log('No match found');
|
||||
}
|
||||
}
|
||||
return streamLinks;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
14
providers/protonMovies/index.ts
Normal file
14
providers/protonMovies/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {protonGenresList, protonCatalogList} from './protonCatalog';
|
||||
import {protonGetPosts, protonGetPostsSearch} from './protonGetPosts';
|
||||
import {protonGetInfo} from './protonGetMeta';
|
||||
import {ProviderType} from '../types';
|
||||
import {protonGetStream} from './protonGetStream';
|
||||
|
||||
export const protonMovies: ProviderType = {
|
||||
catalog: protonCatalogList,
|
||||
genres: protonGenresList,
|
||||
GetMetaData: protonGetInfo,
|
||||
GetHomePosts: protonGetPosts,
|
||||
GetStream: protonGetStream,
|
||||
GetSearchPosts: protonGetPostsSearch,
|
||||
};
|
||||
20
providers/protonMovies/protonCatalog.ts
Normal file
20
providers/protonMovies/protonCatalog.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export const protonCatalogList = [
|
||||
{
|
||||
title: 'Latest',
|
||||
filter: '/movies',
|
||||
},
|
||||
{
|
||||
title: 'Netflix',
|
||||
filter: '/platform/netflix',
|
||||
},
|
||||
{
|
||||
title: 'Disney +',
|
||||
filter: '/platform/disney-hotstar',
|
||||
},
|
||||
{
|
||||
title: 'Amazon Prime',
|
||||
filter: '/platform/amazon-prime-video',
|
||||
},
|
||||
];
|
||||
|
||||
export const protonGenresList = [];
|
||||
109
providers/protonMovies/protonGetMeta.ts
Normal file
109
providers/protonMovies/protonGetMeta.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import {EpisodeLink, Info, Link, ProviderContext} from '../types';
|
||||
|
||||
export const protonGetInfo = async function ({
|
||||
link,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Info> {
|
||||
try {
|
||||
const {axios, cheerio, getBaseUrl} = providerContext;
|
||||
console.log('all', link);
|
||||
const res = await axios.get(link);
|
||||
const data = res.data;
|
||||
|
||||
function decodeHtml(encodedArray: string[]): string {
|
||||
// Join array elements into a single string
|
||||
const joined = encodedArray.join('');
|
||||
|
||||
// Replace escaped quotes
|
||||
const unescaped = joined.replace(/\\"/g, '"').replace(/\\'/g, "'");
|
||||
|
||||
// Remove remaining escape characters
|
||||
const cleaned = unescaped
|
||||
.replace(/\\n/g, '\n')
|
||||
.replace(/\\t/g, '\t')
|
||||
.replace(/\\r/g, '\r');
|
||||
|
||||
// Convert literal string representations back to characters
|
||||
const decoded = cleaned
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/&/g, '&');
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
const $$ = cheerio.load(data);
|
||||
const htmlArray = $$('script:contains("decodeURIComponent")')
|
||||
.text()
|
||||
.split(' = ')?.[1]
|
||||
?.split('protomovies')?.[0]
|
||||
?.trim()
|
||||
?.slice(0, -1); // remove the last character
|
||||
// console.log('protonGetInfo', htmlArray);
|
||||
const html = decodeHtml(JSON.parse(htmlArray));
|
||||
// console.log('all', html);
|
||||
const $ = cheerio.load(html);
|
||||
|
||||
const title = $(
|
||||
'.trending-text.fw-bold.texture-text.text-uppercase.my-0.fadeInLeft.animated.d-inline-block',
|
||||
).text();
|
||||
const image = $('#thumbnail').attr('src');
|
||||
const type = link.includes('series') ? 'series' : 'movie';
|
||||
const synopsis =
|
||||
$('.col-12.iq-mb-30.animated.fadeIn').first().text() ||
|
||||
$('.description-content').text();
|
||||
const tags = $('.p-0.mt-2.list-inline.d-flex.flex-wrap.movie-tag')
|
||||
.find('li')
|
||||
.map((i, el) => $(el).text())
|
||||
.slice(0, 3)
|
||||
.get();
|
||||
|
||||
const baseUrl = await getBaseUrl('protonMovies');
|
||||
const links: Link[] = [];
|
||||
|
||||
if (type === 'movie') {
|
||||
const directLinks: EpisodeLink[] = [];
|
||||
directLinks.push({title: 'Movie', link: link});
|
||||
links.push({title: 'Movie', directLinks: directLinks});
|
||||
} else {
|
||||
$('#episodes')
|
||||
.children()
|
||||
.map((i, element) => {
|
||||
let directLinks: EpisodeLink[] = [];
|
||||
$(element)
|
||||
.find('.episode-block')
|
||||
.map((j, ep) => {
|
||||
const link = baseUrl + $(ep).find('a').attr('href') || '';
|
||||
const title =
|
||||
'Episode ' + $(ep).find('.episode-number').text().split('E')[1];
|
||||
directLinks.push({title, link});
|
||||
});
|
||||
links.push({title: 'Season ' + (i + 1), directLinks: directLinks});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
image: image || '',
|
||||
imdbId: '',
|
||||
linkList: links,
|
||||
title: title || '',
|
||||
synopsis: synopsis,
|
||||
tags: tags,
|
||||
type: type,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error('prton', err);
|
||||
return {
|
||||
title: '',
|
||||
synopsis: '',
|
||||
image: '',
|
||||
imdbId: '',
|
||||
type: 'movie',
|
||||
linkList: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
107
providers/protonMovies/protonGetPosts.ts
Normal file
107
providers/protonMovies/protonGetPosts.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import {Post, ProviderContext} from '../types';
|
||||
|
||||
export const protonGetPosts = async function ({
|
||||
filter,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
filter: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl, axios, cheerio} = providerContext;
|
||||
const baseUrl = await getBaseUrl('protonMovies');
|
||||
const url = `${baseUrl + filter}/page/${page}/`;
|
||||
return posts({url, baseUrl, signal, axios, cheerio});
|
||||
};
|
||||
|
||||
export const protonGetPostsSearch = async function ({
|
||||
searchQuery,
|
||||
page,
|
||||
signal,
|
||||
providerContext,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
page: number;
|
||||
providerValue: string;
|
||||
signal: AbortSignal;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Post[]> {
|
||||
const {getBaseUrl, axios, cheerio} = providerContext;
|
||||
const baseUrl = await getBaseUrl('protonMovies');
|
||||
const url = `${baseUrl}/search/${searchQuery}/page/${page}/`;
|
||||
return posts({url, baseUrl, signal, axios, cheerio});
|
||||
};
|
||||
|
||||
async function posts({
|
||||
url,
|
||||
baseUrl,
|
||||
signal,
|
||||
axios,
|
||||
cheerio,
|
||||
}: {
|
||||
url: string;
|
||||
baseUrl: string;
|
||||
signal: AbortSignal;
|
||||
axios: ProviderContext['axios'];
|
||||
cheerio: ProviderContext['cheerio'];
|
||||
}): Promise<Post[]> {
|
||||
function decodeHtml(encodedArray: string[]): string {
|
||||
// Join array elements into a single string
|
||||
const joined = encodedArray.join('');
|
||||
|
||||
// Replace escaped quotes
|
||||
const unescaped = joined.replace(/\\"/g, '"').replace(/\\'/g, "'");
|
||||
|
||||
// Remove remaining escape characters
|
||||
const cleaned = unescaped
|
||||
.replace(/\\n/g, '\n')
|
||||
.replace(/\\t/g, '\t')
|
||||
.replace(/\\r/g, '\r');
|
||||
|
||||
// Convert literal string representations back to characters
|
||||
const decoded = cleaned
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/&/g, '&');
|
||||
|
||||
return decoded;
|
||||
}
|
||||
try {
|
||||
const res = await axios.get(url, {
|
||||
headers: {
|
||||
referer: baseUrl,
|
||||
},
|
||||
signal,
|
||||
});
|
||||
const data = res.data;
|
||||
const regex = /\[(?=.*?"<div class")(.*?)\]/g;
|
||||
const htmlArray = data?.match(regex);
|
||||
const html = decodeHtml(JSON.parse(htmlArray[htmlArray.length - 1]));
|
||||
const $ = cheerio.load(html);
|
||||
const catalog: Post[] = [];
|
||||
$('.col.mb-4').map((i, element) => {
|
||||
const title = $(element).find('h5').text();
|
||||
const link = $(element).find('h5').find('a').attr('href');
|
||||
const image =
|
||||
$(element).find('img').attr('data-src') ||
|
||||
$(element).find('img').attr('src') ||
|
||||
'';
|
||||
if (title && link && image) {
|
||||
catalog.push({
|
||||
title: title,
|
||||
link: link,
|
||||
image: image,
|
||||
});
|
||||
}
|
||||
});
|
||||
return catalog;
|
||||
} catch (err) {
|
||||
console.error('protonGetPosts error ', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
200
providers/protonMovies/protonGetStream.ts
Normal file
200
providers/protonMovies/protonGetStream.ts
Normal file
@@ -0,0 +1,200 @@
|
||||
import {Stream, ProviderContext} from '../types';
|
||||
|
||||
function LALLJLutmoZpvvbikjaWM(str: string): ArrayBuffer {
|
||||
var buf = new ArrayBuffer(str.length * 2);
|
||||
var bufView = new Uint8Array(buf);
|
||||
for (var i = 0, strLen = str.length; i < strLen; i++) {
|
||||
bufView[i] = str.charCodeAt(i);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
function getOrCreateUID() {
|
||||
const uid =
|
||||
'uid_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
export const protonGetStream = async function ({
|
||||
link,
|
||||
providerContext,
|
||||
}: {
|
||||
link: string;
|
||||
providerContext: ProviderContext;
|
||||
}): Promise<Stream[]> {
|
||||
const {axios, cheerio, commonHeaders: headers, extractors} = providerContext;
|
||||
const {gofileExtracter} = extractors;
|
||||
function generateMessageToken(baseUrlL: string): string {
|
||||
const hostname = baseUrlL?.replace(/https?:\/\//, '').split('/')[0];
|
||||
console.log('generateMessageToken hostname', hostname);
|
||||
const NsmxUftCNibQ = `[hostname=${hostname}][agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0][tmz=India Standard Time][userTimezoneOffset=-330][{"url":"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js","type":"script","duration":253.30000000074506},{"url":"https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback","type":"script","duration":397.19999999925494},{"url":"https://adoto.net/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js","type":"img","duration":225.90000000223517},{"url":"https://code.jquery.com/jquery-3.3.1.slim.min.js","type":"script","duration":65.30000000074506},{"url":"https://static.cloudflareinsights.com/beacon.min.js/vcd15cbe7772f49c399c6a5babf22c1241717689176015","type":"script","duration":225.89999999850988},{"url":"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js","type":"script","duration":253.30000000074506},{"url":"https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback","type":"script","duration":397.19999999925494},{"url":"https://adoto.net/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js","type":"img","duration":225.90000000223517},{"url":"https://code.jquery.com/jquery-3.3.1.slim.min.js","type":"script","duration":65.30000000074506},{"url":"https://static.cloudflareinsights.com/beacon.min.js/vcd15cbe7772f49c399c6a5babf22c1241717689176015","type":"script","duration":225.89999999850988},{"url":"https://challenges.cloudflare.com/cdn-cgi/challenge-platform/h/b/turnstile/if/ov2/av0/rcv/b3dhg/0x4AAAAAAAQDru7r64xT2ifD/auto/fbE/new/normal/auto/","type":"iframe","duration":2050.300000000745},{"url":"https://new19.gdtot.dad/favicon.ico","type":"img","duration":1003.6999999992549},{"url":"https://vikingfile.com/assets/favicon-64375c377b5df8304acbdad4f4430694.ico","type":"img","duration":183.19999999925494},{"url":"https://gofile.io/dist/img/favicon32.png","type":"img","duration":19177.199999999255},{"url":"https://pub.clickadu.com/assets/scripts/supported-browsers.js","type":"fetch","duration":18.799999997019768},{"url":"https://challenges.cloudflare.com/cdn-cgi/challenge-platform/h/b/turnstile/if/ov2/av0/rcv/b3dhg/0x4AAAAAAAQDru7r64xT2ifD/auto/fbE/auto_expire/normal/auto/","type":"iframe","duration":1612.5999999977648},{"url":"https://challenges.cloudflare.com/cdn-cgi/challenge-platform/h/b/turnstile/if/ov2/av0/rcv/b3dhg/0x4AAAAAAAQDru7r64xT2ifD/auto/fbE/auto_expire/normal/auto/","type":"iframe","duration":1154.0999999977648},{"url":"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js","type":"script","duration":253.30000000074506},{"url":"https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback","type":"script","duration":397.19999999925494},{"url":"https://adoto.net/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js","type":"img","duration":225.90000000223517},{"url":"https://code.jquery.com/jquery-3.3.1.slim.min.js","type":"script","duration":65.30000000074506},{"url":"https://static.cloudflareinsights.com/beacon.min.js/vcd15cbe7772f49c399c6a5babf22c1241717689176015","type":"script","duration":225.89999999850988},{"url":"https://challenges.cloudflare.com/cdn-cgi/challenge-platform/h/b/turnstile/if/ov2/av0/rcv/b3dhg/0x4AAAAAAAQDru7r64xT2ifD/auto/fbE/new/normal/auto/","type":"iframe","duration":2050.300000000745},{"url":"https://new19.gdtot.dad/favicon.ico","type":"img","duration":1003.6999999992549},{"url":"https://vikingfile.com/assets/favicon-64375c377b5df8304acbdad4f4430694.ico","type":"img","duration":183.19999999925494},{"url":"https://gofile.io/dist/img/favicon32.png","type":"img","duration":19177.199999999255},{"url":"https://pub.clickadu.com/assets/scripts/supported-browsers.js","type":"fetch","duration":18.799999997019768},{"url":"https://challenges.cloudflare.com/cdn-cgi/challenge-platform/h/b/turnstile/if/ov2/av0/rcv/b3dhg/0x4AAAAAAAQDru7r64xT2ifD/auto/fbE/auto_expire/normal/auto/","type":"iframe","duration":1612.5999999977648},{"url":"https://challenges.cloudflare.com/cdn-cgi/challenge-platform/h/b/turnstile/if/ov2/av0/rcv/b3dhg/0x4AAAAAAAQDru7r64xT2ifD/auto/fbE/auto_expire/normal/auto/","type":"iframe","duration":1154.0999999977648},{"url":"https://challenges.cloudflare.com/cdn-cgi/challenge-platform/h/b/turnstile/if/ov2/av0/rcv/b3dhg/0x4AAAAAAAQDru7r64xT2ifD/auto/fbE/auto_expire/normal/auto/","type":"iframe","duration":986}][{"elements":{"div":70,"span":68,"img":4,"iframe":0,"script":28,"link":20,"p":5,"a":213,"ul":28,"li":208,"button":9,"input":5},"hidden":{"div":13,"span":60,"img":1,"iframe":0,"script":28,"link":20,"p":0,"a":186,"ul":22,"li":184,"button":6,"input":2},"errors":{"network":0,"js":0},"eventListeners":0}]`;
|
||||
|
||||
var jRpeP = LALLJLutmoZpvvbikjaWM(NsmxUftCNibQ);
|
||||
var jzKEwqEAcWFMNwHZnCCqJQ = new Uint8Array(jRpeP);
|
||||
var kyMXQUxoFYuZIBlKvlHa = jzKEwqEAcWFMNwHZnCCqJQ.toString();
|
||||
var kyMXQUxoFYuZIBlKvlHa = kyMXQUxoFYuZIBlKvlHa.replace(/2/g, '004');
|
||||
var kyMXQUxoFYuZIBlKvlHa = kyMXQUxoFYuZIBlKvlHa.replace(/3/g, '005');
|
||||
var kyMXQUxoFYuZIBlKvlHa = kyMXQUxoFYuZIBlKvlHa.replace(/7/g, '007');
|
||||
var kyMXQUxoFYuZIBlKvlHa = kyMXQUxoFYuZIBlKvlHa.replace(/,0,0,0/g, '');
|
||||
|
||||
return kyMXQUxoFYuZIBlKvlHa;
|
||||
}
|
||||
function decodeHtml(encodedArray: string[]): string {
|
||||
// Join array elements into a single string
|
||||
const joined = encodedArray.join('');
|
||||
|
||||
// Replace escaped quotes
|
||||
const unescaped = joined.replace(/\\"/g, '"').replace(/\\'/g, "'");
|
||||
|
||||
// Remove remaining escape characters
|
||||
const cleaned = unescaped
|
||||
.replace(/\\n/g, '\n')
|
||||
.replace(/\\t/g, '\t')
|
||||
.replace(/\\r/g, '\r');
|
||||
|
||||
// Convert literal string representations back to characters
|
||||
const decoded = cleaned
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/&/g, '&');
|
||||
|
||||
return decoded;
|
||||
}
|
||||
try {
|
||||
const streamLinks: Stream[] = [];
|
||||
const res = await axios.get(link, {headers});
|
||||
const data = res.data;
|
||||
// const regex = /\[(?=.*?"<div class")(.*?)\]/g;
|
||||
// const htmlArray = data?.match(regex);
|
||||
|
||||
// new code
|
||||
const $$ = cheerio.load(data);
|
||||
const htmlArray = $$('script:contains("decodeURIComponent")')
|
||||
.text()
|
||||
.split(' = ')?.[1]
|
||||
?.split('protomovies')?.[0]
|
||||
?.trim()
|
||||
?.slice(0, -1); // remove the last character
|
||||
// console.log('protonGetInfo', htmlArray);
|
||||
// const html = decodeHtml(JSON.parse(htmlArray[htmlArray.length - 1]));
|
||||
|
||||
const html = decodeHtml(JSON.parse(htmlArray));
|
||||
|
||||
// console.log('protonGetInfo', htmlArray[htmlArray.length - 1]);
|
||||
// console.log('all', html);
|
||||
const $ = cheerio.load(html);
|
||||
const idList = [];
|
||||
const id1080 = $('tr:contains("1080p")')
|
||||
.find('button:contains("Info")')
|
||||
.attr('id')
|
||||
?.split('-')[1];
|
||||
if (id1080) {
|
||||
idList.push({
|
||||
id: id1080,
|
||||
quality: '1080p',
|
||||
});
|
||||
}
|
||||
const id720 = $('tr:contains("720p")')
|
||||
.find('button:contains("Info")')
|
||||
.attr('id')
|
||||
?.split('-')[1];
|
||||
|
||||
if (id720) {
|
||||
idList.push({
|
||||
id: id720,
|
||||
quality: '720p',
|
||||
});
|
||||
}
|
||||
|
||||
const id480 = $('tr:contains("480p")')
|
||||
.find('button:contains("Info")')
|
||||
.attr('id')
|
||||
?.split('-')[1];
|
||||
|
||||
if (id480) {
|
||||
idList.push({
|
||||
id: id480,
|
||||
quality: '480p',
|
||||
});
|
||||
}
|
||||
// console.log('idList', idList);
|
||||
|
||||
const baseUrl = link.split('/').slice(0, 3).join('/');
|
||||
|
||||
const secondIdList: {
|
||||
quality: string;
|
||||
id: string;
|
||||
}[] = [];
|
||||
|
||||
await Promise.all(
|
||||
idList.slice(0, 2).map(async id => {
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('downloadid', id.id);
|
||||
formData.append('token', 'ok');
|
||||
const messageToken = generateMessageToken(baseUrl);
|
||||
const uid = getOrCreateUID();
|
||||
|
||||
const idRes = await fetch(`${baseUrl}/ppd.php`, {
|
||||
headers: {
|
||||
accept: '*/*',
|
||||
'accept-language': 'en-US,en;q=0.9,en-IN;q=0.8',
|
||||
'cache-control': 'no-cache',
|
||||
'content-type': 'application/x-www-form-urlencoded',
|
||||
pragma: 'no-cache',
|
||||
priority: 'u=1, i',
|
||||
'sec-ch-ua':
|
||||
'"Chromium";v="136", "Microsoft Edge";v="136", "Not.A/Brand";v="99"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
'sec-fetch-dest': 'empty',
|
||||
'sec-fetch-mode': 'cors',
|
||||
'sec-fetch-site': 'same-origin',
|
||||
cookie:
|
||||
'ext_name=ojplmecpdpgccookcobabopnaifgidhf; tgInvite222=true; cf_clearance=3ynJv2B6lHMj3FCOqtfQaL7lTN4KC3xmPRMgcNtddAc-1748787867-1.2.1.1-SEIhLbWR3ehfib5Y3P5pjzj1Qu9wipc52Icv4AmNkztXn2pTXhjKgxXnvTuA2bNscgHuc1juXujAHteqY_vaMmy2C3djMWnJGzjje_XvXZXKht8rwHZt6sviq7KAYvrYZPTrATqENuopzmqmK6dDFS.CAnWHt0VDn8q06iLm5rYj1AXUo3qkV5p1Idx_25elWHYGG8yengBrQV1MYVM9LMdQqv44PXu69FZvNkgv.d6blCKyneJnoLkw4LHAccu.QRPbFwWqqTDyO9YTLRQW9w29bKghD3_JVxkz.qxpg5FbocJ3i6tJJy74SvROpYdpVUOn0fW1YgQ7RxYwhNoHpdTKy8pvmQJGRuSVW1GjO_k',
|
||||
Referer: 'https://m3.protonmovies.top/download/',
|
||||
'Referrer-Policy': 'strict-origin-when-cross-origin',
|
||||
},
|
||||
body: `downloadid=${id.id}&msg=${messageToken}&uid=${uid}&token=ok`,
|
||||
method: 'POST',
|
||||
});
|
||||
const idData = await idRes.text();
|
||||
secondIdList.push({
|
||||
quality: id.quality,
|
||||
id: idData,
|
||||
});
|
||||
console.log('idData', idData);
|
||||
}),
|
||||
);
|
||||
await Promise.all(
|
||||
secondIdList.map(async id => {
|
||||
const idRes = await axios.post(`${baseUrl}/tmp/${id.id}`);
|
||||
if (idRes.data.ppd['gofile.io']) {
|
||||
const goRes = await gofileExtracter(
|
||||
idRes.data.ppd['gofile.io'].link.split('/').pop(),
|
||||
);
|
||||
console.log('link', goRes.link);
|
||||
if (goRes.link) {
|
||||
streamLinks.push({
|
||||
link: goRes.link,
|
||||
server: 'gofile ' + id.quality,
|
||||
type: 'mkv',
|
||||
headers: {
|
||||
referer: 'https://gofile.io',
|
||||
connection: 'keep-alive',
|
||||
contentType: 'video/x-matroska',
|
||||
cookie: 'accountToken=' + goRes.token,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
return streamLinks;
|
||||
} catch (e) {
|
||||
console.log('proton get stream err', e);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
31
providers/providerContext.ts
Normal file
31
providers/providerContext.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import axios from 'axios';
|
||||
import {getBaseUrl} from './getBaseUrl';
|
||||
import {headers} from './headers';
|
||||
import * as cheerio from 'cheerio';
|
||||
import {hubcloudExtracter} from './hubcloudExtractor';
|
||||
import {gofileExtracter} from './gofileExtracter';
|
||||
import {superVideoExtractor} from './superVideoExtractor';
|
||||
import {gdFlixExtracter} from './gdflixExtractor';
|
||||
import {ProviderContext} from './types';
|
||||
import Aes from 'react-native-aes-crypto';
|
||||
|
||||
/**
|
||||
* Context for provider functions.
|
||||
* This context is used to pass common dependencies to provider functions.
|
||||
*/
|
||||
|
||||
const extractors = {
|
||||
hubcloudExtracter,
|
||||
gofileExtracter,
|
||||
superVideoExtractor,
|
||||
gdFlixExtracter,
|
||||
};
|
||||
|
||||
export const providerContext: ProviderContext = {
|
||||
axios,
|
||||
getBaseUrl,
|
||||
commonHeaders: headers,
|
||||
Aes,
|
||||
cheerio,
|
||||
extractors,
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user