From 232390f3d6d3b0b58446e67cdadca9cac2ec0100 Mon Sep 17 00:00:00 2001 From: Inside4ndroid Date: Mon, 4 May 2026 20:27:49 +0100 Subject: [PATCH 1/2] 02MovieDownloader fixed Co-authored-by: Copilot --- package-lock.json | 1 + .../02moviedownloader/02moviedownloader.ts | 20 +++++++++++++++++-- .../02moviedownloader.types.ts | 5 +++++ 3 files changed, 24 insertions(+), 2 deletions(-) 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..f981197 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,7 @@ 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 +251,17 @@ 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 +295,11 @@ 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; +} From f27889e8850b272ada263727a2df6a3632aa53fc Mon Sep 17 00:00:00 2001 From: Inside4ndroid Date: Mon, 4 May 2026 20:42:56 +0100 Subject: [PATCH 2/2] Prettier found formatting issues in the file I edited. Ran the formatter to fix it --- .../02moviedownloader/02moviedownloader.ts | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/providers/02moviedownloader/02moviedownloader.ts b/src/providers/02moviedownloader/02moviedownloader.ts index f981197..5ad6737 100644 --- a/src/providers/02moviedownloader/02moviedownloader.ts +++ b/src/providers/02moviedownloader/02moviedownloader.ts @@ -8,7 +8,11 @@ import type { SubtitleFormat } from '@omss/framework'; import { BaseProvider, type SourceType, type Subtitle } from '@omss/framework'; -import { EncryptedResponse, 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 { @@ -251,15 +255,24 @@ export class MovieDownloader extends BaseProvider { }; } - private decryptPayload(cipherBundle: string, token: string): MovieDownloaderResponse { + private decryptPayload( + cipherBundle: string, + token: string + ): MovieDownloaderResponse { const parts = cipherBundle.split(':'); - if (parts.length !== 2) throw new Error('Invalid encrypted payload format'); + 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; + const decrypted = Buffer.concat([ + decipher.update(cipherBytes), + decipher.final() + ]); + return JSON.parse( + decrypted.toString('utf8') + ) as MovieDownloaderResponse; } private buildPageUrl(media: ProviderMediaObject): string { @@ -295,7 +308,9 @@ export class MovieDownloader extends BaseProvider { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } - const raw = await response.json() as MovieDownloaderResponse | EncryptedResponse; + const raw = (await response.json()) as + | MovieDownloaderResponse + | EncryptedResponse; if ('encrypted' in raw && raw.encrypted === true) { return this.decryptPayload(raw.data, token); }