chore: cache successful results as long as we safely can

This commit is contained in:
WebStreamr 2025-06-04 09:53:22 +00:00
parent 389461415d
commit b69c9cde03
No known key found for this signature in database
20 changed files with 283 additions and 161 deletions

View file

@ -36,7 +36,11 @@ export class StreamController {
const handlers = this.handlers.filter(handler => handler.countryCodes.filter(countryCode => countryCode in ctx.config).length);
const streams = await this.streamResolver.resolve(ctx, handlers, type, id);
const { streams, ttl } = await this.streamResolver.resolve(ctx, handlers, type, id);
if (ttl && process.env['NODE_ENV'] === 'production') {
res.setHeader('Cache-Control', `max-age=${ttl / 1000}, public`);
}
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ streams }));

View file

@ -42,6 +42,7 @@ export class DoodStream implements Extractor {
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,

View file

@ -39,6 +39,7 @@ export class Dropload implements Extractor {
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,

View file

@ -26,6 +26,7 @@ export class ExternalUrl implements Extractor {
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 } from '../types';
import { Context, UrlResult } from '../types';
import { Fetcher } from '../utils';
jest.mock('../utils/Fetcher');
@ -31,22 +31,21 @@ describe('ExtractorRegistry', () => {
});
test('returns from memory cache if possible', async () => {
const urlResult1 = await extractorRegistry.handle(ctx, new URL('https://dropload.io/lyo2h1snpe5c.html'), { countryCode: 'de' });
const urlResult2 = await extractorRegistry.handle(ctx, new URL('https://dropload.io/lyo2h1snpe5c.html'), { countryCode: 'de' });
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;
expect(urlResult2).toBe(urlResult1);
expect(urlResultRest1).not.toBeUndefined();
expect(urlResultRest2).toStrictEqual(urlResultRest1);
expect(ttl1).not.toBe(undefined);
expect(ttl2).not.toBe(undefined);
});
test('returns from memory cache if possible', async () => {
const urlResult1 = await extractorRegistry.handle(ctx, new URL('https://dropload.io/lyo2h1snpe5c.html'), { countryCode: 'de' });
const urlResult2 = await extractorRegistry.handle(ctx, new URL('https://dropload.io/lyo2h1snpe5c.html'), { countryCode: 'de' });
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' });
expect(urlResult2).toBe(urlResult1);
});
test('ignores not found errors', async () => {
const urlResult = await extractorRegistry.handle(ctx, new URL('https://dropload.io/asdfghijklmn.html'), { countryCode: 'de' });
expect(urlResult).toBeUndefined();
expect(urlResult1).toBeUndefined();
expect(urlResult2).toBeUndefined();
});
});

View file

@ -28,7 +28,7 @@ export class ExtractorRegistry {
readonly handle = async (ctx: Context, url: URL, meta: Meta): Promise<UrlResult | undefined> => {
let urlResult = this.urlResultCache.get(url.href);
if (this.urlResultCache.has(url.href)) {
return urlResult;
return urlResult ? { ...urlResult, ttl: this.urlResultCache.getRemainingTTL(url.href) } : undefined;
}
const extractor = this.extractors.find(extractor => extractor.supports(ctx, url));
@ -53,6 +53,7 @@ export class ExtractorRegistry {
error,
label: url.host,
sourceId: `${extractor.id}`,
ttl: extractor.ttl,
meta,
};
}

View file

@ -32,6 +32,7 @@ export class SuperVideo implements Extractor {
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,

View file

@ -8,6 +8,7 @@ exports[`ExtractorRegistry return external URLs by default 1`] = `
"countryCode": "de",
},
"sourceId": "external_de",
"ttl": 3600000,
"url": "https://mixdrop.ag/e/3nzwveprim63or6",
}
`;
@ -21,6 +22,7 @@ exports[`ExtractorRegistry returns error result from extractor 1`] = `
"countryCode": "en",
},
"sourceId": "external",
"ttl": 3600000,
"url": "https://some-url.test/",
}
`;

View file

@ -11,6 +11,7 @@ exports[`CineHDPlus handle imdb babylon 5 s2e3 (es) 1`] = `
"title": "Babylon 5 2x3",
},
"sourceId": "supervideo_es",
"ttl": 900000,
"url": "https://hfs294.serversicuro.cc/hls/,dnzpealv5xg4a3gyvavh52jryms77x3wwakzvgy2ly3yfusnblczjnvvweua,.urlset/master.m3u8",
},
{
@ -22,6 +23,7 @@ exports[`CineHDPlus handle imdb babylon 5 s2e3 (es) 1`] = `
"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",
},
]
@ -38,6 +40,7 @@ exports[`CineHDPlus handle imdb black mirror s2e3 (mx) 1`] = `
"title": "Black Mirror 2x3",
},
"sourceId": "supervideo_mx",
"ttl": 900000,
"url": "https://hfs299.serversicuro.cc/hls/,dnzpff262hg4a3gyvcex5ojxt23vrieljzut7xhjydwidlbp4g7nqswkpfwq,.urlset/master.m3u8",
},
{
@ -49,6 +52,7 @@ exports[`CineHDPlus handle imdb black mirror s2e3 (mx) 1`] = `
"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",
},
]

