diff --git a/src/providers/all.ts b/src/providers/all.ts index 2056faa..f86a554 100644 --- a/src/providers/all.ts +++ b/src/providers/all.ts @@ -23,6 +23,7 @@ import { tugaflixScraper } from '@/providers/sources/tugaflix'; import { vidsrcScraper } from '@/providers/sources/vidsrc/index'; import { zoechipScraper } from '@/providers/sources/zoechip'; +import { bflixScraper } from './embeds/bflix'; import { closeLoadScraper } from './embeds/closeload'; import { fileMoonScraper } from './embeds/filemoon'; import { ridooScraper } from './embeds/ridoo'; @@ -39,6 +40,7 @@ import { wootlyScraper } from './embeds/wootly'; import { goojaraScraper } from './sources/goojara'; import { hdRezkaScraper } from './sources/hdrezka'; import { nepuScraper } from './sources/nepu'; +import { nitesScraper } from './sources/nites'; import { primewireScraper } from './sources/primewire'; import { ridooMoviesScraper } from './sources/ridomovies'; import { smashyStreamScraper } from './sources/smashystream'; @@ -66,6 +68,7 @@ export function gatherAllSources(): Array { primewireScraper, warezcdnScraper, insertunitScraper, + nitesScraper, soaperTvScraper, tugaflixScraper, ]; @@ -100,5 +103,6 @@ export function gatherAllEmbeds(): Array { vTubeScraper, warezcdnembedHlsScraper, warezcdnembedMp4Scraper, + bflixScraper, ]; } diff --git a/src/providers/embeds/bflix.ts b/src/providers/embeds/bflix.ts new file mode 100644 index 0000000..092bc2a --- /dev/null +++ b/src/providers/embeds/bflix.ts @@ -0,0 +1,42 @@ +import { unpack } from 'unpacker'; + +import { makeEmbed } from '@/providers/base'; + +const evalCodeRegex = /eval\((.*)\)/g; +const mp4Regex = /https?:\/\/.*\.mp4/; + +export const bflixScraper = makeEmbed({ + id: 'bflix', + name: 'bFlix', + rank: 113, + scrape: async (ctx) => { + const mainPage = await ctx.proxiedFetcher(ctx.url); + + const evalCode = mainPage.match(evalCodeRegex); + if (!evalCode) throw new Error('Failed to find eval code'); + const unpacked = unpack(evalCode[0]); + + const file = unpacked.match(mp4Regex); + if (!file?.[0]) throw new Error('Failed to find file'); + + return { + stream: [ + { + id: 'primary', + type: 'file', + flags: [], + captions: [], + qualities: { + unknown: { + type: 'mp4', + url: file[0], + }, + }, + headers: { + Referer: 'https://bflix.gs/', + }, + }, + ], + }; + }, +}); diff --git a/src/providers/sources/nites.ts b/src/providers/sources/nites.ts new file mode 100644 index 0000000..4a3570a --- /dev/null +++ b/src/providers/sources/nites.ts @@ -0,0 +1,79 @@ +import { load } from 'cheerio'; + +import { SourcererOutput, makeSourcerer } from '@/providers/base'; +import { compareMedia } from '@/utils/compare'; +import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context'; +import { NotFoundError } from '@/utils/errors'; + +const baseUrl = 'https://w1.nites.is'; + +async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promise { + const searchPage = await ctx.proxiedFetcher('/wp-admin/admin-ajax.php', { + baseUrl, + method: 'POST', + body: new URLSearchParams({ + action: 'ajax_pagination', + query_vars: 'mixed', + search: ctx.media.title, + }), + }); + + const $search = load(searchPage); + const searchResults: { title: string; year: number; url: string }[] = []; + + $search('li').each((_, element) => { + const title = $search(element).find('.entry-title').first().text().trim(); + const year = parseInt($search(element).find('.year').first().text().trim(), 10); + const url = $search(element).find('.lnk-blk').attr('href'); + if (!title || !year || !url) return; + + searchResults.push({ title, year, url }); + }); + + let watchPageUrl = searchResults.find((x) => x && compareMedia(ctx.media, x.title, x.year))?.url; + if (!watchPageUrl) throw new NotFoundError('No watchable item found'); + + if (ctx.media.type === 'show') { + const match = watchPageUrl.match(/\/series\/([^/]+)\/?/); + if (!match) throw new Error('Failed to parse watch page url'); + watchPageUrl = watchPageUrl.replace( + `/series/${match[1]}`, + `/episode/${match[1]}-${ctx.media.season.number}x${ctx.media.episode.number}`, + ); + } + + const watchPage = load(await ctx.proxiedFetcher(watchPageUrl)); + + // it embeds vidsrc when it bflix does not has the stream + // i think all shows embed vidsrc, not sure + const embedUrl = watchPage('ul.bx-lst li a:contains("- Bflix")') + .closest('aside') + .next('div.video-options') + .find('iframe') + .attr('data-lazy-src'); + + if (!embedUrl) throw new Error('Failed to find embed url'); + + const embedPage = load(await ctx.proxiedFetcher(embedUrl)); + + const url = embedPage('iframe').attr('src'); + if (!url) throw new Error('Failed to find embed url'); + + return { + embeds: [ + { + embedId: 'bflix', + url, + }, + ], + }; +} + +export const nitesScraper = makeSourcerer({ + id: 'nites', + name: 'Nites', + rank: 90, + flags: [], + scrapeMovie: comboScraper, + scrapeShow: comboScraper, +});