diff --git a/src/utils/StreamResolver.test.ts b/src/utils/StreamResolver.test.ts index f037184..cc0ad69 100644 --- a/src/utils/StreamResolver.test.ts +++ b/src/utils/StreamResolver.test.ts @@ -128,7 +128,7 @@ describe('resolve', () => { protected readonly extractInternal = async (): Promise => [ { - url: new URL('https://example.com'), + url: new URL('https://example1.com'), format: Format.unknown, isExternal: true, label: 'hoster.com', @@ -137,106 +137,11 @@ describe('resolve', () => { countryCodes: [CountryCode.de], }, }, - { - url: new URL('https://example.com'), - format: Format.unknown, - isExternal: true, - error: new BlockedError(new URL('https://example.com'), BlockedReason.cloudflare_challenge, {}), - label: 'hoster.com', - ttl: this.ttl, - meta: { - countryCodes: [CountryCode.de], - }, - }, - { - url: new URL('https://example.com'), - format: Format.unknown, - isExternal: true, - error: new BlockedError(new URL('https://example.com'), BlockedReason.cloudflare_censor, {}), - label: 'hoster.com', - ttl: this.ttl, - meta: { - countryCodes: [CountryCode.de], - }, - }, - { - url: new URL('https://example.com'), - format: Format.unknown, - isExternal: true, - error: new BlockedError(new URL('https://example.com'), BlockedReason.media_flow_proxy_auth, {}), - label: 'hoster.com', - ttl: this.ttl, - meta: { - countryCodes: [CountryCode.de], - }, - }, - { - url: new URL('https://example.com'), - format: Format.unknown, - isExternal: true, - error: new BlockedError(new URL('https://example.com'), BlockedReason.unknown, {}), - label: 'hoster.com', - ttl: this.ttl, - meta: { - countryCodes: [CountryCode.de], - }, - }, - { - url: new URL('https://working2.com'), - format: Format.unknown, - label: 'working1', - ttl: this.ttl, - meta: { - countryCodes: [CountryCode.de], - }, - }, - { - url: new URL('https://example.com'), - format: Format.unknown, - isExternal: true, - error: new TooManyRequestsError(new URL('https://example.com'), 10), - label: 'hoster.com', - ttl: this.ttl, - meta: { - countryCodes: [CountryCode.de], - }, - }, - { - url: new URL('https://example.com'), - format: Format.unknown, - isExternal: true, - error: new TooManyTimeoutsError(new URL('https://example.com')), - label: 'hoster.com', - ttl: this.ttl, - meta: { - countryCodes: [CountryCode.de], - }, - }, - { - url: new URL('https://working1.com'), - format: Format.unknown, - label: 'working2', - ttl: this.ttl, - meta: { - countryCodes: [CountryCode.de], - }, - }, - { - url: new URL('https://example2.com'), - format: Format.unknown, - isExternal: true, - error: new TypeError(), - label: 'hoster.com', - ttl: this.ttl, - meta: { - countryCodes: [CountryCode.de], - }, - }, { url: new URL('https://example2.com'), format: Format.unknown, isExternal: true, - error: new TimeoutError(new URL('https://example2.com')), + error: new BlockedError(new URL('https://example2.com'), BlockedReason.cloudflare_challenge, {}), label: 'hoster.com', ttl: this.ttl, meta: { @@ -247,7 +152,7 @@ describe('resolve', () => { url: new URL('https://example3.com'), format: Format.unknown, isExternal: true, - error: new QueueIsFullError(new URL('https://example3.com')), + error: new BlockedError(new URL('https://example3.com'), BlockedReason.cloudflare_censor, {}), label: 'hoster.com', ttl: this.ttl, meta: { @@ -258,7 +163,7 @@ describe('resolve', () => { url: new URL('https://example4.com'), format: Format.unknown, isExternal: true, - error: new HttpError(new URL('https://example4.com'), 500, 'Internal Server Error', { 'x-foo': 'bar' }), + error: new BlockedError(new URL('https://example4.com'), BlockedReason.media_flow_proxy_auth, {}), label: 'hoster.com', ttl: this.ttl, meta: { @@ -269,7 +174,102 @@ describe('resolve', () => { url: new URL('https://example5.com'), format: Format.unknown, isExternal: true, - error: new HttpError(new URL('https://example5.com'), 418, 'I\'m a tea pot', { 'x-foo': 'bar' }), + error: new BlockedError(new URL('https://example5.com'), BlockedReason.unknown, {}), + label: 'hoster.com', + ttl: this.ttl, + meta: { + countryCodes: [CountryCode.de], + }, + }, + { + url: new URL('https://example6.com'), + format: Format.unknown, + label: 'working1', + ttl: this.ttl, + meta: { + countryCodes: [CountryCode.de], + }, + }, + { + url: new URL('https://example7.com'), + format: Format.unknown, + isExternal: true, + error: new TooManyRequestsError(new URL('https://example7.com'), 10), + label: 'hoster.com', + ttl: this.ttl, + meta: { + countryCodes: [CountryCode.de], + }, + }, + { + url: new URL('https://example8.com'), + format: Format.unknown, + isExternal: true, + error: new TooManyTimeoutsError(new URL('https://example8.com')), + label: 'hoster.com', + ttl: this.ttl, + meta: { + countryCodes: [CountryCode.de], + }, + }, + { + url: new URL('https://example9.com'), + format: Format.unknown, + label: 'working2', + ttl: this.ttl, + meta: { + countryCodes: [CountryCode.de], + }, + }, + { + url: new URL('https://example10.com'), + format: Format.unknown, + isExternal: true, + error: new TypeError(), + label: 'hoster.com', + ttl: this.ttl, + meta: { + countryCodes: [CountryCode.de], + }, + }, + { + url: new URL('https://example11.com'), + format: Format.unknown, + isExternal: true, + error: new TimeoutError(new URL('https://example11.com')), + label: 'hoster.com', + ttl: this.ttl, + meta: { + countryCodes: [CountryCode.de], + }, + }, + { + url: new URL('https://example12.com'), + format: Format.unknown, + isExternal: true, + error: new QueueIsFullError(new URL('https://example12.com')), + label: 'hoster.com', + ttl: this.ttl, + meta: { + countryCodes: [CountryCode.de], + }, + }, + { + url: new URL('https://example13.com'), + format: Format.unknown, + isExternal: true, + error: new HttpError(new URL('https://example13.com'), 500, 'Internal Server Error', { 'x-foo': 'bar' }), + label: 'hoster.com', + ttl: this.ttl, + meta: { + countryCodes: [CountryCode.de], + }, + }, + { + url: new URL('https://example14.com'), + format: Format.unknown, + isExternal: true, + error: new HttpError(new URL('https://example14.com'), 418, 'I\'m a tea pot', { 'x-foo': 'bar' }), label: 'hoster.com', ttl: this.ttl, meta: { diff --git a/src/utils/StreamResolver.ts b/src/utils/StreamResolver.ts index ff641d1..bff70d7 100644 --- a/src/utils/StreamResolver.ts +++ b/src/utils/StreamResolver.ts @@ -144,6 +144,10 @@ export class StreamResolver { streams.push( ...urlResults.filter(urlResult => (!urlResult.error || showErrors(ctx.config)) && !isResolutionExcluded(ctx.config, getClosestResolution(urlResult.meta?.height))) + .filter((urlResult, index, self) => + // Remove duplicate URLs + index === self.findIndex(t => t.url.href === urlResult.url.href), + ) .map(urlResult => ({ ...this.buildUrl(urlResult), name: this.buildName(ctx, urlResult), diff --git a/src/utils/__snapshots__/StreamResolver.test.ts.snap b/src/utils/__snapshots__/StreamResolver.test.ts.snap index dd3d42b..d5e9ca5 100644 --- a/src/utils/__snapshots__/StreamResolver.test.ts.snap +++ b/src/utils/__snapshots__/StreamResolver.test.ts.snap @@ -10,7 +10,7 @@ exports[`resolve adds error info 1`] = ` }, "name": "WebStreamr 🇩🇪", "title": "🔗 working1", - "url": "https://working2.com/", + "url": "https://example6.com/", }, { "behaviorHints": { @@ -19,14 +19,14 @@ exports[`resolve adds error info 1`] = ` }, "name": "WebStreamr 🇩🇪", "title": "🔗 working2", - "url": "https://working1.com/", + "url": "https://example9.com/", }, { "behaviorHints": { "bingeGroup": "webstreamr-undefined-undefined-de", "notWebReady": true, }, - "externalUrl": "https://example.com/", + "externalUrl": "https://example1.com/", "name": "WebStreamr 🇩🇪", "title": "🔗 hoster.com", }, @@ -43,47 +43,47 @@ exports[`resolve adds error info 2`] = ` "bingeGroup": "webstreamr-undefined-undefined-de", "notWebReady": true, }, - "externalUrl": "https://example5.com/", + "externalUrl": "https://example14.com/", "name": "WebStreamr 🇩🇪", "title": "🔗 hoster.com -❌ Request to example5.com failed with status 418 (I'm a tea pot). Request-id: test.", +❌ Request to example14.com failed with status 418 (I'm a tea pot). Request-id: test.", }, { "behaviorHints": { "bingeGroup": "webstreamr-undefined-undefined-de", "notWebReady": true, }, - "externalUrl": "https://example4.com/", + "externalUrl": "https://example13.com/", "name": "WebStreamr 🇩🇪", "title": "🔗 hoster.com -❌ Remote server example4.com has issues. We can't fix this, please try later again.", +❌ Remote server example13.com has issues. We can't fix this, please try later again.", }, { "behaviorHints": { "bingeGroup": "webstreamr-undefined-undefined-de", "notWebReady": true, }, - "externalUrl": "https://example3.com/", + "externalUrl": "https://example12.com/", "name": "WebStreamr 🇩🇪", "title": "🔗 hoster.com -⏳ Request queue for example3.com is full. Please try again later or consider self-hosting.", +⏳ Request queue for example12.com is full. Please try again later or consider self-hosting.", }, { "behaviorHints": { "bingeGroup": "webstreamr-undefined-undefined-de", "notWebReady": true, }, - "externalUrl": "https://example2.com/", + "externalUrl": "https://example11.com/", "name": "WebStreamr 🇩🇪", "title": "🔗 hoster.com -🐢 Request to example2.com timed out.", +🐢 Request to example11.com timed out.", }, { "behaviorHints": { "bingeGroup": "webstreamr-undefined-undefined-de", "notWebReady": true, }, - "externalUrl": "https://example2.com/", + "externalUrl": "https://example10.com/", "name": "WebStreamr 🇩🇪", "title": "🔗 hoster.com ❌ Request failed. Request-id: test.", @@ -93,37 +93,37 @@ exports[`resolve adds error info 2`] = ` "bingeGroup": "webstreamr-undefined-undefined-de", "notWebReady": true, }, - "externalUrl": "https://example.com/", + "externalUrl": "https://example8.com/", "name": "WebStreamr 🇩🇪", "title": "🔗 hoster.com -🚦 Too many recent timeouts when requesting example.com. Please try again later.", +🚦 Too many recent timeouts when requesting example8.com. Please try again later.", }, { "behaviorHints": { "bingeGroup": "webstreamr-undefined-undefined-de", "notWebReady": true, }, - "externalUrl": "https://example.com/", + "externalUrl": "https://example7.com/", "name": "WebStreamr 🇩🇪", "title": "🔗 hoster.com -🚦 Request to example.com was rate-limited. Please try again later or consider self-hosting.", +🚦 Request to example7.com was rate-limited. Please try again later or consider self-hosting.", }, { "behaviorHints": { "bingeGroup": "webstreamr-undefined-undefined-de", "notWebReady": true, }, - "externalUrl": "https://example.com/", + "externalUrl": "https://example5.com/", "name": "WebStreamr 🇩🇪", "title": "🔗 hoster.com -⚠️ Request to example.com was blocked. Reason: unknown", +⚠️ Request to example5.com was blocked. Reason: unknown", }, { "behaviorHints": { "bingeGroup": "webstreamr-undefined-undefined-de", "notWebReady": true, }, - "externalUrl": "https://example.com/", + "externalUrl": "https://example4.com/", "name": "WebStreamr 🇩🇪", "title": "🔗 hoster.com ⚠️ MediaFlow Proxy authentication failed. Please set the correct password.", @@ -133,20 +133,20 @@ exports[`resolve adds error info 2`] = ` "bingeGroup": "webstreamr-undefined-undefined-de", "notWebReady": true, }, - "externalUrl": "https://example.com/", + "externalUrl": "https://example3.com/", "name": "WebStreamr 🇩🇪", "title": "🔗 hoster.com -⚠️ Request to example.com was blocked. Reason: cloudflare_censor", +⚠️ Request to example3.com was blocked. Reason: cloudflare_censor", }, { "behaviorHints": { "bingeGroup": "webstreamr-undefined-undefined-de", "notWebReady": true, }, - "externalUrl": "https://example.com/", + "externalUrl": "https://example2.com/", "name": "WebStreamr 🇩🇪", "title": "🔗 hoster.com -⚠️ Request to example.com was blocked. Reason: cloudflare_challenge", +⚠️ Request to example2.com was blocked. Reason: cloudflare_challenge", }, { "behaviorHints": { @@ -155,7 +155,7 @@ exports[`resolve adds error info 2`] = ` }, "name": "WebStreamr 🇩🇪", "title": "🔗 working1", - "url": "https://working2.com/", + "url": "https://example6.com/", }, { "behaviorHints": { @@ -164,14 +164,14 @@ exports[`resolve adds error info 2`] = ` }, "name": "WebStreamr 🇩🇪", "title": "🔗 working2", - "url": "https://working1.com/", + "url": "https://example9.com/", }, { "behaviorHints": { "bingeGroup": "webstreamr-undefined-undefined-de", "notWebReady": true, }, - "externalUrl": "https://example.com/", + "externalUrl": "https://example1.com/", "name": "WebStreamr 🇩🇪", "title": "🔗 hoster.com", },