View file

@ -11,6 +11,7 @@ exports[`Eurostreaming handle imdb black mirror s2e4 1`] = `
"title": "Black Mirror 2x4",
},
"sourceId": "supervideo_it",
"ttl": 900000,
"url": "https://hfs309.serversicuro.cc/hls/dnzpdeoe5xg4a3gyvaqx5ojpswtxjd5a22rklgah7,khdhascykjrixs7huqq,obtfascykj3vna7rk5a,.urlset/master.m3u8",
},
{
@ -22,6 +23,7 @@ exports[`Eurostreaming handle imdb black mirror s2e4 1`] = `
"title": "Black Mirror 2x4",
},
"sourceId": "supervideo_it",
"ttl": 900000,
"url": "https://hfs309.serversicuro.cc/hls/dnzpdeoe5xg4a3gyvaqx5ojpswtxjd5a22rklgah7,khdhascykjrixs7huqq,obtfascykj3vna7rk5a,.urlset/master.m3u8",
},
{
@ -33,6 +35,7 @@ exports[`Eurostreaming handle imdb black mirror s2e4 1`] = `
"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",
},
]

View file

@ -11,6 +11,7 @@ exports[`Frembed handle imdb black mirror s4e2 1`] = `
"title": "Black Mirror 4x2",
},
"sourceId": "external",
"ttl": 3600000,
"url": "https://ahvsh.com/e/83izf7qzwpae,https://netu.frembed.fun/e/0DFgfkcXOsDP,https://likessb.com/e/7yjgl1x56n08.html,https://ds2play.com/e/fzfvfq3ngig0",
},
{
@ -23,6 +24,7 @@ exports[`Frembed handle imdb black mirror s4e2 1`] = `
"Referer": "http://dood.to/",
},
"sourceId": "doodstream_fr",
"ttl": 900000,
"url": "https://ee317r.cloudatacdn.com/u5kj63yvxddlsdgge7qremqqka27irwiupc4k7o5cikbh7fdq4j4mwzraf7q/1y4sn4ndoi~mocked-random-string?token=fh3rdlhjvao7chgxndsi3ra7&expiry=639837296000",
},
{
@ -33,6 +35,7 @@ exports[`Frembed handle imdb black mirror s4e2 1`] = `
"title": "Black Mirror 4x2",
},
"sourceId": "external_fr",
"ttl": 3600000,
"url": "https://netu.fanstream.us/e/0DFgfkcXOsDP",
},
{
@ -43,6 +46,7 @@ exports[`Frembed handle imdb black mirror s4e2 1`] = `
"title": "Black Mirror 4x2",
},
"sourceId": "external_fr",
"ttl": 3600000,
"url": "https://johnalwayssame.com/e/cqy9oue7sv0g",
},
{
@ -54,6 +58,7 @@ exports[`Frembed handle imdb black mirror s4e2 1`] = `
"title": "Black Mirror 4x2",
},
"sourceId": "external",
"ttl": 3600000,
"url": "https://ds2play.com/e/fzfvfq3ngig0",
},
]

View file

