From 5735b4cd87b44c48baff979820dc10076c9fd8db Mon Sep 17 00:00:00 2001 From: TPN Date: Wed, 17 Jul 2024 12:35:03 +0100 Subject: [PATCH] Add moviplus source --- src/providers/all.ts | 2 + src/providers/sources/moviplus.ts | 94 +++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 src/providers/sources/moviplus.ts diff --git a/src/providers/all.ts b/src/providers/all.ts index ebaaebf..5172ee7 100644 --- a/src/providers/all.ts +++ b/src/providers/all.ts @@ -22,6 +22,7 @@ import { goMoviesScraper } from '@/providers/sources/gomovies/index'; import { insertunitScraper } from '@/providers/sources/insertunit'; import { kissAsianScraper } from '@/providers/sources/kissasian/index'; import { lookmovieScraper } from '@/providers/sources/lookmovie'; +import { moviplusScraper } from '@/providers/sources/moviplus'; import { nsbxScraper } from '@/providers/sources/nsbx'; import { remotestreamScraper } from '@/providers/sources/remotestream'; import { showboxScraper } from '@/providers/sources/showbox/index'; @@ -95,6 +96,7 @@ export function gatherAllSources(): Array { autoembedScraper, tugaflixScraper, ee3Scraper, + moviplusScraper, whvxScraper, ]; } diff --git a/src/providers/sources/moviplus.ts b/src/providers/sources/moviplus.ts new file mode 100644 index 0000000..4bf5b4d --- /dev/null +++ b/src/providers/sources/moviplus.ts @@ -0,0 +1,94 @@ +// todo: tv shows +// I just forgot about tv shows +// and they are gonna need a lot of season and episode parsing +// and i dont feel like doing that now +import { load } from 'cheerio'; + +import { SourcererEmbed, SourcererOutput, makeSourcerer } from '@/providers/base'; +import { compareMedia } from '@/utils/compare'; +import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context'; +import { NotFoundError } from '@/utils/errors'; + +const baseUrl = 'https://moviplus.net'; + +async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promise { + const searchPage = await ctx.proxiedFetcher('/', { + baseUrl, + query: { + s: ctx.media.title, + }, + }); + + const search$ = load(searchPage); + const searchResults: { title: string; year?: number; id: string }[] = []; + + search$('.item-box').each((_, element) => { + const [, title, year] = + search$(element) + .find('a') + .attr('title') + ?.match(/^(.*?)\s*(?:\(?\s*(\d{4})(?:\s*-\s*\d{0,4})?\s*\)?)?\s*$/) || []; + const id = search$(element).find('span').first().attr('data-itemid'); + if (!title || !id) return; + + searchResults.push({ title, year: year ? Number(year) : undefined, id }); + }); + + const id = searchResults.find((x) => x && compareMedia(ctx.media, x.title, x.year))?.id; + if (!id) throw new NotFoundError('No watchable item found'); + + const apiRes: { embed_url: string } = await ctx.proxiedFetcher('/wp-admin/admin-ajax.php', { + baseUrl, + method: 'POST', + body: new URLSearchParams({ + action: 'zeta_player_ajax', + post: id, + nume: '1', + type: 'mv', + }), + }); + if (!apiRes.embed_url) throw new Error('No sources found'); + + const iframeUrl = load(apiRes.embed_url)('iframe').attr('src'); + if (!iframeUrl) throw new Error('iFrame Url not found'); + + const iframePage$ = load(await ctx.proxiedFetcher(iframeUrl)); + + const links: string[] = []; + iframePage$('.dropdown-item').each((_, element) => { + const link = iframePage$(element).attr('href'); + if (link?.startsWith('https:')) links.push(link); + }); + + const embeds: SourcererEmbed[] = []; + + for (const url of links) { + if (links.includes(url)) { + const origin = new URL(url).hostname; + + let embedId; + switch (origin) { + case 'vidker.com': + embedId = 'vidker'; + break; + default: + embedId = undefined; + } + + if (!embedId) continue; + embeds.push({ embedId, url }); + } + } + + return { + embeds, + }; +} + +export const moviplusScraper = makeSourcerer({ + id: 'moviplus', + name: 'MoviPlus', + rank: 92, + flags: [], + scrapeMovie: comboScraper, +});