From 921c35b3ed0221ffcd55560b73429d0ce2a5d5f1 Mon Sep 17 00:00:00 2001 From: teddyHV11 Date: Tue, 9 Apr 2024 07:16:41 +0300 Subject: [PATCH] Add caption scraping + types --- src/providers/all.ts | 2 +- src/providers/sources/insertunit.ts | 74 --------- .../sources/insertunit/insertunit.ts | 147 ++++++++++++++++++ src/providers/sources/insertunit/types.ts | 30 ++++ 4 files changed, 178 insertions(+), 75 deletions(-) delete mode 100644 src/providers/sources/insertunit.ts create mode 100644 src/providers/sources/insertunit/insertunit.ts create mode 100644 src/providers/sources/insertunit/types.ts diff --git a/src/providers/all.ts b/src/providers/all.ts index 887290d..675aa36 100644 --- a/src/providers/all.ts +++ b/src/providers/all.ts @@ -14,7 +14,7 @@ import { vidsrcembedScraper } from '@/providers/embeds/vidsrc'; import { vTubeScraper } from '@/providers/embeds/vtube'; import { flixhqScraper } from '@/providers/sources/flixhq/index'; import { goMoviesScraper } from '@/providers/sources/gomovies/index'; -import { insertunitScraper } from '@/providers/sources/insertunit'; +import { insertunitScraper } from '@/providers/sources/insertunit/insertunit'; import { kissAsianScraper } from '@/providers/sources/kissasian/index'; import { lookmovieScraper } from '@/providers/sources/lookmovie'; import { remotestreamScraper } from '@/providers/sources/remotestream'; diff --git a/src/providers/sources/insertunit.ts b/src/providers/sources/insertunit.ts deleted file mode 100644 index 4dd9795..0000000 --- a/src/providers/sources/insertunit.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { flags } from '@/entrypoint/utils/targets'; -import { makeSourcerer } from '@/providers/base'; -import { NotFoundError } from '@/utils/errors'; - -const insertunitbase = 'https://api.insertunit.ws/'; - -export const insertunitScraper = makeSourcerer({ - id: 'insertunit', - name: 'Insertunit', - disabled: false, - rank: 60, - flags: [flags.CORS_ALLOWED], - async scrapeShow(ctx) { - const playerData = await ctx.fetcher(`${insertunitbase}/embed/imdb/${ctx.media.imdbId}`); - ctx.progress(30); - - const seasonDataJSONregex = /seasons:(.*)/; - const seasonData = seasonDataJSONregex.exec(playerData); - - if (seasonData === null || seasonData[1] === null) { - throw new NotFoundError('No result found'); - } - ctx.progress(60); - - const seasonTable = JSON.parse(seasonData[1]); - for (const seasonElement of seasonTable) { - if (seasonElement.season === ctx.media.season.number) { - for (const episodeElement of seasonElement.episodes) { - if (episodeElement.episode.includes(ctx.media.episode.number)) { - return { - embeds: [], - stream: [ - { - id: 'primary', - captions: [], - playlist: episodeElement.hls, - type: 'hls', - flags: [flags.CORS_ALLOWED], - }, - ], - }; - } - } - } - } - - throw new NotFoundError('No result found'); - }, - async scrapeMovie(ctx) { - const playerData = await ctx.fetcher(`${insertunitbase}/embed/imdb/${ctx.media.imdbId}`); - ctx.progress(50); - - const streamRegex = /hls: "([^"]*)/; - const streamData = streamRegex.exec(playerData); - - if (streamData === null || streamData[1] === null) { - throw new NotFoundError('No result found'); - } - ctx.progress(90); - - return { - embeds: [], - stream: [ - { - id: 'primary', - type: 'hls', - playlist: streamData[1], - flags: [flags.CORS_ALLOWED], - captions: [], - }, - ], - }; - }, -}); diff --git a/src/providers/sources/insertunit/insertunit.ts b/src/providers/sources/insertunit/insertunit.ts new file mode 100644 index 0000000..5c89663 --- /dev/null +++ b/src/providers/sources/insertunit/insertunit.ts @@ -0,0 +1,147 @@ +import { flags } from '@/entrypoint/utils/targets'; +import { makeSourcerer } from '@/providers/base'; +import { Caption, removeDuplicatedLanguages } from '@/providers/captions'; +import { NotFoundError } from '@/utils/errors'; + +import { Season, Subtitle } from './types'; + +const insertUnitBase = 'https://api.insertunit.ws/'; + +export const insertunitScraper = makeSourcerer({ + id: 'insertunit', + name: 'Insertunit', + disabled: false, + rank: 60, + flags: [flags.CORS_ALLOWED], + async scrapeShow(ctx) { + const playerData = await ctx.fetcher(`/embed/imdb/${ctx.media.imdbId}`, { + baseUrl: insertUnitBase, + }); + ctx.progress(30); + + const seasonDataJSONregex = /seasons:(.*)/; + const seasonData = seasonDataJSONregex.exec(playerData); + + if (seasonData === null || seasonData[1] === null) { + throw new NotFoundError('No result found'); + } + ctx.progress(60); + + const seasonTable: Season[] = JSON.parse(seasonData[1]) as Season[]; + + const currentSeason = seasonTable.find( + (seasonElement) => seasonElement.season === ctx.media.season.number && !seasonElement.blocked, + ); + + const currentEpisode = currentSeason?.episodes.find((episodeElement) => + episodeElement.episode.includes(ctx.media.episode.number.toString()), + ); + + if (!currentEpisode?.hls) throw new NotFoundError('No result found'); + + let captions: Caption[] = []; + + ctx.progress(80); + + if (currentEpisode.cc != null) { + let subtitle: Subtitle; + for (subtitle of currentEpisode.cc) { + let language = ''; + + if (subtitle.name.includes('Рус')) { + language = 'ru'; + } else if (subtitle.name.includes('Укр')) { + language = 'uk'; + } else if (subtitle.name.includes('Eng')) { + language = 'en'; + } else { + continue; + } + + captions.push({ + id: subtitle.url, + url: subtitle.url, + type: 'vtt', + language, + hasCorsRestrictions: false, + }); + } + captions = removeDuplicatedLanguages(captions); + } + + ctx.progress(95); + + return { + embeds: [], + stream: [ + { + id: 'primary', + playlist: currentEpisode.hls, + type: 'hls', + flags: [flags.CORS_ALLOWED], + captions, + }, + ], + }; + }, + async scrapeMovie(ctx) { + const playerData = await ctx.fetcher(`/embed/imdb/${ctx.media.imdbId}`, { + baseUrl: insertUnitBase, + }); + ctx.progress(35); + + const streamRegex = /hls: "([^"]*)/; + const streamData = streamRegex.exec(playerData); + + if (streamData === null || streamData[1] === null) { + throw new NotFoundError('No result found'); + } + ctx.progress(75); + + const subtitleRegex = /cc: (.*)/; + const subtitleJSONData = subtitleRegex.exec(playerData); + + let captions: Caption[] = []; + + if (subtitleJSONData != null && subtitleJSONData[1] != null) { + const subtitleData = JSON.parse(subtitleJSONData[1]); + let subtitle: Subtitle; + for (subtitle of subtitleData as Subtitle[]) { + let language = ''; + + if (subtitle.name.includes('Рус')) { + language = 'ru'; + } else if (subtitle.name.includes('Укр')) { + language = 'uk'; + } else if (subtitle.name.includes('Eng')) { + language = 'en'; + } else { + continue; + } + + captions.push({ + id: subtitle.url, + url: subtitle.url, + type: 'vtt', + language, + hasCorsRestrictions: false, + }); + } + captions = removeDuplicatedLanguages(captions); + } + + + return { + embeds: [], + stream: [ + { + id: 'primary', + type: 'hls', + playlist: streamData[1], + flags: [flags.CORS_ALLOWED], + captions, + }, + ], + }; + }, +}); diff --git a/src/providers/sources/insertunit/types.ts b/src/providers/sources/insertunit/types.ts new file mode 100644 index 0000000..0649275 --- /dev/null +++ b/src/providers/sources/insertunit/types.ts @@ -0,0 +1,30 @@ +export interface Episode { + episode: string; + id: number; + videoKey: string; + hls: string; + audio: { + names: []; + order: []; + } + cc: [] + duration: number; + title: string; + download: string; + sections: [] + poster: string; + preview: { + src: string; + } +} + +export interface Subtitle { + url: string; + name: string; +} + +export interface Season { + season: number, + blocked: boolean, + episodes: Episode[] +} \ No newline at end of file