diff --git a/package-lock.json b/package-lock.json index f1e0b82..85a8cea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1671,6 +1671,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/src/providers/02moviedownloader/02moviedownloader.ts b/src/providers/02moviedownloader/02moviedownloader.ts index 8154f7f..5ad6737 100644 --- a/src/providers/02moviedownloader/02moviedownloader.ts +++ b/src/providers/02moviedownloader/02moviedownloader.ts @@ -1,3 +1,4 @@ +import { createDecipheriv, createHash } from 'crypto'; import type { Diagnostic, ProviderCapabilities, @@ -7,7 +8,11 @@ import type { SubtitleFormat } from '@omss/framework'; import { BaseProvider, type SourceType, type Subtitle } from '@omss/framework'; -import { MovieDownloaderResponse, Token } from './02moviedownloader.types.js'; +import { + EncryptedResponse, + MovieDownloaderResponse, + Token +} from './02moviedownloader.types.js'; import { generateRandomUserAgent } from '../../utils/ua.js'; export class MovieDownloader extends BaseProvider { @@ -250,6 +255,26 @@ export class MovieDownloader extends BaseProvider { }; } + private decryptPayload( + cipherBundle: string, + token: string + ): MovieDownloaderResponse { + const parts = cipherBundle.split(':'); + if (parts.length !== 2) + throw new Error('Invalid encrypted payload format'); + const iv = Buffer.from(parts[0], 'base64'); + const cipherBytes = Buffer.from(parts[1], 'base64'); + const key = createHash('sha256').update(token).digest(); + const decipher = createDecipheriv('aes-256-cbc', key, iv); + const decrypted = Buffer.concat([ + decipher.update(cipherBytes), + decipher.final() + ]); + return JSON.parse( + decrypted.toString('utf8') + ) as MovieDownloaderResponse; + } + private buildPageUrl(media: ProviderMediaObject): string { const tmdbId = media.tmdbId; if (media.type === 'movie') { @@ -283,7 +308,13 @@ export class MovieDownloader extends BaseProvider { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } - return await response.json(); + const raw = (await response.json()) as + | MovieDownloaderResponse + | EncryptedResponse; + if ('encrypted' in raw && raw.encrypted === true) { + return this.decryptPayload(raw.data, token); + } + return raw as MovieDownloaderResponse; } catch (error) { throw new Error( `Failed to fetch page for ${media.title}: ${error}` diff --git a/src/providers/02moviedownloader/02moviedownloader.types.ts b/src/providers/02moviedownloader/02moviedownloader.types.ts index 34c5523..a870637 100644 --- a/src/providers/02moviedownloader/02moviedownloader.types.ts +++ b/src/providers/02moviedownloader/02moviedownloader.types.ts @@ -62,3 +62,8 @@ export interface Token { token: string; expiresIn: number; } + +export interface EncryptedResponse { + encrypted: true; + data: string; +}