From 32c656cee957fc81a8332d2b4bed21a71a7a6e15 Mon Sep 17 00:00:00 2001 From: Pas <74743263+Pasithea0@users.noreply.github.com> Date: Wed, 21 May 2025 18:28:28 -0600 Subject: [PATCH] add cinemaos --- src/providers/all.ts | 4 ++ src/providers/embeds/cinemaos.ts | 90 +++++++++++++++++++++++++++++++ src/providers/sources/cinemaos.ts | 72 +++++++++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 src/providers/embeds/cinemaos.ts create mode 100644 src/providers/sources/cinemaos.ts diff --git a/src/providers/all.ts b/src/providers/all.ts index a3eb05e..0d76f17 100644 --- a/src/providers/all.ts +++ b/src/providers/all.ts @@ -37,6 +37,7 @@ import { autoembedTamilScraper, autoembedTeluguScraper, } from './embeds/autoembed'; +import { cinemaosEmbeds } from './embeds/cinemaos'; import { closeLoadScraper } from './embeds/closeload'; import { ConsumetStreamSBScraper, @@ -88,6 +89,7 @@ import { import { oneServerScraper } from './sources/1server'; import { EightStreamScraper } from './sources/8stream'; import { animeflvScraper } from './sources/animeflv'; +import { cinemaosScraper } from './sources/cinemaos'; import { coitusScraper } from './sources/coitus'; import { ConsumetScraper } from './sources/consumet'; import { cuevana3Scraper } from './sources/cuevana3'; @@ -142,6 +144,7 @@ export function gatherAllSources(): Array { oneServerScraper, wecimaScraper, animeflvScraper, + cinemaosScraper, ]; } @@ -216,5 +219,6 @@ export function gatherAllEmbeds(): Array { streamwishSpanishScraper, streamwishEnglishScraper, streamtapeLatinoScraper, + ...cinemaosEmbeds, ]; } diff --git a/src/providers/embeds/cinemaos.ts b/src/providers/embeds/cinemaos.ts new file mode 100644 index 0000000..7c53cb8 --- /dev/null +++ b/src/providers/embeds/cinemaos.ts @@ -0,0 +1,90 @@ +import { flags } from '@/entrypoint/utils/targets'; +import { EmbedOutput, makeEmbed } from '@/providers/base'; +import { NotFoundError } from '@/utils/errors'; + +const CINEMAOS_API = 'https://cinemaos-v3.vercel.app/api/neo/backendfetch'; + +export function makeCinemaOSEmbed(server: string, rank: number) { + return makeEmbed({ + id: `cinemaos-${server}`, + name: `CinemaOS: ${server.charAt(0).toUpperCase() + server.slice(1)}`, + rank, + async scrape(ctx): Promise { + const query = JSON.parse(ctx.url); + const { tmdbId, type, season, episode } = query; + let url = `${CINEMAOS_API}?requestID=${type === 'show' ? 'tvVideoProvider' : 'movieVideoProvider'}&id=${tmdbId}&service=${server}`; + if (type === 'show') { + url += `&season=${season}&episode=${episode}`; + } + const res = await ctx.proxiedFetcher(url); + const data = typeof res === 'string' ? JSON.parse(res) : res; + const sources = data?.data?.sources; + if (!sources || !Array.isArray(sources) || sources.length === 0) { + throw new NotFoundError('No sources found'); + } + // If only one source, return as a single HLS stream + if (sources.length === 1) { + return { + stream: [ + { + id: 'primary', + type: 'hls', + playlist: sources[0].url, + flags: [flags.CORS_ALLOWED], + captions: [], + }, + ], + }; + } + // If multiple sources, treat as file with qualities + const qualityMap: Record = {}; + for (const src of sources) { + // Use quality or source as the key, fallback to 'unknown' + const key = (src.quality || src.source || 'unknown').toString(); + qualityMap[key] = { + type: 'mp4', + url: src.url, + }; + } + return { + stream: [ + { + id: 'primary', + type: 'file', + flags: [flags.CORS_ALLOWED], + qualities: qualityMap, + captions: [], + }, + ], + }; + }, + }); +} + +// List of supported servers and their ranks (descending order) +const CINEMAOS_SERVERS = [ + 'flowcast', + 'shadow', + 'asiacloud', + 'hindicast', + 'anime', + 'animez', + 'guard', + 'hq', + 'ninja', + 'alpha', + 'kaze', + 'zenith', + 'cast', + 'ghost', + 'halo', + 'kinoecho', + 'ee3', + 'volt', + 'putafilme', + 'ophim', + 'kage', +]; + +// Export all embeds +export const cinemaosEmbeds = CINEMAOS_SERVERS.map((server, i) => makeCinemaOSEmbed(server, 300 - i)); diff --git a/src/providers/sources/cinemaos.ts b/src/providers/sources/cinemaos.ts new file mode 100644 index 0000000..3471de7 --- /dev/null +++ b/src/providers/sources/cinemaos.ts @@ -0,0 +1,72 @@ +import { flags } from '@/entrypoint/utils/targets'; +import { SourcererOutput, makeSourcerer } from '@/providers/base'; +import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context'; + +const CINEMAOS_SERVERS = [ + 'flowcast', + 'shadow', + 'asiacloud', + 'hindicast', + 'anime', + 'animez', + 'guard', + 'hq', + 'ninja', + 'alpha', + 'kaze', + 'zenith', + 'cast', + 'ghost', + 'halo', + 'kinoecho', + 'ee3', + 'volt', + 'putafilme', + 'ophim', + 'kage', +]; + +async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promise { + const res = await ctx.proxiedFetcher( + 'https://cinemaos-v3.vercel.app/api/neo/backendfetch?requestID=VideoProviderServices', + ); + let availableServers = []; + try { + const data = typeof res === 'string' ? JSON.parse(res) : res; + availableServers = Array.isArray(data?.data) ? data.data : []; + } catch (e) { + availableServers = []; + } + + const filteredServers = availableServers.filter((server: string) => CINEMAOS_SERVERS.includes(server)); + + const query: any = { + type: ctx.media.type, + tmdbId: ctx.media.tmdbId, + }; + + if (ctx.media.type === 'show') { + query.season = ctx.media.season.number; + query.episode = ctx.media.episode.number; + } + + const embeds = filteredServers.map((server: string) => ({ + embedId: `cinemaos-${server}`, + url: JSON.stringify({ ...query, service: server }), + })); + + // eslint-disable-next-line no-console + console.log(embeds); + + return { embeds }; +} + +export const cinemaosScraper = makeSourcerer({ + id: 'cinemaos', + name: 'CinemaOS', + rank: 230, + disabled: false, + flags: [flags.CORS_ALLOWED], + scrapeMovie: comboScraper, + scrapeShow: comboScraper, +});