diff --git a/src/providers/all.ts b/src/providers/all.ts index ab82a2e..ee3c55f 100644 --- a/src/providers/all.ts +++ b/src/providers/all.ts @@ -45,12 +45,7 @@ import { supervideoScraper } from './embeds/supervideo'; import { vidCloudScraper } from './embeds/vidcloud'; import { vidhideEnglishScraper, vidhideLatinoScraper, vidhideSpanishScraper } from './embeds/vidhide'; import { vidifyEmbeds } from './embeds/vidify'; -import { - vidnestAllmoviesEmbed, - vidnestFlixhqEmbed, - vidnestHollymoviehdEmbed, - vidnestOfficialEmbed, -} from './embeds/vidnest'; +import { vidnestAllmoviesEmbed, vidnestHollymoviehdEmbed } from './embeds/vidnest'; import { VidsrcsuServer10Scraper, VidsrcsuServer11Scraper, @@ -200,8 +195,6 @@ export function gatherAllEmbeds(): Array { ...AnimetsuEmbeds, vidnestHollymoviehdEmbed, vidnestAllmoviesEmbed, - vidnestFlixhqEmbed, - vidnestOfficialEmbed, myanimesubScraper, myanimedubScraper, filemoonScraper, diff --git a/src/providers/embeds/vidnest.ts b/src/providers/embeds/vidnest.ts index c494839..f9e5654 100644 --- a/src/providers/embeds/vidnest.ts +++ b/src/providers/embeds/vidnest.ts @@ -2,28 +2,67 @@ import { flags } from '@/entrypoint/utils/targets'; import { makeEmbed } from '@/providers/base'; import { HlsBasedStream } from '@/providers/streams'; import { NotFoundError } from '@/utils/errors'; -import { createM3U8ProxyUrl } from '@/utils/proxy'; + +const PASSPHRASE = 'T8c8PQlSQVU4mBuW4CbE/g57VBbM5009QHd+ym93aZZ5pEeVpToY6OdpYPvRMVYp'; + +async function decryptVidnestData(encryptedBase64: string): Promise { + // Decode base64 to get encrypted bytes + const encryptedBytes = Uint8Array.from(atob(encryptedBase64), (c) => c.charCodeAt(0)); + + // Extract IV (first 12 bytes), ciphertext (middle), and auth tag (last 16 bytes) + const iv = encryptedBytes.slice(0, 12); + const ciphertext = encryptedBytes.slice(12, -16); + const tag = encryptedBytes.slice(-16); + + // Create key from passphrase (decode base64 first, then take first 32 bytes) + const keyData = Uint8Array.from(atob(PASSPHRASE), (c) => c.charCodeAt(0)).slice(0, 32); + const key = await crypto.subtle.importKey('raw', keyData, { name: 'AES-GCM' }, false, ['decrypt']); + + // Combine ciphertext and tag for decryption + const encrypted = new Uint8Array([...ciphertext, ...tag]); + + try { + const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, encrypted); + + const decryptedText = new TextDecoder().decode(decrypted); + return JSON.parse(decryptedText); + } catch (error) { + throw new NotFoundError('Failed to decrypt data'); + } +} export const vidnestHollymoviehdEmbed = makeEmbed({ id: 'vidnest-hollymoviehd', - name: 'HollyMovie', + name: 'Vidnest HollyMovie', rank: 104, - flags: [flags.CORS_ALLOWED], - disabled: true, + flags: [], + disabled: false, async scrape(ctx) { - const serverStreams = await ctx.proxiedFetcher(ctx.url); - if (!serverStreams.success || !serverStreams.sources) throw new NotFoundError('No streams found'); + const response = await ctx.proxiedFetcher(ctx.url); + if (!response.data) throw new NotFoundError('No encrypted data found'); + const decryptedData = await decryptVidnestData(response.data); + if (!decryptedData.success && !decryptedData.sources) throw new NotFoundError('No streams found'); + + const sources = decryptedData.sources || decryptedData.streams; const streams: HlsBasedStream[] = []; - for (const source of serverStreams.sources) { - if (source.file.includes('pkaystream.cc/pl/')) { + + const streamHeaders = { + Origin: 'https://flashstream.cc', + Referer: 'https://flashstream.cc/', + '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 (source.file && (source.file.includes('pkaystream.cc') || source.file.includes('flashstream.cc'))) { streams.push({ - id: `hollymoviehd-${source.label}`, + id: `hollymoviehd-${source.label || 'default'}`, type: 'hls', - playlist: createM3U8ProxyUrl(source.file, ctx.features), - headers: {}, - flags: [flags.CORS_ALLOWED], + playlist: source.file, + flags: [], captions: [], + headers: streamHeaders, } as HlsBasedStream); } } @@ -36,23 +75,28 @@ export const vidnestHollymoviehdEmbed = makeEmbed({ export const vidnestAllmoviesEmbed = makeEmbed({ id: 'vidnest-allmovies', - name: 'AllMovies (Hindi)', + name: 'Vidnest AllMovies (Hindi)', rank: 103, flags: [flags.CORS_ALLOWED], - disabled: true, + disabled: false, async scrape(ctx) { - const serverStreams = await ctx.proxiedFetcher(ctx.url); - if (!serverStreams.streams) throw new NotFoundError('No streams found'); + const response = await ctx.proxiedFetcher(ctx.url); + if (!response.data) throw new NotFoundError('No encrypted data found'); + const decryptedData = await decryptVidnestData(response.data); + if (!decryptedData.success && !decryptedData.streams) throw new NotFoundError('No streams found'); + + const sources = decryptedData.sources || decryptedData.streams; const streams = []; - for (const stream of serverStreams.streams) { + + for (const stream of sources) { streams.push({ - id: `allmovies-${stream.language}`, + id: `allmovies-${stream.language || 'default'}`, type: 'hls', - playlist: stream.url, + playlist: stream.url || stream.file, flags: [flags.CORS_ALLOWED], captions: [], - preferredHeaders: stream.headers, + preferredHeaders: stream.headers || {}, } as HlsBasedStream); } @@ -61,25 +105,3 @@ export const vidnestAllmoviesEmbed = makeEmbed({ }; }, }); - -export const vidnestFlixhqEmbed = makeEmbed({ - id: 'vidnest-flixhq', - name: 'FlixHQ', - rank: 102, - disabled: true, - flags: [flags.CORS_ALLOWED], - async scrape() { - throw new Error('Not implemented'); - }, -}); - -export const vidnestOfficialEmbed = makeEmbed({ - id: 'vidnest-official', - name: 'Official', - rank: 101, - disabled: true, - flags: [flags.CORS_ALLOWED], - async scrape() { - throw new Error('Not implemented'); - }, -}); diff --git a/src/providers/sources/vidnest.ts b/src/providers/sources/vidnest.ts index e0be184..fd45d92 100644 --- a/src/providers/sources/vidnest.ts +++ b/src/providers/sources/vidnest.ts @@ -2,9 +2,9 @@ import { flags } from '@/entrypoint/utils/targets'; import { makeSourcerer } from '@/providers/base'; import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context'; -const backendUrl = 'https://backend.vidnest.fun'; +const backendUrl = 'https://second.vidnest.fun'; -const servers = ['hollymoviehd', 'allmovies', 'flixhq', 'official']; +const servers = ['hollymoviehd', 'allmovies']; async function scrape(ctx: MovieScrapeContext | ShowScrapeContext, type: 'movie' | 'tv') { const embeds = []; @@ -32,7 +32,7 @@ const vidnestScraper = makeSourcerer({ id: 'vidnest', name: 'Vidnest', rank: 130, - disabled: true, + disabled: false, flags: [flags.CORS_ALLOWED], scrapeMovie: (ctx: MovieScrapeContext) => scrape(ctx, 'movie'), scrapeShow: (ctx: ShowScrapeContext) => scrape(ctx, 'tv'),