From e4dd16e9d1e500dbcb7cc0b33cf7e26c480f9674 Mon Sep 17 00:00:00 2001 From: WebStreamr <210764791+webstreamr@users.noreply.github.com> Date: Mon, 2 Jun 2025 15:31:15 +0000 Subject: [PATCH] chore: improve results format and refactor name/title generation --- src/utils/StreamResolver.ts | 93 ++++++++++--------- .../__snapshots__/StreamResolver.test.ts.snap | 63 ++++++++----- src/utils/index.ts | 1 + src/utils/languageFromCountryCode.ts | 14 +++ 4 files changed, 103 insertions(+), 68 deletions(-) create mode 100644 src/utils/languageFromCountryCode.ts diff --git a/src/utils/StreamResolver.ts b/src/utils/StreamResolver.ts index 2dc30d9..c2b394a 100644 --- a/src/utils/StreamResolver.ts +++ b/src/utils/StreamResolver.ts @@ -5,6 +5,7 @@ import bytes from 'bytes'; import { Context, UrlResult } from '../types'; import { Handler } from '../handler'; import { NotFoundError } from '../error'; +import { languageFromCountryCode } from './languageFromCountryCode'; export class StreamResolver { private readonly logger: winston.Logger; @@ -68,51 +69,57 @@ export class StreamResolver { this.logger.info(`Return ${urlResults.length} streams`, ctx); streams.push( - ...urlResults.map((urlResult) => { - let name = 'WebStreamr'; - if (urlResult.meta.countryCode) { - name += ` ${flag(urlResult.meta.countryCode)}`; - } - if (urlResult.meta.height) { - name += ` ${urlResult.meta.height}p`; - } - if (urlResult.isExternal) { - name += ` external`; - } - - const titleSecondLineEntries: string[] = []; - if (urlResult.meta.bytes) { - titleSecondLineEntries.push(`💾 ${bytes.format(urlResult.meta.bytes, { unitSeparator: ' ' })}`); - } - titleSecondLineEntries.push(`⚙️ ${urlResult.label}`); - - const titleLines = []; - if (urlResult.meta.title) { - titleLines.push(urlResult.meta.title); - } - titleLines.push(titleSecondLineEntries.join(' ')); - if (urlResult.blocked) { - titleLines.push('Request was blocked.'); - } - - const title = titleLines.join('\n'); - - return { - [urlResult.isExternal ? 'externalUrl' : 'url']: urlResult.url.href, - name, - title, - behaviorHints: { - ...(urlResult.sourceId && { bingeGroup: `webstreamr-${urlResult.sourceId}` }), - ...(urlResult.requestHeaders !== undefined && { - notWebReady: true, - proxyHeaders: { request: urlResult.requestHeaders }, - }), - ...(urlResult.meta.bytes && { videoSize: urlResult.meta.bytes }), - }, - }; - }), + ...urlResults.map(urlResult => ({ + [urlResult.isExternal ? 'externalUrl' : 'url']: urlResult.url.href, + name: this.buildName(urlResult), + title: this.buildTitle(urlResult), + behaviorHints: { + ...(urlResult.sourceId && { bingeGroup: `webstreamr-${urlResult.sourceId}` }), + ...(urlResult.requestHeaders !== undefined && { + notWebReady: true, + proxyHeaders: { request: urlResult.requestHeaders }, + }), + ...(urlResult.meta.bytes && { videoSize: urlResult.meta.bytes }), + }, + })), ); return streams; }; + + private readonly buildName = (urlResult: UrlResult): string => { + let name = process.env['MANIFEST_NAME'] || 'WebStreamr'; + + name += urlResult.meta.height ? ` ${urlResult.meta.height}P` : ' N/A'; + + if (urlResult.isExternal) { + name += ` ⚠️ external`; + } + + return name; + }; + + private readonly buildTitle = (urlResult: UrlResult): string => { + const titleLines = []; + + if (urlResult.meta.title) { + titleLines.push(`📂 ${urlResult.meta.title}`); + } + + if (urlResult.meta.bytes) { + titleLines.push(`💾 ${bytes.format(urlResult.meta.bytes, { unitSeparator: ' ' })}`); + } + + if (urlResult.meta.countryCode) { + titleLines.push(`🌐 ${languageFromCountryCode(urlResult.meta.countryCode)} ${flag(urlResult.meta.countryCode)}`); + } + + titleLines.push(`🔗 ${urlResult.label}`); + + if (urlResult.blocked) { + titleLines.push('⚠️ Request was blocked.'); + } + + return titleLines.join('\n'); + }; } diff --git a/src/utils/__snapshots__/StreamResolver.test.ts.snap b/src/utils/__snapshots__/StreamResolver.test.ts.snap index 2753b44..f6ad097 100644 --- a/src/utils/__snapshots__/StreamResolver.test.ts.snap +++ b/src/utils/__snapshots__/StreamResolver.test.ts.snap @@ -5,9 +5,10 @@ exports[`resolve adds Cloudflare blocked info 1`] = ` { "behaviorHints": {}, "externalUrl": "https://example.com/", - "name": "WebStreamr 🇩🇪 external", - "title": "⚙️ example.com -Request was blocked.", + "name": "WebStreamr N/A ⚠️ external", + "title": "🌐 German 🇩🇪 +🔗 example.com +⚠️ Request was blocked.", }, ] `; @@ -19,9 +20,11 @@ exports[`resolve returns sorted results 1`] = ` "bingeGroup": "webstreamr-dropload_de", "videoSize": 1395864371, }, - "name": "WebStreamr 🇩🇪 1080p", - "title": "des-teufels-bad-2024 -💾 1.3 GB ⚙️ Dropload", + "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", }, { @@ -29,9 +32,11 @@ exports[`resolve returns sorted results 1`] = ` "bingeGroup": "webstreamr-dropload_it", "videoSize": 1181116006, }, - "name": "WebStreamr 🇮🇹 720p", - "title": "the-devils-bath-2024-sd-sub-ita -💾 1.1 GB ⚙️ Dropload", + "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", }, { @@ -39,9 +44,11 @@ exports[`resolve returns sorted results 1`] = ` "bingeGroup": "webstreamr-supervideo_it", "videoSize": 1181116006, }, - "name": "WebStreamr 🇮🇹 720p", - "title": "the devils bath 2024 sub ita -💾 1.1 GB ⚙️ SuperVideo", + "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", }, { @@ -49,9 +56,11 @@ exports[`resolve returns sorted results 1`] = ` "bingeGroup": "webstreamr-supervideo_de", "videoSize": 1073741824, }, - "name": "WebStreamr 🇩🇪 720p", - "title": "des teufels bad 2024 -💾 1 GB ⚙️ SuperVideo", + "name": "WebStreamr 720P", + "title": "📂 des teufels bad 2024 +💾 1 GB +🌐 German 🇩🇪 +🔗 SuperVideo", "url": "https://hfs290.serversicuro.cc/hls/,dnzpfi3d27g4a3gyvbmh5klwtl65qh654hyjtgupd6p56thhyqu6ra3olbfa,.urlset/master.m3u8", }, { @@ -64,9 +73,10 @@ exports[`resolve returns sorted results 1`] = ` }, }, }, - "name": "WebStreamr 🇩🇪", - "title": "des-teufels-bad-2024 -⚙️ DoodStream", + "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", }, { @@ -79,9 +89,10 @@ exports[`resolve returns sorted results 1`] = ` }, }, }, - "name": "WebStreamr 🇮🇹", - "title": "the-devils-bath-2024-sd-sub-ita -⚙️ DoodStream", + "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", }, { @@ -89,16 +100,18 @@ exports[`resolve returns sorted results 1`] = ` "bingeGroup": "webstreamr-external_de", }, "externalUrl": "https://mixdrop.ag/e/3nzwveprim63or6", - "name": "WebStreamr 🇩🇪 external", - "title": "⚙️ mixdrop.ag", + "name": "WebStreamr N/A ⚠️ external", + "title": "🌐 German 🇩🇪 +🔗 mixdrop.ag", }, { "behaviorHints": { "bingeGroup": "webstreamr-external_it", }, "externalUrl": "https://mixdrop.ag/e/vk196d6xfzwwo1", - "name": "WebStreamr 🇮🇹 external", - "title": "⚙️ mixdrop.ag", + "name": "WebStreamr N/A ⚠️ external", + "title": "🌐 Italian 🇮🇹 +🔗 mixdrop.ag", }, ] `; diff --git a/src/utils/index.ts b/src/utils/index.ts index 54af3ae..4785172 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -2,5 +2,6 @@ export * from './Fetcher'; export * from './StreamResolver'; export * from './embed'; export * from './imdb'; +export * from './languageFromCountryCode'; export * from './manifest'; export * from './tmdb'; diff --git a/src/utils/languageFromCountryCode.ts b/src/utils/languageFromCountryCode.ts new file mode 100644 index 0000000..cda9e3f --- /dev/null +++ b/src/utils/languageFromCountryCode.ts @@ -0,0 +1,14 @@ +import { CountryCode } from '../types'; + +const countryCodeLanguageMap: Record = { + de: 'German', + en: 'English', + es: 'Castilian Spanish', + fr: 'French', + it: 'Italian', + mx: 'Latin American Spanish', +}; + +export const languageFromCountryCode = (countryCode: CountryCode) => { + return countryCodeLanguageMap[countryCode]; +};