diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d0f0ca6..7458772 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1 @@ -* @movie-web/core - -.github @binaryoverload +* @movie-web/project-leads diff --git a/package.json b/package.json index 4b91441..890aa50 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@movie-web/providers", - "version": "2.0.1", + "version": "2.0.2", "description": "Package that contains all the providers of movie-web", "main": "./lib/index.umd.js", "types": "./lib/index.d.ts", diff --git a/src/dev-cli/validate.ts b/src/dev-cli/validate.ts index b600454..dd1f638 100644 --- a/src/dev-cli/validate.ts +++ b/src/dev-cli/validate.ts @@ -81,6 +81,7 @@ export async function processOptions(sources: Array, options: const providerOptions: ProviderMakerOptions = { fetcher, target: targets.ANY, + consistentIpForRequests: true, }; return { diff --git a/src/entrypoint/providers.ts b/src/entrypoint/providers.ts index b306417..e456eb0 100644 --- a/src/entrypoint/providers.ts +++ b/src/entrypoint/providers.ts @@ -2,9 +2,9 @@ import { gatherAllEmbeds, gatherAllSources } from '@/providers/all'; import { Embed, Sourcerer } from '@/providers/base'; export function getBuiltinSources(): Sourcerer[] { - return gatherAllSources(); + return gatherAllSources().filter((v) => !v.disabled); } export function getBuiltinEmbeds(): Embed[] { - return gatherAllEmbeds(); + return gatherAllEmbeds().filter((v) => !v.disabled); } diff --git a/src/providers/embeds/febbox/hls.ts b/src/providers/embeds/febbox/hls.ts index d9fa54f..792c112 100644 --- a/src/providers/embeds/febbox/hls.ts +++ b/src/providers/embeds/febbox/hls.ts @@ -1,5 +1,4 @@ import { MediaTypes } from '@/entrypoint/utils/media'; -import { flags } from '@/entrypoint/utils/targets'; import { makeEmbed } from '@/providers/base'; import { parseInputUrl } from '@/providers/embeds/febbox/common'; import { getStreams } from '@/providers/embeds/febbox/fileList'; @@ -16,6 +15,7 @@ export const febboxHlsScraper = makeEmbed({ id: 'febbox-hls', name: 'Febbox (HLS)', rank: 160, + disabled: true, async scrape(ctx) { const { type, id, season, episode } = parseInputUrl(ctx.url); const sharelinkResult = await ctx.proxiedFetcher<{ @@ -40,7 +40,7 @@ export const febboxHlsScraper = makeEmbed({ { id: 'primary', type: 'hls', - flags: [flags.CORS_ALLOWED], + flags: [], captions: await getSubtitles(ctx, id, firstStream.fid, type as MediaTypes, season, episode), playlist: `https://www.febbox.com/hls/main/${firstStream.oss_fid}.m3u8`, }, diff --git a/src/providers/embeds/febbox/subtitles.ts b/src/providers/embeds/febbox/subtitles.ts index b1b3064..70a94cb 100644 --- a/src/providers/embeds/febbox/subtitles.ts +++ b/src/providers/embeds/febbox/subtitles.ts @@ -37,22 +37,28 @@ export async function getSubtitles( const subResult = (await sendRequest(ctx, subtitleApiQuery)) as CaptionApiResponse; const subtitleList = subResult.data.list; const output: Caption[] = []; + const languagesAdded: Record = {}; subtitleList.forEach((sub) => { const subtitle = sub.subtitles.sort((a, b) => b.order - a.order)[0]; if (!subtitle) return; + const subtitleFilePath = subtitle.file_path .replace(captionsDomains[0], captionsDomains[1]) .replace(/\s/g, '+') .replace(/[()]/g, (c) => { return `%${c.charCodeAt(0).toString(16)}`; }); + const subtitleType = getCaptionTypeFromUrl(subtitleFilePath); if (!subtitleType) return; const validCode = isValidLanguageCode(subtitle.lang); if (!validCode) return; + if (languagesAdded[subtitle.lang]) return; + languagesAdded[subtitle.lang] = true; + output.push({ id: subtitleFilePath, language: subtitle.lang, diff --git a/src/providers/sources/lookmovie/index.ts b/src/providers/sources/lookmovie/index.ts index 5cd82e9..73226dc 100644 --- a/src/providers/sources/lookmovie/index.ts +++ b/src/providers/sources/lookmovie/index.ts @@ -10,8 +10,8 @@ async function universalScraper(ctx: MovieScrapeContext | ShowScrapeContext): Pr if (!lookmovieData) throw new NotFoundError('Media not found'); ctx.progress(30); - const videoUrl = await scrape(ctx, ctx.media, lookmovieData); - if (!videoUrl) throw new NotFoundError('No video found'); + const video = await scrape(ctx, ctx.media, lookmovieData); + if (!video.playlist) throw new NotFoundError('No video found'); ctx.progress(60); @@ -20,10 +20,10 @@ async function universalScraper(ctx: MovieScrapeContext | ShowScrapeContext): Pr stream: [ { id: 'primary', - playlist: videoUrl, + playlist: video.playlist, type: 'hls', flags: [flags.IP_LOCKED], - captions: [], + captions: video.captions, }, ], }; @@ -33,6 +33,7 @@ export const lookmovieScraper = makeSourcerer({ id: 'lookmovie', name: 'LookMovie', rank: 1, + disabled: true, flags: [flags.IP_LOCKED], scrapeShow: universalScraper, scrapeMovie: universalScraper, diff --git a/src/providers/sources/lookmovie/type.ts b/src/providers/sources/lookmovie/type.ts index 8335c96..47ccc55 100644 --- a/src/providers/sources/lookmovie/type.ts +++ b/src/providers/sources/lookmovie/type.ts @@ -39,8 +39,17 @@ interface VideoSources { [key: string]: string; } +interface VideoSubtitles { + id?: number; + id_movie?: number; + url: string; + language: string; + shard?: string; +} + export interface StreamsDataResult { streams: VideoSources; + subtitles: VideoSubtitles[]; } export interface ResultItem { diff --git a/src/providers/sources/lookmovie/util.ts b/src/providers/sources/lookmovie/util.ts index 7c8f202..6057f76 100644 --- a/src/providers/sources/lookmovie/util.ts +++ b/src/providers/sources/lookmovie/util.ts @@ -4,7 +4,9 @@ import { ScrapeContext } from '@/utils/context'; import { NotFoundError } from '@/utils/errors'; import { Result, ResultItem, ShowDataResult, episodeObj } from './type'; -import { getVideoUrl } from './video'; +import { getVideo } from './video'; + +export const baseUrl = 'https://lmscript.xyz'; export async function searchAndFindMedia( ctx: ScrapeContext, @@ -12,7 +14,7 @@ export async function searchAndFindMedia( ): Promise { if (media.type === 'show') { const searchRes = await ctx.fetcher(`/v1/shows`, { - baseUrl: 'https://lmscript.xyz', + baseUrl, query: { 'filters[q]': media.title }, }); @@ -23,7 +25,7 @@ export async function searchAndFindMedia( } if (media.type === 'movie') { const searchRes = await ctx.fetcher(`/v1/movies`, { - baseUrl: 'https://lmscript.xyz', + baseUrl, query: { 'filters[q]': media.title }, }); @@ -40,7 +42,7 @@ export async function scrape(ctx: ScrapeContext, media: MovieMedia | ShowMedia, id = result.id_movie; } else if (media.type === 'show') { const data = await ctx.fetcher(`/v1/shows`, { - baseUrl: 'https://lmscript.xyz', + baseUrl, query: { expand: 'episodes', id: result.id_show }, }); @@ -54,6 +56,6 @@ export async function scrape(ctx: ScrapeContext, media: MovieMedia | ShowMedia, // Check ID if (id === null) throw new NotFoundError('Not found'); - const videoUrl = await getVideoUrl(ctx, id, media); - return videoUrl; + const video = await getVideo(ctx, id, media); + return video; } diff --git a/src/providers/sources/lookmovie/video.ts b/src/providers/sources/lookmovie/video.ts index f439229..48bcafc 100644 --- a/src/providers/sources/lookmovie/video.ts +++ b/src/providers/sources/lookmovie/video.ts @@ -1,7 +1,9 @@ import { MovieMedia, ShowMedia } from '@/entrypoint/utils/media'; +import { Caption } from '@/providers/captions'; import { ScrapeContext } from '@/utils/context'; import { StreamsDataResult } from './type'; +import { baseUrl } from './util'; export async function getVideoSources( ctx: ScrapeContext, @@ -17,17 +19,17 @@ export async function getVideoSources( path = `/v1/movies/view`; } const data = await ctx.fetcher(path, { - baseUrl: 'https://lmscript.xyz', - query: { expand: 'streams', id }, + baseUrl, + query: { expand: 'streams,subtitles', id }, }); return data; } -export async function getVideoUrl( +export async function getVideo( ctx: ScrapeContext, id: string, media: MovieMedia | ShowMedia, -): Promise { +): Promise<{ playlist: string | null; captions: Caption[] }> { // Get sources const data = await getVideoSources(ctx, id, media); const videoSources = data.streams; @@ -42,5 +44,16 @@ export async function getVideoUrl( } } - return videoUrl; + const captions: Caption[] = data.subtitles.map((sub) => ({ + id: sub.url, + type: 'vtt', + url: `${baseUrl}${sub.url}`, + hasCorsRestrictions: false, + language: sub.language, + })); + + return { + playlist: videoUrl, + captions, + }; }