diff --git a/src/providers/sources/fed/fedapi.ts b/src/providers/sources/fed/fedapi.ts index 627ac63..e0803fa 100644 --- a/src/providers/sources/fed/fedapi.ts +++ b/src/providers/sources/fed/fedapi.ts @@ -1,12 +1,11 @@ import { flags } from '@/entrypoint/utils/targets'; import { SourcererOutput, makeSourcerer } from '@/providers/base'; -import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context'; import { NotFoundError } from '@/utils/errors'; -import { Caption, labelToLanguageCode } from '../../captions'; +import { labelToLanguageCode } from '../../captions'; const BASE_URL = 'https://fedapi.asteral-ss2.workers.dev'; -const getUserToken = (): string | null => { +const getUserToken = () => { try { if (typeof window === 'undefined') return null; @@ -14,26 +13,29 @@ const getUserToken = (): string | null => { if (!prefData) return null; const parsed = JSON.parse(prefData); - return parsed?.state?.febboxKey ?? null; + return parsed?.state?.febboxKey || null; } catch { return null; } }; -const getRegion = (): string | null => { +const getRegion = () => { 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) { + return parsed?.state?.region || null; + } catch { return null; } }; -function selectSubdomainByRegion(input: string | null): string | null { +function selectSubdomainByRegion(input) { const region = (input || '').toLowerCase(); + const match = region.match(/(usa5|usa6|usa7|uk1|de2|hk1|ca1|au1|sg1|in1)/); if (match) return match[1]; @@ -41,37 +43,44 @@ function selectSubdomainByRegion(input: string | null): string | null { if (region.includes('portland')) return 'usa6'; if (region.includes('new-york')) return 'usa7'; if (region.includes('paris')) return Math.random() < 0.5 ? 'uk1' : 'de2'; - return null; + + return null; } -function rewriteSheguSubdomain(originalUrl: string, subdomain: string): string { +function rewriteSheguSubdomain(url, subdomain) { try { - const parsed = new URL(originalUrl); + const parsed = new URL(url); + if (parsed.hostname.endsWith('.shegu.net')) { parsed.hostname = `${subdomain}.shegu.net`; return parsed.toString(); } - return originalUrl; + + return url; } catch { - return originalUrl; + return url; } } -async function FedScraper(ctx: MovieScrapeContext | ShowScrapeContext): Promise { +async function FedScraper(ctx) { + const token = getUserToken(); + if (!token) throw new NotFoundError('Missing user token'); + const tmdbId = ctx.media.tmdbId; if (!tmdbId) throw new NotFoundError('Missing TMDB ID'); const region = getRegion(); ctx.progress(30); - const url = ctx.media.type === 'movie' - ? `${BASE_URL}/movie/${tmdbId}` - : `${BASE_URL}/tv/${tmdbId}/${ctx.media.season.number}/${ctx.media.episode.number}`; + const url = + ctx.media.type === 'movie' + ? `${BASE_URL}/movie/${tmdbId}` + : `${BASE_URL}/tv/${tmdbId}/${ctx.media.season.number}/${ctx.media.episode.number}`; - const data = await ctx.fetcher(url); + const data = await ctx.fetcher(url); if (!data || !data.success || !data.stream) { - throw new NotFoundError('No stream found in Thunderleaf'); + throw new NotFoundError('No stream found'); } let finalStreamUrl = data.stream; @@ -83,12 +92,15 @@ async function FedScraper(ctx: MovieScrapeContext | ShowScrapeContext): Promise< ctx.progress(80); - const captions: Caption[] = []; + const captions = []; + if (data.subtitles) { - Object.entries(data.subtitles).forEach(([langKey, sub]: [string, any]) => { + Object.entries(data.subtitles).forEach(([langKey, sub]) => { const languageName = langKey.split('_')[0]; - const languageCode = labelToLanguageCode(languageName)?.toLowerCase() ?? 'unknown'; - if (sub.url) { + const languageCode = + labelToLanguageCode(languageName)?.toLowerCase() || 'unknown'; + + if (sub?.url) { captions.push({ type: sub.url.endsWith('.vtt') ? 'vtt' : 'srt', id: sub.url, @@ -100,24 +112,24 @@ async function FedScraper(ctx: MovieScrapeContext | ShowScrapeContext): Promise< }); } -const stream = - token - ? [ - { + return { + embeds: [], + stream: [ + { id: 'primary', type: 'file', - flags: [], + flags: [], captions, - qualities: { - unknown: { - type: 'mp4', - url: finalStreamUrl, + qualities: { + unknown: { + type: 'mp4', + url: finalStreamUrl, }, }, headers: {}, - } as const, - ], - return { embeds: [], stream }; + }, + ], + }; } export const FedApiScraper = makeSourcerer({