From ec6524389c317a29a6a8e796ff6d5052fd55a487 Mon Sep 17 00:00:00 2001 From: Jorrin Date: Wed, 10 Apr 2024 22:40:55 +0200 Subject: [PATCH 1/4] add soapertv source --- src/providers/all.ts | 2 + src/providers/sources/soapertv/index.ts | 120 ++++++++++++++++++++++++ src/providers/sources/soapertv/types.ts | 15 +++ 3 files changed, 137 insertions(+) create mode 100644 src/providers/sources/soapertv/index.ts create mode 100644 src/providers/sources/soapertv/types.ts diff --git a/src/providers/all.ts b/src/providers/all.ts index 63be995..d91af17 100644 --- a/src/providers/all.ts +++ b/src/providers/all.ts @@ -38,6 +38,7 @@ import { nepuScraper } from './sources/nepu'; import { primewireScraper } from './sources/primewire'; import { ridooMoviesScraper } from './sources/ridomovies'; import { smashyStreamScraper } from './sources/smashystream'; +import { soaperTvScraper } from './sources/soapertv'; import { vidSrcToScraper } from './sources/vidsrcto'; export function gatherAllSources(): Array { @@ -58,6 +59,7 @@ export function gatherAllSources(): Array { goojaraScraper, hdRezkaScraper, primewireScraper, + soaperTvScraper, ]; } diff --git a/src/providers/sources/soapertv/index.ts b/src/providers/sources/soapertv/index.ts new file mode 100644 index 0000000..feee555 --- /dev/null +++ b/src/providers/sources/soapertv/index.ts @@ -0,0 +1,120 @@ +import { load } from 'cheerio'; + +import { flags } from '@/entrypoint/utils/targets'; +import { Caption, labelToLanguageCode } from '@/providers/captions'; +import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context'; +import { NotFoundError } from '@/utils/errors'; + +import { InfoResponse } from './types'; +import { SourcererOutput, makeSourcerer } from '../../base'; + +const baseUrl = 'https://soaper.tv'; + +const universalScraper = async (ctx: MovieScrapeContext | ShowScrapeContext): Promise => { + const searchResult = await ctx.proxiedFetcher('/search.html', { + baseUrl, + query: { + keyword: ctx.media.title, + }, + }); + const searchResult$ = load(searchResult); + let showLink = searchResult$('a') + .filter((_, el) => searchResult$(el).text() === ctx.media.title) + .attr('href'); + if (!showLink) throw new NotFoundError('Content not found'); + + if (ctx.media.type === 'show') { + const seasonNumber = ctx.media.season.number; + const episodeNumber = ctx.media.episode.number; + const showPage = await ctx.proxiedFetcher(showLink, { baseUrl }); + const showPage$ = load(showPage); + const seasonBlock = showPage$('h4') + .filter((_, el) => showPage$(el).text().trim().split(':')[0].trim() === `Season${seasonNumber}`) + .parent(); + const episodes = seasonBlock.find('a').toArray(); + showLink = showPage$( + episodes.find((el) => parseInt(showPage$(el).text().split('.')[0], 10) === episodeNumber), + ).attr('href'); + } + if (!showLink) throw new NotFoundError('Content not found'); + const contentPage = await ctx.proxiedFetcher(showLink, { baseUrl }); + const contentPage$ = load(contentPage); + + const pass = contentPage$('#hId').attr('value'); + const param = contentPage$('#divU').text(); + + if (!pass || !param) throw new NotFoundError('Content not found'); + + const formData = new URLSearchParams(); + formData.append('pass', pass); + formData.append('param', param); + formData.append('e2', '0'); + formData.append('server', '0'); + + const infoEndpoint = ctx.media.type === 'show' ? '/home/index/getEInfoAjax' : '/home/index/getMInfoAjax'; + const streamRes = await ctx.proxiedFetcher(infoEndpoint, { + baseUrl, + method: 'POST', + body: formData, + headers: { + referer: `${baseUrl}${showLink}`, + }, + }); + + const streamResJson: InfoResponse = JSON.parse(streamRes); + + const captions: Caption[] = []; + for (const sub of streamResJson.subs) { + // Some subtitles are named .srt, some are named :hi, or just + let language: string | null = ''; + if (sub.name.includes('.srt')) { + language = labelToLanguageCode(sub.name.split('.srt')[0]); + } else if (sub.name.includes(':')) { + language = sub.name.split(':')[0]; + } else { + language = sub.name; + } + if (!language) continue; + + captions.push({ + id: sub.path, + url: sub.path, + type: 'srt', + hasCorsRestrictions: false, + language, + }); + } + + return { + embeds: [], + stream: [ + { + id: 'primary', + playlist: streamResJson.val, + type: 'hls', + flags: [flags.IP_LOCKED], + captions, + }, + ...(streamResJson.val_bak + ? [ + { + id: 'backup', + playlist: streamResJson.val_bak, + type: 'hls' as const, + flags: [flags.IP_LOCKED], + captions, + }, + ] + : []), + ], + }; +}; + +export const soaperTvScraper = makeSourcerer({ + id: 'soapertv', + name: 'SoaperTV', + rank: 115, + flags: [flags.IP_LOCKED], + scrapeMovie: universalScraper, + scrapeShow: universalScraper, +}); diff --git a/src/providers/sources/soapertv/types.ts b/src/providers/sources/soapertv/types.ts new file mode 100644 index 0000000..70fb602 --- /dev/null +++ b/src/providers/sources/soapertv/types.ts @@ -0,0 +1,15 @@ +export interface Subtitle { + path: string; + name: string; +} + +export interface InfoResponse { + key: boolean; + val: string; + vtt: string; + val_bak: string; + pos: number; + type: string; + subs: Subtitle[]; + ip: string; +} From 9e06035e27ca6724b76755993271e5761c282950 Mon Sep 17 00:00:00 2001 From: Ciarands <74070993+Ciarands@users.noreply.github.com> Date: Thu, 11 Apr 2024 12:03:04 +0100 Subject: [PATCH 2/4] Update RCP base url --- src/providers/sources/vidsrc/common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/providers/sources/vidsrc/common.ts b/src/providers/sources/vidsrc/common.ts index 4ccc93c..6f6fd71 100644 --- a/src/providers/sources/vidsrc/common.ts +++ b/src/providers/sources/vidsrc/common.ts @@ -1,2 +1,2 @@ export const vidsrcBase = 'https://vidsrc.me'; -export const vidsrcRCPBase = 'https://rcp.vidsrc.me'; +export const vidsrcRCPBase = 'https://vidsrc.stream'; From 125021e4325d6c86ff2883a6b155b8e95de4eacb Mon Sep 17 00:00:00 2001 From: Ciarands <74070993+Ciarands@users.noreply.github.com> Date: Thu, 11 Apr 2024 12:08:03 +0100 Subject: [PATCH 3/4] remove CORS_ALLOWED flag --- src/providers/sources/vidsrc/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/providers/sources/vidsrc/index.ts b/src/providers/sources/vidsrc/index.ts index d6b15a8..3046fb8 100644 --- a/src/providers/sources/vidsrc/index.ts +++ b/src/providers/sources/vidsrc/index.ts @@ -1,4 +1,3 @@ -import { flags } from '@/entrypoint/utils/targets'; import { makeSourcerer } from '@/providers/base'; import { scrapeMovie } from '@/providers/sources/vidsrc/scrape-movie'; import { scrapeShow } from '@/providers/sources/vidsrc/scrape-show'; @@ -7,7 +6,7 @@ export const vidsrcScraper = makeSourcerer({ id: 'vidsrc', name: 'VidSrc', rank: 90, - flags: [flags.CORS_ALLOWED], + flags: [], scrapeMovie, scrapeShow, }); From 61952b0e87f0ca67f6ed1f32d7514aa0e2f2bd52 Mon Sep 17 00:00:00 2001 From: Ciarands <74070993+Ciarands@users.noreply.github.com> Date: Thu, 11 Apr 2024 12:08:31 +0100 Subject: [PATCH 4/4] Remove CORS_ALLOWED flag and add headers --- src/providers/embeds/vidsrc.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/providers/embeds/vidsrc.ts b/src/providers/embeds/vidsrc.ts index ae945d2..716c82c 100644 --- a/src/providers/embeds/vidsrc.ts +++ b/src/providers/embeds/vidsrc.ts @@ -1,5 +1,5 @@ -import { flags } from '@/entrypoint/utils/targets'; import { makeEmbed } from '@/providers/base'; +import { vidsrcRCPBase } from '@/providers/sources/vidsrc/common'; const hlsURLRegex = /file:"(.*?)"/; const setPassRegex = /var pass_path = "(.*set_pass\.php.*)";/; @@ -56,7 +56,11 @@ export const vidsrcembedScraper = makeEmbed({ id: 'primary', type: 'hls', playlist: finalUrl, - flags: [flags.CORS_ALLOWED], + headers: { + Referer: vidsrcRCPBase, + Origin: vidsrcRCPBase, + }, + flags: [], captions: [], }, ],