From 20d3ecc07408217147cfa83767f5592334566d71 Mon Sep 17 00:00:00 2001 From: freearhey <7253922+freearhey@users.noreply.github.com> Date: Thu, 4 Dec 2025 18:32:25 +0300 Subject: [PATCH] Update scripts --- .../{api/generate.ts => playlist/export.ts} | 0 scripts/commands/playlist/test.ts | 8 +-- scripts/commands/playlist/update.ts | 25 ++++---- scripts/commands/playlist/validate.ts | 10 +-- scripts/commands/report/create.ts | 12 ++-- scripts/core/issueParser.ts | 18 +++--- scripts/core/playlistParser.ts | 4 +- scripts/generators/languagesGenerator.ts | 4 +- scripts/models/stream.ts | 64 ++++++------------- 9 files changed, 60 insertions(+), 85 deletions(-) rename scripts/commands/{api/generate.ts => playlist/export.ts} (100%) diff --git a/scripts/commands/api/generate.ts b/scripts/commands/playlist/export.ts similarity index 100% rename from scripts/commands/api/generate.ts rename to scripts/commands/playlist/export.ts diff --git a/scripts/commands/playlist/test.ts b/scripts/commands/playlist/test.ts index 737b2dbea7..9446e8c4ad 100644 --- a/scripts/commands/playlist/test.ts +++ b/scripts/commands/playlist/test.ts @@ -1,5 +1,5 @@ import { PlaylistParser, StreamTester, CliTable } from '../../core' -import type { TestResult } from '../../core/streamTester' +import type { StreamTesterResult } from '../../core/streamTester' import { ROOT_DIR, STREAMS_DIR } from '../../constants' import { Logger, Collection } from '@freearhey/core' import { program, OptionValues } from 'commander' @@ -92,10 +92,10 @@ async function runTest(stream: Stream) { const key = stream.getUniqKey() results[key] = chalk.white('LOADING...') - const result: TestResult = await tester.test(stream) + const result: StreamTesterResult = await tester.test(stream) let status = '' - const errorStatusCodes = ['ENOTFOUND', 'HTTP_404_NOT_FOUND'] + const errorStatusCodes = ['ENOTFOUND', 'HTTP_404_NOT_FOUND', 'HTTP_404_UNKONWN_ERROR'] if (result.status.ok) status = chalk.green('OK') else if (errorStatusCodes.includes(result.status.code)) { status = chalk.red(result.status.code) @@ -144,7 +144,7 @@ function drawTable() { } } -function onFinish(error: Error) { +function onFinish(error: Error | null | undefined) { clearInterval(interval) if (error) { diff --git a/scripts/commands/playlist/update.ts b/scripts/commands/playlist/update.ts index 600b23ac34..1c5f17ee33 100644 --- a/scripts/commands/playlist/update.ts +++ b/scripts/commands/playlist/update.ts @@ -71,9 +71,9 @@ async function removeStreams({ requests.forEach((issue: Issue) => { const data = issue.data - if (data.missing('streamUrl')) return + if (data.missing('stream_url')) return - const streamUrls = data.getString('streamUrl') || '' + const streamUrls = data.getString('stream_url') || '' let changed = false streamUrls @@ -104,14 +104,14 @@ async function editStreams({ requests.forEach((issue: Issue) => { const data = issue.data - if (data.missing('streamUrl')) return + if (data.missing('stream_url')) return const stream: Stream = streams.first( - (_stream: Stream) => _stream.url === data.getString('streamUrl') + (_stream: Stream) => _stream.url === data.getString('stream_url') ) if (!stream) return - const streamId = data.getString('streamId') || '' + const streamId = data.getString('stream_id') || '' const [channelId, feedId] = streamId.split('@') if (channelId) { @@ -138,12 +138,12 @@ async function addStreams({ ) requests.forEach((issue: Issue) => { const data = issue.data - if (data.missing('streamId') || data.missing('streamUrl')) return - if (streams.includes((_stream: Stream) => _stream.url === data.getString('streamUrl'))) return - const streamUrl = data.getString('streamUrl') || '' + if (data.missing('stream_id') || data.missing('stream_url')) return + if (streams.includes((_stream: Stream) => _stream.url === data.getString('stream_url'))) return + const streamUrl = data.getString('stream_url') || '' if (!isURI(streamUrl)) return - const streamId = data.getString('streamId') || '' + const streamId = data.getString('stream_id') || '' const [channelId, feedId] = streamId.split('@') const channel: sdk.Models.Channel | undefined = apiData.channelsKeyById.get(channelId) @@ -151,9 +151,8 @@ async function addStreams({ const label = data.getString('label') || '' const quality = data.getString('quality') || null - const httpUserAgent = data.getString('httpUserAgent') || null - const httpReferrer = data.getString('httpReferrer') || null - const directives = data.getArray('directives') || [] + const httpUserAgent = data.getString('http_user_agent') || null + const httpReferrer = data.getString('http_referrer') || null const stream = new Stream({ channel: channelId, @@ -166,7 +165,7 @@ async function addStreams({ }) stream.label = label - stream.setDirectives(directives).updateTitle().updateFilepath() + stream.updateTitle().updateFilepath() streams.add(stream) processedIssues.add(issue.number) diff --git a/scripts/commands/playlist/validate.ts b/scripts/commands/playlist/validate.ts index 36ec037e23..c05964f562 100644 --- a/scripts/commands/playlist/validate.ts +++ b/scripts/commands/playlist/validate.ts @@ -31,8 +31,8 @@ async function main() { const streams = await parser.parse(files) logger.info(`found ${streams.count()} streams`) - let errors = new Collection() - let warnings = new Collection() + const errors = new Collection() + const warnings = new Collection() const streamsGroupedByFilepath = streams.groupBy((stream: Stream) => stream.getFilepath()) for (const filepath of streamsGroupedByFilepath.keys()) { const streams = streamsGroupedByFilepath.get(filepath) @@ -97,8 +97,10 @@ async function main() { console.log(` ${chalk.gray(position)}${status}${logItem.message}`) }) - errors = errors.concat(log.filter((logItem: LogItem) => logItem.type === 'error')) - warnings = warnings.concat(log.filter((logItem: LogItem) => logItem.type === 'warning')) + log.forEach((logItem: LogItem) => { + if (logItem.type === 'error') errors.add(logItem) + else if (logItem.type === 'warning') warnings.add(logItem) + }) } } diff --git a/scripts/commands/report/create.ts b/scripts/commands/report/create.ts index 52986637fd..93488471d3 100644 --- a/scripts/commands/report/create.ts +++ b/scripts/commands/report/create.ts @@ -47,7 +47,7 @@ async function main() { issue.labels.find((label: string) => label === 'streams:remove') ) removeRequests.forEach((issue: Issue) => { - const streamUrls = issue.data.getArray('streamUrl') || [] + const streamUrls = issue.data.getArray('stream_url') || [] if (!streamUrls.length) { const result = { @@ -82,8 +82,8 @@ async function main() { const addRequests = issues.filter(issue => issue.labels.includes('streams:add')) const addRequestsBuffer = new Dictionary() addRequests.forEach((issue: Issue) => { - const streamId = issue.data.getString('streamId') || '' - const streamUrl = issue.data.getString('streamUrl') || '' + const streamId = issue.data.getString('stream_id') || '' + const streamUrl = issue.data.getString('stream_url') || '' const [channelId] = streamId.split('@') const result = { @@ -114,8 +114,8 @@ async function main() { issue.labels.find((label: string) => label === 'streams:edit') ) editRequests.forEach((issue: Issue) => { - const streamId = issue.data.getString('streamId') || '' - const streamUrl = issue.data.getString('streamUrl') || '' + const streamId = issue.data.getString('stream_id') || '' + const streamUrl = issue.data.getString('stream_url') || '' const [channelId] = streamId.split('@') const result = { @@ -140,7 +140,7 @@ async function main() { ) const channelSearchRequestsBuffer = new Dictionary() channelSearchRequests.forEach((issue: Issue) => { - const streamId = issue.data.getString('streamId') || issue.data.getString('channelId') || '' + const streamId = issue.data.getString('stream_id') || issue.data.getString('channel_id') || '' const [channelId, feedId] = streamId.split('@') const result = { diff --git a/scripts/core/issueParser.ts b/scripts/core/issueParser.ts index ad488e6c5d..54ebd694b1 100644 --- a/scripts/core/issueParser.ts +++ b/scripts/core/issueParser.ts @@ -3,20 +3,18 @@ import { IssueData } from './issueData' import { Issue } from '../models' const FIELDS = new Dictionary({ - 'Stream ID': 'streamId', - 'Channel ID': 'channelId', - 'Feed ID': 'feedId', - 'Stream URL': 'streamUrl', - 'New Stream URL': 'newStreamUrl', + 'Stream ID': 'stream_id', + 'Channel ID': 'channel_id', + 'Feed ID': 'feed_id', + 'Stream URL': 'stream_url', Label: 'label', Quality: 'quality', - 'HTTP User-Agent': 'httpUserAgent', - 'HTTP User Agent': 'httpUserAgent', - 'HTTP Referrer': 'httpReferrer', + 'HTTP User-Agent': 'http_user_agent', + 'HTTP User Agent': 'http_user_agent', + 'HTTP Referrer': 'http_referrer', 'What happened to the stream?': 'reason', Reason: 'reason', - Notes: 'notes', - Directives: 'directives' + Notes: 'notes' }) export class IssueParser { diff --git a/scripts/core/playlistParser.ts b/scripts/core/playlistParser.ts index 08b2542ff9..e1d4a84562 100644 --- a/scripts/core/playlistParser.ts +++ b/scripts/core/playlistParser.ts @@ -20,7 +20,9 @@ export class PlaylistParser { for (const filepath of files) { if (!this.storage.existsSync(filepath)) continue const _parsed: Collection = await this.parseFile(filepath) - parsed.concat(_parsed) + _parsed.forEach((item: Stream) => { + parsed.add(item) + }) } return parsed diff --git a/scripts/generators/languagesGenerator.ts b/scripts/generators/languagesGenerator.ts index 28fce5241a..3e7de3f0d7 100644 --- a/scripts/generators/languagesGenerator.ts +++ b/scripts/generators/languagesGenerator.ts @@ -25,7 +25,9 @@ export class LanguagesGenerator implements Generator { const languages = new Collection() streams.forEach((stream: Stream) => { - languages.concat(stream.getLanguages()) + stream.getLanguages().forEach((language: sdk.Models.Language) => { + languages.add(language) + }) }) languages diff --git a/scripts/models/stream.ts b/scripts/models/stream.ts index c050930b4d..002a6cc2e1 100644 --- a/scripts/models/stream.ts +++ b/scripts/models/stream.ts @@ -7,7 +7,6 @@ import { data } from '../api' import path from 'node:path' export class Stream extends sdk.Models.Stream { - directives: Collection filepath?: string line?: number groupTitle: string = 'Undefined' @@ -19,18 +18,14 @@ export class Stream extends sdk.Models.Stream { const data = { label: issueData.getString('label'), quality: issueData.getString('quality'), - httpUserAgent: issueData.getString('httpUserAgent'), - httpReferrer: issueData.getString('httpReferrer'), - newStreamUrl: issueData.getString('newStreamUrl'), - directives: issueData.getArray('directives') + httpUserAgent: issueData.getString('http_user_agent'), + httpReferrer: issueData.getString('http_referrer') } if (data.label !== undefined) this.label = data.label if (data.quality !== undefined) this.quality = data.quality if (data.httpUserAgent !== undefined) this.user_agent = data.httpUserAgent if (data.httpReferrer !== undefined) this.referrer = data.httpReferrer - if (data.newStreamUrl !== undefined) this.url = data.newStreamUrl - if (data.directives !== undefined) this.setDirectives(data.directives) return this } @@ -54,24 +49,6 @@ export class Stream extends sdk.Models.Stream { return { title, label, quality } } - function parseDirectives(string: string): Collection { - const directives = new Collection() - - if (!string) return directives - - const supportedDirectives = ['#EXTVLCOPT', '#KODIPROP'] - const lines = string.split('\r\n') - const regex = new RegExp(`^${supportedDirectives.join('|')}`, 'i') - - lines.forEach((line: string) => { - if (regex.test(line)) { - directives.add(line.trim()) - } - }) - - return directives - } - if (!data.name) throw new Error('"name" property is required') if (!data.url) throw new Error('"url" property is required') @@ -91,7 +68,6 @@ export class Stream extends sdk.Models.Stream { stream.tvgId = data.tvg.id stream.line = data.line stream.label = label || null - stream.directives = parseDirectives(data.raw) return stream } @@ -235,7 +211,9 @@ export class Stream extends sdk.Models.Stream { .intersects(new Collection(region.countries)) .isNotEmpty() ) - regions.concat(relatedRegions) + relatedRegions.forEach(region => { + regions.add(region) + }) break } case 'country': { @@ -246,7 +224,9 @@ export class Stream extends sdk.Models.Stream { (code: string) => code === country.code ) ) - regions.concat(countryRegions) + countryRegions.forEach(region => { + regions.add(region) + }) break } case 'subdivision': { @@ -257,7 +237,9 @@ export class Stream extends sdk.Models.Stream { (code: string) => code === subdivision.country ) ) - regions.concat(subdivisionRegions) + subdivisionRegions.forEach(region => { + regions.add(region) + }) break } case 'city': { @@ -268,7 +250,9 @@ export class Stream extends sdk.Models.Stream { (code: string) => code === city.country ) ) - regions.concat(cityRegions) + cityRegions.forEach(region => { + regions.add(region) + }) break } } @@ -306,14 +290,6 @@ export class Stream extends sdk.Models.Stream { return !!found } - setDirectives(directives: string[]): this { - this.directives = new Collection(directives).filter((directive: string) => - /^(#KODIPROP|#EXTVLCOPT)/.test(directive) - ) - - return this - } - updateTvgId(): this { if (!this.channel) return this if (this.feed) { @@ -418,20 +394,16 @@ export class Stream extends sdk.Models.Stream { output += ` tvg-logo="${this.getTvgLogo()}" group-title="${this.groupTitle}"` } + output += `,${this.getFullTitle()}` + if (this.referrer) { - output += ` http-referrer="${this.referrer}"` + output += `\r\n#EXTVLCOPT:http-referrer=${this.referrer}` } if (this.user_agent) { - output += ` http-user-agent="${this.user_agent}"` + output += `\r\n#EXTVLCOPT:http-user-agent=${this.user_agent}` } - output += `,${this.getFullTitle()}` - - this.directives.forEach((prop: string) => { - output += `\r\n${prop}` - }) - output += `\r\n${this.url}` return output