diff --git a/src/providers/all.ts b/src/providers/all.ts index 066d065..0f9f57f 100644 --- a/src/providers/all.ts +++ b/src/providers/all.ts @@ -1,11 +1,5 @@ import { Embed, Sourcerer } from '@/providers/base'; import { doodScraper } from '@/providers/embeds/dood'; -import { - hianimeHd1DubEmbed, - hianimeHd1SubEmbed, - hianimeHd2DubEmbed, - hianimeHd2SubEmbed, -} from '@/providers/embeds/hianime'; import { mixdropScraper } from '@/providers/embeds/mixdrop'; import { turbovidScraper } from '@/providers/embeds/turbovid'; import { upcloudScraper } from '@/providers/embeds/upcloud'; @@ -13,23 +7,11 @@ import { autoembedScraper } from '@/providers/sources/autoembed'; import { catflixScraper } from '@/providers/sources/catflix'; import { ee3Scraper } from '@/providers/sources/ee3'; import { fsharetvScraper } from '@/providers/sources/fsharetv'; -import { hianimeScraper } from '@/providers/sources/hianime'; import { insertunitScraper } from '@/providers/sources/insertunit'; import { mp4hydraScraper } from '@/providers/sources/mp4hydra'; import { tugaflixScraper } from '@/providers/sources/tugaflix'; import { vidsrcsuScraper } from '@/providers/sources/vidsrcsu'; -import { - oneServerAnimepaheEmbed, - oneServerAnizoneEmbed, - oneServerAutoembedEmbed, - oneServerFlixhqEmbed, - oneServerFoxstreamEmbed, - oneServerGokuEmbed, - oneServerHianimeEmbed, - oneServerPrimeboxEmbed, - oneServerVidsrcsuEmbed, -} from './embeds/1server'; import { autoembedBengaliScraper, autoembedEnglishScraper, @@ -39,13 +21,6 @@ import { } from './embeds/autoembed'; import { cinemaosEmbeds } from './embeds/cinemaos'; import { closeLoadScraper } from './embeds/closeload'; -import { - ConsumetStreamSBScraper, - ConsumetStreamTapeScraper, - ConsumetVidCloudScraper, - ConsumetVidStreamingScraper, -} from './embeds/consumet'; -import { FedAPIPrivateScraper, FedDBScraper } from './embeds/fedapi'; import { mp4hydraServer1Scraper, mp4hydraServer2Scraper } from './embeds/mp4hydra'; import { ridooScraper } from './embeds/ridoo'; import { streamtapeLatinoScraper, streamtapeScraper } from './embeds/streamtape'; @@ -76,43 +51,23 @@ import { viperScraper } from './embeds/viper'; import { warezcdnembedHlsScraper } from './embeds/warezcdn/hls'; import { warezcdnembedMp4Scraper } from './embeds/warezcdn/mp4'; import { warezPlayerScraper } from './embeds/warezcdn/warezplayer'; -import { webtor1080Scraper, webtor480Scraper, webtor4kScraper, webtor720Scraper } from './embeds/webtor'; -import { - xprimeApolloEmbed, - xprimeFendiEmbed, - xprimeFoxEmbed, - xprimeHarbourEmbed, - xprimeMarantEmbed, - xprimePhoenixEmbed, - xprimePrimenetEmbed, - xprimeStreamboxEmbed, - xprimeVolkswagenEmbed, -} from './embeds/xprime'; -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'; import { embedsuScraper } from './sources/embedsu'; -import { FedAPIScraper } from './sources/fedapi'; import { hdRezkaScraper } from './sources/hdrezka'; -import { hollymoviehdScraper } from './sources/hollymoviehd'; import { iosmirrorScraper } from './sources/iosmirror'; import { iosmirrorPVScraper } from './sources/iosmirrorpv'; import { nunflixScraper } from './sources/nunflix'; -import { oneroomScraper } from './sources/oneroom'; import { ridooMoviesScraper } from './sources/ridomovies'; import { slidemoviesScraper } from './sources/slidemovies'; import { soaperTvScraper } from './sources/soapertv'; import { streamboxScraper } from './sources/streambox'; -import { uiraliveScraper } from './sources/uiralive'; import { vidapiClickScraper } from './sources/vidapiclick'; import { warezcdnScraper } from './sources/warezcdn'; -import { webtorScraper } from './sources/webtor'; import { wecimaScraper } from './sources/wecima'; -import { xprimeScraper } from './sources/xprime'; export function gatherAllSources(): Array { // all sources are gathered here @@ -130,27 +85,18 @@ export function gatherAllSources(): Array { fsharetvScraper, vidsrcsuScraper, mp4hydraScraper, - webtorScraper, embedsuScraper, - FedAPIScraper, slidemoviesScraper, iosmirrorScraper, iosmirrorPVScraper, - uiraliveScraper, vidapiClickScraper, coitusScraper, streamboxScraper, nunflixScraper, EightStreamScraper, - xprimeScraper, - ConsumetScraper, - hianimeScraper, - oneServerScraper, wecimaScraper, animeflvScraper, cinemaosScraper, - hollymoviehdScraper, - oneroomScraper, ]; } @@ -189,39 +135,7 @@ export function gatherAllEmbeds(): Array { VidsrcsuServer11Scraper, VidsrcsuServer12Scraper, VidsrcsuServer20Scraper, - webtor4kScraper, - webtor1080Scraper, - webtor720Scraper, - webtor480Scraper, viperScraper, - FedAPIPrivateScraper, - FedDBScraper, - xprimeFoxEmbed, - xprimeApolloEmbed, - xprimeStreamboxEmbed, - xprimeMarantEmbed, - xprimeFendiEmbed, - xprimePrimenetEmbed, - xprimeVolkswagenEmbed, - xprimeHarbourEmbed, - xprimePhoenixEmbed, - ConsumetVidCloudScraper, - ConsumetStreamSBScraper, - ConsumetVidStreamingScraper, - ConsumetStreamTapeScraper, - hianimeHd1DubEmbed, - hianimeHd2DubEmbed, - hianimeHd1SubEmbed, - hianimeHd2SubEmbed, - oneServerAutoembedEmbed, - oneServerVidsrcsuEmbed, - oneServerPrimeboxEmbed, - oneServerFoxstreamEmbed, - oneServerFlixhqEmbed, - oneServerGokuEmbed, - oneServerHianimeEmbed, - oneServerAnimepaheEmbed, - oneServerAnizoneEmbed, streamwishJapaneseScraper, streamwishLatinoScraper, streamwishSpanishScraper, diff --git a/src/providers/embeds/1server.ts b/src/providers/embeds/1server.ts deleted file mode 100644 index 088e43a..0000000 --- a/src/providers/embeds/1server.ts +++ /dev/null @@ -1,294 +0,0 @@ -/* eslint-disable no-console */ -import { flags } from '@/entrypoint/utils/targets'; -import { EmbedOutput, makeEmbed } from '@/providers/base'; -import { NotFoundError } from '@/utils/errors'; -import { createM3U8ProxyUrl, updateM3U8ProxyUrl } from '@/utils/proxy'; - -const baseUrl = 'https://flix.1anime.app'; - -const languageMap: Record = { - 'chinese - hong kong': 'zh', - 'chinese - traditional': 'zh', - czech: 'cs', - danish: 'da', - dutch: 'nl', - english: 'en', - 'english - sdh': 'en', - finnish: 'fi', - french: 'fr', - german: 'de', - greek: 'el', - hungarian: 'hu', - italian: 'it', - korean: 'ko', - norwegian: 'no', - polish: 'pl', - portuguese: 'pt', - 'portuguese - brazilian': 'pt', - romanian: 'ro', - 'spanish - european': 'es', - 'spanish - latin american': 'es', - swedish: 'sv', - turkish: 'tr', - اَلْعَرَبِيَّةُ: 'ar', - বাংলা: 'bn', - filipino: 'tl', - indonesia: 'id', - اردو: 'ur', -}; - -function createProxyUrl(originalUrl: string, referer?: string): string { - const headers: Record = {}; - if (referer) { - headers.referer = referer; - } - - return createM3U8ProxyUrl(originalUrl, headers); -} - -function processProxiedURL(url: string): string { - // Handle orbitproxy URLs - if (url.includes('orbitproxy')) { - try { - const urlParts = url.split(/orbitproxy\.[^/]+\//); - if (urlParts.length >= 2) { - const encryptedPart = urlParts[1].split('.m3u8')[0]; - try { - const decodedData = - typeof window !== 'undefined' - ? atob(encryptedPart) - : Buffer.from(encryptedPart, 'base64').toString('utf-8'); - - const jsonData = JSON.parse(decodedData); - const originalUrl = jsonData.u; - const referer = jsonData.r || ''; - - return createProxyUrl(originalUrl, referer); - } catch (jsonError) { - console.error('Error decoding/parsing orbitproxy data:', jsonError); - } - } - } catch (error) { - console.error('Error processing orbitproxy URL:', error); - } - } - - // Handle other proxied URLs - if (url.includes('/m3u8-proxy?url=')) { - return updateM3U8ProxyUrl(url); - } - - return createProxyUrl(url); -} - -function isOnionflixerUrl(url: string): boolean { - return url.includes('onionflixer'); -} - -function processSubtitles(subtitles: any[] | undefined): any[] { - const captions = []; - - if (subtitles && Array.isArray(subtitles)) { - for (const sub of subtitles) { - const url = sub.url || sub.file; - const lang = sub.lang || sub.label || 'unknown'; - - if (url) { - captions.push({ - type: sub.type || 'vtt', - url, - language: languageMap[lang.toLowerCase()] || lang.toLowerCase() || 'unknown', - }); - } - } - } - - return captions; -} - -function processApiResponse(response: any, ctx: any): EmbedOutput { - if (!response) { - throw new NotFoundError('No response received'); - } - - if (response.error) { - throw new NotFoundError(`${response.error}${response.hint ? ` - ${response.hint}` : ''}`); - } - - // Handle array responses (multiple provider options) - if (Array.isArray(response)) { - for (const item of response) { - // Handle format with headers and sources array - if (item.headers && item.sources && Array.isArray(item.sources)) { - const bestSource = item.sources.find((s: any) => s.isM3U8); - if (bestSource && bestSource.url) { - const playlistUrl = processProxiedURL(bestSource.url); - const captions = processSubtitles(item.subtitles); - - return { - stream: [ - { - id: 'primary', - type: 'hls', - playlist: playlistUrl, - flags: [flags.CORS_ALLOWED], - captions, - }, - ], - }; - } - } - - // Handle format with source.provider and source.files - if (item.source && item.source.files && Array.isArray(item.source.files)) { - const bestFile = item.source.files.find((f: any) => f.type === 'hls' || f.file.includes('.m3u8')); - if (bestFile && bestFile.file) { - const playlistUrl = processProxiedURL(bestFile.file); - const captions = processSubtitles(item.source.subtitles); - - return { - stream: [ - { - id: 'primary', - type: 'hls', - playlist: playlistUrl, - flags: [flags.CORS_ALLOWED], - captions, - }, - ], - }; - } - } - } - } - - // Handle original format with sources object - const sourcesObj = response.sources; - if (sourcesObj) { - let bestSource = null; - - // Look through all providers in the sources object - for (const provider in sourcesObj) { - if (Object.prototype.hasOwnProperty.call(sourcesObj, provider)) { - const providerSources = sourcesObj[provider]; - if (providerSources && providerSources.length > 0) { - // Find the highest quality non-onionflixer source - for (const source of providerSources) { - if (source.url && source.isM3U8 && !isOnionflixerUrl(source.url)) { - bestSource = source; - break; - } - } - // If we found a good source, no need to check other providers - if (bestSource) break; - } - } - } - - // If no non-onionflixer source was found, use the first available one - if (!bestSource) { - for (const provider in sourcesObj) { - if (Object.prototype.hasOwnProperty.call(sourcesObj, provider)) { - const providerSources = sourcesObj[provider]; - if (providerSources && providerSources.length > 0) { - bestSource = providerSources[0]; - break; - } - } - } - } - - if (bestSource && bestSource.url) { - const playlistUrl = processProxiedURL(bestSource.url); - const captions = processSubtitles(response.subtitles); - - ctx.progress(100); - - return { - stream: [ - { - id: 'primary', - type: 'hls', - playlist: createProxyUrl(playlistUrl, ctx.referer), - flags: [flags.CORS_ALLOWED], - captions, - }, - ], - }; - } - } - - throw new NotFoundError('No valid stream URL found in response'); -} - -/* MOVIE & TV PROVIDERS */ -const movieTvProviders = [ - { id: 'autoembed', name: 'Autoembed', rank: 165 }, - { id: 'vidsrcsu', name: 'vidsrc.su', rank: 164, disabled: true }, - { id: 'primebox', name: 'Primebox', rank: 162, disabled: true }, - { id: 'foxstream', name: 'Foxstream', rank: 161, disabled: true }, - { id: 'flixhq', name: 'FlixHQ', rank: 166 }, - { id: 'goku', name: 'Goku', rank: 163, disabled: true }, -]; - -const createMovieTvEmbed = (provider: { id: string; name: string; rank: number; disabled?: boolean }) => - makeEmbed({ - id: `oneserver-${provider.id}`, - name: provider.name, - rank: provider.rank, - disabled: provider.disabled, - async scrape(ctx) { - const query = JSON.parse(ctx.url); - const apiUrl = - query.type === 'movie' - ? `${baseUrl}/movie/${provider.id}/${query.tmdbId}` - : `${baseUrl}/tv/${provider.id}/${query.tmdbId}/${query.season}/${query.episode}`; - - try { - const response = await ctx.fetcher(apiUrl); - ctx.progress(50); - return processApiResponse(response, ctx); - } catch (error) { - if (error instanceof NotFoundError) throw error; - throw new NotFoundError(`Failed to fetch from ${provider.id}: ${error}`); - } - }, - }); - -export const [ - oneServerAutoembedEmbed, - oneServerVidsrcsuEmbed, - oneServerPrimeboxEmbed, - oneServerFoxstreamEmbed, - oneServerFlixhqEmbed, - oneServerGokuEmbed, -] = movieTvProviders.map(createMovieTvEmbed); - -/* ANIME PROVIDERS */ -const animeProviders = [ - { id: 'hianime', name: 'Hianime', rank: 269 }, - { id: 'animepahe', name: 'Animepahe', rank: 268 }, - { id: 'anizone', name: 'Anizone', rank: 267 }, -]; - -const createAnimeEmbed = (provider: { id: string; name: string; rank: number }) => - makeEmbed({ - id: `oneserver-${provider.id}`, - name: provider.name, - rank: provider.rank, - async scrape(ctx) { - const query = JSON.parse(ctx.url); - const apiUrl = `${baseUrl}/anime/${provider.id}/${query.anilistId}${query.episode ? `/${query.episode}` : ''}`; - - try { - const response = await ctx.fetcher(apiUrl); - return processApiResponse(response, ctx); - } catch (error) { - if (error instanceof NotFoundError) throw error; - throw new NotFoundError(`Failed to fetch from ${provider.id}: ${error}`); - } - }, - }); - -export const [oneServerHianimeEmbed, oneServerAnimepaheEmbed, oneServerAnizoneEmbed] = - animeProviders.map(createAnimeEmbed); diff --git a/src/providers/embeds/consumet.ts b/src/providers/embeds/consumet.ts deleted file mode 100644 index 6426dda..0000000 --- a/src/providers/embeds/consumet.ts +++ /dev/null @@ -1,161 +0,0 @@ -/* eslint-disable no-console */ -import { flags } from '@/entrypoint/utils/targets'; -import { EmbedOutput, makeEmbed } from '@/providers/base'; -import { NotFoundError } from '@/utils/errors'; -import { createM3U8ProxyUrl } from '@/utils/proxy'; - -import { Caption } from '../captions'; - -interface StreamData { - headers: { - Referer: string; - Origin?: string; - }; - intro: { - start: number; - end: number; - }; - outro: { - start: number; - end: number; - }; - sources: Array<{ - url: string; - isM3U8: boolean; - type: string; - }>; - subtitles: Array<{ - url: string; - lang: string; - }>; -} - -const providers = [ - { - id: 'consumet-vidcloud', - rank: 405, - name: 'VidCloud', - server: 'vidcloud', - }, - { - id: 'consumet-streamsb', - rank: 404, - name: 'StreamSB', - server: 'streamsb', - disabled: true, - }, - { - id: 'consumet-vidstreaming', - rank: 403, - name: 'VidStreaming', - server: 'vidstreaming', - disabled: true, - }, - { - id: 'consumet-streamtape', - rank: 402, - name: 'StreamTape', - server: 'streamtape', - disabled: true, - }, -]; - -const languageMap: Record = { - English: 'en', - Spanish: 'es', - French: 'fr', - German: 'de', - Italian: 'it', - Portuguese: 'pt', - Arabic: 'ar', - Russian: 'ru', - Japanese: 'ja', - Korean: 'ko', - Chinese: 'zh', - Hindi: 'hi', - Turkish: 'tr', - Dutch: 'nl', - Polish: 'pl', - Swedish: 'sv', - Indonesian: 'id', - Thai: 'th', - Vietnamese: 'vi', -}; - -function embed(provider: { id: string; rank: number; name: string; server: string; disabled?: boolean }) { - return makeEmbed({ - id: provider.id, - name: provider.name, - rank: provider.rank, - disabled: provider.disabled, - async scrape(ctx): Promise { - const query = JSON.parse(ctx.url); - const apiUrl = `https://api.1anime.app/anime/zoro/watch?episodeId=${query.episodeId}&server=${provider.server}`; - - const data = await ctx.fetcher(apiUrl); - - if (!data?.sources?.length) { - throw new NotFoundError('No stream found'); - } - - ctx.progress(50); - - const captions: Caption[] = data.subtitles - .filter((sub) => sub.lang !== 'thumbnails') - .map((sub) => ({ - type: 'vtt', - id: sub.url, - url: sub.url, - language: languageMap[sub.lang] || 'unknown', - hasCorsRestrictions: false, - })); - - const streams = data.sources.reduce( - (acc, source) => { - if (source.isM3U8) { - acc.unknown = source.url; - } - return acc; - }, - {} as Record, - ); - - const thumbnailTrack = data.subtitles.find((sub) => sub.lang === 'thumbnails'); - - ctx.progress(90); - - const headers: Record = {}; - if (data.headers.Referer) { - headers.referer = data.headers.Referer; - } - if (data.headers.Origin) { - headers.origin = data.headers.Origin; - } - - return { - stream: [ - { - id: 'primary', - captions, - playlist: createM3U8ProxyUrl(streams.unknown, headers), - type: 'hls', - flags: [flags.CORS_ALLOWED], - ...(thumbnailTrack && { - thumbnailTrack: { - type: 'vtt', - url: thumbnailTrack.url, - }, - }), - }, - ], - }; - }, - }); -} - -export const [ - ConsumetVidCloudScraper, - ConsumetStreamSBScraper, - ConsumetVidStreamingScraper, - ConsumetStreamTapeScraper, -] = providers.map(embed); diff --git a/src/providers/embeds/fedapi.ts b/src/providers/embeds/fedapi.ts deleted file mode 100644 index fc16a15..0000000 --- a/src/providers/embeds/fedapi.ts +++ /dev/null @@ -1,298 +0,0 @@ -/* eslint-disable no-console */ - -// Thanks Nemo for this API! -import { flags } from '@/entrypoint/utils/targets'; -import { EmbedOutput, makeEmbed } from '@/providers/base'; -import { NotFoundError } from '@/utils/errors'; - -import { Caption } from '../captions'; - -const getRegion = (): string | null => { - try { - if (typeof window === 'undefined') return null; - const regionData = window.localStorage.getItem('__MW::region'); - if (!regionData) return null; - const parsed = JSON.parse(regionData); - return parsed?.state?.region ?? null; - } catch (e) { - console.warn('Unable to access localStorage or parse auth data:', e); - return null; - } -}; - -const getBaseUrl = (): string => { - const region = getRegion(); - switch (region) { - case 'us-east': - return 'https://fed-api-east.pstream.org'; - case 'us-west': - return 'https://fed-api-west.pstream.org'; - case 'south-america': - return 'https://fed-api-south.pstream.org'; - case 'asia': - return 'https://fed-api-asia.pstream.org'; - case 'europe': - return 'https://fed-api-europe.pstream.org'; - default: - return 'https://fed-api-east.pstream.org'; - } -}; - -const BASE_URL = getBaseUrl(); - -// Language mapping for subtitles -const languageMap: Record = { - 'chinese - hong kong': 'zh', - 'chinese - traditional': 'zh', - czech: 'cs', - danish: 'da', - dutch: 'nl', - english: 'en', - 'english - sdh': 'en', - finnish: 'fi', - french: 'fr', - german: 'de', - greek: 'el', - hungarian: 'hu', - italian: 'it', - korean: 'ko', - norwegian: 'no', - polish: 'pl', - portuguese: 'pt', - 'portuguese - brazilian': 'pt', - romanian: 'ro', - 'spanish - european': 'es', - 'spanish - latin american': 'es', - swedish: 'sv', - turkish: 'tr', - اَلْعَرَبِيَّةُ: 'ar', - বাংলা: 'bn', - filipino: 'tl', - indonesia: 'id', - اردو: 'ur', - English: 'en', - Arabic: 'ar', - Bosnian: 'bs', - Bulgarian: 'bg', - Croatian: 'hr', - Czech: 'cs', - Danish: 'da', - Dutch: 'nl', - Estonian: 'et', - Finnish: 'fi', - French: 'fr', - German: 'de', - Greek: 'el', - Hebrew: 'he', - Hungarian: 'hu', - Indonesian: 'id', - Italian: 'it', - Norwegian: 'no', - Persian: 'fa', - Polish: 'pl', - Portuguese: 'pt', - 'Protuguese (BR)': 'pt-br', - Romanian: 'ro', - Russian: 'ru', - Serbian: 'sr', - Slovenian: 'sl', - Spanish: 'es', - Swedish: 'sv', - Thai: 'th', - Turkish: 'tr', -}; - -interface StreamData { - streams: Record; - subtitles: Record; - error?: string; - name?: string; - size?: string; -} - -const providers = [ - { - id: 'fedapi-private', - rank: 303, - name: 'FED API (Private)', - useToken: true, - useCacheUrl: false, - }, - { - id: 'feddb', - rank: 302, - name: 'FED DB', - useToken: false, - useCacheUrl: true, - }, -]; - -function embed(provider: { - id: string; - rank: number; - name: string; - useToken: boolean; - useCacheUrl: boolean; - disabled?: boolean; -}) { - return makeEmbed({ - id: provider.id, - name: provider.name, - rank: provider.rank, - disabled: provider.disabled, - async scrape(ctx): Promise { - // Parse the query parameters from the URL - const query = JSON.parse(ctx.url); - - // Build the API URL based on the provider configuration and media type - let apiUrl: string; - - if (provider.useCacheUrl) { - // Cache URL format - apiUrl = - query.type === 'movie' - ? `${BASE_URL}/cache/${query.imdbId}` - : `${BASE_URL}/cache/${query.imdbId}/${query.season}/${query.episode}`; - } else { - // Standard API URL format - apiUrl = - query.type === 'movie' - ? `${BASE_URL}/movie/${query.imdbId}` - : `${BASE_URL}/tv/${query.imdbId}/${query.season}/${query.episode}`; - } - - // Prepare request headers - const headers: Record = {}; - if (provider.useToken && query.token) { - headers['ui-token'] = query.token; - } - - // Fetch data from the API - const data = await ctx.fetcher(apiUrl, { - headers: Object.keys(headers).length > 0 ? headers : undefined, - }); - - if (data?.error && data.error.startsWith('No results found in MovieBox search')) { - throw new NotFoundError('No stream found'); - } - if (data?.error === 'No cached data found for this episode') { - throw new NotFoundError('No stream found'); - } - if (data?.error === 'No cached data found for this ID') { - throw new NotFoundError('No stream found'); - } - if (!data) throw new NotFoundError('No response from API'); - - ctx.progress(50); - - // Process streams data - const streams = Object.entries(data.streams).reduce((acc: Record, [quality, url]) => { - let qualityKey: number; - if (quality === 'ORG') { - // Only add unknown quality if it's an mp4 (handle URLs with query parameters) - const urlPath = url.split('?')[0]; // Remove query parameters - if (urlPath.toLowerCase().endsWith('.mp4')) { - acc.unknown = url; - } - return acc; - } - if (quality === '4K') { - qualityKey = 2160; - } else { - qualityKey = parseInt(quality.replace('P', ''), 10); - } - if (Number.isNaN(qualityKey) || acc[qualityKey]) return acc; - acc[qualityKey] = url; - return acc; - }, {}); - - // Filter qualities based on provider type - const filteredStreams = Object.entries(streams).reduce((acc: Record, [quality, url]) => { - // Skip unknown for cached provider - if (provider.useCacheUrl && quality === 'unknown') { - return acc; - } - - acc[quality] = url; - return acc; - }, {}); - - // Process captions data - const captions: Caption[] = []; - if (data.subtitles) { - for (const [langKey, subtitleData] of Object.entries(data.subtitles)) { - // Extract language name from key - const languageKeyPart = langKey.split('_')[0]; - const languageName = languageKeyPart.charAt(0).toUpperCase() + languageKeyPart.slice(1); - const languageCode = languageMap[languageName]?.toLowerCase() ?? 'unknown'; - - // Check if the subtitle data is in the new format (has subtitle_link) - if (subtitleData.subtitle_link) { - const url = subtitleData.subtitle_link; - const isVtt = url.toLowerCase().endsWith('.vtt'); - captions.push({ - type: isVtt ? 'vtt' : 'srt', - id: url, - url, - language: languageCode, - hasCorsRestrictions: false, - }); - } - } - } - - ctx.progress(90); - - return { - stream: [ - { - id: 'primary', - captions, - qualities: { - ...(filteredStreams[2160] && { - '4k': { - type: 'mp4', - url: filteredStreams[2160], - }, - }), - ...(filteredStreams[1080] && { - 1080: { - type: 'mp4', - url: filteredStreams[1080], - }, - }), - ...(filteredStreams[720] && { - 720: { - type: 'mp4', - url: filteredStreams[720], - }, - }), - ...(filteredStreams[480] && { - 480: { - type: 'mp4', - url: filteredStreams[480], - }, - }), - ...(filteredStreams[360] && { - 360: { - type: 'mp4', - url: filteredStreams[360], - }, - }), - ...(filteredStreams.unknown && { - unknown: { - type: 'mp4', - url: filteredStreams.unknown, - }, - }), - }, - type: 'file', - flags: [flags.CORS_ALLOWED], - }, - ], - }; - }, - }); -} - -export const [FedAPIPrivateScraper, FedDBScraper] = providers.map(embed); diff --git a/src/providers/embeds/hianime.ts b/src/providers/embeds/hianime.ts deleted file mode 100644 index fa82f4d..0000000 --- a/src/providers/embeds/hianime.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { flags } from '@/entrypoint/utils/targets'; -import { EmbedOutput, makeEmbed } from '@/providers/base'; -import { NotFoundError } from '@/utils/errors'; -import { createM3U8ProxyUrl } from '@/utils/proxy'; - -export const hianimeHd1DubEmbed = makeEmbed({ - id: 'hianime-hd1-dub', - name: 'HD-1 (Dub)', - rank: 250, - async scrape(ctx): Promise { - const query = JSON.parse(ctx.url); - const url = `https://hianime.pstream.org/api/v2/hianime/episode/sources?animeEpisodeId=${query.episodeId}&server=hd-1&category=dub`; - - const data = await ctx.fetcher(url); - if (!data) throw new NotFoundError('No response received'); - if (!data.data?.sources?.[0]?.url) throw new NotFoundError('No stream URL found in response'); - - const thumbnailTrack = data.data.tracks?.find((track: { kind: string }) => track.kind === 'thumbnails')?.file; - - return { - stream: [ - { - type: 'hls', - id: 'primary', - playlist: createM3U8ProxyUrl(data.data.sources[0].url, data.data.headers), - flags: [flags.CORS_ALLOWED], - captions: [], - ...(thumbnailTrack - ? { - thumbnailTrack: { - type: 'vtt', - url: thumbnailTrack, - }, - } - : {}), - }, - ], - }; - }, -}); - -export const hianimeHd2DubEmbed = makeEmbed({ - id: 'hianime-hd2-dub', - name: 'HD-2 (Dub)', - rank: 251, - async scrape(ctx): Promise { - const query = JSON.parse(ctx.url); - const url = `https://hianime.pstream.org/api/v2/hianime/episode/sources?animeEpisodeId=${query.episodeId}&server=hd-2&category=dub`; - - const data = await ctx.fetcher(url); - if (!data) throw new NotFoundError('No response received'); - if (!data.data?.sources?.[0]?.url) throw new NotFoundError('No stream URL found in response'); - - const thumbnailTrack = data.data.tracks?.find((track: { kind: string }) => track.kind === 'thumbnails')?.file; - - return { - stream: [ - { - type: 'hls', - id: 'primary', - playlist: createM3U8ProxyUrl(data.data.sources[0].url, data.data.headers), - flags: [flags.CORS_ALLOWED], - captions: [], - ...(thumbnailTrack - ? { - thumbnailTrack: { - type: 'vtt', - url: thumbnailTrack, - }, - } - : {}), - }, - ], - }; - }, -}); - -export const hianimeHd1SubEmbed = makeEmbed({ - id: 'hianime-hd1-sub', - name: 'HD-1 (Sub)', - rank: 252, - async scrape(ctx): Promise { - const query = JSON.parse(ctx.url); - const url = `https://hianime.pstream.org/api/v2/hianime/episode/sources?animeEpisodeId=${query.episodeId}&server=hd-1&category=sub`; - - const data = await ctx.fetcher(url); - if (!data) throw new NotFoundError('No response received'); - if (!data.data?.sources?.[0]?.url) throw new NotFoundError('No stream URL found in response'); - - const thumbnailTrack = data.data.tracks?.find((track: { kind: string }) => track.kind === 'thumbnails')?.file; - - return { - stream: [ - { - type: 'hls', - id: 'primary', - playlist: createM3U8ProxyUrl(data.data.sources[0].url, data.data.headers), - flags: [flags.CORS_ALLOWED], - captions: [], - ...(thumbnailTrack - ? { - thumbnailTrack: { - type: 'vtt', - url: thumbnailTrack, - }, - } - : {}), - }, - ], - }; - }, -}); - -export const hianimeHd2SubEmbed = makeEmbed({ - id: 'hianime-hd2-sub', - name: 'HD-2 (Sub)', - rank: 253, - async scrape(ctx): Promise { - const query = JSON.parse(ctx.url); - const url = `https://hianime.pstream.org/api/v2/hianime/episode/sources?animeEpisodeId=${query.episodeId}&server=hd-2&category=sub`; - - const data = await ctx.fetcher(url); - if (!data) throw new NotFoundError('No response received'); - if (!data.data?.sources?.[0]?.url) throw new NotFoundError('No stream URL found in response'); - - const thumbnailTrack = data.data.tracks?.find((track: { kind: string }) => track.kind === 'thumbnails')?.file; - - return { - stream: [ - { - type: 'hls', - id: 'primary', - playlist: createM3U8ProxyUrl(data.data.sources[0].url, data.data.headers), - flags: [flags.CORS_ALLOWED], - captions: [], - ...(thumbnailTrack - ? { - thumbnailTrack: { - type: 'vtt', - url: thumbnailTrack, - }, - } - : {}), - }, - ], - }; - }, -}); diff --git a/src/providers/embeds/webtor.ts b/src/providers/embeds/webtor.ts deleted file mode 100644 index b8a8ee3..0000000 --- a/src/providers/embeds/webtor.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { flags } from '@/entrypoint/utils/targets'; -import { makeEmbed } from '@/providers/base'; - -const providers = [ - { id: 'webtor-1080', rank: 80 }, // 1080p should be a higher rank becuase it loads faster - { id: 'webtor-4k', rank: 79 }, - { id: 'webtor-720', rank: 78 }, - { id: 'webtor-480', rank: 77 }, -]; - -function embed(provider: { id: string; rank: number }) { - return makeEmbed({ - id: provider.id, - name: `Webtor ${provider.id.split('-')[1].toUpperCase()}`, - rank: provider.rank, - async scrape(ctx) { - return { - stream: [ - { - id: 'primary', - type: 'hls', - playlist: ctx.url, - flags: [flags.CORS_ALLOWED], - captions: [], - }, - ], - }; - }, - }); -} - -export const [webtor4kScraper, webtor1080Scraper, webtor720Scraper, webtor480Scraper] = providers.map(embed); diff --git a/src/providers/embeds/xprime.ts b/src/providers/embeds/xprime.ts deleted file mode 100644 index 7779d29..0000000 --- a/src/providers/embeds/xprime.ts +++ /dev/null @@ -1,477 +0,0 @@ -/* eslint-disable no-console */ -import { flags } from '@/entrypoint/utils/targets'; -import { EmbedOutput, makeEmbed } from '@/providers/base'; -import { NotFoundError } from '@/utils/errors'; - -const foxBaseUrl = 'https://backend.xprime.tv/fox'; -const apolloBaseUrl = 'https://kendrickl-3amar.site'; -const showboxBaseUrl = 'https://backend.xprime.tv/primebox'; -const marantBaseUrl = 'https://backend.xprime.tv/marant'; -const primenetBaseUrl = 'https://backend.xprime.tv/primenet'; -const volkswagenBaseUrl = 'https://backend.xprime.tv/volkswagen'; -const harbourBaseUrl = 'https://backend.xprime.tv/harbour'; -const fendiBaseUrl = 'https://backend.xprime.tv/fendi'; - -const languageMap: Record = { - 'chinese - hong kong': 'zh', - 'chinese - traditional': 'zh', - czech: 'cs', - danish: 'da', - dutch: 'nl', - english: 'en', - 'english - sdh': 'en', - finnish: 'fi', - french: 'fr', - german: 'de', - greek: 'el', - hungarian: 'hu', - italian: 'it', - korean: 'ko', - norwegian: 'no', - polish: 'pl', - portuguese: 'pt', - 'portuguese - brazilian': 'pt', - romanian: 'ro', - 'spanish - european': 'es', - 'spanish - latin american': 'es', - swedish: 'sv', - turkish: 'tr', - اَلْعَرَبِيَّةُ: 'ar', - বাংলা: 'bn', - filipino: 'tl', - indonesia: 'id', - اردو: 'ur', - English: 'en', - Arabic: 'ar', - Bosnian: 'bs', - Bulgarian: 'bg', - Croatian: 'hr', - Czech: 'cs', - Danish: 'da', - Dutch: 'nl', - Estonian: 'et', - Finnish: 'fi', - French: 'fr', - German: 'de', - Greek: 'el', - Hebrew: 'he', - Hungarian: 'hu', - Indonesian: 'id', - Italian: 'it', - Norwegian: 'no', - Persian: 'fa', - Polish: 'pl', - Portuguese: 'pt', - 'Protuguese (BR)': 'pt-br', - Romanian: 'ro', - Russian: 'ru', - Serbian: 'sr', - Slovenian: 'sl', - Spanish: 'es', - Swedish: 'sv', - Thai: 'th', - Turkish: 'tr', -}; - -export const xprimeApolloEmbed = makeEmbed({ - id: 'xprime-apollo', - name: 'Appolo', - rank: 237, - async scrape(ctx): Promise { - const query = JSON.parse(ctx.url); - let url = `${apolloBaseUrl}/${query.tmdbId}`; - - if (query.type === 'show') { - url += `/${query.season}/${query.episode}`; - } - - const data = await ctx.fetcher(url); - - if (!data) throw new NotFoundError('No response received'); - if (data.error) throw new NotFoundError(data.error); - if (!data.url) throw new NotFoundError('No stream URL found in response'); - - const captions = - data.subtitles?.map((sub: { file: string; label: string }) => ({ - type: 'vtt', - url: sub.file, - language: languageMap[sub.label.toLowerCase()] || 'unknown', - })) || []; - - ctx.progress(90); - - return { - stream: [ - { - type: 'hls', - id: 'primary', - playlist: data.url, - flags: [flags.CORS_ALLOWED], - captions, - ...(data.thumbnails?.file - ? { - thumbnailTrack: { - type: 'vtt', - url: data.thumbnails.file, - }, - } - : {}), - }, - ], - }; - }, -}); - -export const xprimeStreamboxEmbed = makeEmbed({ - id: 'xprime-streambox', - name: 'Streambox', - rank: 236, - async scrape(ctx): Promise { - const query = JSON.parse(ctx.url); - - let url = `${showboxBaseUrl}?name=${query.title}&year=${query.releaseYear}&fallback_year=${query.releaseYear}`; - - if (query.type === 'show') { - url += `&season=${query.season}&episode=${query.episode}`; - } - - // Old handling in case - // if (query.type === 'show') { - // url += `?id=${query.tmdbId}&season=${query.season}&episode=${query.episode}`; - // } else { - // url += `?id=${query.tmdbId}`; - // } - - const data = await ctx.fetcher(url); - - if (!data) throw new NotFoundError('No response received'); - if (data.error) throw new NotFoundError(data.error); - if (!data.streams) throw new NotFoundError('No streams found in response'); - - const captions = - data.subtitles?.map((sub: { file: string; label: string }) => ({ - id: sub.label, - url: sub.file, - language: languageMap[sub.label.toLowerCase()] || 'unknown', - type: 'srt', - })) || []; - - const qualityMap: Record = {}; - - Object.entries(data.streams).forEach(([key, value]) => { - const normalizedKey = key.toLowerCase().replace('p', ''); - qualityMap[normalizedKey] = { - type: 'mp4', - url: value as string, - }; - }); - - return { - stream: [ - { - id: 'primary', - captions, - qualities: qualityMap, - type: 'file', - flags: [flags.CORS_ALLOWED], - }, - ], - }; - }, -}); - -export const xprimePrimenetEmbed = makeEmbed({ - id: 'xprime-primenet', - name: 'Primenet', - rank: 235, - async scrape(ctx): Promise { - const query = JSON.parse(ctx.url); - let url = `${primenetBaseUrl}?id=${query.tmdbId}`; - - if (query.type === 'show') { - url += `&season=${query.season}&episode=${query.episode}`; - } - - const data = await ctx.fetcher(url); - - if (!data) throw new NotFoundError('No response received'); - if (data.error) throw new NotFoundError(data.error); - if (!data.url) throw new NotFoundError('No stream URL found in response'); - - ctx.progress(90); - - return { - stream: [ - { - type: 'hls', - id: 'primary', - playlist: data.url, - flags: [flags.CORS_ALLOWED], - captions: [], - }, - ], - }; - }, -}); - -export const xprimePhoenixEmbed = makeEmbed({ - id: 'xprime-phoenix', - name: 'Phoenix', - rank: 234, - async scrape(ctx): Promise { - const query = JSON.parse(ctx.url); - - const params = new URLSearchParams(); - params.append('id', query.tmdbId); - params.append('imdb', query.imdbId); - - // For TV shows, add season and episode - if (query.type === 'show') { - params.append('season', query.season.toString()); - params.append('episode', query.episode.toString()); - } - - const url = `https://backend.xprime.tv/phoenix?${params.toString()}`; - ctx.progress(50); - - const data = await ctx.fetcher(url); - - if (!data) throw new NotFoundError('No response received'); - if (data.error) throw new NotFoundError(data.error); - if (!data.url) throw new NotFoundError('No stream URL found in response'); - - ctx.progress(90); - - // Parse and format captions - const captions = data.subtitles - ? data.subtitles.map((sub: any) => { - // Extract the base label without number suffixes - const baseLabel = sub.label.split(' ')[0]; - // Use mapped ISO code or the original label if not found in the map - const langCode = languageMap[baseLabel] || baseLabel.toLowerCase().substring(0, 2); - - return { - id: `${sub.label.replace(/\s+/g, '_').toLowerCase()}`, - language: langCode, - url: sub.file, - label: sub.label, - type: 'vtt', - }; - }) - : []; - - return { - stream: [ - { - type: 'hls', - id: 'primary', - playlist: data.url, - flags: [flags.CORS_ALLOWED], - captions, - }, - ], - }; - }, -}); - -export const xprimeFoxEmbed = makeEmbed({ - id: 'xprime-fox', - name: 'Fox', - rank: 233, - async scrape(ctx): Promise { - const query = JSON.parse(ctx.url); - const params = new URLSearchParams({ - name: query.title, - pstream: 'true', - }); - - if (query.type === 'show') { - params.append('season', query.season.toString()); - params.append('episode', query.episode.toString()); - } - - const apiRes = await ctx.fetcher(`${foxBaseUrl}?${params.toString()}`); - if (!apiRes) throw new NotFoundError('No response received'); - const data = await JSON.parse(apiRes); - if (!data.url) throw new NotFoundError('No stream URL found in response'); - - const captions = - data.subtitles?.map((sub: { file: string; label: string }) => ({ - type: 'vtt', - url: sub.file, - language: languageMap[sub.label.toLowerCase()] || 'unknown', - })) || []; - - ctx.progress(90); - - return { - stream: [ - { - type: 'hls', - id: 'primary', - playlist: `https://oca.kendrickl-3amar.site/?v=${encodeURIComponent(data.url)}&headers=${encodeURIComponent(JSON.stringify({ referer: 'https://megacloud.store/', origin: 'https://megacloud.store' }))}`, - flags: [flags.CORS_ALLOWED], - captions, - }, - ], - }; - }, -}); - -export const xprimeHarbourEmbed = makeEmbed({ - id: 'xprime-harbour', - name: 'Harbour', - rank: 232, - async scrape(ctx): Promise { - const query = JSON.parse(ctx.url); - const params = new URLSearchParams({ - name: query.title, - year: query.releaseYear.toString(), - }); - - if (query.type === 'show') { - params.append('season', query.season.toString()); - params.append('episode', query.episode.toString()); - } - - const apiRes = await ctx.fetcher(`${harbourBaseUrl}?${params.toString()}`); - if (!apiRes) throw new NotFoundError('No response received'); - const data = await JSON.parse(apiRes); - if (!data.url) throw new NotFoundError('No stream URL found in response'); - - const captions = - data.subtitles?.map((sub: { file: string; label: string }) => ({ - type: 'vtt', - url: sub.file, - language: languageMap[sub.label.toLowerCase()] || 'unknown', - })) || []; - - ctx.progress(90); - - return { - stream: [ - { - type: 'hls', - id: 'primary', - playlist: data.url, - flags: [flags.CORS_ALLOWED], - captions, - }, - ], - }; - }, -}); - -export const xprimeFendiEmbed = makeEmbed({ - id: 'xprime-fendi', - name: 'Fendi', - rank: 231, - async scrape(ctx): Promise { - const query = JSON.parse(ctx.url); - let url = `${fendiBaseUrl}?id=${query.tmdbId}`; - - if (query.type === 'show') { - url += `&season=${query.season}&episode=${query.episode}`; - } - - const data = await ctx.fetcher(url); - - if (!data) throw new NotFoundError('No response received'); - if (data.error) throw new NotFoundError(data.error); - if (!data.url) throw new NotFoundError('No stream URL found in response'); - - ctx.progress(90); - - return { - stream: [ - { - type: 'hls', - id: 'primary', - playlist: data.url, - flags: [flags.CORS_ALLOWED], - captions: [], - }, - ], - }; - }, -}); - -export const xprimeMarantEmbed = makeEmbed({ - id: 'xprime-marant', - name: 'Marant (French + English)', - rank: 230, - async scrape(ctx): Promise { - const query = JSON.parse(ctx.url); - let url = `${marantBaseUrl}?id=${query.tmdbId}`; - - if (query.type === 'show') { - url += `&season=${query.season}&episode=${query.episode}`; - } - - const data = await ctx.fetcher(url); - - if (!data) throw new NotFoundError('No response received'); - if (data.error) throw new NotFoundError(data.error); - if (!data.url) throw new NotFoundError('No stream URL found in response'); - - ctx.progress(90); - - return { - stream: [ - { - type: 'hls', - id: 'primary', - playlist: data.url, - flags: [flags.CORS_ALLOWED], - captions: [], - }, - ], - }; - }, -}); - -export const xprimeVolkswagenEmbed = makeEmbed({ - id: 'xprime-volkswagen', - name: 'Volkswagen (German)', - rank: 229, - async scrape(ctx): Promise { - const query = JSON.parse(ctx.url); - let url = `${volkswagenBaseUrl}?name=${query.title}`; - - if (query.type === 'show') { - url += `&season=${query.season}&episode=${query.episode}`; - } else { - url += `&year=${query.releaseYear}`; - } - - const data = await ctx.fetcher(url); - - if (!data) throw new NotFoundError('No response received'); - if (data.error) throw new NotFoundError(data.error); - if (!data.streams) throw new NotFoundError('No streams found in response'); - - const qualityMap: Record = {}; - - Object.entries(data.streams).forEach(([key, value]) => { - const normalizedKey = key.toLowerCase().replace('p', ''); - qualityMap[normalizedKey] = { - type: 'mp4', - url: value as string, - }; - }); - - ctx.progress(90); - - return { - stream: [ - { - id: 'primary', - type: 'file', - flags: [flags.CORS_ALLOWED], - qualities: qualityMap, - captions: [], - }, - ], - }; - }, -}); diff --git a/src/providers/sources/1server.ts b/src/providers/sources/1server.ts deleted file mode 100644 index 4049796..0000000 --- a/src/providers/sources/1server.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { flags } from '@/entrypoint/utils/targets'; -import { SourcererOutput, makeSourcerer } from '@/providers/base'; -import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context'; - -async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promise { - const query = { - type: ctx.media.type, - title: ctx.media.title, - tmdbId: ctx.media.tmdbId.toString(), - ...(ctx.media.type === 'show' && { - season: ctx.media.season.number, - episode: ctx.media.episode.number, - }), - }; - - const embeds = [ - { - embedId: 'oneserver-autoembed', - url: JSON.stringify(query), - }, - { - embedId: 'oneserver-vidsrcsu', - url: JSON.stringify(query), - }, - { - embedId: 'oneserver-primebox', - url: JSON.stringify(query), - }, - { - embedId: 'oneserver-foxstream', - url: JSON.stringify(query), - }, - { - embedId: 'oneserver-flixhq', - url: JSON.stringify(query), - }, - { - embedId: 'oneserver-goku', - url: JSON.stringify(query), - }, - // { - // embedId: 'oneserver-hianime', - // url: JSON.stringify(query), - // }, - // { - // embedId: 'oneserver-animepahe', - // url: JSON.stringify(query), - // }, - // { - // embedId: 'oneserver-anizone', - // url: JSON.stringify(query), - // }, - ]; - - return { embeds }; -} - -export const oneServerScraper = makeSourcerer({ - id: '1server', - name: '1Server 🤝', - rank: 119, - disabled: false, - flags: [flags.CORS_ALLOWED], - scrapeMovie: comboScraper, - scrapeShow: comboScraper, -}); diff --git a/src/providers/sources/consumet/index.ts b/src/providers/sources/consumet/index.ts deleted file mode 100644 index d37f5d9..0000000 --- a/src/providers/sources/consumet/index.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { flags } from '@/entrypoint/utils/targets'; -import { SourcererOutput, makeSourcerer } from '@/providers/base'; -import { ShowScrapeContext } from '@/utils/context'; - -import { InfoResponse, SearchResponse } from './types'; - -async function consumetScraper(ctx: ShowScrapeContext): Promise { - // Search - const searchQuery = ctx.media.title; - const page = 1; - - const searchUrl = `https://api.1anime.app/anime/zoro/${encodeURIComponent(searchQuery)}?page=${page}`; - const searchResponse = await ctx.fetcher(searchUrl); - - if (!searchResponse?.results?.length) { - throw new Error('No results found'); - } - - const bestMatch = - searchResponse.results.find((result) => result.title.toLowerCase() === ctx.media.title.toLowerCase()) || - searchResponse.results[0]; - - // Get episode list - const infoUrl = `https://api.1anime.app/anime/zoro/info?id=${bestMatch.id}`; - const infoResponse = await ctx.fetcher(infoUrl); - - if (!infoResponse?.episodes?.length) { - throw new Error('No episodes found'); - } - - const targetEpisode = infoResponse.episodes.find((ep) => ep.number === ctx.media.episode.number); - - if (!targetEpisode) { - throw new Error('Episode not found'); - } - - // Parse embeds - const query = { - episodeId: `${bestMatch.id}$${ctx.media.season.number}$${targetEpisode.id}$both`, - }; - - const embeds = [ - { - embedId: 'consumet-vidcloud', - url: JSON.stringify({ ...query, server: 'vidcloud' }), - }, - { - embedId: 'consumet-streamsb', - url: JSON.stringify({ ...query, server: 'streamsb' }), - }, - { - embedId: 'consumet-vidstreaming', - url: JSON.stringify({ ...query, server: 'vidstreaming' }), - }, - { - embedId: 'consumet-streamtape', - url: JSON.stringify({ ...query, server: 'streamtape' }), - }, - ]; - - return { - embeds, - }; -} - -export const ConsumetScraper = makeSourcerer({ - id: 'consumet', - name: 'Consumet (Anime) 🔥', - rank: 5, - disabled: false, - flags: [flags.CORS_ALLOWED], - scrapeShow: consumetScraper, -}); diff --git a/src/providers/sources/consumet/types.ts b/src/providers/sources/consumet/types.ts deleted file mode 100644 index 11bd741..0000000 --- a/src/providers/sources/consumet/types.ts +++ /dev/null @@ -1,36 +0,0 @@ -export interface SearchResult { - id: string; - title: string; - image: string; - releaseDate: string | null; - subOrDub: 'sub' | 'dub'; -} - -export interface SearchResponse { - totalPages: number; - currentPage: number; - hasNextPage: boolean; - results: SearchResult[]; -} - -export interface Episode { - id: string; - number: number; - url: string; -} - -export interface InfoResponse { - id: string; - title: string; - url: string; - image: string; - releaseDate: string | null; - description: string | null; - genres: string[]; - subOrDub: 'sub' | 'dub'; - type: string | null; - status: string; - otherName: string | null; - totalEpisodes: number; - episodes: Episode[]; -} diff --git a/src/providers/sources/fedapi.ts b/src/providers/sources/fedapi.ts deleted file mode 100644 index 530311c..0000000 --- a/src/providers/sources/fedapi.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { flags } from '@/entrypoint/utils/targets'; -import { SourcererOutput, makeSourcerer } from '@/providers/base'; -import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context'; - -const getUserToken = (): string | null => { - try { - if (typeof window === 'undefined') return null; - const prefData = window.localStorage.getItem('__MW::preferences'); - if (!prefData) return null; - const parsedAuth = JSON.parse(prefData); - return parsedAuth?.state?.febboxKey || null; - } catch (e) { - console.warn('Unable to access localStorage or parse auth data:', e); - return null; - } -}; - -async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promise { - const query = { - type: ctx.media.type, - imdbId: ctx.media.imdbId, - tmdbId: ctx.media.tmdbId, - ...(ctx.media.type === 'show' && { - season: ctx.media.season.number, - episode: ctx.media.episode.number, - }), - }; - - const userToken = getUserToken(); - const embeds = []; - - if (userToken) { - embeds.push({ - embedId: 'fedapi-private', - url: `${JSON.stringify({ ...query, token: userToken })}`, - }); - } - - if (!userToken) { - embeds.push({ - embedId: 'feddb', - url: `${JSON.stringify(query)}`, - }); - } - - return { - embeds, - }; -} - -export const FedAPIScraper = makeSourcerer({ - id: 'fedapi', - name: 'FED API (4K) 🔥', - rank: 260, - flags: [flags.CORS_ALLOWED], - scrapeMovie: comboScraper, - scrapeShow: comboScraper, -}); diff --git a/src/providers/sources/hianime.ts b/src/providers/sources/hianime.ts deleted file mode 100644 index f999ec0..0000000 --- a/src/providers/sources/hianime.ts +++ /dev/null @@ -1,142 +0,0 @@ -/* eslint-disable no-console */ -import { flags } from '@/entrypoint/utils/targets'; -import { SourcererOutput, makeSourcerer } from '@/providers/base'; -import { ShowScrapeContext } from '@/utils/context'; -import { NotFoundError } from '@/utils/errors'; - -const apiKey = '5b9790d9305dca8713b9a0afad42ea8d'; // plz dont abuse -const baseUrl = 'https://hianime.pstream.org/'; - -interface HianimeSearchResult { - success: boolean; - data: { - animes: Array<{ - id: string; - name: string; - }>; - }; -} - -interface HianimeEpisodeResult { - success: boolean; - data: { - episodes: Array<{ - number: number; - title: string; - episodeId: string; - }>; - }; -} - -async function searchAnime(title: string): Promise { - const response = await fetch(`${baseUrl}api/v2/hianime/search?q=${encodeURIComponent(title)}`); - if (!response.ok) throw new Error('Failed to search anime'); - const data: HianimeSearchResult = await response.json(); - - if (!data.success || !data.data.animes.length) { - throw new Error('Anime not found'); - } - - // Try to find exact match (case-insensitive) - const match = data.data.animes.find((anime) => anime.name.toLowerCase() === title.toLowerCase()); - - // Return the matched ID or fallback to the first result - return match?.id ?? data.data.animes[0].id; -} - -async function fetchTmdbShowDetails(tmdbShowId: string): Promise { - const response = await fetch(`https://api.themoviedb.org/3/tv/${tmdbShowId}?api_key=${apiKey}`); - if (!response.ok) throw new NotFoundError('Failed to fetch show data from TMDB'); - const data = await response.json(); - - // Return the English title, falling back to the original title if not available - return data.name || data.original_name; -} - -async function fetchTmdbSeasonEpisodes(tmdbShowId: string, seasonNumber: number): Promise { - const response = await fetch( - `https://api.themoviedb.org/3/tv/${tmdbShowId}/season/${seasonNumber}?api_key=${apiKey}`, - ); - if (!response.ok) throw new NotFoundError('Failed to fetch season data from TMDB'); - const data = await response.json(); - return data.episodes; // each item has 'episode_number' and 'season_number' -} - -async function calculateAbsoluteEpisodeNumber( - tmdbShowId: string, - seasonNumber: number, - episodeNumber: number, -): Promise { - const previousSeasons = await Promise.all( - Array.from({ length: seasonNumber - 1 }, (_, i) => fetchTmdbSeasonEpisodes(tmdbShowId, i + 1)), - ); - - const episodesBefore = previousSeasons.reduce((sum, seasonEpisodes) => sum + seasonEpisodes.length, 0); - - return episodesBefore + episodeNumber; -} - -async function fetchEpisodeData(animeId: string): Promise { - const response = await fetch(`${baseUrl}api/v2/hianime/anime/${animeId}/episodes`); - if (!response.ok) throw new NotFoundError('Failed to fetch episode data'); - return response.json(); -} - -async function comboScraper(ctx: ShowScrapeContext): Promise { - // Get the English title from TMDB first - const englishTitle = await fetchTmdbShowDetails(ctx.media.tmdbId); - - // Use the English title to search for the anime - const animeId = await searchAnime(englishTitle); - - const absoluteEp = await calculateAbsoluteEpisodeNumber( - ctx.media.tmdbId, - ctx.media.season.number, - ctx.media.episode.number, - ); - - // console.log(absoluteEp); - - const episodeData = await fetchEpisodeData(animeId); - // console.log(episodeData); - const episode = episodeData.data.episodes.find((ep) => ep.number === absoluteEp); - if (!episode) throw new NotFoundError('Episode not found'); - - const embeds = [ - { - embedId: 'hianime-hd1-dub', - url: JSON.stringify({ - episodeId: episode.episodeId, - }), - }, - { - embedId: 'hianime-hd2-dub', - url: JSON.stringify({ - episodeId: episode.episodeId, - }), - }, - { - embedId: 'hianime-hd1-sub', - url: JSON.stringify({ - episodeId: episode.episodeId, - }), - }, - { - embedId: 'hianime-hd2-sub', - url: JSON.stringify({ - episodeId: episode.episodeId, - }), - }, - ]; - - return { embeds }; -} - -export const hianimeScraper = makeSourcerer({ - id: 'hianime', - name: 'Hianime 🔥', - rank: 175, - disabled: false, - flags: [flags.CORS_ALLOWED], - scrapeShow: comboScraper, -}); diff --git a/src/providers/sources/hollymoviehd.ts b/src/providers/sources/hollymoviehd.ts deleted file mode 100644 index 5b86ffb..0000000 --- a/src/providers/sources/hollymoviehd.ts +++ /dev/null @@ -1,59 +0,0 @@ -import CryptoJS from 'crypto-js'; - -import { flags } from '@/entrypoint/utils/targets'; -import { SourcererOutput, makeSourcerer } from '@/providers/base'; -import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context'; -import { NotFoundError } from '@/utils/errors'; -import { convertPlaylistsToDataUrls } from '@/utils/playlist'; - -const VRF_SECRET_KEY = atob('c3VwZXJzZWNyZXRrZXk='); -const apiBase = 'https://reyna.bludclart.com/api/source/hollymoviehd'; - -function generateVrf(tmdbId: string | number, season: string | number = '', episode: string | number = ''): string { - const msg = `${tmdbId}:${season}:${episode}`; - const hash = CryptoJS.HmacSHA256(msg, VRF_SECRET_KEY); - return hash.toString(CryptoJS.enc.Hex); -} - -async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promise { - let url = `${apiBase}/${ctx.media.tmdbId}`; - let season = ''; - let episode = ''; - if (ctx.media.type === 'show') { - season = ctx.media.season.number.toString(); - episode = ctx.media.episode.number.toString(); - url += `/${season}/${episode}`; - } - const vrf = generateVrf(ctx.media.tmdbId, season, episode); - url += `?vrf=${vrf}`; - - const data = await ctx.proxiedFetcher(url); - const firstUrl = data?.sources?.[0]?.file; - if (!firstUrl) throw new NotFoundError('Sources not found.'); - ctx.progress(50); - - ctx.progress(90); - return { - embeds: [], - stream: [ - { - id: 'primary', - type: 'hls', - playlist: await convertPlaylistsToDataUrls(ctx.proxiedFetcher, firstUrl), - proxyDepth: 2, - flags: [flags.CORS_ALLOWED], - captions: [], - }, - ], - }; -} - -export const hollymoviehdScraper = makeSourcerer({ - id: 'hollymoviehd', - name: 'BludClart: HollyMovieHD 🤝', - rank: 180, - disabled: false, - flags: [flags.CORS_ALLOWED], - scrapeMovie: comboScraper, - scrapeShow: comboScraper, -}); diff --git a/src/providers/sources/oneroom.ts b/src/providers/sources/oneroom.ts deleted file mode 100644 index 8f56978..0000000 --- a/src/providers/sources/oneroom.ts +++ /dev/null @@ -1,70 +0,0 @@ -import CryptoJS from 'crypto-js'; - -import { flags } from '@/entrypoint/utils/targets'; -import { SourcererOutput, makeSourcerer } from '@/providers/base'; -import { Qualities } from '@/providers/streams'; -import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context'; -import { NotFoundError } from '@/utils/errors'; - -const VRF_SECRET_KEY = atob('c3VwZXJzZWNyZXRrZXk='); -const apiBase = 'https://reyna.bludclart.com/api/source/oneroom'; - -function generateVrf(tmdbId: string | number, season: string | number = '', episode: string | number = ''): string { - const msg = `${tmdbId}:${season}:${episode}`; - const hash = CryptoJS.HmacSHA256(msg, VRF_SECRET_KEY); - return hash.toString(CryptoJS.enc.Hex); -} - -async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promise { - let url = `${apiBase}/${ctx.media.tmdbId}`; - let season = ''; - let episode = ''; - if (ctx.media.type === 'show') { - season = ctx.media.season.number.toString(); - episode = ctx.media.episode.number.toString(); - url += `/${season}/${episode}`; - } - const vrf = generateVrf(ctx.media.tmdbId, season, episode); - url += `?vrf=${vrf}`; - - const data = await ctx.proxiedFetcher(url); - const sources = data?.sources; - if (!sources || sources.length === 0) throw new NotFoundError('Sources not found.'); - ctx.progress(50); - - // Build qualities object for mp4 sources - const qualities: Partial> = {}; - for (const source of sources) { - // Try to extract quality from label (e.g., '720p') - const match = /([0-9]{3,4})p/.exec(source.label); - const quality = match ? match[1] : 'unknown'; - qualities[quality as Qualities] = { - type: 'mp4', - url: source.file, - }; - } - - ctx.progress(90); - return { - embeds: [], - stream: [ - { - id: 'primary', - type: 'file', - qualities, - flags: [flags.CORS_ALLOWED], - captions: [], - }, - ], - }; -} - -export const oneroomScraper = makeSourcerer({ - id: 'oneroom', - name: 'BludClart: OneRoom 🤝', - rank: 179, - disabled: false, - flags: [flags.CORS_ALLOWED], - scrapeMovie: comboScraper, - scrapeShow: comboScraper, -}); diff --git a/src/providers/sources/uiralive.ts b/src/providers/sources/uiralive.ts deleted file mode 100644 index 1d61a2f..0000000 --- a/src/providers/sources/uiralive.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { flags } from '@/entrypoint/utils/targets'; -import { SourcererOutput, makeSourcerer } from '@/providers/base'; -import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context'; -import { NotFoundError } from '@/utils/errors'; - -// thanks uira for this api! -const baseUrl = 'https://xj4h5qk3tf7v2mlr9s.uira.live/'; - -async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promise { - const fetchUrl = `${baseUrl}all/${ctx.media.tmdbId}${ - ctx.media.type === 'movie' ? '' : `?s=${ctx.media.season.number}&e=${ctx.media.episode.number}` - }`; - - let result; - try { - result = await ctx.fetcher(fetchUrl); - } catch (e: any) { - if (e instanceof NotFoundError) throw new NotFoundError(`${e.message}`); - throw e; - } - - if (!result) { - try { - result = await ctx.fetcher(fetchUrl); - } catch (e: any) { - if (e instanceof NotFoundError) throw new NotFoundError(`${e.message}`); - throw e; - } - } - - if (!result || !result.sources || result.sources.length === 0) { - throw new NotFoundError('No sources found'); - } - - ctx.progress(90); - - if (!result.sources[0].url) { - throw new Error('Source URL is missing'); - } - - return { - embeds: [], - stream: [ - { - id: 'primary', - playlist: result.sources[0].url, - type: 'hls', - flags: [flags.CORS_ALLOWED], - captions: result.captions || [], - }, - ], - }; -} - -export const uiraliveScraper = makeSourcerer({ - id: 'uiralive', - name: 'uira.live 🤝', - rank: 250, - disabled: true, - flags: [flags.CORS_ALLOWED], - scrapeMovie: comboScraper, - scrapeShow: comboScraper, -}); diff --git a/src/providers/sources/webtor/common.ts b/src/providers/sources/webtor/common.ts deleted file mode 100644 index 9acfc06..0000000 --- a/src/providers/sources/webtor/common.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Stream } from './types'; - -const trackers = [ - 'udp://tracker.opentrackr.org:1337/announce', - 'udp://open.demonii.com:1337/announce', - 'udp://open.tracker.cl:1337/announce', - 'udp://open.stealth.si:80/announce', - 'udp://tracker.torrent.eu.org:451/announce', - 'udp://explodie.org:6969/announce', - 'udp://tracker.qu.ax:6969/announce', - 'udp://tracker.ololosh.space:6969/announce', - 'udp://tracker.dump.cl:6969/announce', - 'udp://tracker.dler.org:6969/announce', - 'udp://tracker.bittor.pw:1337/announce', - 'udp://tracker-udp.gbitt.info:80/announce', - 'udp://opentracker.io:6969/announce', - 'udp://open.free-tracker.ga:6969/announce', - 'udp://ns-1.x-fins.com:6969/announce', - 'udp://leet-tracker.moe:1337/announce', - 'udp://isk.richardsw.club:6969/announce', - 'udp://discord.heihachi.pw:6969/announce', - 'http://www.torrentsnipe.info:2701/announce', - 'http://www.genesis-sp.org:2710/announce', -]; - -export function getMagnetUrl(infoHash: string, name: string): string { - const encodedName = encodeURIComponent(name); - const trackerParams = trackers.map((tracker) => `&tr=${encodeURIComponent(tracker)}`).join(''); - return `magnet:?xt=urn:btih:${infoHash}&dn=${encodedName}${trackerParams}`; -} - -export function constructProxyUrl(magnetUrl: string): string { - const encodedMagnet = encodeURIComponent(magnetUrl); - return `https://savingshub.online/api/fetchHls?magnet=${encodedMagnet}`; // Thanks to Custom and DebateMyRoomba for this API -} - -export function categorizeStreams(streams: Stream[]): Record { - const categories: Record = { - '4k': [], - '1080p': [], - '720p': [], - '480p': [], - }; - - streams.forEach((stream) => { - const name = stream.name.toLowerCase(); - if (name.includes('4k')) { - categories['4k'].push(stream); - } else if (name.includes('1080p')) { - categories['1080p'].push(stream); - } else if (name.includes('720p')) { - categories['720p'].push(stream); - } else if (name.includes('480p')) { - categories['480p'].push(stream); - } - }); - - return categories; -} - -export function getTopStreamsBySeeders(categoryStreams: Stream[], limit: number): Stream[] { - return categoryStreams - .sort((a, b) => { - const seedersA = parseInt(a.title.match(/👤 (\d+) /)?.[1] || '0', 10); - const seedersB = parseInt(b.title.match(/👤 (\d+) /)?.[1] || '0', 10); - return seedersB - seedersA; - }) - .slice(0, limit); -} diff --git a/src/providers/sources/webtor/index.ts b/src/providers/sources/webtor/index.ts deleted file mode 100644 index f933f22..0000000 --- a/src/providers/sources/webtor/index.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { flags } from '@/entrypoint/utils/targets'; -import { SourcererOutput, makeSourcerer } from '@/providers/base'; -import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context'; - -import { categorizeStreams, constructProxyUrl, getMagnetUrl, getTopStreamsBySeeders } from './common'; -import { Response } from './types'; - -async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promise { - const search = - ctx.media.type === 'movie' - ? `movie/${ctx.media.imdbId}.json` - : `series/${ctx.media.imdbId}:${ctx.media.season.number}:${ctx.media.episode.number}.json`; - - const response: Response = await ctx - .fetcher( - `https://torrentio.strem.fun/providers=yts,eztv,rarbg,1337x,thepiratebay,kickasstorrents,torrentgalaxy,magnetdl,horriblesubs,nyaasi,tokyotosho,anidex/stream/${search}`, - ) - .then((res) => (typeof res === 'string' ? JSON.parse(res) : res)); - - ctx.progress(50); - - const categories = categorizeStreams(response.streams); - const embeds: { embedId: string; url: string }[] = []; - - const qualityResults = await Promise.all( - Object.entries(categories).map(async ([category, streams]) => { - const [topStream] = getTopStreamsBySeeders(streams, 1); - if (!topStream) return null; - - try { - const magnet = getMagnetUrl(topStream.infoHash, topStream.name); - const apiUrl = constructProxyUrl(magnet); - - const apiResponse = await ctx.fetcher(apiUrl); - const responseData = typeof apiResponse === 'string' ? JSON.parse(apiResponse) : apiResponse; - if (!responseData?.m3u8Link) throw new Error('No m3u8 link in response'); - - return { - quality: category, - url: responseData.m3u8Link, - }; - } catch (error) { - console.error(`Failed to fetch ${category}:`, error); - return null; - } - }), - ); - - qualityResults.forEach((result) => { - if (result?.url) { - embeds.push({ - embedId: `webtor-${result.quality.replace('p', '')}`, - url: result.url, - }); - } - }); - ctx.progress(90); - - return { embeds }; -} - -export const webtorScraper = makeSourcerer({ - id: 'webtor', - name: 'Webtor 🤝', - rank: 2, - disabled: false, - flags: [flags.CORS_ALLOWED], - scrapeMovie: comboScraper, - scrapeShow: comboScraper, -}); diff --git a/src/providers/sources/webtor/types.ts b/src/providers/sources/webtor/types.ts deleted file mode 100644 index 2ffc377..0000000 --- a/src/providers/sources/webtor/types.ts +++ /dev/null @@ -1,17 +0,0 @@ -export interface Stream { - name: string; - title: string; - infoHash: string; - fileIdx: number; - behaviorHints: { - bingeGroup: string; - filename: string; - }; -} - -export interface Response { - streams: Stream[]; - cacheMaxAge: number; - staleRevalidate: number; - staleError: number; -} diff --git a/src/providers/sources/xprime.ts b/src/providers/sources/xprime.ts deleted file mode 100644 index d7f8579..0000000 --- a/src/providers/sources/xprime.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { flags } from '@/entrypoint/utils/targets'; -import { SourcererOutput, makeSourcerer } from '@/providers/base'; -import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context'; - -async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promise { - const query = { - type: ctx.media.type, - title: ctx.media.title, - tmdbId: ctx.media.tmdbId, - imdbId: ctx.media.imdbId, - ...(ctx.media.type === 'show' && { - season: ctx.media.season.number, - episode: ctx.media.episode.number, - }), - releaseYear: ctx.media.releaseYear, - }; - - const embeds = [ - { - embedId: 'xprime-apollo', - url: JSON.stringify(query), - }, - { - embedId: 'xprime-streambox', - url: JSON.stringify(query), - }, - { - embedId: 'xprime-primenet', - url: JSON.stringify(query), - }, - { - embedId: 'xprime-phoenix', - url: JSON.stringify(query), - }, - { - embedId: 'xprime-fox', - url: JSON.stringify(query), - }, - { - embedId: 'xprime-fendi', - url: JSON.stringify(query), - }, - { - embedId: 'xprime-marant', - url: JSON.stringify(query), - }, - { - embedId: 'xprime-volkswagen', - url: JSON.stringify(query), - }, - ]; - - return { embeds }; -} - -export const xprimeScraper = makeSourcerer({ - id: 'xprimetv', - name: 'xprime.tv 🤝', - rank: 240, - disabled: false, - flags: [flags.CORS_ALLOWED], - scrapeMovie: comboScraper, - scrapeShow: comboScraper, -}); diff --git a/src/utils/valid.ts b/src/utils/valid.ts index 3bf8106..480fc5f 100644 --- a/src/utils/valid.ts +++ b/src/utils/valid.ts @@ -1,30 +1,6 @@ // import { alphaScraper, deltaScraper } from '@/providers/embeds/nsbx'; // import { astraScraper, novaScraper, orionScraper } from '@/providers/embeds/whvx'; -import { - oneServerAnimepaheEmbed, - oneServerAnizoneEmbed, - oneServerAutoembedEmbed, - oneServerFlixhqEmbed, - oneServerFoxstreamEmbed, - oneServerGokuEmbed, - oneServerHianimeEmbed, - oneServerPrimeboxEmbed, - oneServerVidsrcsuEmbed, -} from '@/providers/embeds/1server'; import { cinemaosHexaEmbeds } from '@/providers/embeds/cinemaos'; -import { - ConsumetStreamSBScraper, - ConsumetStreamTapeScraper, - ConsumetVidCloudScraper, - ConsumetVidStreamingScraper, -} from '@/providers/embeds/consumet'; -import { FedAPIPrivateScraper, FedDBScraper } from '@/providers/embeds/fedapi'; -import { - hianimeHd1DubEmbed, - hianimeHd1SubEmbed, - hianimeHd2DubEmbed, - hianimeHd2SubEmbed, -} from '@/providers/embeds/hianime'; import { streamwishEnglishScraper, streamwishLatinoScraper, @@ -32,20 +8,8 @@ import { } from '@/providers/embeds/streamwish'; import { viperScraper } from '@/providers/embeds/viper'; import { warezcdnembedMp4Scraper } from '@/providers/embeds/warezcdn/mp4'; -import { - xprimeApolloEmbed, - xprimeFendiEmbed, - xprimeFoxEmbed, - xprimeHarbourEmbed, - xprimeMarantEmbed, - xprimePhoenixEmbed, - xprimePrimenetEmbed, - xprimeStreamboxEmbed, - xprimeVolkswagenEmbed, -} from '@/providers/embeds/xprime'; import { embedsuScraper } from '@/providers/sources/embedsu'; import { soaperTvScraper } from '@/providers/sources/soapertv'; -import { uiraliveScraper } from '@/providers/sources/uiralive'; import { wecimaScraper } from '@/providers/sources/wecima'; import { Stream } from '@/providers/streams'; import { IndividualEmbedRunnerOptions } from '@/runners/individualRunner'; @@ -62,36 +26,7 @@ const SKIP_VALIDATION_CHECK_IDS = [ streamwishLatinoScraper.id, streamwishSpanishScraper.id, streamwishEnglishScraper.id, - uiraliveScraper.id, embedsuScraper.id, - FedAPIPrivateScraper.id, - FedDBScraper.id, - xprimeFoxEmbed.id, - xprimeApolloEmbed.id, - xprimeStreamboxEmbed.id, - xprimeMarantEmbed.id, - xprimeFendiEmbed.id, - xprimePrimenetEmbed.id, - xprimeVolkswagenEmbed.id, - xprimeHarbourEmbed.id, - xprimePhoenixEmbed.id, - ConsumetVidCloudScraper.id, - ConsumetStreamSBScraper.id, - ConsumetVidStreamingScraper.id, - ConsumetStreamTapeScraper.id, - hianimeHd1DubEmbed.id, - hianimeHd1SubEmbed.id, - hianimeHd2DubEmbed.id, - hianimeHd2SubEmbed.id, - oneServerAutoembedEmbed.id, - oneServerVidsrcsuEmbed.id, - oneServerPrimeboxEmbed.id, - oneServerFoxstreamEmbed.id, - oneServerFlixhqEmbed.id, - oneServerGokuEmbed.id, - oneServerHianimeEmbed.id, - oneServerAnimepaheEmbed.id, - oneServerAnizoneEmbed.id, wecimaScraper.id, ...cinemaosHexaEmbeds.map((e) => e.id), soaperTvScraper.id,