From f32a3f9e77bd0217f65499811cab8156dcaad760 Mon Sep 17 00:00:00 2001 From: freearhey <7253922+freearhey@users.noreply.github.com> Date: Sun, 30 Mar 2025 03:01:05 +0300 Subject: [PATCH] Update scripts --- scripts/commands/playlist/format.ts | 2 +- scripts/commands/playlist/generate.ts | 8 +-- scripts/generators/indexRegionGenerator.ts | 2 +- scripts/models/feed.ts | 12 ++--- scripts/models/stream.ts | 63 ++++++++++++++++++---- 5 files changed, 64 insertions(+), 23 deletions(-) diff --git a/scripts/commands/playlist/format.ts b/scripts/commands/playlist/format.ts index 8dc5dedac..6ac14cb62 100644 --- a/scripts/commands/playlist/format.ts +++ b/scripts/commands/playlist/format.ts @@ -57,7 +57,7 @@ async function main() { streams = streams.orderBy( [ (stream: Stream) => stream.name, - (stream: Stream) => stream.getHorizontalResolution(), + (stream: Stream) => stream.getVerticalResolution(), (stream: Stream) => stream.getLabel(), (stream: Stream) => stream.url ], diff --git a/scripts/commands/playlist/generate.ts b/scripts/commands/playlist/generate.ts index 46f2a2665..7acbbba4b 100644 --- a/scripts/commands/playlist/generate.ts +++ b/scripts/commands/playlist/generate.ts @@ -89,7 +89,7 @@ async function main() { regionsGroupedByCode, subdivisionsGroupedByCode ) - .withBroadcastRegions(regions, regionsGroupedByCode) + .withBroadcastRegions(regions) .withBroadcastSubdivisions(subdivisionsGroupedByCode) ) const feedsGroupedByChannelId = feeds.groupBy((feed: Feed) => @@ -106,14 +106,16 @@ async function main() { const files = await storage.list('**/*.m3u') let streams = await parser.parse(files) const totalStreams = streams.count() - streams = streams.uniqBy((stream: Stream) => stream.getId() || uniqueId()) + streams = streams.uniqBy((stream: Stream) => + stream.hasId() ? stream.getChannelId() + stream.getFeedId() : uniqueId() + ) logger.info(`found ${totalStreams} streams (including ${streams.count()} unique)`) logger.info('sorting streams...') streams = streams.orderBy( [ (stream: Stream) => stream.getId(), - (stream: Stream) => stream.getHorizontalResolution(), + (stream: Stream) => stream.getVerticalResolution(), (stream: Stream) => stream.getLabel() ], ['asc', 'asc', 'desc'] diff --git a/scripts/generators/indexRegionGenerator.ts b/scripts/generators/indexRegionGenerator.ts index c67d29bd5..1e31d4416 100644 --- a/scripts/generators/indexRegionGenerator.ts +++ b/scripts/generators/indexRegionGenerator.ts @@ -26,7 +26,7 @@ export class IndexRegionGenerator implements Generator { let groupedStreams = new Collection() this.streams .orderBy((stream: Stream) => stream.getTitle()) - .filter((stream: Stream) => stream.isSFW()) + .filter((stream: Stream) => stream.isSFW() && !stream.isInternational()) .forEach((stream: Stream) => { if (!stream.hasBroadcastArea()) { const streamClone = stream.clone() diff --git a/scripts/models/feed.ts b/scripts/models/feed.ts index db4be5011..67d37a254 100644 --- a/scripts/models/feed.ts +++ b/scripts/models/feed.ts @@ -122,17 +122,15 @@ export class Feed { return this } - withBroadcastRegions(regions: Collection, regionsGroupedByCode: Dictionary): this { + withBroadcastRegions(regions: Collection): this { if (!this.broadcastCountries) return this const countriesCodes = this.broadcastCountries.map((country: Country) => country.code) - const broadcastRegions = regions.filter((region: Region) => - region.countryCodes.intersects(countriesCodes) - ) + this.broadcastRegions = regions.filter((region: Region) => { + if (region.code === 'INT') return false - if (this.isInternational()) broadcastRegions.add(regionsGroupedByCode.get('INT')) - - this.broadcastRegions = broadcastRegions + return region.countryCodes.intersects(countriesCodes) + }) return this } diff --git a/scripts/models/stream.ts b/scripts/models/stream.ts index aabee817f..383790900 100644 --- a/scripts/models/stream.ts +++ b/scripts/models/stream.ts @@ -14,7 +14,8 @@ export class Stream { filepath?: string line: number label?: string - quality?: string + verticalResolution?: number + isInterlaced?: boolean httpReferrer?: string httpUserAgent?: string removed: boolean = false @@ -25,6 +26,7 @@ export class Stream { const [channelId, feedId] = data.tvg.id.split('@') const { name, label, quality } = parseTitle(data.name) + const { verticalResolution, isInterlaced } = parseQuality(quality) this.id = data.tvg.id || undefined this.feedId = feedId || undefined @@ -32,7 +34,8 @@ export class Stream { this.line = data.line this.label = label || undefined this.name = name - this.quality = quality || undefined + this.verticalResolution = verticalResolution || undefined + this.isInterlaced = isInterlaced || undefined this.url = data.url this.httpReferrer = data.http.referrer || undefined this.httpUserAgent = data.http['user-agent'] || undefined @@ -52,7 +55,7 @@ export class Stream { const channelFeeds = feedsGroupedByChannelId.get(this.channelId) || [] if (this.feedId) this.feed = channelFeeds.find((feed: Feed) => feed.id === this.feedId) - if (!this.feed) this.feed = channelFeeds.find((feed: Feed) => feed.isMain) + if (!this.feedId && !this.feed) this.feed = channelFeeds.find((feed: Feed) => feed.isMain) return this } @@ -82,7 +85,10 @@ export class Stream { } setQuality(quality: string): this { - this.quality = quality + const { verticalResolution, isInterlaced } = parseQuality(quality) + + this.verticalResolution = verticalResolution || undefined + this.isInterlaced = isInterlaced || undefined return this } @@ -113,6 +119,16 @@ export class Stream { return this } + getChannelId(): string { + return this.channelId || '' + } + + getFeedId(): string { + if (this.feedId) return this.feedId + if (this.feed) return this.feed.id + return '' + } + getFilepath(): string { return this.filepath || '' } @@ -126,14 +142,25 @@ export class Stream { } getQuality(): string { - return this.quality || '' + if (!this.verticalResolution) return '' + + let quality = this.verticalResolution.toString() + + if (this.isInterlaced) quality += 'i' + else quality += 'p' + + return quality + } + + hasId(): boolean { + return !!this.id } hasQuality(): boolean { - return !!this.quality + return !!this.verticalResolution } - getHorizontalResolution(): number { + getVerticalResolution(): number { if (!this.hasQuality()) return 0 return parseInt(this.getQuality().replace(/p|i/, '')) @@ -257,8 +284,8 @@ export class Stream { getTitle(): string { let title = `${this.name}` - if (this.quality) { - title += ` (${this.quality})` + if (this.getQuality()) { + title += ` (${this.getQuality()})` } if (this.label) { @@ -284,7 +311,8 @@ export class Stream { filepath: this.filepath, label: this.label, name: this.name, - quality: this.quality, + verticalResolution: this.verticalResolution, + isInterlaced: this.isInterlaced, url: this.url, httpReferrer: this.httpReferrer, httpUserAgent: this.httpUserAgent, @@ -333,7 +361,11 @@ export class Stream { } } -function parseTitle(title: string): { name: string; label: string; quality: string } { +function parseTitle(title: string): { + name: string + label: string + quality: string +} { const [, label] = title.match(/ \[(.*)\]$/) || [null, ''] title = title.replace(new RegExp(` \\[${escapeRegExp(label)}\\]$`), '') const [, quality] = title.match(/ \(([0-9]+p)\)$/) || [null, ''] @@ -345,3 +377,12 @@ function parseTitle(title: string): { name: string; label: string; quality: stri function escapeRegExp(text) { return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') } + +function parseQuality(quality: string): { verticalResolution: number; isInterlaced: boolean } { + let [, verticalResolutionString] = quality.match(/^(\d+)/) || [null, undefined] + const isInterlaced = /i$/i.test(quality) + let verticalResolution = 0 + if (verticalResolutionString) verticalResolution = parseInt(verticalResolutionString) + + return { verticalResolution, isInterlaced } +}