From f58438ba57bbbcebff990b18f2565784ceefc79a Mon Sep 17 00:00:00 2001 From: Pas <74743263+Pasithea0@users.noreply.github.com> Date: Mon, 3 Feb 2025 14:30:11 -0700 Subject: [PATCH] add psvl --- src/providers/all.ts | 2 + src/providers/sources/vidlink.ts | 64 ++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 src/providers/sources/vidlink.ts diff --git a/src/providers/all.ts b/src/providers/all.ts index d7a9c02..d435370 100644 --- a/src/providers/all.ts +++ b/src/providers/all.ts @@ -91,6 +91,7 @@ import { primewireScraper } from './sources/primewire'; import { ridooMoviesScraper } from './sources/ridomovies'; import { smashyStreamScraper } from './sources/smashystream'; import { soaperTvScraper } from './sources/soapertv'; +import { vidlinkScraper } from './sources/vidlink'; import { vidSrcToScraper } from './sources/vidsrcto'; import { warezcdnScraper } from './sources/warezcdn'; import { webtorScraper } from './sources/webtor'; @@ -132,6 +133,7 @@ export function gatherAllSources(): Array { mp4hydraScraper, webtorScraper, embedsuScraper, + vidlinkScraper, ]; } diff --git a/src/providers/sources/vidlink.ts b/src/providers/sources/vidlink.ts new file mode 100644 index 0000000..e27df46 --- /dev/null +++ b/src/providers/sources/vidlink.ts @@ -0,0 +1,64 @@ +/* eslint-disable no-console */ +import { flags } from '@/entrypoint/utils/targets'; +import { Caption, labelToLanguageCode } from '@/providers/captions'; +import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context'; +import { NotFoundError } from '@/utils/errors'; + +import { SourcererOutput, makeSourcerer } from '../base'; + +async function comboScraper(ctx: MovieScrapeContext | ShowScrapeContext): Promise { + const embedUrl = + ctx.media.type === 'movie' + ? `https://vidlink.pro/movie/${ctx.media.tmdbId}` + : `https://vidlink.pro/tv/${ctx.media.tmdbId}/${ctx.media.season.number}/${ctx.media.episode.number}`; + + const apiResponse = await ctx.proxiedFetcher<{ + results: Array<{ + video_urls: string[]; + subtitles: Array<{ label: string; file: string }>; + }>; + }>('https://psvl.api.pstream.org/api/video-url', { + query: { embedUrl }, + }); + + if (!apiResponse?.results?.length) throw new NotFoundError('No results found'); + const primaryResult = apiResponse.results[0]; + + if (!primaryResult.video_urls?.length) throw new NotFoundError('No video URLs found'); + + const captions: Caption[] = []; + for (const sub of primaryResult.subtitles) { + const language = labelToLanguageCode(sub.label.split('-')[0].trim()); + if (!language) continue; + + captions.push({ + id: sub.file, + url: sub.file, + type: 'vtt', + hasCorsRestrictions: false, + language, + }); + } + + return { + embeds: [], + stream: [ + { + id: 'primary', + playlist: primaryResult.video_urls[0], + type: 'hls', + flags: [flags.CORS_ALLOWED], + captions, + }, + ], + }; +} + +export const vidlinkScraper = makeSourcerer({ + id: 'vidlink', + name: 'PSVL', + rank: 113, + flags: [flags.CORS_ALLOWED], + scrapeMovie: comboScraper, + scrapeShow: comboScraper, +});