@ -11,6 +11,7 @@ exports[`FrenchCloud handle imdb the devil's bath 1`] = `
"title": "the devils bath enfant pour diable 2024 cam",
},
"sourceId": "supervideo_fr",
"ttl": 900000,
"url": "https://hfs292.serversicuro.cc/hls/,dnzpfwdj5dg4a3gyvbwx5lbvtu65tuwysrizwl7puv6u7dkpym3afmw5hnga,.urlset/master.m3u8",
},
{
@ -22,6 +23,7 @@ exports[`FrenchCloud handle imdb the devil's bath 1`] = `
"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",
},
{
@ -31,6 +33,7 @@ exports[`FrenchCloud handle imdb the devil's bath 1`] = `
"countryCode": "fr",
},
"sourceId": "external_fr",
"ttl": 3600000,
"url": "https://mixdrop.ag/e/l7v73zqrfdj19z",
},
{
@ -41,6 +44,7 @@ exports[`FrenchCloud handle imdb the devil's bath 1`] = `
"countryCode": "fr",
},
"sourceId": "external",
"ttl": 3600000,
"url": "https://streamtape.com/e/gjA1OQ4klyHxgJ",
},
{
@ -53,6 +57,7 @@ exports[`FrenchCloud handle imdb the devil's bath 1`] = `
"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

@ -11,6 +11,7 @@ exports[`KinoKiste handle imdb black mirror s2e4 1`] = `
"title": "Black Mirror 2x4",
},
"sourceId": "supervideo_de",
"ttl": 900000,
"url": "https://hfs279.serversicuro.cc/hls/,dnzpervt3xg4a3gyvdix52ttsqpj5jgxs7keazdmhvru2uyin5g7f67a5u4a,.urlset/master.m3u8",
},
{
@ -22,6 +23,7 @@ exports[`KinoKiste handle imdb black mirror s2e4 1`] = `
"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",
},
]

View file

@ -11,6 +11,7 @@ exports[`MeineCloud handle imdb the devil's bath 1`] = `
"title": "des teufels bad 2024",
},
"sourceId": "supervideo_de",
"ttl": 900000,
"url": "https://hfs290.serversicuro.cc/hls/,dnzpfi3d27g4a3gyvbmh5klwtl65qh654hyjtgupd6p56thhyqu6ra3olbfa,.urlset/master.m3u8",
},
{
@ -22,6 +23,7 @@ exports[`MeineCloud handle imdb the devil's bath 1`] = `
"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",
},
{
@ -31,6 +33,7 @@ exports[`MeineCloud handle imdb the devil's bath 1`] = `
"countryCode": "de",
},
"sourceId": "external_de",
"ttl": 3600000,
"url": "https://mixdrop.ag/e/3nzwveprim63or6",
},
{
@ -43,6 +46,7 @@ exports[`MeineCloud handle imdb the devil's bath 1`] = `
"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

@ -11,6 +11,7 @@ exports[`MostraGuarda handle imdb the devil's bath 1`] = `
"title": "the devils bath 2024 sub ita",
},
"sourceId": "supervideo_it",
"ttl": 900000,
"url": "https://hfs279.serversicuro.cc/hls/,dnzpejj427g4a3gyvbth53rxqewqgqqzp3wr6zwutysvud7zroar3cb75d3q,.urlset/master.m3u8",
},
{
@ -22,6 +23,7 @@ exports[`MostraGuarda handle imdb the devil's bath 1`] = `
"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",
},
{
@ -31,6 +33,7 @@ exports[`MostraGuarda handle imdb the devil's bath 1`] = `
"countryCode": "it",
},
"sourceId": "external_it",
"ttl": 3600000,
"url": "https://mixdrop.ag/e/vk196d6xfzwwo1",
},
{
@ -43,6 +46,7 @@ exports[`MostraGuarda handle imdb the devil's bath 1`] = `
"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

@ -11,6 +11,7 @@ exports[`VerHdLink handle titanic 1`] = `
"title": "titanic 1997 [latino]",
},
"sourceId": "supervideo_mx",
"ttl": 900000,
"url": "https://hfs292.serversicuro.cc/hls/,dnzpejlw37g4a3gyvdzh5p3xttjqd3ccheao6qexhjbv4ecdpod7hxlh4a7a,.urlset/master.m3u8",
},
{
@ -22,6 +23,7 @@ exports[`VerHdLink handle titanic 1`] = `
"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",
},
{
@ -31,6 +33,7 @@ exports[`VerHdLink handle titanic 1`] = `
"countryCode": "mx",
},
"sourceId": "external_mx",
"ttl": 3600000,
"url": "https://mixdrop.ag/e/vn0wx308fq984q",
},
{
@ -41,6 +44,7 @@ exports[`VerHdLink handle titanic 1`] = `
"countryCode": "mx",
},
"sourceId": "external",
"ttl": 3600000,
"url": "https://streamtape.com/e/Bjp2vjrdBxsK82",
},
{
@ -52,6 +56,7 @@ exports[`VerHdLink handle titanic 1`] = `
"title": "titanic 1997 2[castellano]",
},
"sourceId": "supervideo_es",
"ttl": 900000,
"url": "https://hfs295.serversicuro.cc/hls/,dnzpfv3w37g4a3gyvdzh5kjeyi4vtoyw4x4it5gxl4zzwiv4t3fxkvagrhea,.urlset/master.m3u8",
},
{
@ -63,6 +68,7 @@ exports[`VerHdLink handle titanic 1`] = `
"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",
},
{
@ -72,6 +78,7 @@ exports[`VerHdLink handle titanic 1`] = `
"countryCode": "es",
},
"sourceId": "external_es",
"ttl": 3600000,
"url": "https://mixdrop.ag/e/xokzmv61hrwe8o",
},
]

