refactor: UrlResult[] instead of UrlResult | undefined

This commit is contained in:
WebStreamr 2025-06-08 18:55:03 +00:00
parent 364bf166ae
commit 0446d52e78
No known key found for this signature in database
21 changed files with 677 additions and 580 deletions

View file

@ -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/',
},
};
];
};
}

View file

@ -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,
},
},
};
];
};
}

View file

@ -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,
},
];
};
}

View file

@ -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([]);
});
});

View file

@ -13,7 +13,7 @@ import { NotFoundError } from '../error';
export class ExtractorRegistry {
private readonly logger: winston.Logger;
private readonly extractors: Extractor[];
private readonly urlResultCache: TTLCache<string, UrlResult | undefined>;
private readonly urlResultCache: TTLCache<string, UrlResult[]>;
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<UrlResult | undefined> => {
let urlResult = this.urlResultCache.get(url.href);
readonly handle = async (ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> => {
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;
};
}

View file

@ -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,
},
},
};
];
};
}

View file

@ -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,
},
},
};
];
};
}

View file

@ -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/",
}
]
`;

View file

@ -9,5 +9,5 @@ export interface Extractor {
readonly supports: (ctx: Context, url: URL) => boolean;
readonly extract: (ctx: Context, url: URL, meta: Meta) => Promise<UrlResult>;
readonly extract: (ctx: Context, url: URL, meta: Meta) => Promise<UrlResult[]>;
}

View file

@ -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",
},
],
]
`;

View file

@ -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",
},
],
]
`;

View file

@ -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",
},
],
]
`;

View file

@ -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",
},
],
]
`;

View file

@ -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",
},
],
]
`;

View file

@ -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",
},
],
]
`;

View file

@ -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",
},
],
]
`;

View file

@ -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",
},
],
]
`;

View file

@ -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",
},
],
[],
]
`;

View file

@ -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[])[]>;
}

View file

@ -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',
},
},
},
],
];
};
}

View file

@ -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;