This commit is contained in:
Pas 2026-01-15 12:59:58 -07:00
parent 58b229df40
commit 2f8add0e8c
3 changed files with 103 additions and 107 deletions

View file

@ -45,7 +45,7 @@ import { supervideoScraper } from './embeds/supervideo';
import { vidCloudScraper } from './embeds/vidcloud'; import { vidCloudScraper } from './embeds/vidcloud';
import { vidhideEnglishScraper, vidhideLatinoScraper, vidhideSpanishScraper } from './embeds/vidhide'; import { vidhideEnglishScraper, vidhideLatinoScraper, vidhideSpanishScraper } from './embeds/vidhide';
import { vidifyEmbeds } from './embeds/vidify'; import { vidifyEmbeds } from './embeds/vidify';
import { vidnestAllmoviesEmbed, vidnestHollymoviehdEmbed } from './embeds/vidnest'; import { VidnestEmbeds } from './embeds/vidnest';
import { import {
VidsrcsuServer10Scraper, VidsrcsuServer10Scraper,
VidsrcsuServer11Scraper, VidsrcsuServer11Scraper,
@ -193,8 +193,7 @@ export function gatherAllEmbeds(): Array<Embed> {
...vidifyEmbeds, ...vidifyEmbeds,
...zunimeEmbeds, ...zunimeEmbeds,
...AnimetsuEmbeds, ...AnimetsuEmbeds,
vidnestHollymoviehdEmbed, ...VidnestEmbeds,
vidnestAllmoviesEmbed,
myanimesubScraper, myanimesubScraper,
myanimedubScraper, myanimedubScraper,
filemoonScraper, filemoonScraper,

View file

@ -1,103 +1,108 @@
import { flags } from '@/entrypoint/utils/targets';
import { makeEmbed } from '@/providers/base';
import { HlsBasedStream } from '@/providers/streams';
import { NotFoundError } from '@/utils/errors'; import { NotFoundError } from '@/utils/errors';
import { makeEmbed } from '../base';
const VIDNEST_SERVERS = ['hollymoviehd', 'allmovies'] as const;
const baseUrl = 'https://second.vidnest.fun';
const PASSPHRASE = 'A7kP9mQeXU2BWcD4fRZV+Sg8yN0/M5tLbC1HJQwYe6pOKFaE3vTnPZsRuYdVmLq2'; const PASSPHRASE = 'A7kP9mQeXU2BWcD4fRZV+Sg8yN0/M5tLbC1HJQwYe6pOKFaE3vTnPZsRuYdVmLq2';
async function decryptVidnestData(encryptedBase64: string): Promise<any> { const serverConfigs: Record<string, { streamDomains: string[] | null; origin: string; referer: string }> = {
const encryptedBytes = Uint8Array.from(atob(encryptedBase64), (c) => c.charCodeAt(0)); hollymoviehd: {
streamDomains: ['pkaystream.cc', 'flashstream.cc'],
origin: 'https://flashstream.cc',
referer: 'https://flashstream.cc/',
},
allmovies: {
streamDomains: null,
origin: '',
referer: '',
},
};
function base64ToUint8Array(base64: string): Uint8Array {
const binaryString = atob(base64);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes;
}
async function decryptVidnestData(encryptedBase64: string): Promise<any> {
const encryptedBytes = base64ToUint8Array(encryptedBase64);
const iv = encryptedBytes.slice(0, 12); const iv = encryptedBytes.slice(0, 12);
const ciphertext = encryptedBytes.slice(12, -16); const ciphertext = encryptedBytes.slice(12, -16);
const tag = encryptedBytes.slice(-16); const tag = encryptedBytes.slice(-16);
const keyData = base64ToUint8Array(PASSPHRASE).slice(0, 32);
const keyData = Uint8Array.from(atob(PASSPHRASE), (c) => c.charCodeAt(0)).slice(0, 32); const cryptoKey = await crypto.subtle.importKey('raw', keyData, { name: 'AES-GCM' }, false, ['decrypt']);
const key = await crypto.subtle.importKey('raw', keyData, { name: 'AES-GCM' }, false, ['decrypt']);
const encrypted = new Uint8Array([...ciphertext, ...tag]); const combined = new Uint8Array(ciphertext.length + tag.length);
combined.set(ciphertext, 0);
combined.set(tag, ciphertext.length);
try { const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, cryptoKey, combined);
const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, encrypted); return JSON.parse(new TextDecoder('utf-8').decode(decrypted));
const decryptedText = new TextDecoder().decode(decrypted);
return JSON.parse(decryptedText);
} catch (error) {
throw new NotFoundError('Failed to decrypt data');
}
} }
export const vidnestHollymoviehdEmbed = makeEmbed({ export function makeVidnestEmbed(id: string, rank: number = 100) {
id: 'vidnest-hollymoviehd', const config = serverConfigs[id];
name: 'Vidnest HollyMovie',
rank: 104,
flags: [],
disabled: false,
async scrape(ctx) {
const response = await ctx.proxiedFetcher<any>(ctx.url);
if (!response.data) throw new NotFoundError('No encrypted data found');
const decryptedData = await decryptVidnestData(response.data); return makeEmbed({
if (!decryptedData.success && !decryptedData.sources) throw new NotFoundError('No streams found'); id: `vidnest-${id}`,
name: `Vidnest ${id}`,
rank,
disabled: false,
flags: [],
async scrape(ctx) {
const query = JSON.parse(ctx.url);
const { type, tmdbId, season, episode } = query;
const sources = decryptedData.sources || decryptedData.streams; const endpoint = type === 'movie' ? `/${id}/movie/${tmdbId}` : `/${id}/tv/${tmdbId}/${season}/${episode}`;
const streams: HlsBasedStream[] = [];
const streamHeaders = { const res = await ctx.proxiedFetcher<{ data?: string }>(endpoint, {
Origin: 'https://flashstream.cc', baseUrl,
Referer: 'https://flashstream.cc/', headers: {
}; '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',
},
});
for (const source of sources) { if (!res?.data) throw new NotFoundError('No data');
if (source.file && (source.file.includes('pkaystream.cc') || source.file.includes('flashstream.cc'))) {
streams.push({ const decrypted = await decryptVidnestData(res.data);
id: `hollymoviehd-${source.label || 'default'}`, const sources = decrypted.sources || decrypted.streams || [];
type: 'hls',
playlist: source.file, const streams: string[] = [];
flags: [], for (const source of sources) {
captions: [], const url = source.file || source.url;
headers: streamHeaders, if (!url) continue;
skipValidation: true, if (config?.streamDomains && !config.streamDomains.some((d) => url.includes(d))) continue;
} as HlsBasedStream); streams.push(url);
} }
}
return { if (!streams.length) throw new NotFoundError('No streams');
stream: streams,
};
},
});
export const vidnestAllmoviesEmbed = makeEmbed({ ctx.progress(100);
id: 'vidnest-allmovies',
name: 'Vidnest AllMovies (Hindi)',
rank: 103,
flags: [flags.CORS_ALLOWED],
disabled: false,
async scrape(ctx) {
const response = await ctx.proxiedFetcher<any>(ctx.url);
if (!response.data) throw new NotFoundError('No encrypted data found');
const decryptedData = await decryptVidnestData(response.data); return {
if (!decryptedData.success && !decryptedData.streams) throw new NotFoundError('No streams found'); stream: [
{
id,
type: 'hls',
playlist: streams[0],
headers: {
Origin: config?.origin,
Referer: config?.referer,
},
flags: [],
captions: [],
},
],
};
},
});
}
const sources = decryptedData.sources || decryptedData.streams; export const VidnestEmbeds = VIDNEST_SERVERS.map((server, i) => makeVidnestEmbed(server, 104 - i));
const streams = [];
for (const stream of sources) {
streams.push({
id: `allmovies-${stream.language || 'default'}`,
type: 'hls',
playlist: stream.url || stream.file,
flags: [flags.CORS_ALLOWED],
captions: [],
preferredHeaders: stream.headers || {},
skipValidation: true,
} as HlsBasedStream);
}
return {
stream: streams,
};
},
});

View file

@ -1,29 +1,22 @@
import { makeSourcerer } from '@/providers/base'; import { SourcererOutput, makeSourcerer } from '@/providers/base';
import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context'; import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context';
const backendUrl = 'https://second.vidnest.fun'; async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promise<SourcererOutput> {
const query: Record<string, any> = {
type: ctx.media.type,
tmdbId: ctx.media.tmdbId,
};
const servers = ['hollymoviehd', 'allmovies']; if (ctx.media.type === 'show') {
query.season = ctx.media.season.number;
async function scrape(ctx: MovieScrapeContext | ShowScrapeContext, type: 'movie' | 'tv') { query.episode = ctx.media.episode.number;
const embeds = [];
for (const server of servers) {
let url = '';
if (type === 'movie') {
url = `${backendUrl}/${server}/movie/${ctx.media.tmdbId}`;
} else if (ctx.media.type === 'show') {
url = `${backendUrl}/${server}/tv/${ctx.media.tmdbId}/${ctx.media.season.number}/${ctx.media.episode.number}`;
}
embeds.push({
embedId: `vidnest-${server}`,
url,
});
} }
return { return {
embeds, embeds: [
{ embedId: 'vidnest-hollymoviehd', url: JSON.stringify(query) },
{ embedId: 'vidnest-allmovies', url: JSON.stringify(query) },
],
}; };
} }
@ -31,8 +24,7 @@ export const vidnestScraper = makeSourcerer({
id: 'vidnest', id: 'vidnest',
name: 'Vidnest', name: 'Vidnest',
rank: 115, rank: 115,
disabled: true,
flags: [], flags: [],
scrapeMovie: (ctx: MovieScrapeContext) => scrape(ctx, 'movie'), scrapeMovie: comboScraper,
scrapeShow: (ctx: ShowScrapeContext) => scrape(ctx, 'tv'), scrapeShow: comboScraper,
}); });