View file

@ -30,6 +30,7 @@ export interface UrlResult {
error?: unknown;
label: string;
sourceId: string;
ttl?: number;
meta: Meta;
requestHeaders?: Record<string, string>;
}

View file

@ -21,11 +21,7 @@ describe('resolve', () => {
test('returns info as stream if no handlers were configured', async () => {
const streams = await streamResolver.resolve(ctx, [], 'movie', 'tt123456789');
expect(streams).toStrictEqual([{
name: 'WebStreamr',
title: '⚠️ No handlers found. Please re-configure the plugin.',
ytId: 'E4WlUXrJgy4',
}]);
expect(streams).toMatchSnapshot();
});
test('returns handler errors as stream', async () => {
@ -33,23 +29,21 @@ describe('resolve', () => {
const streams = await streamResolver.resolve(ctx, [meineCloud], 'movie', 'tt123456789');
expect(streams).toStrictEqual([{
name: 'WebStreamr',
title: '🔗 MeineCloud\n❌ Request failed. Request-id: id.',
ytId: 'E4WlUXrJgy4',
}]);
expect(streams).toMatchSnapshot();
fetcherSpy.mockRestore();
});
test('returns empty array if no handler found anything', async () => {
const streams = await streamResolver.resolve(ctx, [meineCloud, mostraGuarda], 'movie', 'tt12345678');
expect(streams).toStrictEqual([]);
expect(streams).toMatchSnapshot();
});
test('returns empty array if no handler supported the type', async () => {
const streams = await streamResolver.resolve(ctx, [meineCloud, mostraGuarda], 'series', 'tt12345678:1:1');
expect(streams).toStrictEqual([]);
expect(streams).toMatchSnapshot();
});
test('returns sorted results', async () => {
@ -130,6 +124,7 @@ describe('resolve', () => {
};
const streams = await streamResolver.resolve(ctx, [mockHandler], 'movie', 'tt12345678');
expect(streams).toStrictEqual([]);
expect(streams).toMatchSnapshot();
});
});

View file

@ -7,6 +7,11 @@ import { Handler } from '../handler';
import { BlockedError, NotFoundError, QueueIsFullError } from '../error';
import { languageFromCountryCode } from './languageFromCountryCode';
interface ResolveResponse {
streams: Stream[];
ttl?: number;
}
export class StreamResolver {
private readonly logger: winston.Logger;
@ -14,17 +19,22 @@ export class StreamResolver {
this.logger = logger;
}
readonly resolve = async (ctx: Context, handlers: Handler[], type: string, id: string): Promise<Stream[]> => {
readonly resolve = async (ctx: Context, handlers: Handler[], type: string, id: string): Promise<ResolveResponse> => {
if (handlers.length === 0) {
return [{
name: 'WebStreamr',
title: '⚠️ No handlers found. Please re-configure the plugin.',
ytId: 'E4WlUXrJgy4',
}];
return {
streams: [
{
name: 'WebStreamr',
title: '⚠️ No handlers found. Please re-configure the plugin.',
ytId: 'E4WlUXrJgy4',
},
],
};
}
const streams: Stream[] = [];
let handlerErrorOccurred = false;
const urlResults: UrlResult[] = [];
const handlerPromises = handlers.map(async (handler) => {
if (!handler.contentTypes.includes(type)) {
@ -41,6 +51,8 @@ export class StreamResolver {
return;
}
handlerErrorOccurred = true;
streams.push({
name: process.env['MANIFEST_NAME'] || 'WebStreamr',
title: [`🔗 ${handler.label}`, this.logErrorAndReturnNiceString(ctx, handler.id, error)].join('\n'),
@ -83,7 +95,24 @@ export class StreamResolver {
})),
);
return streams;
const ttl = !handlerErrorOccurred ? this.determineTtl(urlResults) : undefined;
return {
streams,
...(ttl && { ttl }),
};
};
private readonly determineTtl = (urlResults: UrlResult[]): number | undefined => {
if (!urlResults.length) {
return 900000; // 15m
}
if (urlResults.some(urlResult => urlResult.ttl === undefined)) {
return undefined;
}
return Math.min(...urlResults.map(urlResult => urlResult.ttl as number));
};
private readonly showExternalUrls = (ctx: Context): boolean => !('excludeExternalUrls' in ctx.config);

View file

@ -1,178 +1,231 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`resolve adds error info 1`] = `
[
{
"behaviorHints": {},
"externalUrl": "https://example.com/",
"name": "WebStreamr N/A ⚠️ external",
"title": "🌐 German 🇩🇪
{
"streams": [
{
"behaviorHints": {},
"externalUrl": "https://example.com/",
"name": "WebStreamr N/A ⚠️ external",
"title": "🌐 German 🇩🇪
🔗 hoster.com
⚠️ Request was blocked.",
},
{
"behaviorHints": {},
"externalUrl": "https://example2.com/",
"name": "WebStreamr N/A ⚠️ external",
"title": "🌐 German 🇩🇪
},
{
"behaviorHints": {},
"externalUrl": "https://example2.com/",
"name": "WebStreamr N/A ⚠️ external",
"title": "🌐 German 🇩🇪
🔗 hoster.com
❌ Request failed. Request-id: id.",
},
{
"behaviorHints": {},
"externalUrl": "https://example2.com/",
"name": "WebStreamr N/A ⚠️ external",
"title": "🌐 German 🇩🇪
},
{
"behaviorHints": {},
"externalUrl": "https://example2.com/",
"name": "WebStreamr N/A ⚠️ external",
"title": "🌐 German 🇩🇪
🔗 hoster.com
🐢 Request timed out.",
},
{
"behaviorHints": {},
"externalUrl": "https://example3.com/",
"name": "WebStreamr N/A ⚠️ external",
"title": "🌐 German 🇩🇪
},
{
"behaviorHints": {},
"externalUrl": "https://example3.com/",
"name": "WebStreamr N/A ⚠️ external",
"title": "🌐 German 🇩🇪
🔗 hoster.com
⏳ Request queue is full. Please try again later or consider self-hosting.",
},
]
},
],
}
`;
exports[`resolve adds error info 2`] = `
[
{
"behaviorHints": {},
"name": "WebStreamr N/A",
"title": "🌐 German 🇩🇪
{
"streams": [
{
"behaviorHints": {},
"name": "WebStreamr N/A",
"title": "🌐 German 🇩🇪
🔗 hoster.com
⚠️ Request was blocked.",
"ytId": "E4WlUXrJgy4",
},
{
"behaviorHints": {},
"name": "WebStreamr N/A",
"title": "🌐 German 🇩🇪
"ytId": "E4WlUXrJgy4",
},
{
"behaviorHints": {},
"name": "WebStreamr N/A",
"title": "🌐 German 🇩🇪
🔗 hoster.com
❌ Request failed. Request-id: id.",
"ytId": "E4WlUXrJgy4",
},
{
"behaviorHints": {},
"name": "WebStreamr N/A",
"title": "🌐 German 🇩🇪
"ytId": "E4WlUXrJgy4",
},
{
"behaviorHints": {},
"name": "WebStreamr N/A",
"title": "🌐 German 🇩🇪
🔗 hoster.com
🐢 Request timed out.",
"ytId": "E4WlUXrJgy4",
},
{
"behaviorHints": {},
"name": "WebStreamr N/A",
"title": "🌐 German 🇩🇪
"ytId": "E4WlUXrJgy4",
},
{
"behaviorHints": {},
"name": "WebStreamr N/A",
"title": "🌐 German 🇩🇪
🔗 hoster.com
⏳ Request queue is full. Please try again later or consider self-hosting.",
"ytId": "E4WlUXrJgy4",
},
]
"ytId": "E4WlUXrJgy4",
},
],
}
`;
exports[`resolve ignores not found errors 1`] = `
{
"streams": [],
"ttl": 900000,
}
`;
exports[`resolve returns empty array if no handler found anything 1`] = `
{
"streams": [],
"ttl": 900000,
}
`;
exports[`resolve returns empty array if no handler supported the type 1`] = `
{
"streams": [],
"ttl": 900000,
}
`;
exports[`resolve returns handler errors as stream 1`] = `
{
"streams": [
{
"name": "WebStreamr",
"title": "🔗 MeineCloud
❌ Request failed. Request-id: id.",
"ytId": "E4WlUXrJgy4",
},
],
}
`;
exports[`resolve returns info as stream if no handlers were configured 1`] = `
{
"streams": [
{
"name": "WebStreamr",
"title": "⚠️ No handlers found. Please re-configure the plugin.",
"ytId": "E4WlUXrJgy4",
},
],
}
`;
exports[`resolve returns sorted results 1`] = `
[
{
"behaviorHints": {
"bingeGroup": "webstreamr-dropload_de",
"videoSize": 1395864371,
},
"name": "WebStreamr 1080P",
"title": "📂 des-teufels-bad-2024
{
"streams": [
{
"behaviorHints": {
"bingeGroup": "webstreamr-dropload_de",
"videoSize": 1395864371,
},
"name": "WebStreamr 1080P",
"title": "📂 des-teufels-bad-2024
💾 1.3 GB
🌐 German 🇩🇪
🔗 Dropload",
"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",
},
{
"behaviorHints": {
"bingeGroup": "webstreamr-dropload_it",
"videoSize": 1181116006,
"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",
},
"name": "WebStreamr 720P",
"title": "📂 the-devils-bath-2024-sd-sub-ita
{
"behaviorHints": {
"bingeGroup": "webstreamr-dropload_it",
"videoSize": 1181116006,
},
"name": "WebStreamr 720P",
"title": "📂 the-devils-bath-2024-sd-sub-ita
💾 1.1 GB
🌐 Italian 🇮🇹
🔗 Dropload",
"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",
},
{
"behaviorHints": {
"bingeGroup": "webstreamr-supervideo_it",
"videoSize": 1181116006,
"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",
},
"name": "WebStreamr 720P",
"title": "📂 the devils bath 2024 sub ita
{
"behaviorHints": {
"bingeGroup": "webstreamr-supervideo_it",
"videoSize": 1181116006,
},
"name": "WebStreamr 720P",
"title": "📂 the devils bath 2024 sub ita
💾 1.1 GB
🌐 Italian 🇮🇹
🔗 SuperVideo",
"url": "https://hfs279.serversicuro.cc/hls/,dnzpejj427g4a3gyvbth53rxqewqgqqzp3wr6zwutysvud7zroar3cb75d3q,.urlset/master.m3u8",
},
{
"behaviorHints": {
"bingeGroup": "webstreamr-supervideo_de",
"videoSize": 1073741824,
"url": "https://hfs279.serversicuro.cc/hls/,dnzpejj427g4a3gyvbth53rxqewqgqqzp3wr6zwutysvud7zroar3cb75d3q,.urlset/master.m3u8",
},
"name": "WebStreamr 720P",
"title": "📂 des teufels bad 2024
{
"behaviorHints": {
"bingeGroup": "webstreamr-supervideo_de",
"videoSize": 1073741824,
},
"name": "WebStreamr 720P",
"title": "📂 des teufels bad 2024
💾 1 GB
🌐 German 🇩🇪
🔗 SuperVideo",
"url": "https://hfs290.serversicuro.cc/hls/,dnzpfi3d27g4a3gyvbmh5klwtl65qh654hyjtgupd6p56thhyqu6ra3olbfa,.urlset/master.m3u8",
},
{
"behaviorHints": {
"bingeGroup": "webstreamr-doodstream_de",
"notWebReady": true,
"proxyHeaders": {
"request": {
"Referer": "http://dood.to/",
"url": "https://hfs290.serversicuro.cc/hls/,dnzpfi3d27g4a3gyvbmh5klwtl65qh654hyjtgupd6p56thhyqu6ra3olbfa,.urlset/master.m3u8",
},
{
"behaviorHints": {
"bingeGroup": "webstreamr-doodstream_de",
"notWebReady": true,
"proxyHeaders": {
"request": {
"Referer": "http://dood.to/",
},
},
},
},
"name": "WebStreamr N/A",
"title": "📂 des-teufels-bad-2024
"name": "WebStreamr N/A",
"title": "📂 des-teufels-bad-2024
🌐 German 🇩🇪
🔗 DoodStream",
"url": "https://aa360cc.cloudatacdn.com/u5kjv4jxytd3sdgge5uogji5dg4huat2pxrm2qibdbm5rtpmbzgb5tornooa/k9wk0js17e~mocked-random-string?token=7uebebipnnhusa4xnyea1er4&expiry=639837296000",
},
{
"behaviorHints": {
"bingeGroup": "webstreamr-doodstream_it",
"notWebReady": true,
"proxyHeaders": {
"request": {
"Referer": "http://dood.to/",
"url": "https://aa360cc.cloudatacdn.com/u5kjv4jxytd3sdgge5uogji5dg4huat2pxrm2qibdbm5rtpmbzgb5tornooa/k9wk0js17e~mocked-random-string?token=7uebebipnnhusa4xnyea1er4&expiry=639837296000",
},
{
"behaviorHints": {
"bingeGroup": "webstreamr-doodstream_it",
"notWebReady": true,
"proxyHeaders": {
"request": {
"Referer": "http://dood.to/",
},
},
},
},
"name": "WebStreamr N/A",
"title": "📂 the-devils-bath-2024-sd-sub-ita
"name": "WebStreamr N/A",
"title": "📂 the-devils-bath-2024-sd-sub-ita
🌐 Italian 🇮🇹
🔗 DoodStream",
"url": "https://kk892as.cloudatacdn.com/u5kj7j7s27d3sdgge5woezkbi4pu672wktq3aqujw47rbpl3xog2gtqnw2xa/awn9rgotuu~mocked-random-string?token=aw2v2d8uhbrj2ky54d573ujk&expiry=639837296000",
},
{
"behaviorHints": {
"bingeGroup": "webstreamr-external_de",
"url": "https://kk892as.cloudatacdn.com/u5kj7j7s27d3sdgge5woezkbi4pu672wktq3aqujw47rbpl3xog2gtqnw2xa/awn9rgotuu~mocked-random-string?token=aw2v2d8uhbrj2ky54d573ujk&expiry=639837296000",
},
"externalUrl": "https://mixdrop.ag/e/3nzwveprim63or6",
"name": "WebStreamr N/A ⚠️ external",
"title": "🌐 German 🇩🇪
{
"behaviorHints": {
"bingeGroup": "webstreamr-external_de",
},
"externalUrl": "https://mixdrop.ag/e/3nzwveprim63or6",
"name": "WebStreamr N/A ⚠️ external",
"title": "🌐 German 🇩🇪
🔗 mixdrop.ag",
},
{
"behaviorHints": {
"bingeGroup": "webstreamr-external_it",
},
"externalUrl": "https://mixdrop.ag/e/vk196d6xfzwwo1",
"name": "WebStreamr N/A ⚠️ external",
"title": "🌐 Italian 🇮🇹
{
"behaviorHints": {
"bingeGroup": "webstreamr-external_it",
},
"externalUrl": "https://mixdrop.ag/e/vk196d6xfzwwo1",
"name": "WebStreamr N/A ⚠️ external",
"title": "🌐 Italian 🇮🇹
🔗 mixdrop.ag",
},
]
},
],
"ttl": 900000,
}
`;