From 0446d52e7879b8c2e35954f1179447097021a291 Mon Sep 17 00:00:00 2001 From: WebStreamr <210764791+webstreamr@users.noreply.github.com> Date: Sun, 8 Jun 2025 18:55:03 +0000 Subject: [PATCH] refactor: `UrlResult[]` instead of `UrlResult | undefined` --- src/extractor/DoodStream.ts | 26 +-- src/extractor/Dropload.ts | 24 +-- src/extractor/ExternalUrl.ts | 18 +- src/extractor/ExtractorRegistry.test.ts | 23 +-- src/extractor/ExtractorRegistry.ts | 38 ++-- src/extractor/Soaper.ts | 20 +- src/extractor/SuperVideo.ts | 24 +-- .../ExtractorRegistry.test.ts.snap | 40 ++-- src/extractor/types.ts | 2 +- .../__snapshots__/CineHDPlus.test.ts.snap | 96 ++++----- .../__snapshots__/Eurostreaming.test.ts.snap | 72 +++---- .../__snapshots__/Frembed.test.ts.snap | 184 ++++++++++-------- .../__snapshots__/FrenchCloud.test.ts.snap | 114 ++++++----- .../__snapshots__/KinoKiste.test.ts.snap | 48 ++--- .../__snapshots__/MeineCloud.test.ts.snap | 94 +++++---- .../__snapshots__/MostraGuarda.test.ts.snap | 94 +++++---- src/handler/__snapshots__/Soaper.test.ts.snap | 66 ++++--- .../__snapshots__/VerHdLink.test.ts.snap | 158 ++++++++------- src/handler/types.ts | 2 +- src/utils/StreamResolver.test.ts | 112 +++++------ src/utils/StreamResolver.ts | 2 +- 21 files changed, 677 insertions(+), 580 deletions(-) diff --git a/src/extractor/DoodStream.ts b/src/extractor/DoodStream.ts index dc88281..3dfb176 100644 --- a/src/extractor/DoodStream.ts +++ b/src/extractor/DoodStream.ts @@ -38,18 +38,20 @@ export class DoodStream implements Extractor { const $ = cheerio.load(html); const title = $('title').text().trim().replace(/ - DoodStream$/, '').trim(); - return { - url: new URL(`${baseUrl}${randomstring.generate(10)}?token=${token}&expiry=${Date.now()}`), - label: this.label, - sourceId: `${this.id}_${meta.countryCode.toLowerCase()}`, - ttl: this.ttl, - meta: { - title, - ...meta, + return [ + { + url: new URL(`${baseUrl}${randomstring.generate(10)}?token=${token}&expiry=${Date.now()}`), + label: this.label, + sourceId: `${this.id}_${meta.countryCode.toLowerCase()}`, + ttl: this.ttl, + meta: { + title, + ...meta, + }, + requestHeaders: { + Referer: 'http://dood.to/', + }, }, - requestHeaders: { - Referer: 'http://dood.to/', - }, - }; + ]; }; } diff --git a/src/extractor/Dropload.ts b/src/extractor/Dropload.ts index 03c5403..b6eaa8e 100644 --- a/src/extractor/Dropload.ts +++ b/src/extractor/Dropload.ts @@ -35,17 +35,19 @@ export class Dropload implements Extractor { const $ = cheerio.load(html); const title = $('.videoplayer h1').text().trim(); - return { - url: extractUrlFromPacked(html, [/sources:\[{file:"(.*?)"/]), - label: this.label, - sourceId: `${this.id}_${meta.countryCode.toLowerCase()}`, - ttl: this.ttl, - meta: { - bytes: bytes.parse(sizeMatch[1] as string) as number, - height: parseInt(heightMatch[1] as string) as number, - title, - ...meta, + return [ + { + url: extractUrlFromPacked(html, [/sources:\[{file:"(.*?)"/]), + label: this.label, + sourceId: `${this.id}_${meta.countryCode.toLowerCase()}`, + ttl: this.ttl, + meta: { + bytes: bytes.parse(sizeMatch[1] as string) as number, + height: parseInt(heightMatch[1] as string) as number, + title, + ...meta, + }, }, - }; + ]; }; } diff --git a/src/extractor/ExternalUrl.ts b/src/extractor/ExternalUrl.ts index 5fc7708..b8f9d81 100644 --- a/src/extractor/ExternalUrl.ts +++ b/src/extractor/ExternalUrl.ts @@ -21,13 +21,15 @@ export class ExternalUrl implements Extractor { // We only want to make sure that the URL is accessible await this.fetcher.head(ctx, url); - return { - url: url, - isExternal: true, - label: `${url.host}`, - sourceId: `${this.id}_${meta.countryCode.toLowerCase()}`, - ttl: this.ttl, - meta, - }; + return [ + { + url: url, + isExternal: true, + label: `${url.host}`, + sourceId: `${this.id}_${meta.countryCode.toLowerCase()}`, + ttl: this.ttl, + meta, + }, + ]; }; } diff --git a/src/extractor/ExtractorRegistry.test.ts b/src/extractor/ExtractorRegistry.test.ts index 066ad42..cfe4fc1 100644 --- a/src/extractor/ExtractorRegistry.test.ts +++ b/src/extractor/ExtractorRegistry.test.ts @@ -1,6 +1,6 @@ import winston from 'winston'; import { ExtractorRegistry } from './ExtractorRegistry'; -import { Context, UrlResult } from '../types'; +import { Context } from '../types'; import { Fetcher } from '../utils'; jest.mock('../utils/Fetcher'); @@ -27,25 +27,22 @@ describe('ExtractorRegistry', () => { test('does not return external URLs if disabled by config', async () => { const urlResult = await extractorRegistry.handle({ ...ctx, config: { ...ctx.config, excludeExternalUrls: 'on' } }, new URL('https://mixdrop.ag/e/l7v73zqrfdj19z'), { countryCode: 'de' }); - expect(urlResult).toBeUndefined(); + expect(urlResult).toStrictEqual([]); }); test('returns from memory cache if possible', async () => { - const { ttl: ttl1, ...urlResultRest1 } = await extractorRegistry.handle(ctx, new URL('https://dropload.io/lyo2h1snpe5c.html'), { countryCode: 'de' }) as UrlResult; - const { ttl: ttl2, ...urlResultRest2 } = await extractorRegistry.handle(ctx, new URL('https://dropload.io/lyo2h1snpe5c.html'), { countryCode: 'de' }) as UrlResult; + const urlResults1 = await extractorRegistry.handle(ctx, new URL('https://dropload.io/lyo2h1snpe5c.html'), { countryCode: 'de' }); + const urlResults2 = await extractorRegistry.handle(ctx, new URL('https://dropload.io/lyo2h1snpe5c.html'), { countryCode: 'de' }); - expect(urlResultRest1).not.toBeUndefined(); - expect(urlResultRest2).toStrictEqual(urlResultRest1); - - expect(ttl1).not.toBe(undefined); - expect(ttl2).not.toBe(undefined); + expect(urlResults1).not.toStrictEqual([]); + expect(urlResults2).not.toStrictEqual([]); }); test('ignores not found errors but caches them', async () => { - const urlResult1 = await extractorRegistry.handle(ctx, new URL('https://dropload.io/asdfghijklmn.html'), { countryCode: 'de' }); - const urlResult2 = await extractorRegistry.handle(ctx, new URL('https://dropload.io/asdfghijklmn.html'), { countryCode: 'de' }); + const urlResults1 = await extractorRegistry.handle(ctx, new URL('https://dropload.io/asdfghijklmn.html'), { countryCode: 'de' }); + const urlResults2 = await extractorRegistry.handle(ctx, new URL('https://dropload.io/asdfghijklmn.html'), { countryCode: 'de' }); - expect(urlResult1).toBeUndefined(); - expect(urlResult2).toBeUndefined(); + expect(urlResults1).toStrictEqual([]); + expect(urlResults2).toStrictEqual([]); }); }); diff --git a/src/extractor/ExtractorRegistry.ts b/src/extractor/ExtractorRegistry.ts index 4458e20..d19646b 100644 --- a/src/extractor/ExtractorRegistry.ts +++ b/src/extractor/ExtractorRegistry.ts @@ -13,7 +13,7 @@ import { NotFoundError } from '../error'; export class ExtractorRegistry { private readonly logger: winston.Logger; private readonly extractors: Extractor[]; - private readonly urlResultCache: TTLCache; + private readonly urlResultCache: TTLCache; constructor(logger: winston.Logger, fetcher: Fetcher) { this.logger = logger; @@ -27,40 +27,42 @@ export class ExtractorRegistry { this.urlResultCache = new TTLCache({ max: 1024 }); } - readonly handle = async (ctx: Context, url: URL, meta: Meta): Promise => { - let urlResult = this.urlResultCache.get(url.href); + readonly handle = async (ctx: Context, url: URL, meta: Meta): Promise => { + let urlResults = this.urlResultCache.get(url.href) ?? []; if (this.urlResultCache.has(url.href)) { - return urlResult ? { ...urlResult, ttl: this.urlResultCache.getRemainingTTL(url.href) } : undefined; + return urlResults.map(urlResult => ({ ...urlResult, ttl: this.urlResultCache.getRemainingTTL(url.href) })); } const extractor = this.extractors.find(extractor => extractor.supports(ctx, url)); if (!extractor) { - return undefined; + return []; } this.logger.info(`Extract stream URL using ${extractor.id} extractor from ${url}`, ctx); try { - urlResult = await extractor.extract(ctx, url, meta); + urlResults = await extractor.extract(ctx, url, meta); } catch (error) { if (error instanceof NotFoundError) { - this.urlResultCache.set(url.href, urlResult, { ttl: extractor.ttl }); + this.urlResultCache.set(url.href, urlResults, { ttl: extractor.ttl }); - return undefined; + return []; } - return { - url, - isExternal: true, - error, - label: url.host, - sourceId: `${extractor.id}`, - meta, - }; + return [ + { + url, + isExternal: true, + error, + label: url.host, + sourceId: `${extractor.id}`, + meta, + }, + ]; } - this.urlResultCache.set(url.href, urlResult, { ttl: extractor.ttl }); + this.urlResultCache.set(url.href, urlResults, { ttl: extractor.ttl }); - return urlResult; + return urlResults; }; } diff --git a/src/extractor/Soaper.ts b/src/extractor/Soaper.ts index fc88ecf..9b70b4e 100644 --- a/src/extractor/Soaper.ts +++ b/src/extractor/Soaper.ts @@ -48,15 +48,17 @@ export class Soaper implements Extractor { const m3u8Data = await this.fetcher.text(ctx, m3u8Url); const height = m3u8Data.match(/\d+x(\d+)|(\d+)p/) as string[]; - return { - url: new URL(jsonResponse['val'], url.origin), - label: this.label, - sourceId: `${this.id}_${meta.countryCode.toLowerCase()}`, - ttl: this.ttl, - meta: { - ...(height && { height: parseInt(height[1] ?? height[2] as string) }), - ...meta, + return [ + { + url: new URL(jsonResponse['val'], url.origin), + label: this.label, + sourceId: `${this.id}_${meta.countryCode.toLowerCase()}`, + ttl: this.ttl, + meta: { + ...(height && { height: parseInt(height[1] ?? height[2] as string) }), + ...meta, + }, }, - }; + ]; }; } diff --git a/src/extractor/SuperVideo.ts b/src/extractor/SuperVideo.ts index 593986f..93cd630 100644 --- a/src/extractor/SuperVideo.ts +++ b/src/extractor/SuperVideo.ts @@ -28,17 +28,19 @@ export class SuperVideo implements Extractor { const $ = cheerio.load(html); const title = $('title').text().trim().replace(/^Watch /, '').trim(); - return { - url: extractUrlFromPacked(html, [/sources:\[{file:"(.*?)"/]), - label: this.label, - sourceId: `${this.id}_${meta.countryCode.toLowerCase()}`, - ttl: this.ttl, - meta: { - bytes: bytes.parse(heightAndSizeMatch[2] as string) as number, - height: parseInt(heightAndSizeMatch[1] as string) as number, - title, - ...meta, + return [ + { + url: extractUrlFromPacked(html, [/sources:\[{file:"(.*?)"/]), + label: this.label, + sourceId: `${this.id}_${meta.countryCode.toLowerCase()}`, + ttl: this.ttl, + meta: { + bytes: bytes.parse(heightAndSizeMatch[2] as string) as number, + height: parseInt(heightAndSizeMatch[1] as string) as number, + title, + ...meta, + }, }, - }; + ]; }; } diff --git a/src/extractor/__snapshots__/ExtractorRegistry.test.ts.snap b/src/extractor/__snapshots__/ExtractorRegistry.test.ts.snap index 2d1450f..7bced58 100644 --- a/src/extractor/__snapshots__/ExtractorRegistry.test.ts.snap +++ b/src/extractor/__snapshots__/ExtractorRegistry.test.ts.snap @@ -1,27 +1,31 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ExtractorRegistry return external URLs by default 1`] = ` -{ - "isExternal": true, - "label": "mixdrop.ag", - "meta": { - "countryCode": "de", +[ + { + "isExternal": true, + "label": "mixdrop.ag", + "meta": { + "countryCode": "de", + }, + "sourceId": "external_de", + "ttl": 3600000, + "url": "https://mixdrop.ag/e/3nzwveprim63or6", }, - "sourceId": "external_de", - "ttl": 3600000, - "url": "https://mixdrop.ag/e/3nzwveprim63or6", -} +] `; exports[`ExtractorRegistry returns error result from extractor 1`] = ` -{ - "error": [Error: TypeError: fetch failed], - "isExternal": true, - "label": "some-url.test", - "meta": { - "countryCode": "en", +[ + { + "error": [Error: TypeError: fetch failed], + "isExternal": true, + "label": "some-url.test", + "meta": { + "countryCode": "en", + }, + "sourceId": "external", + "url": "https://some-url.test/", }, - "sourceId": "external", - "url": "https://some-url.test/", -} +] `; diff --git a/src/extractor/types.ts b/src/extractor/types.ts index ba64921..c793fae 100644 --- a/src/extractor/types.ts +++ b/src/extractor/types.ts @@ -9,5 +9,5 @@ export interface Extractor { readonly supports: (ctx: Context, url: URL) => boolean; - readonly extract: (ctx: Context, url: URL, meta: Meta) => Promise; + readonly extract: (ctx: Context, url: URL, meta: Meta) => Promise; } diff --git a/src/handler/__snapshots__/CineHDPlus.test.ts.snap b/src/handler/__snapshots__/CineHDPlus.test.ts.snap index b4845f9..d7e7b15 100644 --- a/src/handler/__snapshots__/CineHDPlus.test.ts.snap +++ b/src/handler/__snapshots__/CineHDPlus.test.ts.snap @@ -2,58 +2,66 @@ exports[`CineHDPlus handle imdb babylon 5 s2e3 (es) 1`] = ` [ - { - "label": "SuperVideo", - "meta": { - "bytes": 219571814, - "countryCode": "es", - "height": 344, - "title": "Babylon 5 2x3", + [ + { + "label": "SuperVideo", + "meta": { + "bytes": 219571814, + "countryCode": "es", + "height": 344, + "title": "Babylon 5 2x3", + }, + "sourceId": "supervideo_es", + "ttl": 900000, + "url": "https://hfs294.serversicuro.cc/hls/,dnzpealv5xg4a3gyvavh52jryms77x3wwakzvgy2ly3yfusnblczjnvvweua,.urlset/master.m3u8", }, - "sourceId": "supervideo_es", - "ttl": 900000, - "url": "https://hfs294.serversicuro.cc/hls/,dnzpealv5xg4a3gyvavh52jryms77x3wwakzvgy2ly3yfusnblczjnvvweua,.urlset/master.m3u8", - }, - { - "label": "Dropload", - "meta": { - "bytes": 219571814, - "countryCode": "es", - "height": 344, - "title": "Babylon 5 2x3", + ], + [ + { + "label": "Dropload", + "meta": { + "bytes": 219571814, + "countryCode": "es", + "height": 344, + "title": "Babylon 5 2x3", + }, + "sourceId": "dropload_es", + "ttl": 900000, + "url": "https://srv29.dropload.io/hls2/01/00295/957hny8mzrvh_h/master.m3u8?t=VpcZJYlXpp0FJb0Nh0yJR0nyI8-SKB2tGFwpcTx9v2w&s=1747213958&e=14400&f=1476559&i=0.0&sp=0&ii=130.61.236.204", }, - "sourceId": "dropload_es", - "ttl": 900000, - "url": "https://srv29.dropload.io/hls2/01/00295/957hny8mzrvh_h/master.m3u8?t=VpcZJYlXpp0FJb0Nh0yJR0nyI8-SKB2tGFwpcTx9v2w&s=1747213958&e=14400&f=1476559&i=0.0&sp=0&ii=130.61.236.204", - }, + ], ] `; exports[`CineHDPlus handle imdb black mirror s2e3 (mx) 1`] = ` [ - { - "label": "SuperVideo", - "meta": { - "bytes": 146800640, - "countryCode": "mx", - "height": 360, - "title": "Black Mirror 2x3", + [ + { + "label": "SuperVideo", + "meta": { + "bytes": 146800640, + "countryCode": "mx", + "height": 360, + "title": "Black Mirror 2x3", + }, + "sourceId": "supervideo_mx", + "ttl": 900000, + "url": "https://hfs299.serversicuro.cc/hls/,dnzpff262hg4a3gyvcex5ojxt23vrieljzut7xhjydwidlbp4g7nqswkpfwq,.urlset/master.m3u8", }, - "sourceId": "supervideo_mx", - "ttl": 900000, - "url": "https://hfs299.serversicuro.cc/hls/,dnzpff262hg4a3gyvcex5ojxt23vrieljzut7xhjydwidlbp4g7nqswkpfwq,.urlset/master.m3u8", - }, - { - "label": "Dropload", - "meta": { - "bytes": 146800640, - "countryCode": "mx", - "height": 360, - "title": "Black Mirror 2x3", + ], + [ + { + "label": "Dropload", + "meta": { + "bytes": 146800640, + "countryCode": "mx", + "height": 360, + "title": "Black Mirror 2x3", + }, + "sourceId": "dropload_mx", + "ttl": 900000, + "url": "https://srv27.dropload.io/hls2/01/00075/t058ulwwkwn6_h/master.m3u8?t=GkktV2WgIMrvrgNLyjn6Bxeo2fArEAz6y9nSi_6dVAs&s=1747213564&e=14400&f=376684&i=0.0&sp=0&ii=130.61.236.204", }, - "sourceId": "dropload_mx", - "ttl": 900000, - "url": "https://srv27.dropload.io/hls2/01/00075/t058ulwwkwn6_h/master.m3u8?t=GkktV2WgIMrvrgNLyjn6Bxeo2fArEAz6y9nSi_6dVAs&s=1747213564&e=14400&f=376684&i=0.0&sp=0&ii=130.61.236.204", - }, + ], ] `; diff --git a/src/handler/__snapshots__/Eurostreaming.test.ts.snap b/src/handler/__snapshots__/Eurostreaming.test.ts.snap index e36b2c4..bb3d460 100644 --- a/src/handler/__snapshots__/Eurostreaming.test.ts.snap +++ b/src/handler/__snapshots__/Eurostreaming.test.ts.snap @@ -2,41 +2,47 @@ exports[`Eurostreaming handle imdb black mirror s2e4 1`] = ` [ - { - "label": "SuperVideo", - "meta": { - "bytes": 875875532, - "countryCode": "it", - "height": 1080, - "title": "Black Mirror 2x4", + [ + { + "label": "SuperVideo", + "meta": { + "bytes": 875875532, + "countryCode": "it", + "height": 1080, + "title": "Black Mirror 2x4", + }, + "sourceId": "supervideo_it", + "ttl": 900000, + "url": "https://hfs309.serversicuro.cc/hls/dnzpdeoe5xg4a3gyvaqx5ojpswtxjd5a22rklgah7,khdhascykjrixs7huqq,obtfascykj3vna7rk5a,.urlset/master.m3u8", }, - "sourceId": "supervideo_it", - "ttl": 900000, - "url": "https://hfs309.serversicuro.cc/hls/dnzpdeoe5xg4a3gyvaqx5ojpswtxjd5a22rklgah7,khdhascykjrixs7huqq,obtfascykj3vna7rk5a,.urlset/master.m3u8", - }, - { - "label": "SuperVideo", - "meta": { - "bytes": 875875532, - "countryCode": "it", - "height": 1080, - "title": "Black Mirror 2x4", + ], + [ + { + "label": "SuperVideo", + "meta": { + "bytes": 875875532, + "countryCode": "it", + "height": 1080, + "title": "Black Mirror 2x4", + }, + "sourceId": "supervideo_it", + "ttl": 900000, + "url": "https://hfs309.serversicuro.cc/hls/dnzpdeoe5xg4a3gyvaqx5ojpswtxjd5a22rklgah7,khdhascykjrixs7huqq,obtfascykj3vna7rk5a,.urlset/master.m3u8", }, - "sourceId": "supervideo_it", - "ttl": 900000, - "url": "https://hfs309.serversicuro.cc/hls/dnzpdeoe5xg4a3gyvaqx5ojpswtxjd5a22rklgah7,khdhascykjrixs7huqq,obtfascykj3vna7rk5a,.urlset/master.m3u8", - }, - { - "label": "Dropload", - "meta": { - "bytes": 875875532, - "countryCode": "it", - "height": 1080, - "title": "Black Mirror 2x4", + ], + [ + { + "label": "Dropload", + "meta": { + "bytes": 875875532, + "countryCode": "it", + "height": 1080, + "title": "Black Mirror 2x4", + }, + "sourceId": "dropload_it", + "ttl": 900000, + "url": "https://srv24.dropload.io/hls2/01/00289/978xyyxi3ldq_h/master.m3u8?t=unq9qxjYC-zgcmoXiSQ6rkMu7qHrSpN_pWOc95IPYwk&s=1747217151&e=14400&f=1448116&i=0.0&sp=0&ii=130.61.236.204", }, - "sourceId": "dropload_it", - "ttl": 900000, - "url": "https://srv24.dropload.io/hls2/01/00289/978xyyxi3ldq_h/master.m3u8?t=unq9qxjYC-zgcmoXiSQ6rkMu7qHrSpN_pWOc95IPYwk&s=1747217151&e=14400&f=1448116&i=0.0&sp=0&ii=130.61.236.204", - }, + ], ] `; diff --git a/src/handler/__snapshots__/Frembed.test.ts.snap b/src/handler/__snapshots__/Frembed.test.ts.snap index 35cad7d..49b913d 100644 --- a/src/handler/__snapshots__/Frembed.test.ts.snap +++ b/src/handler/__snapshots__/Frembed.test.ts.snap @@ -2,102 +2,118 @@ exports[`Frembed handle imdb black mirror s4e2 1`] = ` [ - { - "label": "DoodStream", - "meta": { - "countryCode": "fr", - "title": "Black Mirror 4x2", + [ + { + "label": "DoodStream", + "meta": { + "countryCode": "fr", + "title": "Black Mirror 4x2", + }, + "requestHeaders": { + "Referer": "http://dood.to/", + }, + "sourceId": "doodstream_fr", + "ttl": 900000, + "url": "https://ee317r.cloudatacdn.com/u5kj63yvxddlsdgge7qremqqka27irwiupc4k7o5cikbh7fdq4j4mwzraf7q/1y4sn4ndoi~mocked-random-string?token=fh3rdlhjvao7chgxndsi3ra7&expiry=639837296000", }, - "requestHeaders": { - "Referer": "http://dood.to/", + ], + [ + { + "isExternal": true, + "label": "netu.fanstream.us", + "meta": { + "countryCode": "fr", + "title": "Black Mirror 4x2", + }, + "sourceId": "external_fr", + "ttl": 3600000, + "url": "https://netu.fanstream.us/e/0DFgfkcXOsDP", }, - "sourceId": "doodstream_fr", - "ttl": 900000, - "url": "https://ee317r.cloudatacdn.com/u5kj63yvxddlsdgge7qremqqka27irwiupc4k7o5cikbh7fdq4j4mwzraf7q/1y4sn4ndoi~mocked-random-string?token=fh3rdlhjvao7chgxndsi3ra7&expiry=639837296000", - }, - { - "isExternal": true, - "label": "netu.fanstream.us", - "meta": { - "countryCode": "fr", - "title": "Black Mirror 4x2", + ], + [ + { + "isExternal": true, + "label": "johnalwayssame.com", + "meta": { + "countryCode": "fr", + "title": "Black Mirror 4x2", + }, + "sourceId": "external_fr", + "ttl": 3600000, + "url": "https://johnalwayssame.com/e/cqy9oue7sv0g", }, - "sourceId": "external_fr", - "ttl": 3600000, - "url": "https://netu.fanstream.us/e/0DFgfkcXOsDP", - }, - { - "isExternal": true, - "label": "johnalwayssame.com", - "meta": { - "countryCode": "fr", - "title": "Black Mirror 4x2", + ], + [ + { + "error": [Error: TypeError: fetch failed], + "isExternal": true, + "label": "ds2play.com", + "meta": { + "countryCode": "fr", + "title": "Black Mirror 4x2", + }, + "sourceId": "external", + "url": "https://ds2play.com/e/fzfvfq3ngig0", }, - "sourceId": "external_fr", - "ttl": 3600000, - "url": "https://johnalwayssame.com/e/cqy9oue7sv0g", - }, - { - "error": [Error: TypeError: fetch failed], - "isExternal": true, - "label": "ds2play.com", - "meta": { - "countryCode": "fr", - "title": "Black Mirror 4x2", - }, - "sourceId": "external", - "url": "https://ds2play.com/e/fzfvfq3ngig0", - }, + ], ] `; exports[`Frembed handle tmdb black mirror s4e2 1`] = ` [ - { - "label": "DoodStream", - "meta": { - "countryCode": "fr", - "title": "Black Mirror 4x2", + [ + { + "label": "DoodStream", + "meta": { + "countryCode": "fr", + "title": "Black Mirror 4x2", + }, + "requestHeaders": { + "Referer": "http://dood.to/", + }, + "sourceId": "doodstream_fr", + "ttl": 900000, + "url": "https://ee317r.cloudatacdn.com/u5kj63yvxddlsdgge7qremqqka27irwiupc4k7o5cikbh7fdq4j4mwzraf7q/1y4sn4ndoi~mocked-random-string?token=fh3rdlhjvao7chgxndsi3ra7&expiry=639837296000", }, - "requestHeaders": { - "Referer": "http://dood.to/", + ], + [ + { + "isExternal": true, + "label": "netu.fanstream.us", + "meta": { + "countryCode": "fr", + "title": "Black Mirror 4x2", + }, + "sourceId": "external_fr", + "ttl": 3600000, + "url": "https://netu.fanstream.us/e/0DFgfkcXOsDP", }, - "sourceId": "doodstream_fr", - "ttl": 900000, - "url": "https://ee317r.cloudatacdn.com/u5kj63yvxddlsdgge7qremqqka27irwiupc4k7o5cikbh7fdq4j4mwzraf7q/1y4sn4ndoi~mocked-random-string?token=fh3rdlhjvao7chgxndsi3ra7&expiry=639837296000", - }, - { - "isExternal": true, - "label": "netu.fanstream.us", - "meta": { - "countryCode": "fr", - "title": "Black Mirror 4x2", + ], + [ + { + "isExternal": true, + "label": "johnalwayssame.com", + "meta": { + "countryCode": "fr", + "title": "Black Mirror 4x2", + }, + "sourceId": "external_fr", + "ttl": 3600000, + "url": "https://johnalwayssame.com/e/cqy9oue7sv0g", }, - "sourceId": "external_fr", - "ttl": 3600000, - "url": "https://netu.fanstream.us/e/0DFgfkcXOsDP", - }, - { - "isExternal": true, - "label": "johnalwayssame.com", - "meta": { - "countryCode": "fr", - "title": "Black Mirror 4x2", + ], + [ + { + "error": [Error: TypeError: fetch failed], + "isExternal": true, + "label": "ds2play.com", + "meta": { + "countryCode": "fr", + "title": "Black Mirror 4x2", + }, + "sourceId": "external", + "url": "https://ds2play.com/e/fzfvfq3ngig0", }, - "sourceId": "external_fr", - "ttl": 3600000, - "url": "https://johnalwayssame.com/e/cqy9oue7sv0g", - }, - { - "error": [Error: TypeError: fetch failed], - "isExternal": true, - "label": "ds2play.com", - "meta": { - "countryCode": "fr", - "title": "Black Mirror 4x2", - }, - "sourceId": "external", - "url": "https://ds2play.com/e/fzfvfq3ngig0", - }, + ], ] `; diff --git a/src/handler/__snapshots__/FrenchCloud.test.ts.snap b/src/handler/__snapshots__/FrenchCloud.test.ts.snap index 8710a24..d73042e 100644 --- a/src/handler/__snapshots__/FrenchCloud.test.ts.snap +++ b/src/handler/__snapshots__/FrenchCloud.test.ts.snap @@ -2,62 +2,72 @@ exports[`FrenchCloud handle imdb the devil's bath 1`] = ` [ - { - "label": "SuperVideo", - "meta": { - "bytes": 966682214, - "countryCode": "fr", - "height": 720, - "title": "the devils bath enfant pour diable 2024 cam", + [ + { + "label": "SuperVideo", + "meta": { + "bytes": 966682214, + "countryCode": "fr", + "height": 720, + "title": "the devils bath enfant pour diable 2024 cam", + }, + "sourceId": "supervideo_fr", + "ttl": 900000, + "url": "https://hfs292.serversicuro.cc/hls/,dnzpfwdj5dg4a3gyvbwx5lbvtu65tuwysrizwl7puv6u7dkpym3afmw5hnga,.urlset/master.m3u8", }, - "sourceId": "supervideo_fr", - "ttl": 900000, - "url": "https://hfs292.serversicuro.cc/hls/,dnzpfwdj5dg4a3gyvbwx5lbvtu65tuwysrizwl7puv6u7dkpym3afmw5hnga,.urlset/master.m3u8", - }, - { - "label": "Dropload", - "meta": { - "bytes": 966682214, - "countryCode": "fr", - "height": 720, - "title": "the-devils-bath-un-enfant-pour-le-diable-2024-cam", + ], + [ + { + "label": "Dropload", + "meta": { + "bytes": 966682214, + "countryCode": "fr", + "height": 720, + "title": "the-devils-bath-un-enfant-pour-le-diable-2024-cam", + }, + "sourceId": "dropload_fr", + "ttl": 900000, + "url": "https://srv28.dropload.io/hls2/01/00215/w4yit5wiia9y_h/master.m3u8?t=ujTsd4AYOdgaA6EhuMJDrC-xYzMVEbqrrd3qsoZ8iAY&s=1747054860&e=14400&f=1076096&i=0.0&sp=0&ii=130.61.236.204", }, - "sourceId": "dropload_fr", - "ttl": 900000, - "url": "https://srv28.dropload.io/hls2/01/00215/w4yit5wiia9y_h/master.m3u8?t=ujTsd4AYOdgaA6EhuMJDrC-xYzMVEbqrrd3qsoZ8iAY&s=1747054860&e=14400&f=1076096&i=0.0&sp=0&ii=130.61.236.204", - }, - { - "isExternal": true, - "label": "mixdrop.ag", - "meta": { - "countryCode": "fr", + ], + [ + { + "isExternal": true, + "label": "mixdrop.ag", + "meta": { + "countryCode": "fr", + }, + "sourceId": "external_fr", + "ttl": 3600000, + "url": "https://mixdrop.ag/e/l7v73zqrfdj19z", }, - "sourceId": "external_fr", - "ttl": 3600000, - "url": "https://mixdrop.ag/e/l7v73zqrfdj19z", - }, - { - "error": [Error: Fetcher error: 404: Not Found], - "isExternal": true, - "label": "streamtape.com", - "meta": { - "countryCode": "fr", + ], + [ + { + "error": [Error: Fetcher error: 404: Not Found], + "isExternal": true, + "label": "streamtape.com", + "meta": { + "countryCode": "fr", + }, + "sourceId": "external", + "url": "https://streamtape.com/e/gjA1OQ4klyHxgJ", }, - "sourceId": "external", - "url": "https://streamtape.com/e/gjA1OQ4klyHxgJ", - }, - { - "label": "DoodStream", - "meta": { - "countryCode": "fr", - "title": "the-devils-bath-un-enfant-pour-le-diable-2024-cam", + ], + [ + { + "label": "DoodStream", + "meta": { + "countryCode": "fr", + "title": "the-devils-bath-un-enfant-pour-le-diable-2024-cam", + }, + "requestHeaders": { + "Referer": "http://dood.to/", + }, + "sourceId": "doodstream_fr", + "ttl": 900000, + "url": "https://ty1053vs.cloudatacdn.com/u5kjz2cvh7blsdgge4mmgoifjigorrf6o6mlfwqbndqkhkcvu43dcrk7wfga/6zwayqucuf~mocked-random-string?token=y0n5z6g48kft9apq8imziegv&expiry=639837296000", }, - "requestHeaders": { - "Referer": "http://dood.to/", - }, - "sourceId": "doodstream_fr", - "ttl": 900000, - "url": "https://ty1053vs.cloudatacdn.com/u5kjz2cvh7blsdgge4mmgoifjigorrf6o6mlfwqbndqkhkcvu43dcrk7wfga/6zwayqucuf~mocked-random-string?token=y0n5z6g48kft9apq8imziegv&expiry=639837296000", - }, + ], ] `; diff --git a/src/handler/__snapshots__/KinoKiste.test.ts.snap b/src/handler/__snapshots__/KinoKiste.test.ts.snap index 0073a1c..ef34084 100644 --- a/src/handler/__snapshots__/KinoKiste.test.ts.snap +++ b/src/handler/__snapshots__/KinoKiste.test.ts.snap @@ -2,29 +2,33 @@ exports[`KinoKiste handle imdb black mirror s2e4 1`] = ` [ - { - "label": "SuperVideo", - "meta": { - "bytes": 733793484, - "countryCode": "de", - "height": 720, - "title": "Black Mirror 2x4", + [ + { + "label": "SuperVideo", + "meta": { + "bytes": 733793484, + "countryCode": "de", + "height": 720, + "title": "Black Mirror 2x4", + }, + "sourceId": "supervideo_de", + "ttl": 900000, + "url": "https://hfs279.serversicuro.cc/hls/,dnzpervt3xg4a3gyvdix52ttsqpj5jgxs7keazdmhvru2uyin5g7f67a5u4a,.urlset/master.m3u8", }, - "sourceId": "supervideo_de", - "ttl": 900000, - "url": "https://hfs279.serversicuro.cc/hls/,dnzpervt3xg4a3gyvdix52ttsqpj5jgxs7keazdmhvru2uyin5g7f67a5u4a,.urlset/master.m3u8", - }, - { - "label": "Dropload", - "meta": { - "bytes": 733793484, - "countryCode": "de", - "height": 720, - "title": "Black Mirror 2x4", + ], + [ + { + "label": "Dropload", + "meta": { + "bytes": 733793484, + "countryCode": "de", + "height": 720, + "title": "Black Mirror 2x4", + }, + "sourceId": "dropload_de", + "ttl": 900000, + "url": "https://srv34.dropload.io/hls2/01/00007/jvjwrkpijr0f_h/master.m3u8?t=9B5k5sYgDD2kS_549tQ4WYh1o74hO1QR9zzyXrVRqv4&s=1746903685&e=14400&f=35986&srv=srv27&i=0.0&sp=0&ii=130.61.236.204&p1=srv27&p2=srv27", }, - "sourceId": "dropload_de", - "ttl": 900000, - "url": "https://srv34.dropload.io/hls2/01/00007/jvjwrkpijr0f_h/master.m3u8?t=9B5k5sYgDD2kS_549tQ4WYh1o74hO1QR9zzyXrVRqv4&s=1746903685&e=14400&f=35986&srv=srv27&i=0.0&sp=0&ii=130.61.236.204&p1=srv27&p2=srv27", - }, + ], ] `; diff --git a/src/handler/__snapshots__/MeineCloud.test.ts.snap b/src/handler/__snapshots__/MeineCloud.test.ts.snap index 34becc8..5507322 100644 --- a/src/handler/__snapshots__/MeineCloud.test.ts.snap +++ b/src/handler/__snapshots__/MeineCloud.test.ts.snap @@ -2,52 +2,60 @@ exports[`MeineCloud handle imdb the devil's bath 1`] = ` [ - { - "label": "SuperVideo", - "meta": { - "bytes": 1073741824, - "countryCode": "de", - "height": 720, - "title": "des teufels bad 2024", + [ + { + "label": "SuperVideo", + "meta": { + "bytes": 1073741824, + "countryCode": "de", + "height": 720, + "title": "des teufels bad 2024", + }, + "sourceId": "supervideo_de", + "ttl": 900000, + "url": "https://hfs290.serversicuro.cc/hls/,dnzpfi3d27g4a3gyvbmh5klwtl65qh654hyjtgupd6p56thhyqu6ra3olbfa,.urlset/master.m3u8", }, - "sourceId": "supervideo_de", - "ttl": 900000, - "url": "https://hfs290.serversicuro.cc/hls/,dnzpfi3d27g4a3gyvbmh5klwtl65qh654hyjtgupd6p56thhyqu6ra3olbfa,.urlset/master.m3u8", - }, - { - "label": "Dropload", - "meta": { - "bytes": 1395864371, - "countryCode": "de", - "height": 1080, - "title": "des-teufels-bad-2024", + ], + [ + { + "label": "Dropload", + "meta": { + "bytes": 1395864371, + "countryCode": "de", + "height": 1080, + "title": "des-teufels-bad-2024", + }, + "sourceId": "dropload_de", + "ttl": 900000, + "url": "https://srv27.dropload.io/hls2/01/00197/lyo2h1snpe5c_h/master.m3u8?t=qTZsRGIMnUjXsQ4o2LRLlsT4tGG1AdJrRBRDGttNLPM&s=1746903744&e=14400&f=987607&i=0.0&sp=0&ii=130.61.236.204", }, - "sourceId": "dropload_de", - "ttl": 900000, - "url": "https://srv27.dropload.io/hls2/01/00197/lyo2h1snpe5c_h/master.m3u8?t=qTZsRGIMnUjXsQ4o2LRLlsT4tGG1AdJrRBRDGttNLPM&s=1746903744&e=14400&f=987607&i=0.0&sp=0&ii=130.61.236.204", - }, - { - "isExternal": true, - "label": "mixdrop.ag", - "meta": { - "countryCode": "de", + ], + [ + { + "isExternal": true, + "label": "mixdrop.ag", + "meta": { + "countryCode": "de", + }, + "sourceId": "external_de", + "ttl": 3600000, + "url": "https://mixdrop.ag/e/3nzwveprim63or6", }, - "sourceId": "external_de", - "ttl": 3600000, - "url": "https://mixdrop.ag/e/3nzwveprim63or6", - }, - { - "label": "DoodStream", - "meta": { - "countryCode": "de", - "title": "des-teufels-bad-2024", + ], + [ + { + "label": "DoodStream", + "meta": { + "countryCode": "de", + "title": "des-teufels-bad-2024", + }, + "requestHeaders": { + "Referer": "http://dood.to/", + }, + "sourceId": "doodstream_de", + "ttl": 900000, + "url": "https://aa360cc.cloudatacdn.com/u5kjv4jxytd3sdgge5uogji5dg4huat2pxrm2qibdbm5rtpmbzgb5tornooa/k9wk0js17e~mocked-random-string?token=7uebebipnnhusa4xnyea1er4&expiry=639837296000", }, - "requestHeaders": { - "Referer": "http://dood.to/", - }, - "sourceId": "doodstream_de", - "ttl": 900000, - "url": "https://aa360cc.cloudatacdn.com/u5kjv4jxytd3sdgge5uogji5dg4huat2pxrm2qibdbm5rtpmbzgb5tornooa/k9wk0js17e~mocked-random-string?token=7uebebipnnhusa4xnyea1er4&expiry=639837296000", - }, + ], ] `; diff --git a/src/handler/__snapshots__/MostraGuarda.test.ts.snap b/src/handler/__snapshots__/MostraGuarda.test.ts.snap index 6910f0d..fa45a8f 100644 --- a/src/handler/__snapshots__/MostraGuarda.test.ts.snap +++ b/src/handler/__snapshots__/MostraGuarda.test.ts.snap @@ -2,52 +2,60 @@ exports[`MostraGuarda handle imdb the devil's bath 1`] = ` [ - { - "label": "SuperVideo", - "meta": { - "bytes": 1181116006, - "countryCode": "it", - "height": 720, - "title": "the devils bath 2024 sub ita", + [ + { + "label": "SuperVideo", + "meta": { + "bytes": 1181116006, + "countryCode": "it", + "height": 720, + "title": "the devils bath 2024 sub ita", + }, + "sourceId": "supervideo_it", + "ttl": 900000, + "url": "https://hfs279.serversicuro.cc/hls/,dnzpejj427g4a3gyvbth53rxqewqgqqzp3wr6zwutysvud7zroar3cb75d3q,.urlset/master.m3u8", }, - "sourceId": "supervideo_it", - "ttl": 900000, - "url": "https://hfs279.serversicuro.cc/hls/,dnzpejj427g4a3gyvbth53rxqewqgqqzp3wr6zwutysvud7zroar3cb75d3q,.urlset/master.m3u8", - }, - { - "label": "Dropload", - "meta": { - "bytes": 1181116006, - "countryCode": "it", - "height": 720, - "title": "the-devils-bath-2024-sd-sub-ita", + ], + [ + { + "label": "Dropload", + "meta": { + "bytes": 1181116006, + "countryCode": "it", + "height": 720, + "title": "the-devils-bath-2024-sd-sub-ita", + }, + "sourceId": "dropload_it", + "ttl": 900000, + "url": "https://srv34.dropload.io/hls2/01/00200/xsr90y2ltdyx_h/master.m3u8?t=avFOZ-10hDxo6__iaoSUrq7o4yY3ldLw6XDlXxpXF8E&s=1747059001&e=14400&f=1004116&srv=srv24&i=0.0&sp=0&ii=130.61.236.204&p1=srv24&p2=srv24", }, - "sourceId": "dropload_it", - "ttl": 900000, - "url": "https://srv34.dropload.io/hls2/01/00200/xsr90y2ltdyx_h/master.m3u8?t=avFOZ-10hDxo6__iaoSUrq7o4yY3ldLw6XDlXxpXF8E&s=1747059001&e=14400&f=1004116&srv=srv24&i=0.0&sp=0&ii=130.61.236.204&p1=srv24&p2=srv24", - }, - { - "isExternal": true, - "label": "mixdrop.ag", - "meta": { - "countryCode": "it", + ], + [ + { + "isExternal": true, + "label": "mixdrop.ag", + "meta": { + "countryCode": "it", + }, + "sourceId": "external_it", + "ttl": 3600000, + "url": "https://mixdrop.ag/e/vk196d6xfzwwo1", }, - "sourceId": "external_it", - "ttl": 3600000, - "url": "https://mixdrop.ag/e/vk196d6xfzwwo1", - }, - { - "label": "DoodStream", - "meta": { - "countryCode": "it", - "title": "the-devils-bath-2024-sd-sub-ita", + ], + [ + { + "label": "DoodStream", + "meta": { + "countryCode": "it", + "title": "the-devils-bath-2024-sd-sub-ita", + }, + "requestHeaders": { + "Referer": "http://dood.to/", + }, + "sourceId": "doodstream_it", + "ttl": 900000, + "url": "https://kk892as.cloudatacdn.com/u5kj7j7s27d3sdgge5woezkbi4pu672wktq3aqujw47rbpl3xog2gtqnw2xa/awn9rgotuu~mocked-random-string?token=aw2v2d8uhbrj2ky54d573ujk&expiry=639837296000", }, - "requestHeaders": { - "Referer": "http://dood.to/", - }, - "sourceId": "doodstream_it", - "ttl": 900000, - "url": "https://kk892as.cloudatacdn.com/u5kj7j7s27d3sdgge5woezkbi4pu672wktq3aqujw47rbpl3xog2gtqnw2xa/awn9rgotuu~mocked-random-string?token=aw2v2d8uhbrj2ky54d573ujk&expiry=639837296000", - }, + ], ] `; diff --git a/src/handler/__snapshots__/Soaper.test.ts.snap b/src/handler/__snapshots__/Soaper.test.ts.snap index 4f2f4d5..73d1da5 100644 --- a/src/handler/__snapshots__/Soaper.test.ts.snap +++ b/src/handler/__snapshots__/Soaper.test.ts.snap @@ -2,48 +2,54 @@ exports[`Soaper handle imdb black mirror s4e2 1`] = ` [ - { - "label": "Soaper", - "meta": { - "countryCode": "en", - "height": 720, - "title": "Black Mirror 4x2", + [ + { + "label": "Soaper", + "meta": { + "countryCode": "en", + "height": 720, + "title": "Black Mirror 4x2", + }, + "sourceId": "soaper_en", + "ttl": 900000, + "url": "https://soaper.live/home/index/TVM3U8?key=zoeyOo54b7s8NAPnOW0div4OdvmbYxIzpE2RnmAoSXqMAm7eZKs79V4lxEnZsvQ6qYNrOEiqKO4dAwdBiYx3KmwyVRc9oPzLWoOYcLQVArr2j0.m3u8", }, - "sourceId": "soaper_en", - "ttl": 900000, - "url": "https://soaper.live/home/index/TVM3U8?key=zoeyOo54b7s8NAPnOW0div4OdvmbYxIzpE2RnmAoSXqMAm7eZKs79V4lxEnZsvQ6qYNrOEiqKO4dAwdBiYx3KmwyVRc9oPzLWoOYcLQVArr2j0.m3u8", - }, + ], ] `; exports[`Soaper handle imdb full metal jacket 1`] = ` [ - { - "label": "Soaper", - "meta": { - "countryCode": "en", - "height": 1080, - "title": "Full Metal Jacket (1987)", + [ + { + "label": "Soaper", + "meta": { + "countryCode": "en", + "height": 1080, + "title": "Full Metal Jacket (1987)", + }, + "sourceId": "soaper_en", + "ttl": 900000, + "url": "https://soaper.live/home/index/M3U8?key=VnlzaOr0NYimoY5BLezvsJ8zVLzvdAUVW6XKL711TqadxBBy7AheAYoXRl28s78dmP5WOQUVdxX9RWdOHNRanKJaQ7F5mwRpaWN5fPdMm8M.m3u8", }, - "sourceId": "soaper_en", - "ttl": 900000, - "url": "https://soaper.live/home/index/M3U8?key=VnlzaOr0NYimoY5BLezvsJ8zVLzvdAUVW6XKL711TqadxBBy7AheAYoXRl28s78dmP5WOQUVdxX9RWdOHNRanKJaQ7F5mwRpaWN5fPdMm8M.m3u8", - }, + ], ] `; exports[`Soaper handle tmdb black mirror s4e2 1`] = ` [ - { - "label": "Soaper", - "meta": { - "countryCode": "en", - "height": 720, - "title": "Black Mirror 4x2", + [ + { + "label": "Soaper", + "meta": { + "countryCode": "en", + "height": 720, + "title": "Black Mirror 4x2", + }, + "sourceId": "soaper_en", + "ttl": 900000, + "url": "https://soaper.live/home/index/TVM3U8?key=zoeyOo54b7s8NAPnOW0div4OdvmbYxIzpE2RnmAoSXqMAm7eZKs79V4lxEnZsvQ6qYNrOEiqKO4dAwdBiYx3KmwyVRc9oPzLWoOYcLQVArr2j0.m3u8", }, - "sourceId": "soaper_en", - "ttl": 900000, - "url": "https://soaper.live/home/index/TVM3U8?key=zoeyOo54b7s8NAPnOW0div4OdvmbYxIzpE2RnmAoSXqMAm7eZKs79V4lxEnZsvQ6qYNrOEiqKO4dAwdBiYx3KmwyVRc9oPzLWoOYcLQVArr2j0.m3u8", - }, + ], ] `; diff --git a/src/handler/__snapshots__/VerHdLink.test.ts.snap b/src/handler/__snapshots__/VerHdLink.test.ts.snap index 298f628..ee8fd21 100644 --- a/src/handler/__snapshots__/VerHdLink.test.ts.snap +++ b/src/handler/__snapshots__/VerHdLink.test.ts.snap @@ -2,83 +2,99 @@ exports[`VerHdLink handle titanic 1`] = ` [ - { - "label": "SuperVideo", - "meta": { - "bytes": 1503238553, - "countryCode": "mx", - "height": 556, - "title": "titanic 1997 [latino]", + [ + { + "label": "SuperVideo", + "meta": { + "bytes": 1503238553, + "countryCode": "mx", + "height": 556, + "title": "titanic 1997 [latino]", + }, + "sourceId": "supervideo_mx", + "ttl": 900000, + "url": "https://hfs292.serversicuro.cc/hls/,dnzpejlw37g4a3gyvdzh5p3xttjqd3ccheao6qexhjbv4ecdpod7hxlh4a7a,.urlset/master.m3u8", }, - "sourceId": "supervideo_mx", - "ttl": 900000, - "url": "https://hfs292.serversicuro.cc/hls/,dnzpejlw37g4a3gyvdzh5p3xttjqd3ccheao6qexhjbv4ecdpod7hxlh4a7a,.urlset/master.m3u8", - }, - { - "label": "Dropload", - "meta": { - "bytes": 1503238553, - "countryCode": "mx", - "height": 556, - "title": "titanic-1997-[latino]", + ], + [ + { + "label": "Dropload", + "meta": { + "bytes": 1503238553, + "countryCode": "mx", + "height": 556, + "title": "titanic-1997-[latino]", + }, + "sourceId": "dropload_mx", + "ttl": 900000, + "url": "https://srv22.dropload.io/hls2/01/00046/jjjx9j5joiz8_h/master.m3u8?t=_sOFVDjKUqBAK_gJtH7YVQnCm6nj7kr4df3PNsKeKAA&s=1747060128&e=14400&f=230703&i=0.0&sp=0&ii=130.61.236.204", }, - "sourceId": "dropload_mx", - "ttl": 900000, - "url": "https://srv22.dropload.io/hls2/01/00046/jjjx9j5joiz8_h/master.m3u8?t=_sOFVDjKUqBAK_gJtH7YVQnCm6nj7kr4df3PNsKeKAA&s=1747060128&e=14400&f=230703&i=0.0&sp=0&ii=130.61.236.204", - }, - { - "isExternal": true, - "label": "mixdrop.ag", - "meta": { - "countryCode": "mx", + ], + [ + { + "isExternal": true, + "label": "mixdrop.ag", + "meta": { + "countryCode": "mx", + }, + "sourceId": "external_mx", + "ttl": 3600000, + "url": "https://mixdrop.ag/e/vn0wx308fq984q", }, - "sourceId": "external_mx", - "ttl": 3600000, - "url": "https://mixdrop.ag/e/vn0wx308fq984q", - }, - { - "error": [Error: Fetcher error: 404: Not Found], - "isExternal": true, - "label": "streamtape.com", - "meta": { - "countryCode": "mx", + ], + [ + { + "error": [Error: Fetcher error: 404: Not Found], + "isExternal": true, + "label": "streamtape.com", + "meta": { + "countryCode": "mx", + }, + "sourceId": "external", + "url": "https://streamtape.com/e/Bjp2vjrdBxsK82", }, - "sourceId": "external", - "url": "https://streamtape.com/e/Bjp2vjrdBxsK82", - }, - { - "label": "SuperVideo", - "meta": { - "bytes": 1610612736, - "countryCode": "es", - "height": 544, - "title": "titanic 1997 2[castellano]", + ], + [], + [ + { + "label": "SuperVideo", + "meta": { + "bytes": 1610612736, + "countryCode": "es", + "height": 544, + "title": "titanic 1997 2[castellano]", + }, + "sourceId": "supervideo_es", + "ttl": 900000, + "url": "https://hfs295.serversicuro.cc/hls/,dnzpfv3w37g4a3gyvdzh5kjeyi4vtoyw4x4it5gxl4zzwiv4t3fxkvagrhea,.urlset/master.m3u8", }, - "sourceId": "supervideo_es", - "ttl": 900000, - "url": "https://hfs295.serversicuro.cc/hls/,dnzpfv3w37g4a3gyvdzh5kjeyi4vtoyw4x4it5gxl4zzwiv4t3fxkvagrhea,.urlset/master.m3u8", - }, - { - "label": "Dropload", - "meta": { - "bytes": 1610612736, - "countryCode": "es", - "height": 544, - "title": "titanic-1997-2[castellano]", + ], + [ + { + "label": "Dropload", + "meta": { + "bytes": 1610612736, + "countryCode": "es", + "height": 544, + "title": "titanic-1997-2[castellano]", + }, + "sourceId": "dropload_es", + "ttl": 900000, + "url": "https://srv23.dropload.io/hls2/01/00046/ick4ti66vt6s_h/master.m3u8?t=OUbNiE0qRNUy69JP4AIj1bGcV5kaljyNrAUlCYWGVOs&s=1747060128&e=14400&f=230700&i=0.0&sp=0&ii=130.61.236.204", }, - "sourceId": "dropload_es", - "ttl": 900000, - "url": "https://srv23.dropload.io/hls2/01/00046/ick4ti66vt6s_h/master.m3u8?t=OUbNiE0qRNUy69JP4AIj1bGcV5kaljyNrAUlCYWGVOs&s=1747060128&e=14400&f=230700&i=0.0&sp=0&ii=130.61.236.204", - }, - { - "isExternal": true, - "label": "mixdrop.ag", - "meta": { - "countryCode": "es", + ], + [ + { + "isExternal": true, + "label": "mixdrop.ag", + "meta": { + "countryCode": "es", + }, + "sourceId": "external_es", + "ttl": 3600000, + "url": "https://mixdrop.ag/e/xokzmv61hrwe8o", }, - "sourceId": "external_es", - "ttl": 3600000, - "url": "https://mixdrop.ag/e/xokzmv61hrwe8o", - }, + ], + [], ] `; diff --git a/src/handler/types.ts b/src/handler/types.ts index 3b7007c..2924618 100644 --- a/src/handler/types.ts +++ b/src/handler/types.ts @@ -11,5 +11,5 @@ export interface Handler { readonly countryCodes: CountryCode[]; - readonly handle: (ctx: Context, type: ContentType, id: Id) => Promise<(UrlResult | undefined)[]>; + readonly handle: (ctx: Context, type: ContentType, id: Id) => Promise<(UrlResult[])[]>; } diff --git a/src/utils/StreamResolver.test.ts b/src/utils/StreamResolver.test.ts index 4d7d61c..1c3acdf 100644 --- a/src/utils/StreamResolver.test.ts +++ b/src/utils/StreamResolver.test.ts @@ -63,68 +63,70 @@ describe('resolve', () => { readonly countryCodes: CountryCode[] = ['de']; - readonly handle = async (): Promise<(UrlResult | undefined)[]> => { + readonly handle = async (): Promise<(UrlResult[])[]> => { return [ - { - url: new URL('https://example.com'), - isExternal: true, - error: new BlockedError('cloudflare_challenge', {}), - label: 'hoster.com', - sourceId: '', - meta: { - countryCode: 'de', + [ + { + url: new URL('https://example.com'), + isExternal: true, + error: new BlockedError('cloudflare_challenge', {}), + label: 'hoster.com', + sourceId: '', + meta: { + countryCode: 'de', + }, }, - }, - { - url: new URL('https://example.com'), - isExternal: true, - error: new BlockedError('unknown', {}), - label: 'hoster.com', - sourceId: '', - meta: { - countryCode: 'de', + { + url: new URL('https://example.com'), + isExternal: true, + error: new BlockedError('unknown', {}), + label: 'hoster.com', + sourceId: '', + meta: { + countryCode: 'de', + }, }, - }, - { - url: new URL('https://example2.com'), - isExternal: true, - error: new TypeError(), - label: 'hoster.com', - sourceId: '', - meta: { - countryCode: 'de', + { + url: new URL('https://example2.com'), + isExternal: true, + error: new TypeError(), + label: 'hoster.com', + sourceId: '', + meta: { + countryCode: 'de', + }, }, - }, - { - url: new URL('https://example2.com'), - isExternal: true, - error: TIMEOUT, - label: 'hoster.com', - sourceId: '', - meta: { - countryCode: 'de', + { + url: new URL('https://example2.com'), + isExternal: true, + error: TIMEOUT, + label: 'hoster.com', + sourceId: '', + meta: { + countryCode: 'de', + }, }, - }, - { - url: new URL('https://example3.com'), - isExternal: true, - error: new QueueIsFullError(), - label: 'hoster.com', - sourceId: '', - meta: { - countryCode: 'de', + { + url: new URL('https://example3.com'), + isExternal: true, + error: new QueueIsFullError(), + label: 'hoster.com', + sourceId: '', + meta: { + countryCode: 'de', + }, }, - }, - { - url: new URL('https://example4.com'), - isExternal: true, - error: new HttpError(500, 'Internal Server Error', { 'x-foo': 'bar' }), - label: 'hoster.com', - sourceId: '', - meta: { - countryCode: 'de', + { + url: new URL('https://example4.com'), + isExternal: true, + error: new HttpError(500, 'Internal Server Error', { 'x-foo': 'bar' }), + label: 'hoster.com', + sourceId: '', + meta: { + countryCode: 'de', + }, }, - }, + ], ]; }; } diff --git a/src/utils/StreamResolver.ts b/src/utils/StreamResolver.ts index dd92e66..6f31e25 100644 --- a/src/utils/StreamResolver.ts +++ b/src/utils/StreamResolver.ts @@ -46,7 +46,7 @@ export class StreamResolver { const handlerUrlResults = await handler.handle(ctx, type, id); this.logger.info(`${handler.id} returned ${handlerUrlResults.length} urls`, ctx); - urlResults.push(...(handlerUrlResults.filter(handlerUrlResult => handlerUrlResult !== undefined))); + urlResults.push(...handlerUrlResults.flat()); } catch (error) { if (error instanceof NotFoundError) { return;