diff --git a/package-lock.json b/package-lock.json index 8dfc0f6..ed57450 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.5.0", "license": "MIT", "dependencies": { + "bytes": "^3.1.2", "cheerio": "^1.0.0", "express": "^5.1.0", "lru-cache": "^11.1.0", @@ -20,6 +21,7 @@ "devDependencies": { "@eslint/js": "^9.26.0", "@stylistic/eslint-plugin": "^4.2.0", + "@types/bytes": "^3.1.5", "@types/express": "^5.0.1", "@types/jest": "^29.5.14", "@types/make-fetch-happen": "^10.0.4", @@ -1592,6 +1594,13 @@ "@types/node": "*" } }, + "node_modules/@types/bytes": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@types/bytes/-/bytes-3.1.5.tgz", + "integrity": "sha512-VgZkrJckypj85YxEsEavcMmmSOIzkUHqWmM4CCyia5dc54YwsXzJ5uT4fYxBQNEXx+oF1krlhgCbvfubXqZYsQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/connect": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", diff --git a/package.json b/package.json index a24f06f..86d6764 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "node": "^22.0.0" }, "dependencies": { + "bytes": "^3.1.2", "cheerio": "^1.0.0", "express": "^5.1.0", "lru-cache": "^11.1.0", @@ -41,6 +42,7 @@ "devDependencies": { "@eslint/js": "^9.26.0", "@stylistic/eslint-plugin": "^4.2.0", + "@types/bytes": "^3.1.5", "@types/express": "^5.0.1", "@types/jest": "^29.5.14", "@types/make-fetch-happen": "^10.0.4", diff --git a/src/embed-extractor/Dropload.ts b/src/embed-extractor/Dropload.ts index fc3ab51..c824998 100644 --- a/src/embed-extractor/Dropload.ts +++ b/src/embed-extractor/Dropload.ts @@ -1,6 +1,7 @@ import { EmbedExtractor } from './types'; import { extractUrlFromPacked, Fetcher } from '../utils'; import { Context } from '../types'; +import bytes from 'bytes'; export class Dropload implements EmbedExtractor { readonly id = 'dropload'; @@ -19,17 +20,16 @@ export class Dropload implements EmbedExtractor { const normalizedUrl = url.toString().replace('/e/', '').replace('/embed-', '/'); const html = await this.fetcher.text(ctx, normalizedUrl); - const height = (html.match(/\d{3,}x(\d{3,}),/) as string[])[1]; + const heightMatch = html.match(/\d{3,}x(\d{3,}),/) as string[]; - const sizeMatch = html.match(/([\d.]+) ?([GM]B)/) as string[]; - const size = `${sizeMatch[1]} ${sizeMatch[2]}`; + const sizeMatch = html.match(/([\d.]+ ?[GM]B)/) as string[]; return { url: extractUrlFromPacked(html, [/sources:\[{file:"(.*?)"/]), label: this.label, sourceId: this.id, - height, - size, + height: parseInt(heightMatch[1] as string) as number, + bytes: bytes.parse(sizeMatch[1] as string) as number, language, }; }; diff --git a/src/embed-extractor/SuperVideo.ts b/src/embed-extractor/SuperVideo.ts index 4809b61..5fb5ee6 100644 --- a/src/embed-extractor/SuperVideo.ts +++ b/src/embed-extractor/SuperVideo.ts @@ -1,3 +1,4 @@ +import bytes from 'bytes'; import { EmbedExtractor } from './types'; import { extractUrlFromPacked, Fetcher } from '../utils'; import { Context } from '../types'; @@ -19,16 +20,14 @@ export class SuperVideo implements EmbedExtractor { const normalizedUrl = url.toString().replace('/e/', '/').replace('/embed-', '/'); const html = await this.fetcher.text(ctx, normalizedUrl); - const heightAndSizeMatch = html.match(/\d{3,}x(\d{3,}), ([\d.]+) ?([GM]B)/) as string[]; - const height = heightAndSizeMatch[1]; - const size = `${heightAndSizeMatch[2]} ${heightAndSizeMatch[3]}`; + const heightAndSizeMatch = html.match(/\d{3,}x(\d{3,}), ([\d.]+ ?[GM]B)/) as string[]; return { url: extractUrlFromPacked(html, [/sources:\[{file:"(.*?)"/]), label: this.label, sourceId: this.id, - height, - size, + height: parseInt(heightAndSizeMatch[1] as string) as number, + bytes: bytes.parse(heightAndSizeMatch[2] as string) as number, language, }; }; diff --git a/src/handler/KinoKiste.test.ts b/src/handler/KinoKiste.test.ts index 0e2d023..d7167af 100644 --- a/src/handler/KinoKiste.test.ts +++ b/src/handler/KinoKiste.test.ts @@ -30,8 +30,8 @@ describe('KinoKiste', () => { url: expect.any(URL), label: 'SuperVideo', sourceId: 'supervideo', - height: '720', - size: '699.8 MB', + height: 720, + bytes: 733793484, language: 'de', }); expect(streams[0]?.url.href).toMatch(/^https:\/\/.*?.m3u8/); @@ -39,8 +39,8 @@ describe('KinoKiste', () => { url: expect.any(URL), label: 'Dropload', sourceId: 'dropload', - height: '720', - size: '699.8 MB', + height: 720, + bytes: 733793484, language: 'de', }); expect(streams[1]?.url.href).toMatch(/^https:\/\/.*?.m3u8/); diff --git a/src/handler/MeineCloud.test.ts b/src/handler/MeineCloud.test.ts index 49bde0a..7825d68 100644 --- a/src/handler/MeineCloud.test.ts +++ b/src/handler/MeineCloud.test.ts @@ -30,8 +30,8 @@ describe('MeineCloud', () => { url: expect.any(URL), label: 'SuperVideo', sourceId: 'supervideo', - height: '720', - size: '1.0 GB', + height: 720, + bytes: 1073741824, language: 'de', }); expect(streams[0]?.url.href).toMatch(/^https:\/\/.*?.m3u8/); @@ -39,8 +39,8 @@ describe('MeineCloud', () => { url: expect.any(URL), label: 'Dropload', sourceId: 'dropload', - height: '1080', - size: '1.3 GB', + height: 1080, + bytes: 1395864371, language: 'de', }); expect(streams[1]?.url.href).toMatch(/^https:\/\/.*?.m3u8/); diff --git a/src/index.ts b/src/index.ts index 287fbc6..b7f63e5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,6 +7,7 @@ import { buildManifest, Fetcher, fulfillAllPromises, iso2ToFlag, logInfo } from import { Config, UrlResult } from './types'; import fs from 'node:fs'; import * as os from 'node:os'; +import bytes from 'bytes'; const addon = express(); addon.set('trust proxy', true); @@ -109,12 +110,12 @@ addon.get('/:config/stream/:type/:id.json', async function (req: Request, res: R await fulfillAllPromises(handlerPromises); urlResults.sort((a, b) => { - const heightComparison = parseInt(b.height ?? '0') - parseInt(a.height ?? '0'); + const heightComparison = (b.height ?? 0) - (a.height ?? 0); if (heightComparison !== 0) { return heightComparison; } - return parseFloat(b.size ?? '0') - parseFloat(a.size ?? '0'); + return (b.bytes ?? 0) - (a.bytes ?? 0); }); logInfo(`Return ${urlResults.length} streams`); @@ -126,8 +127,8 @@ addon.get('/:config/stream/:type/:id.json', async function (req: Request, res: R } let title = urlResult.label; - if (urlResult.size) { - title += ` | 💾 ${urlResult.size}`; + if (urlResult.bytes) { + title += ` | 💾 ${bytes.format(urlResult.bytes, { unitSeparator: ' ' })}`; } if (urlResult.language) { title += ` | ${iso2ToFlag(urlResult.language)}`; diff --git a/src/types.ts b/src/types.ts index 4a43684..b3247e7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -10,7 +10,7 @@ export interface UrlResult { url: URL; label: string; sourceId: string; - height: string | undefined; - size: string | undefined; + height: number | undefined; + bytes: number | undefined; language: string | undefined; }