From 3105a569803f38d5b9d26975b3c6d378e6698fc1 Mon Sep 17 00:00:00 2001 From: freearhey <7253922+freearhey@users.noreply.github.com> Date: Sun, 20 Jul 2025 20:28:58 +0300 Subject: [PATCH] Update scripts --- scripts/commands/playlist/generate.ts | 15 ++++- scripts/commands/readme/update.ts | 14 +++- scripts/core/dataProcessor.ts | 6 +- scripts/generators/countriesGenerator.ts | 15 ----- scripts/generators/index.ts | 1 + scripts/generators/subdivisionsGenerator.ts | 46 +++++++++++++ scripts/models/feed.ts | 9 ++- scripts/tables/countryTable.ts | 28 +------- scripts/tables/index.ts | 1 + scripts/tables/subdivisionTable.ts | 72 +++++++++++++++++++++ 10 files changed, 157 insertions(+), 50 deletions(-) create mode 100644 scripts/generators/subdivisionsGenerator.ts create mode 100644 scripts/tables/subdivisionTable.ts diff --git a/scripts/commands/playlist/generate.ts b/scripts/commands/playlist/generate.ts index f610af0e8..ec4b1f33a 100644 --- a/scripts/commands/playlist/generate.ts +++ b/scripts/commands/playlist/generate.ts @@ -9,13 +9,14 @@ import { IndexCategoryGenerator, IndexLanguageGenerator, IndexCountryGenerator, + SubdivisionsGenerator, IndexRegionGenerator, CategoriesGenerator, CountriesGenerator, LanguagesGenerator, RegionsGenerator, - IndexGenerator, SourcesGenerator, + IndexGenerator, RawGenerator } from '../../generators' @@ -32,6 +33,7 @@ async function main() { feedsGroupedByChannelId, logosGroupedByStreamId, channelsKeyById, + subdivisions, categories, countries, regions @@ -71,6 +73,9 @@ async function main() { logger.info('generating categories/...') await new CategoriesGenerator({ categories, streams, logFile }).generate() + logger.info('generating languages/...') + await new LanguagesGenerator({ streams, logFile }).generate() + logger.info('generating countries/...') await new CountriesGenerator({ countries, @@ -78,8 +83,12 @@ async function main() { logFile }).generate() - logger.info('generating languages/...') - await new LanguagesGenerator({ streams, logFile }).generate() + logger.info('generating subdivisions/...') + await new SubdivisionsGenerator({ + subdivisions, + streams, + logFile + }).generate() logger.info('generating regions/...') await new RegionsGenerator({ diff --git a/scripts/commands/readme/update.ts b/scripts/commands/readme/update.ts index 7af55feff..61eeeae12 100644 --- a/scripts/commands/readme/update.ts +++ b/scripts/commands/readme/update.ts @@ -1,5 +1,11 @@ import { Logger } from '@freearhey/core' -import { CategoryTable, CountryTable, LanguageTable, RegionTable } from '../../tables' +import { + CategoryTable, + CountryTable, + LanguageTable, + RegionTable, + SubdivisionTable +} from '../../tables' import { Markdown } from '../../core' import { README_DIR } from '../../constants' import path from 'path' @@ -9,10 +15,12 @@ async function main() { logger.info('creating category table...') await new CategoryTable().make() - logger.info('creating country table...') - await new CountryTable().make() logger.info('creating language table...') await new LanguageTable().make() + logger.info('creating country table...') + await new CountryTable().make() + logger.info('creating subdivision table...') + await new SubdivisionTable().make() logger.info('creating region table...') await new RegionTable().make() diff --git a/scripts/core/dataProcessor.ts b/scripts/core/dataProcessor.ts index 55e0dbb4b..9ca948d1d 100644 --- a/scripts/core/dataProcessor.ts +++ b/scripts/core/dataProcessor.ts @@ -25,7 +25,7 @@ export class DataProcessor { const languages = new Collection(data.languages).map(data => new Language(data)) const languagesKeyByCode = languages.keyBy((language: Language) => language.code) - const subdivisions = new Collection(data.subdivisions).map(data => new Subdivision(data)) + let subdivisions = new Collection(data.subdivisions).map(data => new Subdivision(data)) const subdivisionsKeyByCode = subdivisions.keyBy((subdivision: Subdivision) => subdivision.code) const subdivisionsGroupedByCountryCode = subdivisions.groupBy( (subdivision: Subdivision) => subdivision.countryCode @@ -42,6 +42,10 @@ export class DataProcessor { ) const countriesKeyByCode = countries.keyBy((country: Country) => country.code) + subdivisions = subdivisions.map((subdivision: Subdivision) => + subdivision.withCountry(countriesKeyByCode) + ) + const timezones = new Collection(data.timezones).map(data => new Timezone(data).withCountries(countriesKeyByCode) ) diff --git a/scripts/generators/countriesGenerator.ts b/scripts/generators/countriesGenerator.ts index 5f3bb5d76..7fe42b82d 100644 --- a/scripts/generators/countriesGenerator.ts +++ b/scripts/generators/countriesGenerator.ts @@ -40,21 +40,6 @@ export class CountriesGenerator implements Generator { this.logFile.append( JSON.stringify({ type: 'country', filepath, count: playlist.streams.count() }) + EOL ) - - country.getSubdivisions().forEach(async (subdivision: Subdivision) => { - const subdivisionStreams = streams.filter((stream: Stream) => - stream.isBroadcastInSubdivision(subdivision) - ) - - if (subdivisionStreams.isEmpty()) return - - const playlist = new Playlist(subdivisionStreams, { public: true }) - const filepath = `subdivisions/${subdivision.code.toLowerCase()}.m3u` - await this.storage.save(filepath, playlist.toString()) - this.logFile.append( - JSON.stringify({ type: 'subdivision', filepath, count: playlist.streams.count() }) + EOL - ) - }) }) const undefinedStreams = streams.filter((stream: Stream) => !stream.hasBroadcastArea()) diff --git a/scripts/generators/index.ts b/scripts/generators/index.ts index 200ae729a..e01127ba1 100644 --- a/scripts/generators/index.ts +++ b/scripts/generators/index.ts @@ -10,3 +10,4 @@ export * from './languagesGenerator' export * from './rawGenerator' export * from './regionsGenerator' export * from './sourcesGenerator' +export * from './subdivisionsGenerator' diff --git a/scripts/generators/subdivisionsGenerator.ts b/scripts/generators/subdivisionsGenerator.ts new file mode 100644 index 000000000..e552596a1 --- /dev/null +++ b/scripts/generators/subdivisionsGenerator.ts @@ -0,0 +1,46 @@ +import { Country, Subdivision, Stream, Playlist } from '../models' +import { Collection, Storage, File } from '@freearhey/core' +import { PUBLIC_DIR } from '../constants' +import { Generator } from './generator' +import { EOL } from 'node:os' + +type SubdivisionsGeneratorProps = { + streams: Collection + subdivisions: Collection + logFile: File +} + +export class SubdivisionsGenerator implements Generator { + streams: Collection + subdivisions: Collection + storage: Storage + logFile: File + + constructor({ streams, subdivisions, logFile }: SubdivisionsGeneratorProps) { + this.streams = streams.clone() + this.subdivisions = subdivisions + this.storage = new Storage(PUBLIC_DIR) + this.logFile = logFile + } + + async generate(): Promise { + const streams = this.streams + .orderBy((stream: Stream) => stream.getTitle()) + .filter((stream: Stream) => stream.isSFW()) + + this.subdivisions.forEach(async (subdivision: Subdivision) => { + const subdivisionStreams = streams.filter((stream: Stream) => + stream.isBroadcastInSubdivision(subdivision) + ) + + if (subdivisionStreams.isEmpty()) return + + const playlist = new Playlist(subdivisionStreams, { public: true }) + const filepath = `subdivisions/${subdivision.code.toLowerCase()}.m3u` + await this.storage.save(filepath, playlist.toString()) + this.logFile.append( + JSON.stringify({ type: 'subdivision', filepath, count: playlist.streams.count() }) + EOL + ) + }) + } +} diff --git a/scripts/models/feed.ts b/scripts/models/feed.ts index 8407695e6..f42c4af91 100644 --- a/scripts/models/feed.ts +++ b/scripts/models/feed.ts @@ -190,8 +190,15 @@ export class Feed { isBroadcastInSubdivision(subdivision: Subdivision): boolean { if (this.isInternational()) return false + if (this.broadcastSubdivisionCodes.includes(subdivision.code)) return true + if ( + this.broadcastSubdivisionCodes.isEmpty() && + subdivision.country && + this.isBroadcastInCountry(subdivision.country) + ) + return true - return this.broadcastSubdivisionCodes.includes(subdivision.code) + return false } isBroadcastInCountry(country: Country): boolean { diff --git a/scripts/tables/countryTable.ts b/scripts/tables/countryTable.ts index 2f50ccedf..d0075e62c 100644 --- a/scripts/tables/countryTable.ts +++ b/scripts/tables/countryTable.ts @@ -1,6 +1,6 @@ import { Storage, Collection, File } from '@freearhey/core' import { HTMLTable, LogParser, LogItem } from '../core' -import { Country, Subdivision } from '../models' +import { Country } from '../models' import { DATA_DIR, LOGS_DIR, README_DIR } from '../constants' import { Table } from './table' @@ -13,11 +13,6 @@ export class CountryTable implements Table { const countriesContent = await dataStorage.json('countries.json') const countries = new Collection(countriesContent).map(data => new Country(data)) const countriesGroupedByCode = countries.keyBy((country: Country) => country.code) - const subdivisionsContent = await dataStorage.json('subdivisions.json') - const subdivisions = new Collection(subdivisionsContent).map(data => new Subdivision(data)) - const subdivisionsGroupedByCode = subdivisions.keyBy( - (subdivision: Subdivision) => subdivision.code - ) const parser = new LogParser() const logsStorage = new Storage(LOGS_DIR) @@ -26,27 +21,6 @@ export class CountryTable implements Table { let data = new Collection() - parsed - .filter((logItem: LogItem) => logItem.type === 'subdivision') - .forEach((logItem: LogItem) => { - const file = new File(logItem.filepath) - const code = file.name().toUpperCase() - const [countryCode, subdivisionCode] = code.split('-') || ['', ''] - const country = countriesGroupedByCode.get(countryCode) - - if (country && subdivisionCode) { - const subdivision = subdivisionsGroupedByCode.get(code) - if (subdivision) { - data.add([ - `${country.name}/${subdivision.name}`, - `      ${subdivision.name}`, - logItem.count, - `https://iptv-org.github.io/iptv/${logItem.filepath}` - ]) - } - } - }) - parsed .filter((logItem: LogItem) => logItem.type === 'country') .forEach((logItem: LogItem) => { diff --git a/scripts/tables/index.ts b/scripts/tables/index.ts index f951a21f2..6da33e822 100644 --- a/scripts/tables/index.ts +++ b/scripts/tables/index.ts @@ -2,3 +2,4 @@ export * from './categoryTable' export * from './countryTable' export * from './languageTable' export * from './regionTable' +export * from './subdivisionTable' diff --git a/scripts/tables/subdivisionTable.ts b/scripts/tables/subdivisionTable.ts new file mode 100644 index 000000000..13460738d --- /dev/null +++ b/scripts/tables/subdivisionTable.ts @@ -0,0 +1,72 @@ +import { Storage, Collection, File } from '@freearhey/core' +import { HTMLTable, LogParser, LogItem } from '../core' +import { Country, Subdivision } from '../models' +import { DATA_DIR, LOGS_DIR, README_DIR } from '../constants' +import { Table } from './table' + +export class SubdivisionTable implements Table { + constructor() {} + + async make() { + const dataStorage = new Storage(DATA_DIR) + + const countriesContent = await dataStorage.json('countries.json') + const countries = new Collection(countriesContent).map(data => new Country(data)) + const countriesGroupedByCode = countries.keyBy((country: Country) => country.code) + const subdivisionsContent = await dataStorage.json('subdivisions.json') + const subdivisions = new Collection(subdivisionsContent).map(data => new Subdivision(data)) + const subdivisionsGroupedByCode = subdivisions.keyBy( + (subdivision: Subdivision) => subdivision.code + ) + + const parser = new LogParser() + const logsStorage = new Storage(LOGS_DIR) + const generatorsLog = await logsStorage.load('generators.log') + const parsed = parser.parse(generatorsLog) + const parsedSubdivisions = parsed.filter((logItem: LogItem) => logItem.type === 'subdivision') + + let output = '' + countries.forEach((country: Country) => { + const parsedCountrySubdivisions = parsedSubdivisions.filter((logItem: LogItem) => + logItem.filepath.includes(`subdivisions/${country.code.toLowerCase()}`) + ) + + if (!parsedCountrySubdivisions.length) return + + output += `\r\n
\r\n\${country.name}\r\n` + + let data = new Collection() + + parsedCountrySubdivisions.forEach((logItem: LogItem) => { + const file = new File(logItem.filepath) + const code = file.name().toUpperCase() + const [countryCode, subdivisionCode] = code.split('-') || ['', ''] + const country = countriesGroupedByCode.get(countryCode) + + if (country && subdivisionCode) { + const subdivision = subdivisionsGroupedByCode.get(code) + if (subdivision) { + data.add([ + subdivision.name, + logItem.count, + `https://iptv-org.github.io/iptv/${logItem.filepath}` + ]) + } + } + }) + + const table = new HTMLTable(data.all(), [ + { name: 'Subdivision' }, + { name: 'Channels', align: 'right' }, + { name: 'Playlist', nowrap: true } + ]) + + output += table.toString() + + output += '\r\n
' + }) + + const readmeStorage = new Storage(README_DIR) + await readmeStorage.save('_subdivisions.md', output.trim()) + } +}