diff --git a/.readme/.gitignore b/.readme/.gitignore index e57faaff68..a2ac441348 100644 --- a/.readme/.gitignore +++ b/.readme/.gitignore @@ -1,5 +1,4 @@ _categories.md _countries.md _languages.md -_regions.md -_subdivisions.md \ No newline at end of file +_regions.md \ No newline at end of file diff --git a/.readme/config.json b/.readme/config.json deleted file mode 100644 index ff55cfec76..0000000000 --- a/.readme/config.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "build" : "PLAYLISTS.md", - "files" : ["./.readme/template.md"] -} \ No newline at end of file diff --git a/.readme/template.md b/.readme/template.md index dc5cad228d..c7b26655ea 100644 --- a/.readme/template.md +++ b/.readme/template.md @@ -40,16 +40,17 @@ Same thing, but split up into separate files: -### Grouped by country +### Grouped by broadcast area -Playlists in which channels are grouped by country for which they are broadcasted. +Playlists in which channels are grouped by broadcast area.
Expand -
+ +#### Countries ``` -https://iptv-org.github.io/iptv/index.country.m3u +https://iptv-org.github.io/iptv/index.countries.m3u ``` Same thing, but split up into separate files: @@ -57,31 +58,10 @@ Same thing, but split up into separate files: #include "./.readme/_countries.md" -
- -### Grouped by subdivision - -Playlists in which channels are grouped by subdivision for which they are broadcasted. - -
-Expand -
- - -#include "./.readme/_subdivisions.md" - -
- -### Grouped by region - -Playlists in which channels are grouped by the region for which they are broadcasted. - -
-Expand -
+#### Regions ``` -https://iptv-org.github.io/iptv/index.region.m3u +https://iptv-org.github.io/iptv/index.regions.m3u ``` Same thing, but split up into separate files: diff --git a/package-lock.json b/package-lock.json index a96f29a725..76b8c282a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { + "@alex_neo/jest-expect-message": "^1.0.5", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "^9.32.0", "@freearhey/core": "^0.10.2", @@ -45,6 +46,11 @@ "tsx": "^4.20.3" } }, + "node_modules/@alex_neo/jest-expect-message": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@alex_neo/jest-expect-message/-/jest-expect-message-1.0.5.tgz", + "integrity": "sha512-1eBykZCd0pPGl5qKtV6Z5ARA6yuhXzHsVN2h5GH5/H6svYa37Jr7vMio5OFpiw1LBHtscrZs7amSkZkcwm0cvQ==" + }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -1254,14 +1260,13 @@ } }, "node_modules/@inquirer/editor": { - "version": "4.2.15", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.15.tgz", - "integrity": "sha512-wst31XT8DnGOSS4nNJDIklGKnf+8shuauVrWzgKegWUe28zfCftcWZ2vktGdzJgcylWSS2SrDnYUb6alZcwnCQ==", - "license": "MIT", + "version": "4.2.17", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.17.tgz", + "integrity": "sha512-r6bQLsyPSzbWrZZ9ufoWL+CztkSatnJ6uSxqd6N+o41EZC51sQeWOzI6s5jLb+xxTWxl7PlUppqm8/sow241gg==", "dependencies": { "@inquirer/core": "^10.1.15", - "@inquirer/type": "^3.0.8", - "external-editor": "^3.1.0" + "@inquirer/external-editor": "^1.0.1", + "@inquirer/type": "^3.0.8" }, "engines": { "node": ">=18" @@ -1297,6 +1302,26 @@ } } }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.1.tgz", + "integrity": "sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==", + "dependencies": { + "chardet": "^2.1.0", + "iconv-lite": "^0.6.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, "node_modules/@inquirer/figures": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", @@ -3853,10 +3878,9 @@ } }, "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "license": "MIT" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz", + "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==" }, "node_modules/ci-info": { "version": "4.3.0", @@ -4547,20 +4571,6 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "license": "MIT", - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/fast-content-type-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz", @@ -5033,12 +5043,11 @@ } }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" @@ -6848,15 +6857,6 @@ "node": ">= 0.8.0" } }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/outvariant": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", @@ -7280,8 +7280,7 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { "version": "7.7.2", @@ -7667,18 +7666,6 @@ "resolved": "https://registry.npmjs.org/timer-node/-/timer-node-5.0.9.tgz", "integrity": "sha512-zXxCE/5/YDi0hY9pygqgRqjRbrFRzigYxOudG0I3syaqAAmX9/w9sxex1bNFCN6c1S66RwPtEIJv65dN+1psew==" }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", diff --git a/package.json b/package.json index f9fafdaee9..4c68d9e665 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "private": true, "license": "MIT", "dependencies": { + "@alex_neo/jest-expect-message": "^1.0.5", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "^9.32.0", "@freearhey/core": "^0.10.2", diff --git a/scripts/commands/api/load.ts b/scripts/commands/api/load.ts index e4d89120a2..39cf0a2e8b 100644 --- a/scripts/commands/api/load.ts +++ b/scripts/commands/api/load.ts @@ -18,7 +18,8 @@ async function main() { loader.download('logos.json'), loader.download('timezones.json'), loader.download('guides.json'), - loader.download('streams.json') + loader.download('streams.json'), + loader.download('cities.json') ]) } diff --git a/scripts/commands/playlist/generate.ts b/scripts/commands/playlist/generate.ts index 7165c4b980..58677a59c7 100644 --- a/scripts/commands/playlist/generate.ts +++ b/scripts/commands/playlist/generate.ts @@ -16,6 +16,7 @@ import { LanguagesGenerator, RegionsGenerator, SourcesGenerator, + CitiesGenerator, IndexGenerator, RawGenerator } from '../../generators' @@ -36,7 +37,8 @@ async function main() { subdivisions, categories, countries, - regions + regions, + cities }: DataProcessorData = processor.process(data) logger.info('loading streams...') @@ -90,6 +92,13 @@ async function main() { logFile }).generate() + logger.info('generating cities/...') + await new CitiesGenerator({ + cities, + streams, + logFile + }).generate() + logger.info('generating regions/...') await new RegionsGenerator({ streams, diff --git a/scripts/commands/readme/update.ts b/scripts/commands/readme/update.ts index 86eddfe365..d47f6ba48a 100644 --- a/scripts/commands/readme/update.ts +++ b/scripts/commands/readme/update.ts @@ -1,32 +1,47 @@ -import { Logger } from '@freearhey/core' -import { - CategoryTable, - CountryTable, - LanguageTable, - RegionTable, - SubdivisionTable -} from '../../tables' -import { Markdown } from '../../core' -import { README_DIR } from '../../constants' -import path from 'path' +import { CategoriesTable, CountriesTable, LanguagesTable, RegionsTable } from '../../tables' +import { DataLoader, DataProcessor, Markdown } from '../../core' +import { DataProcessorData } from '../../types/dataProcessor' +import { DataLoaderData } from '../../types/dataLoader' +import { README_DIR, DATA_DIR, ROOT_DIR } from '../../constants' +import { Logger, Storage } from '@freearhey/core' async function main() { const logger = new Logger() + const dataStorage = new Storage(DATA_DIR) + const processor = new DataProcessor() + const loader = new DataLoader({ storage: dataStorage }) + const data: DataLoaderData = await loader.load() + const { + subdivisionsKeyByCode, + languagesKeyByCode, + countriesKeyByCode, + categoriesKeyById, + subdivisions, + countries, + regions, + cities + }: DataProcessorData = processor.process(data) logger.info('creating category table...') - await new CategoryTable().make() + await new CategoriesTable({ categoriesKeyById }).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() + await new LanguagesTable({ languagesKeyByCode }).make() + logger.info('creating countires table...') + await new CountriesTable({ + countriesKeyByCode, + subdivisionsKeyByCode, + subdivisions, + countries, + cities + }).make() logger.info('creating region table...') - await new RegionTable().make() + await new RegionsTable({ regions }).make() logger.info('updating playlists.md...') - const configPath = path.join(README_DIR, 'config.json') - const playlists = new Markdown(configPath) + const playlists = new Markdown({ + build: `${ROOT_DIR}/PLAYLISTS.md`, + template: `${README_DIR}/template.md` + }) playlists.compile() } diff --git a/scripts/core/dataLoader.ts b/scripts/core/dataLoader.ts index d23264769a..89b45c00c0 100644 --- a/scripts/core/dataLoader.ts +++ b/scripts/core/dataLoader.ts @@ -57,7 +57,8 @@ export class DataLoader { logos, timezones, guides, - streams + streams, + cities ] = await Promise.all([ this.storage.json('countries.json'), this.storage.json('regions.json'), @@ -70,7 +71,8 @@ export class DataLoader { this.storage.json('logos.json'), this.storage.json('timezones.json'), this.storage.json('guides.json'), - this.storage.json('streams.json') + this.storage.json('streams.json'), + this.storage.json('cities.json') ]) return { @@ -85,7 +87,8 @@ export class DataLoader { logos, timezones, guides, - streams + streams, + cities } } diff --git a/scripts/core/dataProcessor.ts b/scripts/core/dataProcessor.ts index d36569fd53..dfb796ba70 100644 --- a/scripts/core/dataProcessor.ts +++ b/scripts/core/dataProcessor.ts @@ -1,3 +1,4 @@ +import { DataProcessorData } from '../types/dataProcessor' import { DataLoaderData } from '../types/dataLoader' import { Collection } from '@freearhey/core' import { @@ -11,14 +12,16 @@ import { Region, Stream, Guide, + City, Feed, Logo } from '../models' export class DataProcessor { - constructor() {} + process(data: DataLoaderData): DataProcessorData { + let regions = new Collection(data.regions).map(data => new Region(data)) + let regionsKeyByCode = regions.keyBy((region: Region) => region.code) - process(data: DataLoaderData) { const categories = new Collection(data.categories).map(data => new Category(data)) const categoriesKeyById = categories.keyBy((category: Category) => category.id) @@ -26,25 +29,23 @@ export class DataProcessor { const languagesKeyByCode = languages.keyBy((language: Language) => language.code) let subdivisions = new Collection(data.subdivisions).map(data => new Subdivision(data)) - const subdivisionsKeyByCode = subdivisions.keyBy((subdivision: Subdivision) => subdivision.code) - const subdivisionsGroupedByCountryCode = subdivisions.groupBy( + let subdivisionsKeyByCode = subdivisions.keyBy((subdivision: Subdivision) => subdivision.code) + let subdivisionsGroupedByCountryCode = subdivisions.groupBy( (subdivision: Subdivision) => subdivision.countryCode ) - let regions = new Collection(data.regions).map(data => new Region(data)) - const regionsKeyByCode = regions.keyBy((region: Region) => region.code) + let countries = new Collection(data.countries).map(data => new Country(data)) + let countriesKeyByCode = countries.keyBy((country: Country) => country.code) - const countries = new Collection(data.countries).map(data => - new Country(data) + const cities = new Collection(data.cities).map(data => + new City(data) .withRegions(regions) - .withLanguage(languagesKeyByCode) - .withSubdivisions(subdivisionsGroupedByCountryCode) - ) - const countriesKeyByCode = countries.keyBy((country: Country) => country.code) - - subdivisions = subdivisions.map((subdivision: Subdivision) => - subdivision.withCountry(countriesKeyByCode) + .withCountry(countriesKeyByCode) + .withSubdivision(subdivisionsKeyByCode) ) + const citiesKeyByCode = cities.keyBy((city: City) => city.code) + const citiesGroupedByCountryCode = cities.groupBy((city: City) => city.countryCode) + const citiesGroupedBySubdivisionCode = cities.groupBy((city: City) => city.subdivisionCode) const timezones = new Collection(data.timezones).map(data => new Timezone(data).withCountries(countriesKeyByCode) @@ -56,27 +57,12 @@ export class DataProcessor { (blocklistRecord: BlocklistRecord) => blocklistRecord.channelId ) - let channels = new Collection(data.channels).map(data => - new Channel(data) - .withCategories(categoriesKeyById) - .withCountry(countriesKeyByCode) - .withSubdivision(subdivisionsKeyByCode) - .withCategories(categoriesKeyById) - ) + let channels = new Collection(data.channels).map(data => new Channel(data)) + let channelsKeyById = channels.keyBy((channel: Channel) => channel.id) - const channelsKeyById = channels.keyBy((channel: Channel) => channel.id) - - const feeds = new Collection(data.feeds).map(data => - new Feed(data) - .withChannel(channelsKeyById) - .withLanguages(languagesKeyByCode) - .withTimezones(timezonesKeyById) - .withBroadcastCountries(countriesKeyByCode, regionsKeyByCode, subdivisionsKeyByCode) - .withBroadcastRegions(regions) - .withBroadcastSubdivisions(subdivisionsKeyByCode) - ) - const feedsGroupedByChannelId = feeds.groupBy((feed: Feed) => feed.channelId) - const feedsGroupedById = feeds.groupBy((feed: Feed) => feed.id) + let feeds = new Collection(data.feeds).map(data => new Feed(data)) + let feedsGroupedByChannelId = feeds.groupBy((feed: Feed) => feed.channelId) + let feedsGroupedById = feeds.groupBy((feed: Feed) => feed.id) const logos = new Collection(data.logos).map(data => new Logo(data).withFeed(feedsGroupedById)) const logosGroupedByChannelId = logos.groupBy((logo: Logo) => logo.channelId) @@ -90,11 +76,60 @@ export class DataProcessor { const guides = new Collection(data.guides).map(data => new Guide(data)) const guidesGroupedByStreamId = guides.groupBy((guide: Guide) => guide.getStreamId()) - regions = regions.map((region: Region) => region.withCountries(countriesKeyByCode)) + regions = regions.map((region: Region) => + region + .withCountries(countriesKeyByCode) + .withRegions(regions) + .withSubdivisions(subdivisions) + .withCities(cities) + ) + regionsKeyByCode = regions.keyBy((region: Region) => region.code) + + countries = countries.map((country: Country) => + country + .withCities(citiesGroupedByCountryCode) + .withSubdivisions(subdivisionsGroupedByCountryCode) + .withRegions(regions) + .withLanguage(languagesKeyByCode) + ) + countriesKeyByCode = countries.keyBy((country: Country) => country.code) + + subdivisions = subdivisions.map((subdivision: Subdivision) => + subdivision + .withCities(citiesGroupedBySubdivisionCode) + .withCountry(countriesKeyByCode) + .withRegions(regions) + ) + subdivisionsKeyByCode = subdivisions.keyBy((subdivision: Subdivision) => subdivision.code) + subdivisionsGroupedByCountryCode = subdivisions.groupBy( + (subdivision: Subdivision) => subdivision.countryCode + ) channels = channels.map((channel: Channel) => - channel.withFeeds(feedsGroupedByChannelId).withLogos(logosGroupedByChannelId) + channel + .withFeeds(feedsGroupedByChannelId) + .withLogos(logosGroupedByChannelId) + .withCategories(categoriesKeyById) + .withCountry(countriesKeyByCode) + .withSubdivision(subdivisionsKeyByCode) + .withCategories(categoriesKeyById) ) + channelsKeyById = channels.keyBy((channel: Channel) => channel.id) + + feeds = feeds.map((feed: Feed) => + feed + .withChannel(channelsKeyById) + .withLanguages(languagesKeyByCode) + .withTimezones(timezonesKeyById) + .withBroadcastArea( + citiesKeyByCode, + subdivisionsKeyByCode, + countriesKeyByCode, + regionsKeyByCode + ) + ) + feedsGroupedByChannelId = feeds.groupBy((feed: Feed) => feed.channelId) + feedsGroupedById = feeds.groupBy((feed: Feed) => feed.id) return { blocklistRecordsGroupedByChannelId, @@ -111,6 +146,7 @@ export class DataProcessor { regionsKeyByCode, blocklistRecords, channelsKeyById, + citiesKeyByCode, subdivisions, categories, countries, @@ -119,6 +155,7 @@ export class DataProcessor { channels, regions, streams, + cities, guides, feeds, logos diff --git a/scripts/core/markdown.ts b/scripts/core/markdown.ts index 36834d8b7b..e229999409 100644 --- a/scripts/core/markdown.ts +++ b/scripts/core/markdown.ts @@ -1,33 +1,37 @@ import fs from 'fs' import path from 'path' -export class Markdown { - filepath: string +type MarkdownConfig = { + build: string + template: string +} - constructor(filepath: string) { - this.filepath = filepath +export class Markdown { + build: string + template: string + + constructor(config: MarkdownConfig) { + this.build = config.build + this.template = config.template } compile() { - const config = JSON.parse(fs.readFileSync(this.filepath, 'utf8')) - const workingDir = process.cwd() - - config.files.forEach((templateFile: string) => { - const templatePath = path.resolve(workingDir, templateFile) - const content = fs.readFileSync(templatePath, 'utf8') - const processedContent = this.processIncludes(content, workingDir) - - if (config.build) { - const outputPath = path.resolve(workingDir, config.build) - fs.writeFileSync(outputPath, processedContent, 'utf8') - } - }) + const workingDir = process.cwd() + + const templatePath = path.resolve(workingDir, this.template) + const template = fs.readFileSync(templatePath, 'utf8') + const processedContent = this.processIncludes(template, workingDir) + + if (this.build) { + const outputPath = path.resolve(workingDir, this.build) + fs.writeFileSync(outputPath, processedContent, 'utf8') + } } - private processIncludes(content: string, baseDir: string): string { + private processIncludes(template: string, baseDir: string): string { const includeRegex = /#include\s+"([^"]+)"/g - - return content.replace(includeRegex, (match, includePath) => { + + return template.replace(includeRegex, (match, includePath) => { try { const fullPath = path.resolve(baseDir, includePath) const includeContent = fs.readFileSync(fullPath, 'utf8') diff --git a/scripts/generators/citiesGenerator.ts b/scripts/generators/citiesGenerator.ts new file mode 100644 index 0000000000..7d0891fbc8 --- /dev/null +++ b/scripts/generators/citiesGenerator.ts @@ -0,0 +1,43 @@ +import { City, Stream, Playlist } from '../models' +import { Collection, Storage, File } from '@freearhey/core' +import { PUBLIC_DIR, EOL } from '../constants' +import { Generator } from './generator' + +type CitiesGeneratorProps = { + streams: Collection + cities: Collection + logFile: File +} + +export class CitiesGenerator implements Generator { + streams: Collection + cities: Collection + storage: Storage + logFile: File + + constructor({ streams, cities, logFile }: CitiesGeneratorProps) { + this.streams = streams.clone() + this.cities = cities + 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.cities.forEach(async (city: City) => { + const cityStreams = streams.filter((stream: Stream) => stream.isBroadcastInCity(city)) + + if (cityStreams.isEmpty()) return + + const playlist = new Playlist(cityStreams, { public: true }) + const filepath = `cities/${city.code.toLowerCase()}.m3u` + await this.storage.save(filepath, playlist.toString()) + this.logFile.append( + JSON.stringify({ type: 'city', filepath, count: playlist.streams.count() }) + EOL + ) + }) + } +} diff --git a/scripts/generators/countriesGenerator.ts b/scripts/generators/countriesGenerator.ts index 4cd539deaf..39d7612582 100644 --- a/scripts/generators/countriesGenerator.ts +++ b/scripts/generators/countriesGenerator.ts @@ -41,6 +41,18 @@ export class CountriesGenerator implements Generator { ) }) + const internationalStreams = streams.filter((stream: Stream) => stream.isInternational()) + const internationalPlaylist = new Playlist(internationalStreams, { public: true }) + const internationalFilepath = 'countries/int.m3u' + await this.storage.save(internationalFilepath, internationalPlaylist.toString()) + this.logFile.append( + JSON.stringify({ + type: 'country', + filepath: internationalFilepath, + count: internationalPlaylist.streams.count() + }) + EOL + ) + const undefinedStreams = streams.filter((stream: Stream) => !stream.hasBroadcastArea()) const undefinedPlaylist = new Playlist(undefinedStreams, { public: true }) const undefinedFilepath = 'countries/undefined.m3u' diff --git a/scripts/generators/index.ts b/scripts/generators/index.ts index e01127ba12..7f09a6715b 100644 --- a/scripts/generators/index.ts +++ b/scripts/generators/index.ts @@ -1,4 +1,5 @@ export * from './categoriesGenerator' +export * from './citiesGenerator' export * from './countriesGenerator' export * from './indexCategoryGenerator' export * from './indexCountryGenerator' diff --git a/scripts/generators/indexCountryGenerator.ts b/scripts/generators/indexCountryGenerator.ts index 43e55c2e28..b476d828a8 100644 --- a/scripts/generators/indexCountryGenerator.ts +++ b/scripts/generators/indexCountryGenerator.ts @@ -26,6 +26,13 @@ export class IndexCountryGenerator implements Generator { .orderBy((stream: Stream) => stream.getTitle()) .filter((stream: Stream) => stream.isSFW()) .forEach((stream: Stream) => { + if (stream.isInternational()) { + const streamClone = stream.clone() + streamClone.groupTitle = 'International' + groupedStreams.add(streamClone) + return + } + if (!stream.hasBroadcastArea()) { const streamClone = stream.clone() streamClone.groupTitle = 'Undefined' @@ -33,12 +40,6 @@ export class IndexCountryGenerator implements Generator { return } - if (stream.isInternational()) { - const streamClone = stream.clone() - streamClone.groupTitle = 'International' - groupedStreams.add(streamClone) - } - stream.getBroadcastCountries().forEach((country: Country) => { const streamClone = stream.clone() streamClone.groupTitle = country.name diff --git a/scripts/generators/indexRegionGenerator.ts b/scripts/generators/indexRegionGenerator.ts index 3155d37d30..27a9ae0fe5 100644 --- a/scripts/generators/indexRegionGenerator.ts +++ b/scripts/generators/indexRegionGenerator.ts @@ -28,32 +28,18 @@ export class IndexRegionGenerator implements Generator { .orderBy((stream: Stream) => stream.getTitle()) .filter((stream: Stream) => stream.isSFW()) .forEach((stream: Stream) => { - if (stream.isInternational()) { - const streamClone = stream.clone() - streamClone.groupTitle = 'International' - groupedStreams.push(streamClone) - return - } - - if (!stream.hasBroadcastArea()) { - const streamClone = stream.clone() - streamClone.groupTitle = 'Undefined' - groupedStreams.push(streamClone) - return - } + if (!stream.hasBroadcastArea()) return stream.getBroadcastRegions().forEach((region: Region) => { + if (region.isWorldwide()) return + const streamClone = stream.clone() streamClone.groupTitle = region.name groupedStreams.push(streamClone) }) }) - groupedStreams = groupedStreams.orderBy((stream: Stream) => { - if (stream.groupTitle === 'International') return 'ZZ' - if (stream.groupTitle === 'Undefined') return 'ZZZ' - return stream.groupTitle - }) + groupedStreams = groupedStreams.orderBy((stream: Stream) => stream.groupTitle) const playlist = new Playlist(groupedStreams, { public: true }) const filepath = 'index.region.m3u' diff --git a/scripts/generators/regionsGenerator.ts b/scripts/generators/regionsGenerator.ts index 6711c67ff8..60dab3d614 100644 --- a/scripts/generators/regionsGenerator.ts +++ b/scripts/generators/regionsGenerator.ts @@ -39,25 +39,5 @@ export class RegionsGenerator implements Generator { JSON.stringify({ type: 'region', filepath, count: playlist.streams.count() }) + EOL ) }) - - const internationalStreams = streams.filter((stream: Stream) => stream.isInternational()) - const internationalPlaylist = new Playlist(internationalStreams, { public: true }) - const internationalFilepath = 'regions/int.m3u' - await this.storage.save(internationalFilepath, internationalPlaylist.toString()) - this.logFile.append( - JSON.stringify({ - type: 'region', - filepath: internationalFilepath, - count: internationalPlaylist.streams.count() - }) + EOL - ) - - const undefinedStreams = streams.filter((stream: Stream) => !stream.hasBroadcastArea()) - const playlist = new Playlist(undefinedStreams, { public: true }) - const filepath = 'regions/undefined.m3u' - await this.storage.save(filepath, playlist.toString()) - this.logFile.append( - JSON.stringify({ type: 'region', filepath, count: playlist.streams.count() }) + EOL - ) } } diff --git a/scripts/models/broadcastArea.ts b/scripts/models/broadcastArea.ts index 2b96b7f91f..fa5b43f0e5 100644 --- a/scripts/models/broadcastArea.ts +++ b/scripts/models/broadcastArea.ts @@ -1,11 +1,99 @@ -type BroadcastAreaProps = { - code: string -} +import { Collection, Dictionary } from '@freearhey/core' +import { City, Subdivision, Region, Country } from './' export class BroadcastArea { - code: string + codes: Collection + citiesIncluded: Collection + subdivisionsIncluded: Collection + countriesIncluded: Collection + regionsIncluded: Collection - constructor(data: BroadcastAreaProps) { - this.code = data.code + constructor(codes: Collection) { + this.codes = codes + } + + withLocations( + citiesKeyByCode: Dictionary, + subdivisionsKeyByCode: Dictionary, + countriesKeyByCode: Dictionary, + regionsKeyByCode: Dictionary + ): this { + let citiesIncluded = new Collection() + let subdivisionsIncluded = new Collection() + let countriesIncluded = new Collection() + let regionsIncluded = new Collection() + + this.codes.forEach((value: string) => { + const [type, code] = value.split('/') + + switch (type) { + case 'ct': { + const city: City = citiesKeyByCode.get(code) + if (!city) return + citiesIncluded.add(city) + regionsIncluded = regionsIncluded.concat(city.getRegions()) + } + case 's': { + const subdivision: Subdivision = subdivisionsKeyByCode.get(code) + if (!subdivision) return + subdivisionsIncluded.add(subdivision) + regionsIncluded = regionsIncluded.concat(subdivision.getRegions()) + } + case 'c': { + const country: Country = countriesKeyByCode.get(code) + if (!country) return + countriesIncluded.add(country) + regionsIncluded = regionsIncluded.concat(country.getRegions()) + } + case 'r': { + const region: Region = regionsKeyByCode.get(code) + if (!region) return + regionsIncluded = regionsIncluded.concat(region.getRegions()) + } + } + }) + + this.citiesIncluded = citiesIncluded.uniqBy((city: City) => city.code) + this.subdivisionsIncluded = subdivisionsIncluded.uniqBy( + (subdivision: Subdivision) => subdivision.code + ) + this.countriesIncluded = countriesIncluded.uniqBy((country: Country) => country.code) + this.regionsIncluded = regionsIncluded.uniqBy((region: Region) => region.code) + + return this + } + + getCountries(): Collection { + return this.countriesIncluded || new Collection() + } + + getSubdivisions(): Collection { + return this.subdivisionsIncluded || new Collection() + } + + getCities(): Collection { + return this.citiesIncluded || new Collection() + } + + getRegions(): Collection { + return this.regionsIncluded || new Collection() + } + + includesCountry(country: Country): boolean { + return this.getCountries().includes((_country: Country) => _country.code === country.code) + } + + includesSubdivision(subdivision: Subdivision): boolean { + return this.getSubdivisions().includes( + (_subdivision: Subdivision) => _subdivision.code === subdivision.code + ) + } + + includesRegion(region: Region): boolean { + return this.getRegions().includes((_region: Region) => _region.code === region.code) + } + + includesCity(city: City): boolean { + return this.getCities().includes((_city: City) => _city.code === city.code) } } diff --git a/scripts/models/city.ts b/scripts/models/city.ts new file mode 100644 index 0000000000..6ce9173ac9 --- /dev/null +++ b/scripts/models/city.ts @@ -0,0 +1,78 @@ +import { Collection, Dictionary } from '@freearhey/core' +import { Country, Region, Subdivision } from '.' +import type { CityData, CitySerializedData } from '../types/city' + +export class City { + code: string + name: string + countryCode: string + country?: Country + subdivisionCode?: string + subdivision?: Subdivision + wikidataId: string + regions?: Collection + + constructor(data?: CityData) { + if (!data) return + + this.code = data.code + this.name = data.name + this.countryCode = data.country + this.subdivisionCode = data.subdivision || undefined + this.wikidataId = data.wikidata_id + } + + withCountry(countriesKeyByCode: Dictionary): this { + this.country = countriesKeyByCode.get(this.countryCode) + + return this + } + + withSubdivision(subdivisionsKeyByCode: Dictionary): this { + if (!this.subdivisionCode) return this + + this.subdivision = subdivisionsKeyByCode.get(this.subdivisionCode) + + return this + } + + withRegions(regions: Collection): this { + this.regions = regions.filter((region: Region) => + region.countryCodes.includes(this.countryCode) + ) + + return this + } + + getRegions(): Collection { + if (!this.regions) return new Collection() + + return this.regions + } + + serialize(): CitySerializedData { + return { + code: this.code, + name: this.name, + countryCode: this.countryCode, + country: this.country ? this.country.serialize() : undefined, + subdivisionCode: this.subdivisionCode || null, + subdivision: this.subdivision ? this.subdivision.serialize() : undefined, + wikidataId: this.wikidataId + } + } + + deserialize(data: CitySerializedData): this { + this.code = data.code + this.name = data.name + this.countryCode = data.countryCode + this.country = data.country ? new Country().deserialize(data.country) : undefined + this.subdivisionCode = data.subdivisionCode || undefined + this.subdivision = data.subdivision + ? new Subdivision().deserialize(data.subdivision) + : undefined + this.wikidataId = data.wikidataId + + return this + } +} diff --git a/scripts/models/country.ts b/scripts/models/country.ts index 780c4413f1..b9699f7235 100644 --- a/scripts/models/country.ts +++ b/scripts/models/country.ts @@ -12,6 +12,7 @@ export class Country { language?: Language subdivisions?: Collection regions?: Collection + cities?: Collection constructor(data?: CountryData) { if (!data) return @@ -23,15 +24,19 @@ export class Country { } withSubdivisions(subdivisionsGroupedByCountryCode: Dictionary): this { - this.subdivisions = subdivisionsGroupedByCountryCode.get(this.code) || new Collection() + this.subdivisions = new Collection(subdivisionsGroupedByCountryCode.get(this.code)) return this } withRegions(regions: Collection): this { - this.regions = regions.filter( - (region: Region) => region.code !== 'INT' && region.includesCountryCode(this.code) - ) + this.regions = regions.filter((region: Region) => region.includesCountryCode(this.code)) + + return this + } + + withCities(citiesGroupedByCountryCode: Dictionary): this { + this.cities = new Collection(citiesGroupedByCountryCode.get(this.code)) return this } @@ -54,6 +59,10 @@ export class Country { return this.subdivisions || new Collection() } + getCities(): Collection { + return this.cities || new Collection() + } + serialize(): CountrySerializedData { return { code: this.code, diff --git a/scripts/models/feed.ts b/scripts/models/feed.ts index f42c4af916..a6713e265a 100644 --- a/scripts/models/feed.ts +++ b/scripts/models/feed.ts @@ -1,4 +1,4 @@ -import { Country, Language, Region, Channel, Subdivision } from './index' +import { Country, Language, Region, Channel, Subdivision, BroadcastArea, City } from './index' import { Collection, Dictionary } from '@freearhey/core' import type { FeedData } from '../types/feed' @@ -9,12 +9,7 @@ export class Feed { name: string isMain: boolean broadcastAreaCodes: Collection - broadcastCountryCodes: Collection - broadcastCountries?: Collection - broadcastRegionCodes: Collection - broadcastRegions?: Collection - broadcastSubdivisionCodes: Collection - broadcastSubdivisions?: Collection + broadcastArea?: BroadcastArea languageCodes: Collection languages?: Collection timezoneIds: Collection @@ -32,25 +27,6 @@ export class Feed { this.languageCodes = new Collection(data.languages) this.timezoneIds = new Collection(data.timezones) this.videoFormat = data.video_format - this.broadcastCountryCodes = new Collection() - this.broadcastRegionCodes = new Collection() - this.broadcastSubdivisionCodes = new Collection() - - this.broadcastAreaCodes.forEach((areaCode: string) => { - const [type, code] = areaCode.split('/') - - switch (type) { - case 'c': - this.broadcastCountryCodes.add(code) - break - case 'r': - this.broadcastRegionCodes.add(code) - break - case 's': - this.broadcastSubdivisionCodes.add(code) - break - } - }) } withChannel(channelsKeyById: Dictionary): this { @@ -93,76 +69,36 @@ export class Feed { return this } - withBroadcastSubdivisions(subdivisionsKeyByCode: Dictionary): this { - this.broadcastSubdivisions = this.broadcastSubdivisionCodes.map((code: string) => - subdivisionsKeyByCode.get(code) - ) - - return this - } - - withBroadcastCountries( + withBroadcastArea( + citiesKeyByCode: Dictionary, + subdivisionsKeyByCode: Dictionary, countriesKeyByCode: Dictionary, - regionsKeyByCode: Dictionary, - subdivisionsKeyByCode: Dictionary + regionsKeyByCode: Dictionary ): this { - const broadcastCountries = new Collection() - - if (this.isInternational()) { - this.broadcastCountries = broadcastCountries - return this - } - - this.broadcastCountryCodes.forEach((code: string) => { - broadcastCountries.add(countriesKeyByCode.get(code)) - }) - - this.broadcastRegionCodes.forEach((code: string) => { - const region: Region = regionsKeyByCode.get(code) - if (region) { - region.countryCodes.forEach((countryCode: string) => { - broadcastCountries.add(countriesKeyByCode.get(countryCode)) - }) - } - }) - - this.broadcastSubdivisionCodes.forEach((code: string) => { - const subdivision: Subdivision = subdivisionsKeyByCode.get(code) - if (subdivision) { - broadcastCountries.add(countriesKeyByCode.get(subdivision.countryCode)) - } - }) - - this.broadcastCountries = broadcastCountries.uniq().filter(Boolean) - - return this - } - - withBroadcastRegions(regions: Collection): this { - if (!this.broadcastCountries) return this - const countriesCodes = this.broadcastCountries.map((country: Country) => country.code) - - this.broadcastRegions = regions.filter((region: Region) => { - if (region.code === 'INT') return false - const intersected = region.countryCodes.intersects(countriesCodes) - return intersected.notEmpty() - }) + this.broadcastArea = new BroadcastArea(this.broadcastAreaCodes).withLocations( + citiesKeyByCode, + subdivisionsKeyByCode, + countriesKeyByCode, + regionsKeyByCode + ) return this } hasBroadcastArea(): boolean { - return ( - this.isInternational() || (!!this.broadcastCountries && this.broadcastCountries.notEmpty()) - ) + return !!this.broadcastArea } getBroadcastCountries(): Collection { - return this.broadcastCountries || new Collection() + if (!this.broadcastArea) return new Collection() + + return this.broadcastArea.getCountries() } getBroadcastRegions(): Collection { - return this.broadcastRegions || new Collection() + if (!this.broadcastArea) return new Collection() + + return this.broadcastArea.getRegions() } getTimezones(): Collection { @@ -184,35 +120,34 @@ export class Feed { ) } - isInternational(): boolean { - return this.broadcastAreaCodes.includes('r/INT') + isBroadcastInCity(city: City): boolean { + if (!this.broadcastArea) return false + + return this.broadcastArea.includesCity(city) } 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 + if (!this.broadcastArea) return false - return false + return this.broadcastArea.includesSubdivision(subdivision) } isBroadcastInCountry(country: Country): boolean { - if (this.isInternational()) return false + if (!this.broadcastArea) return false - return this.getBroadcastCountries().includes( - (_country: Country) => _country.code === country.code - ) + return this.broadcastArea.includesCountry(country) } isBroadcastInRegion(region: Region): boolean { - if (this.isInternational()) return false + if (!this.broadcastArea) return false - return this.getBroadcastRegions().includes((_region: Region) => _region.code === region.code) + return this.broadcastArea.includesRegion(region) + } + + isInternational(): boolean { + if (!this.broadcastArea) return false + + return this.broadcastArea.codes.join(',').includes('r/') } getGuides(): Collection { diff --git a/scripts/models/index.ts b/scripts/models/index.ts index 4e11d28b97..e8fe346289 100644 --- a/scripts/models/index.ts +++ b/scripts/models/index.ts @@ -2,6 +2,7 @@ export * from './blocklistRecord' export * from './broadcastArea' export * from './category' export * from './channel' +export * from './city' export * from './country' export * from './feed' export * from './guide' diff --git a/scripts/models/region.ts b/scripts/models/region.ts index ace44bc52f..5fe52ad5a9 100644 --- a/scripts/models/region.ts +++ b/scripts/models/region.ts @@ -1,15 +1,18 @@ import { Collection, Dictionary } from '@freearhey/core' -import { Country, Subdivision } from '.' +import { City, Country, Subdivision } from '.' import type { RegionData, RegionSerializedData } from '../types/region' import { CountrySerializedData } from '../types/country' import { SubdivisionSerializedData } from '../types/subdivision' +import { CitySerializedData } from '../types/city' export class Region { code: string name: string countryCodes: Collection - countries: Collection = new Collection() - subdivisions: Collection = new Collection() + countries?: Collection + subdivisions?: Collection + cities?: Collection + regions?: Collection constructor(data?: RegionData) { if (!data) return @@ -33,20 +36,50 @@ export class Region { return this } + withCities(cities: Collection): this { + this.cities = cities.filter((city: City) => this.countryCodes.indexOf(city.countryCode) > -1) + + return this + } + + withRegions(regions: Collection): this { + this.regions = regions.filter( + (region: Region) => !region.countryCodes.intersects(this.countryCodes).isEmpty() + ) + + return this + } + getSubdivisions(): Collection { + if (!this.subdivisions) return new Collection() + return this.subdivisions } getCountries(): Collection { + if (!this.countries) return new Collection() + return this.countries } + getCities(): Collection { + if (!this.cities) return new Collection() + + return this.cities + } + + getRegions(): Collection { + if (!this.regions) return new Collection() + + return this.regions + } + includesCountryCode(code: string): boolean { return this.countryCodes.includes((countryCode: string) => countryCode === code) } isWorldwide(): boolean { - return this.code === 'INT' + return ['INT', 'WW'].includes(this.code) } serialize(): RegionSerializedData { @@ -54,9 +87,14 @@ export class Region { code: this.code, name: this.name, countryCodes: this.countryCodes.all(), - countries: this.countries.map((country: Country) => country.serialize()).all(), - subdivisions: this.subdivisions + countries: this.getCountries() + .map((country: Country) => country.serialize()) + .all(), + subdivisions: this.getSubdivisions() .map((subdivision: Subdivision) => subdivision.serialize()) + .all(), + cities: this.getCities() + .map((city: City) => city.serialize()) .all() } } @@ -71,6 +109,9 @@ export class Region { this.subdivisions = new Collection(data.subdivisions).map((data: SubdivisionSerializedData) => new Subdivision().deserialize(data) ) + this.cities = new Collection(data.cities).map((data: CitySerializedData) => + new City().deserialize(data) + ) return this } diff --git a/scripts/models/stream.ts b/scripts/models/stream.ts index cd734493b8..a465081ea6 100644 --- a/scripts/models/stream.ts +++ b/scripts/models/stream.ts @@ -1,4 +1,14 @@ -import { Feed, Channel, Category, Region, Subdivision, Country, Language, Logo } from './index' +import { + Feed, + Channel, + Category, + Region, + Subdivision, + Country, + Language, + Logo, + City +} from './index' import { URL, Collection, Dictionary } from '@freearhey/core' import type { StreamData } from '../types/stream' import parser from 'iptv-playlist-parser' @@ -330,6 +340,10 @@ export class Stream { return this.feed ? this.feed.broadcastAreaCodes : new Collection() } + isBroadcastInCity(city: City): boolean { + return this.feed ? this.feed.isBroadcastInCity(city) : false + } + isBroadcastInSubdivision(subdivision: Subdivision): boolean { return this.feed ? this.feed.isBroadcastInSubdivision(subdivision) : false } diff --git a/scripts/models/subdivision.ts b/scripts/models/subdivision.ts index b43d1c88d7..92cfdc9d61 100644 --- a/scripts/models/subdivision.ts +++ b/scripts/models/subdivision.ts @@ -1,12 +1,15 @@ import { SubdivisionData, SubdivisionSerializedData } from '../types/subdivision' -import { Dictionary } from '@freearhey/core' -import { Country } from '.' +import { Dictionary, Collection } from '@freearhey/core' +import { Country, Region } from '.' export class Subdivision { code: string name: string countryCode: string country?: Country + parentCode?: string + regions?: Collection + cities?: Collection constructor(data?: SubdivisionData) { if (!data) return @@ -14,6 +17,7 @@ export class Subdivision { this.code = data.code this.name = data.name this.countryCode = data.country + this.parentCode = data.parent || undefined } withCountry(countriesKeyByCode: Dictionary): this { @@ -22,12 +26,39 @@ export class Subdivision { return this } + withRegions(regions: Collection): this { + this.regions = regions.filter((region: Region) => + region.countryCodes.includes(this.countryCode) + ) + + return this + } + + withCities(citiesGroupedBySubdivisionCode: Dictionary): this { + this.cities = new Collection(citiesGroupedBySubdivisionCode.get(this.code)) + + return this + } + + getRegions(): Collection { + if (!this.regions) return new Collection() + + return this.regions + } + + getCities(): Collection { + if (!this.cities) return new Collection() + + return this.cities + } + serialize(): SubdivisionSerializedData { return { code: this.code, name: this.name, - countryCode: this.code, - country: this.country ? this.country.serialize() : undefined + countryCode: this.countryCode, + country: this.country ? this.country.serialize() : undefined, + parentCode: this.parentCode || null } } @@ -36,6 +67,7 @@ export class Subdivision { this.name = data.name this.countryCode = data.countryCode this.country = data.country ? new Country().deserialize(data.country) : undefined + this.parentCode = data.parentCode || undefined return this } diff --git a/scripts/tables/categoryTable.ts b/scripts/tables/categoriesTable.ts similarity index 61% rename from scripts/tables/categoryTable.ts rename to scripts/tables/categoriesTable.ts index f82f3ffd4a..0b763e4162 100644 --- a/scripts/tables/categoryTable.ts +++ b/scripts/tables/categoriesTable.ts @@ -1,32 +1,35 @@ -import { Storage, Collection, File } from '@freearhey/core' +import { Storage, Collection, File, Dictionary } from '@freearhey/core' import { HTMLTable, LogParser, LogItem } from '../core' +import { LOGS_DIR, README_DIR } from '../constants' import { Category } from '../models' -import { DATA_DIR, LOGS_DIR, README_DIR } from '../constants' import { Table } from './table' -export class CategoryTable implements Table { - constructor() {} +type CategoriesTableProps = { + categoriesKeyById: Dictionary +} + +export class CategoriesTable implements Table { + categoriesKeyById: Dictionary + + constructor({ categoriesKeyById }: CategoriesTableProps) { + this.categoriesKeyById = categoriesKeyById + } async make() { - const dataStorage = new Storage(DATA_DIR) - const categoriesContent = await dataStorage.json('categories.json') - const categories = new Collection(categoriesContent).map(data => new Category(data)) - const categoriesGroupedById = categories.keyBy((category: Category) => category.id) - const parser = new LogParser() const logsStorage = new Storage(LOGS_DIR) const generatorsLog = await logsStorage.load('generators.log') - let data = new Collection() + let items = new Collection() parser .parse(generatorsLog) .filter((logItem: LogItem) => logItem.type === 'category') .forEach((logItem: LogItem) => { const file = new File(logItem.filepath) const categoryId = file.name() - const category: Category = categoriesGroupedById.get(categoryId) + const category: Category = this.categoriesKeyById.get(categoryId) - data.add([ + items.add([ category ? category.name : 'ZZ', category ? category.name : 'Undefined', logItem.count, @@ -34,14 +37,14 @@ export class CategoryTable implements Table { ]) }) - data = data + items = items .orderBy(item => item[0]) .map(item => { item.shift() return item }) - const table = new HTMLTable(data.all(), [ + const table = new HTMLTable(items.all(), [ { name: 'Category' }, { name: 'Channels', align: 'right' }, { name: 'Playlist', nowrap: true } diff --git a/scripts/tables/countriesTable.ts b/scripts/tables/countriesTable.ts new file mode 100644 index 0000000000..0be11c1b3d --- /dev/null +++ b/scripts/tables/countriesTable.ts @@ -0,0 +1,189 @@ +import { Storage, Collection, Dictionary } from '@freearhey/core' +import { City, Country, Subdivision } from '../models' +import { LOGS_DIR, README_DIR } from '../constants' +import { LogParser, LogItem } from '../core' +import { Table } from './table' + +type CountriesTableProps = { + countriesKeyByCode: Dictionary + subdivisionsKeyByCode: Dictionary + countries: Collection + subdivisions: Collection + cities: Collection +} + +export class CountriesTable implements Table { + countriesKeyByCode: Dictionary + subdivisionsKeyByCode: Dictionary + countries: Collection + subdivisions: Collection + cities: Collection + + constructor({ + countriesKeyByCode, + subdivisionsKeyByCode, + countries, + subdivisions, + cities + }: CountriesTableProps) { + this.countriesKeyByCode = countriesKeyByCode + this.subdivisionsKeyByCode = subdivisionsKeyByCode + this.countries = countries + this.subdivisions = subdivisions + this.cities = cities + } + + async make() { + const parser = new LogParser() + const logsStorage = new Storage(LOGS_DIR) + const generatorsLog = await logsStorage.load('generators.log') + const parsed = parser.parse(generatorsLog) + const logCountries = parsed.filter((logItem: LogItem) => logItem.type === 'country') + const logSubdivisions = parsed.filter((logItem: LogItem) => logItem.type === 'subdivision') + const logCities = parsed.filter((logItem: LogItem) => logItem.type === 'city') + + let items = new Collection() + this.countries.forEach((country: Country) => { + const countriesLogItem = logCountries.find( + (logItem: LogItem) => logItem.filepath === `countries/${country.code.toLowerCase()}.m3u` + ) + + let countryItem = { + index: country.name, + count: 0, + link: `https://iptv-org.github.io/iptv/countries/${country.code.toLowerCase()}.m3u`, + name: `${country.flag} ${country.name}`, + children: new Collection() + } + + if (countriesLogItem) { + countryItem.count = countriesLogItem.count + } + + const countrySubdivisions = this.subdivisions.filter( + (subdivision: Subdivision) => subdivision.countryCode === country.code + ) + const countryCities = this.cities.filter((city: City) => city.countryCode === country.code) + if (countrySubdivisions.notEmpty()) { + this.subdivisions.forEach((subdivision: Subdivision) => { + if (subdivision.countryCode !== country.code) return + const subdivisionCities = countryCities.filter( + (city: City) => + (city.subdivisionCode && city.subdivisionCode === subdivision.code) || + city.countryCode === subdivision.countryCode + ) + const subdivisionsLogItem = logSubdivisions.find( + (logItem: LogItem) => + logItem.filepath === `subdivisions/${subdivision.code.toLowerCase()}.m3u` + ) + + let subdivisionItem = { + index: subdivision.name, + name: subdivision.name, + count: 0, + link: `https://iptv-org.github.io/iptv/subdivisions/${subdivision.code.toLowerCase()}.m3u`, + children: new Collection() + } + + if (subdivisionsLogItem) { + subdivisionItem.count = subdivisionsLogItem.count + } + + subdivisionCities.forEach((city: City) => { + if (city.countryCode !== country.code || city.subdivisionCode !== subdivision.code) + return + const citiesLogItem = logCities.find( + (logItem: LogItem) => logItem.filepath === `cities/${city.code.toLowerCase()}.m3u` + ) + + if (!citiesLogItem) return + + subdivisionItem.children.add({ + index: city.name, + name: city.name, + count: citiesLogItem.count, + link: `https://iptv-org.github.io/iptv/${citiesLogItem.filepath}` + }) + }) + + if (subdivisionItem.count > 0 || subdivisionItem.children.notEmpty()) { + countryItem.children.add(subdivisionItem) + } + }) + } else if (countryCities.notEmpty()) { + countryCities.forEach((city: City) => { + const citiesLogItem = logCities.find( + (logItem: LogItem) => logItem.filepath === `cities/${city.code.toLowerCase()}.m3u` + ) + + if (!citiesLogItem) return + + countryItem.children.add({ + index: city.name, + name: city.name, + count: citiesLogItem.count, + link: `https://iptv-org.github.io/iptv/${citiesLogItem.filepath}`, + children: new Collection() + }) + }) + } + + if (countryItem.count > 0 || countryItem.children.notEmpty()) { + items.add(countryItem) + } + }) + + const internationalLogItem = logCountries.find( + (logItem: LogItem) => logItem.filepath === 'countries/int.m3u' + ) + + if (internationalLogItem) { + items.push({ + index: 'ZZ', + name: '🌐 International', + count: internationalLogItem.count, + link: `https://iptv-org.github.io/iptv/${internationalLogItem.filepath}`, + children: new Collection() + }) + } + + const undefinedLogItem = logCountries.find( + (logItem: LogItem) => logItem.filepath === `countries/undefined.m3u` + ) + + if (undefinedLogItem) { + items.push({ + index: 'ZZZ', + name: 'Undefined', + count: undefinedLogItem.count, + link: `https://iptv-org.github.io/iptv/${undefinedLogItem.filepath}`, + children: new Collection() + }) + } + + items = items.orderBy(item => item.index) + + const output = items + .map(item => { + let row = `- ${item.name} ${item.link}` + + item.children + .orderBy(item => item.index) + .forEach(item => { + row += `\r\n\ - ${item.name} ${item.link}` + + item.children + .orderBy(item => item.index) + .forEach(item => { + row += `\r\n\ - ${item.name} ${item.link}` + }) + }) + + return row + }) + .join('\r\n') + + const readmeStorage = new Storage(README_DIR) + await readmeStorage.save('_countries.md', output) + } +} diff --git a/scripts/tables/countryTable.ts b/scripts/tables/countryTable.ts deleted file mode 100644 index d0075e62cd..0000000000 --- a/scripts/tables/countryTable.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { Storage, Collection, File } from '@freearhey/core' -import { HTMLTable, LogParser, LogItem } from '../core' -import { Country } from '../models' -import { DATA_DIR, LOGS_DIR, README_DIR } from '../constants' -import { Table } from './table' - -export class CountryTable 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 parser = new LogParser() - const logsStorage = new Storage(LOGS_DIR) - const generatorsLog = await logsStorage.load('generators.log') - const parsed = parser.parse(generatorsLog) - - let data = new Collection() - - parsed - .filter((logItem: LogItem) => logItem.type === 'country') - .forEach((logItem: LogItem) => { - const file = new File(logItem.filepath) - const code = file.name().toUpperCase() - const [countryCode] = code.split('-') || ['', ''] - const country = countriesGroupedByCode.get(countryCode) - - if (country) { - data.add([ - country.name, - `${country.flag} ${country.name}`, - logItem.count, - `https://iptv-org.github.io/iptv/${logItem.filepath}` - ]) - } else { - data.add([ - 'ZZ', - 'Undefined', - logItem.count, - `https://iptv-org.github.io/iptv/${logItem.filepath}` - ]) - } - }) - - data = data - .orderBy(item => item[0]) - .map(item => { - item.shift() - return item - }) - - const table = new HTMLTable(data.all(), [ - { name: 'Country' }, - { name: 'Channels', align: 'right' }, - { name: 'Playlist', nowrap: true } - ]) - - const readmeStorage = new Storage(README_DIR) - await readmeStorage.save('_countries.md', table.toString()) - } -} diff --git a/scripts/tables/index.ts b/scripts/tables/index.ts index 6da33e8221..f25c0a3a27 100644 --- a/scripts/tables/index.ts +++ b/scripts/tables/index.ts @@ -1,5 +1,4 @@ -export * from './categoryTable' -export * from './countryTable' -export * from './languageTable' -export * from './regionTable' -export * from './subdivisionTable' +export * from './categoriesTable' +export * from './countriesTable' +export * from './languagesTable' +export * from './regionsTable' diff --git a/scripts/tables/languageTable.ts b/scripts/tables/languagesTable.ts similarity index 68% rename from scripts/tables/languageTable.ts rename to scripts/tables/languagesTable.ts index 2014ba6760..7621907453 100644 --- a/scripts/tables/languageTable.ts +++ b/scripts/tables/languagesTable.ts @@ -1,18 +1,21 @@ -import { Storage, Collection, File } from '@freearhey/core' +import { Storage, Collection, File, Dictionary } from '@freearhey/core' import { HTMLTable, LogParser, LogItem } from '../core' +import { LOGS_DIR, README_DIR } from '../constants' import { Language } from '../models' -import { DATA_DIR, LOGS_DIR, README_DIR } from '../constants' import { Table } from './table' -export class LanguageTable implements Table { - constructor() {} +type LanguagesTableProps = { + languagesKeyByCode: Dictionary +} + +export class LanguagesTable implements Table { + languagesKeyByCode: Dictionary + + constructor({ languagesKeyByCode }: LanguagesTableProps) { + this.languagesKeyByCode = languagesKeyByCode + } async make() { - const dataStorage = new Storage(DATA_DIR) - const languagesContent = await dataStorage.json('languages.json') - const languages = new Collection(languagesContent).map(data => new Language(data)) - const languagesGroupedByCode = languages.keyBy((language: Language) => language.code) - const parser = new LogParser() const logsStorage = new Storage(LOGS_DIR) const generatorsLog = await logsStorage.load('generators.log') @@ -24,7 +27,7 @@ export class LanguageTable implements Table { .forEach((logItem: LogItem) => { const file = new File(logItem.filepath) const languageCode = file.name() - const language: Language = languagesGroupedByCode.get(languageCode) + const language: Language = this.languagesKeyByCode.get(languageCode) data.add([ language ? language.name : 'ZZ', diff --git a/scripts/tables/regionTable.ts b/scripts/tables/regionTable.ts deleted file mode 100644 index 84eeaaa4a2..0000000000 --- a/scripts/tables/regionTable.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { Storage, Collection, File } from '@freearhey/core' -import { HTMLTable, LogParser, LogItem } from '../core' -import { Region } from '../models' -import { DATA_DIR, LOGS_DIR, README_DIR } from '../constants' -import { Table } from './table' - -export class RegionTable implements Table { - constructor() {} - - async make() { - const dataStorage = new Storage(DATA_DIR) - const regionsContent = await dataStorage.json('regions.json') - const regions = new Collection(regionsContent).map(data => new Region(data)) - const regionsGroupedByCode = regions.keyBy((region: Region) => region.code) - - const parser = new LogParser() - const logsStorage = new Storage(LOGS_DIR) - const generatorsLog = await logsStorage.load('generators.log') - - let data = new Collection() - parser - .parse(generatorsLog) - .filter((logItem: LogItem) => logItem.type === 'region') - .forEach((logItem: LogItem) => { - const file = new File(logItem.filepath) - const regionCode = file.name().toUpperCase() - const region: Region = regionsGroupedByCode.get(regionCode) - - if (region) { - data.add([ - region.name, - region.name, - logItem.count, - `https://iptv-org.github.io/iptv/${logItem.filepath}` - ]) - } else { - data.add([ - 'ZZZ', - 'Undefined', - logItem.count, - `https://iptv-org.github.io/iptv/${logItem.filepath}` - ]) - } - }) - - data = data - .orderBy(item => item[0]) - .map(item => { - item.shift() - return item - }) - - const table = new HTMLTable(data.all(), [ - { name: 'Region', align: 'left' }, - { name: 'Channels', align: 'right' }, - { name: 'Playlist', align: 'left', nowrap: true } - ]) - - const readmeStorage = new Storage(README_DIR) - await readmeStorage.save('_regions.md', table.toString()) - } -} diff --git a/scripts/tables/regionsTable.ts b/scripts/tables/regionsTable.ts new file mode 100644 index 0000000000..25f2e71bcb --- /dev/null +++ b/scripts/tables/regionsTable.ts @@ -0,0 +1,52 @@ +import { Storage, Collection, File } from '@freearhey/core' +import { HTMLTable, LogParser, LogItem } from '../core' +import { LOGS_DIR, README_DIR } from '../constants' +import { Region } from '../models' +import { Table } from './table' + +type RegionsTableProps = { + regions: Collection +} + +export class RegionsTable implements Table { + regions: Collection + + constructor({ regions }: RegionsTableProps) { + this.regions = regions + } + + async make() { + const parser = new LogParser() + const logsStorage = new Storage(LOGS_DIR) + const generatorsLog = await logsStorage.load('generators.log') + const parsed = parser.parse(generatorsLog) + const logRegions = parsed.filter((logItem: LogItem) => logItem.type === 'region') + + let items = new Collection() + this.regions.forEach((region: Region) => { + const logItem = logRegions.find( + (logItem: LogItem) => logItem.filepath === `regions/${region.code.toLowerCase()}.m3u` + ) + + if (!logItem) return + + items.add({ + index: region.name, + name: region.name, + count: logItem.count, + link: `https://iptv-org.github.io/iptv/${logItem.filepath}` + }) + }) + + items = items.orderBy(item => item.index) + + const output = items + .map(item => { + return `- ${item.name} ${item.link}` + }) + .join('\r\n') + + const readmeStorage = new Storage(README_DIR) + await readmeStorage.save('_regions.md', output) + } +} diff --git a/scripts/tables/subdivisionTable.ts b/scripts/tables/subdivisionTable.ts deleted file mode 100644 index 925d9094e3..0000000000 --- a/scripts/tables/subdivisionTable.ts +++ /dev/null @@ -1,72 +0,0 @@ -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` - - const 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()) - } -} diff --git a/scripts/types/city.d.ts b/scripts/types/city.d.ts new file mode 100644 index 0000000000..5c33ba5a9e --- /dev/null +++ b/scripts/types/city.d.ts @@ -0,0 +1,20 @@ +import { CountrySerializedData } from './country' +import { SubdivisionSerializedData } from './subdivision' + +export type CitySerializedData = { + code: string + name: string + countryCode: string + country?: CountrySerializedData + subdivisionCode: string | null + subdivision?: SubdivisionSerializedData + wikidataId: string +} + +export type CityData = { + code: string + name: string + country: string + subdivision: string | null + wikidata_id: string +} diff --git a/scripts/types/dataLoader.d.ts b/scripts/types/dataLoader.d.ts index ee7ab0f937..708361de99 100644 --- a/scripts/types/dataLoader.d.ts +++ b/scripts/types/dataLoader.d.ts @@ -17,4 +17,5 @@ export type DataLoaderData = { timezones: object | object[] guides: object | object[] streams: object | object[] + cities: object | object[] } diff --git a/scripts/types/dataProcessor.d.ts b/scripts/types/dataProcessor.d.ts index 25f21d1aac..bc76dc28b4 100644 --- a/scripts/types/dataProcessor.d.ts +++ b/scripts/types/dataProcessor.d.ts @@ -15,6 +15,7 @@ export type DataProcessorData = { regionsKeyByCode: Dictionary blocklistRecords: Collection channelsKeyById: Dictionary + citiesKeyByCode: Dictionary subdivisions: Collection categories: Collection countries: Collection @@ -23,6 +24,8 @@ export type DataProcessorData = { channels: Collection regions: Collection streams: Collection + cities: Collection guides: Collection feeds: Collection + logos: Collection } diff --git a/scripts/types/feed.d.ts b/scripts/types/feed.d.ts index 5c6722dde2..ef4aea4669 100644 --- a/scripts/types/feed.d.ts +++ b/scripts/types/feed.d.ts @@ -1,12 +1,10 @@ -import { Collection } from '@freearhey/core' - export type FeedData = { channel: string id: string name: string is_main: boolean - broadcast_area: Collection - languages: Collection - timezones: Collection + broadcast_area: string[] + languages: string[] + timezones: string[] video_format: string } diff --git a/scripts/types/region.d.ts b/scripts/types/region.d.ts index e6773429ee..798224ee7f 100644 --- a/scripts/types/region.d.ts +++ b/scripts/types/region.d.ts @@ -1,9 +1,14 @@ +import { CitySerializedData } from './city' +import { CountrySerializedData } from './country' +import { SubdivisionSerializedData } from './subdivision' + export type RegionSerializedData = { code: string name: string countryCodes: string[] countries?: CountrySerializedData[] subdivisions?: SubdivisionSerializedData[] + cities?: CitySerializedData[] } export type RegionData = { diff --git a/scripts/types/subdivision.d.ts b/scripts/types/subdivision.d.ts index bf46831f72..b2a25982dd 100644 --- a/scripts/types/subdivision.d.ts +++ b/scripts/types/subdivision.d.ts @@ -1,12 +1,16 @@ +import { CountrySerializedData } from './country' + export type SubdivisionSerializedData = { code: string name: string countryCode: string country?: CountrySerializedData + parentCode: string | null } export type SubdivisionData = { code: string name: string country: string + parent: string | null } diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/countries/ad.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/cities/adcan.m3u similarity index 100% rename from tests/__data__/expected/playlist_generate/.gh-pages/countries/ad.m3u rename to tests/__data__/expected/playlist_generate/.gh-pages/cities/adcan.m3u diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/countries/ca.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/countries/ca.m3u index 8aeaaae90e..754a6969c0 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/countries/ca.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/countries/ca.m3u @@ -1,5 +1,3 @@ #EXTM3U #EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="Undefined",5AAB TV http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8 -#EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Weather",Meteomedia -http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/countries/int.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/countries/int.m3u new file mode 100644 index 0000000000..4e507cf645 --- /dev/null +++ b/tests/__data__/expected/playlist_generate/.gh-pages/countries/int.m3u @@ -0,0 +1,7 @@ +#EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="General",Π­Π»Π’Π  (480p) [Not 24/7] +http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/index.country.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/index.country.m3u index 1848f28016..8cc0cf2622 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/index.country.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/index.country.m3u @@ -1,26 +1,14 @@ #EXTM3U -#EXTINF:-1 tvg-id="AndorraTV.ad@SD" tvg-logo="https://i.imgur.com/BnhTn8i.png" group-title="Andorra",ATV -https://iptv-all.lanesh4d0w.repl.co/andorra/atv #EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="Canada",5AAB TV http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8 -#EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Canada",Meteomedia -http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8 -#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Kazakhstan",Π­Π»Π’Π  (480p) [Not 24/7] -http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8 -#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Kyrgyzstan",Π­Π»Π’Π  (480p) [Not 24/7] -http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8 #EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="Russia",Π›Π”ΠŸΠ  Π’Π’ (1080p) http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8 -#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Tajikistan",Π­Π»Π’Π  (480p) [Not 24/7] -http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8 -#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Turkmenistan",Π­Π»Π’Π  (480p) [Not 24/7] -http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8 -#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Uzbekistan",Π­Π»Π’Π  (480p) [Not 24/7] -http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8 #EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="International",BBC News HD http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 #EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="International",Duna World (576i) http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="International",Π­Π»Π’Π  (480p) [Not 24/7] +http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8 #EXTINF:-1 tvg-id="" tvg-logo="" group-title="Undefined" http-referrer="http://imn.iq" http-user-agent="Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148",Andorra TV (720p) [Not 24/7] #EXTVLCOPT:http-referrer=http://imn.iq #EXTVLCOPT:http-user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/index.region.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/index.region.m3u index 3fd36e2146..d8d2d7f6e8 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/index.region.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/index.region.m3u @@ -1,53 +1,139 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Africa",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Africa",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="Americas",5AAB TV http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Americas",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Americas",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Americas",Meteomedia http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Arab world",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Arab world",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Asia",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Asia",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="Asia",Π›Π”ΠŸΠ  Π’Π’ (1080p) http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8 #EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Asia",Π­Π»Π’Π  (480p) [Not 24/7] http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Asia-Pacific",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Asia-Pacific",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Association of Southeast Asian Nations",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Association of Southeast Asian Nations",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Caribbean",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Caribbean",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Central America",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Central America",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Central Asia",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Central Asia",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Central Asia",Π­Π»Π’Π  (480p) [Not 24/7] http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Commonwealth of Independent States",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Commonwealth of Independent States",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="Commonwealth of Independent States",Π›Π”ΠŸΠ  Π’Π’ (1080p) http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8 #EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Commonwealth of Independent States",Π­Π»Π’Π  (480p) [Not 24/7] http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8 #EXTINF:-1 tvg-id="AndorraTV.ad@SD" tvg-logo="https://i.imgur.com/BnhTn8i.png" group-title="Europe",ATV https://iptv-all.lanesh4d0w.repl.co/andorra/atv +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Europe",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Europe",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="Europe",Π›Π”ΠŸΠ  Π’Π’ (1080p) http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8 #EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Europe",Π­Π»Π’Π  (480p) [Not 24/7] http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8 #EXTINF:-1 tvg-id="AndorraTV.ad@SD" tvg-logo="https://i.imgur.com/BnhTn8i.png" group-title="Europe, the Middle East and Africa",ATV https://iptv-all.lanesh4d0w.repl.co/andorra/atv +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Europe, the Middle East and Africa",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Europe, the Middle East and Africa",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="Europe, the Middle East and Africa",Π›Π”ΠŸΠ  Π’Π’ (1080p) http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8 #EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Europe, the Middle East and Africa",Π­Π»Π’Π  (480p) [Not 24/7] http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Hispanic America",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Hispanic America",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Latin America",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Latin America",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Latin America and the Caribbean",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Latin America and the Caribbean",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Maghreb",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Maghreb",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Middle East",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Middle East",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Middle East and North Africa",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Middle East and North Africa",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Nordics",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Nordics",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="North America",5AAB TV http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="North America",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="North America",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="North America",Meteomedia http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8 #EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="Northern America",5AAB TV http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Northern America",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Northern America",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Northern America",Meteomedia http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8 -#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="International",BBC News HD +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Oceania",BBC News HD http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 -#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="International",Duna World (576i) +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Oceania",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="South America",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="South America",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="South Asia",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="South Asia",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Sub-Saharan Africa",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Sub-Saharan Africa",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="West Africa",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="West Africa",Duna World (576i) http://146.59.85.40:89/dunaworld/index.m3u8 -#EXTINF:-1 tvg-id="" tvg-logo="" group-title="Undefined" http-referrer="http://imn.iq" http-user-agent="Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148",Andorra TV (720p) [Not 24/7] -#EXTVLCOPT:http-referrer=http://imn.iq -#EXTVLCOPT:http-user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 -#KODIPROP:inputstream=inputstream.adaptive -#KODIPROP:inputstream.adaptive.manifest_type=mpd -#KODIPROP:inputstream.adaptive.license_type=com.widevine.alpha -#KODIPROP:inputstream.adaptive.license_key=https://drm.ors.at/acquire-license/widevine?BrandGuid=13f2e056-53fe-4469-ba6d-999970dbe549&userToken=v9ZVSksv4S7rT55o10dmYNRa4asye3z05eWCFxD%2FFYIlTJEpuf6tF8asPcyQOFq0h5opS%2B6WoMxnshWkihpHq5qrdrBEZ69piE94J9Feh385snGOqK3PYO7tLLjxmsCAe%2B9%2BNnurSSO5RCAIRsL125nSj1eOR%2F1GSKOgGH80HK2FDLiePxPkeaAxuWzacNBB%2FqnIGGxfe3GlmN65cU9F8WEpKFDlaxW%2Fv3ZSLAp3%2BZEq1aZXJ6Oz%2Fi0diD0EybH7|Content-Type=application/octet-stream|R{SSM}| -http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index2.m3u8|Referer="https://referer.xyz/"|User-Agent="Mozilla/5.0 (iPhone; CPU iPhone OS 17_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1"|Origin="https://origin.xyz" -#EXTINF:-1 tvg-id="AndorraTV.ad@HD" tvg-logo="https://i.imgur.com/CnhTn8i.png" group-title="Undefined",ATV HD -https://iptv-all.lanesh4d0w.repl.co/andorra/atv_hd -#EXTINF:-1 tvg-id="" tvg-logo="" group-title="Undefined",Daawah TV -http://51.15.246.58:8081/daawahtv/daawahtv2/playlist.m3u8 -#EXTINF:-1 tvg-id="Zoo.ad@HD" tvg-logo="https://i.imgur.com/ciTJrnl.png" group-title="Undefined",Zoo (720p) -https://iptv-all.lanesh4d0w.repl.co/andorra/zoo diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/afr.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/afr.m3u index fcd718794a..c549c09ce1 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/afr.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/afr.m3u @@ -1 +1,5 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/amer.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/amer.m3u index 8aeaaae90e..2151d32ae8 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/amer.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/amer.m3u @@ -1,5 +1,9 @@ #EXTM3U #EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="Undefined",5AAB TV http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Weather",Meteomedia http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/apac.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/apac.m3u index fcd718794a..c549c09ce1 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/apac.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/apac.m3u @@ -1 +1,5 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/arab.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/arab.m3u index fcd718794a..c549c09ce1 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/arab.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/arab.m3u @@ -1 +1,5 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/int.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/asean.m3u similarity index 100% rename from tests/__data__/expected/playlist_generate/.gh-pages/regions/int.m3u rename to tests/__data__/expected/playlist_generate/.gh-pages/regions/asean.m3u diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/asia.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/asia.m3u index 6f6d448e87..202cd4e3fa 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/asia.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/asia.m3u @@ -1,4 +1,8 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="General",Π›Π”ΠŸΠ  Π’Π’ (1080p) http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8 #EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="General",Π­Π»Π’Π  (480p) [Not 24/7] diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/carib.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/carib.m3u index fcd718794a..c549c09ce1 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/carib.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/carib.m3u @@ -1 +1,5 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/cas.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/cas.m3u index a9387b8b44..4e507cf645 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/cas.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/cas.m3u @@ -1,3 +1,7 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="General",Π­Π»Π’Π  (480p) [Not 24/7] http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/cenamer.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/cenamer.m3u new file mode 100644 index 0000000000..c549c09ce1 --- /dev/null +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/cenamer.m3u @@ -0,0 +1,5 @@ +#EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/cis.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/cis.m3u index 6f6d448e87..202cd4e3fa 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/cis.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/cis.m3u @@ -1,4 +1,8 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="General",Π›Π”ΠŸΠ  Π’Π’ (1080p) http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8 #EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="General",Π­Π»Π’Π  (480p) [Not 24/7] diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/emea.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/emea.m3u index 87d85279d7..9a8e344397 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/emea.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/emea.m3u @@ -1,6 +1,10 @@ #EXTM3U #EXTINF:-1 tvg-id="AndorraTV.ad@SD" tvg-logo="https://i.imgur.com/BnhTn8i.png" group-title="Undefined",ATV https://iptv-all.lanesh4d0w.repl.co/andorra/atv +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="General",Π›Π”ΠŸΠ  Π’Π’ (1080p) http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8 #EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="General",Π­Π»Π’Π  (480p) [Not 24/7] diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/eur.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/eur.m3u index 87d85279d7..9a8e344397 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/eur.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/eur.m3u @@ -1,6 +1,10 @@ #EXTM3U #EXTINF:-1 tvg-id="AndorraTV.ad@SD" tvg-logo="https://i.imgur.com/BnhTn8i.png" group-title="Undefined",ATV https://iptv-all.lanesh4d0w.repl.co/andorra/atv +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="General",Π›Π”ΠŸΠ  Π’Π’ (1080p) http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8 #EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="General",Π­Π»Π’Π  (480p) [Not 24/7] diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/hispam.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/hispam.m3u index fcd718794a..c549c09ce1 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/hispam.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/hispam.m3u @@ -1 +1,5 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/lac.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/lac.m3u index fcd718794a..c549c09ce1 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/lac.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/lac.m3u @@ -1 +1,5 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/latam.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/latam.m3u index fcd718794a..c549c09ce1 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/latam.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/latam.m3u @@ -1 +1,5 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/maghreb.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/maghreb.m3u index fcd718794a..c549c09ce1 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/maghreb.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/maghreb.m3u @@ -1 +1,5 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/mena.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/mena.m3u index fcd718794a..c549c09ce1 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/mena.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/mena.m3u @@ -1 +1,5 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/mideast.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/mideast.m3u index fcd718794a..c549c09ce1 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/mideast.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/mideast.m3u @@ -1 +1,5 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/nam.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/nam.m3u index 8aeaaae90e..2151d32ae8 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/nam.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/nam.m3u @@ -1,5 +1,9 @@ #EXTM3U #EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="Undefined",5AAB TV http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Weather",Meteomedia http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/noram.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/noram.m3u index 8aeaaae90e..2151d32ae8 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/noram.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/noram.m3u @@ -1,5 +1,9 @@ #EXTM3U #EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="Undefined",5AAB TV http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8 +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 #EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Weather",Meteomedia http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/nord.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/nord.m3u index fcd718794a..c549c09ce1 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/nord.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/nord.m3u @@ -1 +1,5 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/oce.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/oce.m3u index fcd718794a..c549c09ce1 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/oce.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/oce.m3u @@ -1 +1,5 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/sas.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/sas.m3u index fcd718794a..c549c09ce1 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/sas.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/sas.m3u @@ -1 +1,5 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/southam.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/southam.m3u new file mode 100644 index 0000000000..c549c09ce1 --- /dev/null +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/southam.m3u @@ -0,0 +1,5 @@ +#EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/ssa.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/ssa.m3u index fcd718794a..c549c09ce1 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/ssa.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/ssa.m3u @@ -1 +1,5 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/undefined.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/undefined.m3u deleted file mode 100644 index 1770572503..0000000000 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/undefined.m3u +++ /dev/null @@ -1,15 +0,0 @@ -#EXTM3U -#EXTINF:-1 tvg-id="" tvg-logo="" group-title="Undefined" http-referrer="http://imn.iq" http-user-agent="Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148",Andorra TV (720p) [Not 24/7] -#EXTVLCOPT:http-referrer=http://imn.iq -#EXTVLCOPT:http-user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 -#KODIPROP:inputstream=inputstream.adaptive -#KODIPROP:inputstream.adaptive.manifest_type=mpd -#KODIPROP:inputstream.adaptive.license_type=com.widevine.alpha -#KODIPROP:inputstream.adaptive.license_key=https://drm.ors.at/acquire-license/widevine?BrandGuid=13f2e056-53fe-4469-ba6d-999970dbe549&userToken=v9ZVSksv4S7rT55o10dmYNRa4asye3z05eWCFxD%2FFYIlTJEpuf6tF8asPcyQOFq0h5opS%2B6WoMxnshWkihpHq5qrdrBEZ69piE94J9Feh385snGOqK3PYO7tLLjxmsCAe%2B9%2BNnurSSO5RCAIRsL125nSj1eOR%2F1GSKOgGH80HK2FDLiePxPkeaAxuWzacNBB%2FqnIGGxfe3GlmN65cU9F8WEpKFDlaxW%2Fv3ZSLAp3%2BZEq1aZXJ6Oz%2Fi0diD0EybH7|Content-Type=application/octet-stream|R{SSM}| -http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index2.m3u8|Referer="https://referer.xyz/"|User-Agent="Mozilla/5.0 (iPhone; CPU iPhone OS 17_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1"|Origin="https://origin.xyz" -#EXTINF:-1 tvg-id="AndorraTV.ad@HD" tvg-logo="https://i.imgur.com/CnhTn8i.png" group-title="Undefined",ATV HD -https://iptv-all.lanesh4d0w.repl.co/andorra/atv_hd -#EXTINF:-1 tvg-id="" tvg-logo="" group-title="Undefined",Daawah TV -http://51.15.246.58:8081/daawahtv/daawahtv2/playlist.m3u8 -#EXTINF:-1 tvg-id="Zoo.ad@HD" tvg-logo="https://i.imgur.com/ciTJrnl.png" group-title="Undefined",Zoo (720p) -https://iptv-all.lanesh4d0w.repl.co/andorra/zoo diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/regions/wafr.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/regions/wafr.m3u index fcd718794a..c549c09ce1 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/regions/wafr.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/regions/wafr.m3u @@ -1 +1,5 @@ #EXTM3U +#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD +http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 +#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i) +http://146.59.85.40:89/dunaworld/index.m3u8 diff --git a/tests/__data__/expected/playlist_generate/.gh-pages/subdivisions/ca-on.m3u b/tests/__data__/expected/playlist_generate/.gh-pages/subdivisions/ca-on.m3u index 8aeaaae90e..4686c68f4b 100644 --- a/tests/__data__/expected/playlist_generate/.gh-pages/subdivisions/ca-on.m3u +++ b/tests/__data__/expected/playlist_generate/.gh-pages/subdivisions/ca-on.m3u @@ -1,5 +1,3 @@ #EXTM3U -#EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="Undefined",5AAB TV -http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8 #EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Weather",Meteomedia http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8 diff --git a/tests/__data__/expected/playlist_generate/logs/generators.log b/tests/__data__/expected/playlist_generate/logs/generators.log index 2177b05c0e..6dc3d2af68 100644 --- a/tests/__data__/expected/playlist_generate/logs/generators.log +++ b/tests/__data__/expected/playlist_generate/logs/generators.log @@ -5,227 +5,71 @@ {"type":"raw","filepath":"raw/uk.m3u","count":1} {"type":"raw","filepath":"raw/unsorted.m3u","count":4} {"type":"category","filepath":"categories/auto.m3u","count":0} -{"type":"category","filepath":"categories/comedy.m3u","count":0} -{"type":"category","filepath":"categories/business.m3u","count":0} -{"type":"category","filepath":"categories/cooking.m3u","count":0} {"type":"category","filepath":"categories/animation.m3u","count":0} +{"type":"category","filepath":"categories/business.m3u","count":0} {"type":"category","filepath":"categories/classic.m3u","count":0} -{"type":"category","filepath":"categories/documentary.m3u","count":0} -{"type":"category","filepath":"categories/family.m3u","count":0} +{"type":"category","filepath":"categories/cooking.m3u","count":0} {"type":"category","filepath":"categories/culture.m3u","count":0} {"type":"category","filepath":"categories/education.m3u","count":0} -{"type":"category","filepath":"categories/general.m3u","count":3} +{"type":"category","filepath":"categories/documentary.m3u","count":0} +{"type":"category","filepath":"categories/comedy.m3u","count":0} +{"type":"category","filepath":"categories/family.m3u","count":0} {"type":"category","filepath":"categories/kids.m3u","count":0} -{"type":"category","filepath":"categories/lifestyle.m3u","count":0} -{"type":"category","filepath":"categories/movies.m3u","count":0} +{"type":"category","filepath":"categories/legislative.m3u","count":0} +{"type":"category","filepath":"categories/entertainment.m3u","count":0} {"type":"category","filepath":"categories/music.m3u","count":0} {"type":"category","filepath":"categories/outdoor.m3u","count":0} +{"type":"category","filepath":"categories/general.m3u","count":3} +{"type":"category","filepath":"categories/lifestyle.m3u","count":0} +{"type":"category","filepath":"categories/relax.m3u","count":0} +{"type":"category","filepath":"categories/religious.m3u","count":0} +{"type":"category","filepath":"categories/movies.m3u","count":0} +{"type":"category","filepath":"categories/shop.m3u","count":0} {"type":"category","filepath":"categories/science.m3u","count":0} {"type":"category","filepath":"categories/news.m3u","count":1} -{"type":"category","filepath":"categories/religious.m3u","count":0} {"type":"category","filepath":"categories/series.m3u","count":0} -{"type":"category","filepath":"categories/relax.m3u","count":0} {"type":"category","filepath":"categories/sports.m3u","count":0} -{"type":"category","filepath":"categories/undefined.m3u","count":7} -{"type":"category","filepath":"categories/shop.m3u","count":0} -{"type":"category","filepath":"categories/entertainment.m3u","count":0} +{"type":"category","filepath":"categories/weather.m3u","count":1} {"type":"category","filepath":"categories/travel.m3u","count":0} {"type":"category","filepath":"categories/xxx.m3u","count":1} -{"type":"category","filepath":"categories/legislative.m3u","count":0} -{"type":"category","filepath":"categories/weather.m3u","count":1} +{"type":"category","filepath":"categories/undefined.m3u","count":7} {"type":"language","filepath":"languages/cat.m3u","count":1} -{"type":"language","filepath":"languages/rus.m3u","count":1} {"type":"language","filepath":"languages/eng.m3u","count":1} +{"type":"language","filepath":"languages/rus.m3u","count":1} {"type":"language","filepath":"languages/undefined.m3u","count":8} -{"type":"country","filepath":"countries/ca.m3u","count":2} -{"type":"country","filepath":"countries/ad.m3u","count":1} +{"type":"country","filepath":"countries/ca.m3u","count":1} +{"type":"country","filepath":"countries/int.m3u","count":3} {"type":"country","filepath":"countries/ru.m3u","count":1} -{"type":"country","filepath":"countries/uz.m3u","count":1} -{"type":"country","filepath":"countries/kz.m3u","count":1} -{"type":"country","filepath":"countries/tj.m3u","count":1} -{"type":"country","filepath":"countries/tm.m3u","count":1} {"type":"country","filepath":"countries/undefined.m3u","count":4} -{"type":"country","filepath":"countries/kg.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ad-07.m3u","count":1} -{"type":"region","filepath":"regions/afr.m3u","count":0} -{"type":"subdivision","filepath":"subdivisions/ad-02.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ad-04.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ad-08.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ad-03.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ca-ab.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ad-05.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ca-bc.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ca-nl.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ad-06.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ca-mb.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ca-nb.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ca-nt.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ca-nu.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ca-on.m3u","count":2} -{"type":"subdivision","filepath":"subdivisions/ca-ns.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ca-pe.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ca-qc.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ca-sk.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kg-j.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kg-b.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kg-t.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ca-yt.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kg-c.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kg-gb.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kg-n.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kg-y.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-ala.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kg-go.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-alm.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-akm.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-zap.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-aty.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-man.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-yuz.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-kus.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-akt.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-kar.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-kzy.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-ast.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-shy.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-pav.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-vos.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-ad.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-sev.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-al.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-ba.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-da.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-bu.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-in.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-kk.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-kl.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/kz-zha.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-me.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-se.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-mo.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-ko.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-ty.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-kr.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-alt.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-amu.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-bel.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-ast.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-sa.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-che.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-cu.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-ta.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-ce.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-bry.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-irk.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-chu.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-kb.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-iva.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-klu.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-kc.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-ark.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-kda.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-kha.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-kgd.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-kya.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-khm.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-kgn.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-kem.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-kir.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-mag.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-kam.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-krs.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-len.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-kos.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-lip.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-mur.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-mow.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-niz.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-nen.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-ngr.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-ore.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-oms.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-orl.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-nvs.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-mos.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-psk.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-ros.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-per.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-pnz.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-pri.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-sam.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-sak.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-rya.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-spe.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-sar.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-tam.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-tom.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-smo.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-sta.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-tul.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-sve.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-vla.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-tve.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-ud.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-vgg.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-vor.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-uly.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-zab.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-vlg.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-tyu.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/tj-du.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-yan.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/tj-kt.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/tj-gb.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/tj-ra.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/tm-a.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-yev.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/ru-yar.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/tj-su.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/tm-b.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/tm-l.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/tm-m.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/tm-d.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/uz-ji.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/uz-nw.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/uz-bu.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/uz-qr.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/uz-an.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/uz-fa.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/uz-qa.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/uz-si.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/uz-sa.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/uz-tk.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/uz-ng.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/uz-xo.m3u","count":1} -{"type":"subdivision","filepath":"subdivisions/uz-su.m3u","count":1} -{"type":"region","filepath":"regions/apac.m3u","count":0} -{"type":"region","filepath":"regions/amer.m3u","count":2} -{"type":"region","filepath":"regions/asean.m3u","count":0} -{"type":"region","filepath":"regions/arab.m3u","count":0} -{"type":"region","filepath":"regions/carib.m3u","count":0} -{"type":"region","filepath":"regions/cis.m3u","count":2} -{"type":"region","filepath":"regions/cas.m3u","count":1} -{"type":"region","filepath":"regions/cenamer.m3u","count":0} -{"type":"region","filepath":"regions/lac.m3u","count":0} -{"type":"region","filepath":"regions/emea.m3u","count":3} -{"type":"region","filepath":"regions/eur.m3u","count":3} -{"type":"region","filepath":"regions/mena.m3u","count":0} -{"type":"region","filepath":"regions/hispam.m3u","count":0} -{"type":"region","filepath":"regions/latam.m3u","count":0} -{"type":"region","filepath":"regions/maghreb.m3u","count":0} -{"type":"region","filepath":"regions/asia.m3u","count":2} -{"type":"region","filepath":"regions/oce.m3u","count":0} -{"type":"region","filepath":"regions/noram.m3u","count":2} -{"type":"region","filepath":"regions/nord.m3u","count":0} -{"type":"region","filepath":"regions/nam.m3u","count":2} -{"type":"region","filepath":"regions/int.m3u","count":2} -{"type":"region","filepath":"regions/southam.m3u","count":0} -{"type":"region","filepath":"regions/mideast.m3u","count":0} -{"type":"region","filepath":"regions/wafr.m3u","count":0} -{"type":"region","filepath":"regions/sas.m3u","count":0} -{"type":"region","filepath":"regions/ssa.m3u","count":0} -{"type":"region","filepath":"regions/undefined.m3u","count":4} +{"type":"subdivision","filepath":"subdivisions/ca-on.m3u","count":1} +{"type":"city","filepath":"cities/adcan.m3u","count":1} +{"type":"region","filepath":"regions/afr.m3u","count":2} +{"type":"region","filepath":"regions/amer.m3u","count":4} +{"type":"region","filepath":"regions/apac.m3u","count":2} +{"type":"region","filepath":"regions/carib.m3u","count":2} {"type":"source","filepath":"sources/in.m3u","count":1} +{"type":"region","filepath":"regions/asean.m3u","count":2} +{"type":"region","filepath":"regions/arab.m3u","count":2} +{"type":"region","filepath":"regions/asia.m3u","count":4} +{"type":"region","filepath":"regions/emea.m3u","count":5} +{"type":"region","filepath":"regions/cenamer.m3u","count":2} +{"type":"region","filepath":"regions/cis.m3u","count":4} +{"type":"region","filepath":"regions/cas.m3u","count":3} +{"type":"region","filepath":"regions/hispam.m3u","count":2} +{"type":"region","filepath":"regions/maghreb.m3u","count":2} +{"type":"region","filepath":"regions/eur.m3u","count":5} +{"type":"region","filepath":"regions/lac.m3u","count":2} +{"type":"region","filepath":"regions/mideast.m3u","count":2} +{"type":"region","filepath":"regions/noram.m3u","count":4} +{"type":"region","filepath":"regions/latam.m3u","count":2} +{"type":"region","filepath":"regions/oce.m3u","count":2} +{"type":"region","filepath":"regions/nam.m3u","count":4} +{"type":"region","filepath":"regions/southam.m3u","count":2} +{"type":"region","filepath":"regions/mena.m3u","count":2} +{"type":"region","filepath":"regions/wafr.m3u","count":2} +{"type":"region","filepath":"regions/nord.m3u","count":2} +{"type":"region","filepath":"regions/sas.m3u","count":2} +{"type":"region","filepath":"regions/ssa.m3u","count":2} {"type":"source","filepath":"sources/unsorted.m3u","count":4} {"type":"source","filepath":"sources/ca.m3u","count":2} {"type":"source","filepath":"sources/ad.m3u","count":3} @@ -233,6 +77,6 @@ {"type":"source","filepath":"sources/kg.m3u","count":1} {"type":"index","filepath":"index.m3u","count":11} {"type":"index","filepath":"index.category.m3u","count":12} -{"type":"index","filepath":"index.country.m3u","count":15} +{"type":"index","filepath":"index.country.m3u","count":9} {"type":"index","filepath":"index.language.m3u","count":11} -{"type":"index","filepath":"index.region.m3u","count":23} +{"type":"index","filepath":"index.region.m3u","count":69} diff --git a/tests/__data__/expected/readme_update/playlists.md b/tests/__data__/expected/readme_update/playlists.md index 74dd5d970f..120e27f2af 100644 --- a/tests/__data__/expected/readme_update/playlists.md +++ b/tests/__data__/expected/readme_update/playlists.md @@ -1,13 +1,15 @@ -# Playlists +## Playlists + +There are several versions of playlists that differ in the way they are grouped. As of January 30th, 2024, we have stopped distributing NSFW channels. For more information, please look at [this issue](https://github.com/iptv-org/iptv/issues/15723). ### Grouped by category +Playlists in which channels are grouped by category. +
Expand
-Playlist in which each channel has its _category_ as a group title: - ``` https://iptv-org.github.io/iptv/index.category.m3u ``` @@ -56,12 +58,12 @@ Same thing, but split up into separate files: ### Grouped by language +Playlists in which channels are grouped by the language in which they are broadcast. +
Expand
-Playlist in which each channel has its _language_ as a group title: - ``` https://iptv-org.github.io/iptv/index.language.m3u ``` @@ -84,114 +86,77 @@ Same thing, but split up into separate files:
-### Grouped by country +### Grouped by broadcast area + +Playlists in which channels are grouped by broadcast area.
Expand -
-Playlist in which each channel has its _country_ as a group title: +#### Countries ``` -https://iptv-org.github.io/iptv/index.country.m3u +https://iptv-org.github.io/iptv/index.countries.m3u ``` Same thing, but split up into separate files: - - - - - - - - - - - - - - - - - - -
CountryChannelsPlaylist
πŸ‡¨πŸ‡² Cameroon1https://iptv-org.github.io/iptv/countries/cm.m3u
πŸ‡¨πŸ‡¦ Canada2https://iptv-org.github.io/iptv/countries/ca.m3u
πŸ‡¨πŸ‡» Cape Verde1https://iptv-org.github.io/iptv/countries/cv.m3u
πŸ‡¨πŸ‡¬ Republic of the Congo1https://iptv-org.github.io/iptv/countries/cg.m3u
πŸ‡·πŸ‡ͺ RΓ©union1https://iptv-org.github.io/iptv/countries/re.m3u
πŸ‡·πŸ‡΄ Romania1https://iptv-org.github.io/iptv/countries/ro.m3u
πŸ‡·πŸ‡Ί Russia2https://iptv-org.github.io/iptv/countries/ru.m3u
πŸ‡·πŸ‡Ό Rwanda1https://iptv-org.github.io/iptv/countries/rw.m3u
πŸ‡§πŸ‡± Saint BarthΓ©lemy1https://iptv-org.github.io/iptv/countries/bl.m3u
πŸ‡ΈπŸ‡­ Saint Helena1https://iptv-org.github.io/iptv/countries/sh.m3u
πŸ‡°πŸ‡³ Saint Kitts and Nevis1https://iptv-org.github.io/iptv/countries/kn.m3u
Undefined2https://iptv-org.github.io/iptv/countries/undefined.m3u
+- πŸ‡¦πŸ‡© Andorra https://iptv-org.github.io/iptv/countries/ad.m3u + - Canillo https://iptv-org.github.io/iptv/subdivisions/ad-02.m3u + - Canillo https://iptv-org.github.io/iptv/cities/adcan.m3u +- πŸ‡¨πŸ‡² Cameroon https://iptv-org.github.io/iptv/countries/cm.m3u +- πŸ‡¨πŸ‡¦ Canada https://iptv-org.github.io/iptv/countries/ca.m3u + - Ontario https://iptv-org.github.io/iptv/subdivisions/ca-on.m3u +- πŸ‡¨πŸ‡» Cape Verde https://iptv-org.github.io/iptv/countries/cv.m3u +- πŸ‡­πŸ‡° Hong Kong https://iptv-org.github.io/iptv/countries/hk.m3u + - Sai Kung https://iptv-org.github.io/iptv/cities/hk9sk.m3u +- πŸ‡¨πŸ‡¬ Republic of the Congo https://iptv-org.github.io/iptv/countries/cg.m3u +- πŸ‡·πŸ‡ͺ RΓ©union https://iptv-org.github.io/iptv/countries/re.m3u +- πŸ‡·πŸ‡΄ Romania https://iptv-org.github.io/iptv/countries/ro.m3u +- πŸ‡·πŸ‡Ί Russia https://iptv-org.github.io/iptv/countries/ru.m3u +- πŸ‡·πŸ‡Ό Rwanda https://iptv-org.github.io/iptv/countries/rw.m3u +- πŸ‡§πŸ‡± Saint BarthΓ©lemy https://iptv-org.github.io/iptv/countries/bl.m3u +- πŸ‡ΈπŸ‡­ Saint Helena https://iptv-org.github.io/iptv/countries/sh.m3u +- πŸ‡°πŸ‡³ Saint Kitts and Nevis https://iptv-org.github.io/iptv/countries/kn.m3u +- 🌐 International https://iptv-org.github.io/iptv/countries/int.m3u +- Undefined https://iptv-org.github.io/iptv/countries/undefined.m3u -
- -### Grouped by subdivision - -
-Expand -
- - -
-Canada - - - - - - - -
SubdivisionChannelsPlaylist
Ontario1https://iptv-org.github.io/iptv/subdivisions/ca-on.m3u
-
- -
- -### Grouped by region - -
-Expand -
- -Playlist in which each channel has its _region_ as a group title: +#### Regions ``` -https://iptv-org.github.io/iptv/index.region.m3u +https://iptv-org.github.io/iptv/index.regions.m3u ``` Same thing, but split up into separate files: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RegionChannelsPlaylist
Africa0https://iptv-org.github.io/iptv/regions/afr.m3u
Americas1https://iptv-org.github.io/iptv/regions/amer.m3u
Arab world0https://iptv-org.github.io/iptv/regions/arab.m3u
Asia2https://iptv-org.github.io/iptv/regions/asia.m3u
Asia-Pacific1https://iptv-org.github.io/iptv/regions/apac.m3u
Association of Southeast Asian Nations0https://iptv-org.github.io/iptv/regions/asean.m3u
Caribbean0https://iptv-org.github.io/iptv/regions/carib.m3u
Central America0https://iptv-org.github.io/iptv/regions/cenamer.m3u
Central Asia0https://iptv-org.github.io/iptv/regions/cas.m3u
Commonwealth of Independent States1https://iptv-org.github.io/iptv/regions/cis.m3u
Europe3https://iptv-org.github.io/iptv/regions/eur.m3u
Europe, the Middle East and Africa3https://iptv-org.github.io/iptv/regions/emea.m3u
Hispanic America0https://iptv-org.github.io/iptv/regions/hispam.m3u
Latin America0https://iptv-org.github.io/iptv/regions/latam.m3u
Latin America and the Caribbean0https://iptv-org.github.io/iptv/regions/lac.m3u
Maghreb0https://iptv-org.github.io/iptv/regions/maghreb.m3u
Middle East0https://iptv-org.github.io/iptv/regions/mideast.m3u
Middle East and North Africa0https://iptv-org.github.io/iptv/regions/mena.m3u
Nordics0https://iptv-org.github.io/iptv/regions/nord.m3u
North America1https://iptv-org.github.io/iptv/regions/noram.m3u
Northern America1https://iptv-org.github.io/iptv/regions/nam.m3u
Oceania0https://iptv-org.github.io/iptv/regions/oce.m3u
South America0https://iptv-org.github.io/iptv/regions/southam.m3u
South Asia1https://iptv-org.github.io/iptv/regions/sas.m3u
Sub-Saharan Africa0https://iptv-org.github.io/iptv/regions/ssa.m3u
West Africa0https://iptv-org.github.io/iptv/regions/wafr.m3u
Worldwide1https://iptv-org.github.io/iptv/regions/int.m3u
Undefined2https://iptv-org.github.io/iptv/regions/undefined.m3u
+- Africa https://iptv-org.github.io/iptv/regions/afr.m3u +- Americas https://iptv-org.github.io/iptv/regions/amer.m3u +- Arab world https://iptv-org.github.io/iptv/regions/arab.m3u +- Asia https://iptv-org.github.io/iptv/regions/asia.m3u +- Asia-Pacific https://iptv-org.github.io/iptv/regions/apac.m3u +- Association of Southeast Asian Nations https://iptv-org.github.io/iptv/regions/asean.m3u +- Caribbean https://iptv-org.github.io/iptv/regions/carib.m3u +- Central America https://iptv-org.github.io/iptv/regions/cenamer.m3u +- Central Asia https://iptv-org.github.io/iptv/regions/cas.m3u +- Commonwealth of Independent States https://iptv-org.github.io/iptv/regions/cis.m3u +- Europe https://iptv-org.github.io/iptv/regions/eur.m3u +- Europe, the Middle East and Africa https://iptv-org.github.io/iptv/regions/emea.m3u +- Hispanic America https://iptv-org.github.io/iptv/regions/hispam.m3u +- Latin America https://iptv-org.github.io/iptv/regions/latam.m3u +- Latin America and the Caribbean https://iptv-org.github.io/iptv/regions/lac.m3u +- Maghreb https://iptv-org.github.io/iptv/regions/maghreb.m3u +- Middle East https://iptv-org.github.io/iptv/regions/mideast.m3u +- Middle East and North Africa https://iptv-org.github.io/iptv/regions/mena.m3u +- Nordics https://iptv-org.github.io/iptv/regions/nord.m3u +- North America https://iptv-org.github.io/iptv/regions/noram.m3u +- Northern America https://iptv-org.github.io/iptv/regions/nam.m3u +- Oceania https://iptv-org.github.io/iptv/regions/oce.m3u +- South America https://iptv-org.github.io/iptv/regions/southam.m3u +- South Asia https://iptv-org.github.io/iptv/regions/sas.m3u +- Sub-Saharan Africa https://iptv-org.github.io/iptv/regions/ssa.m3u +- West Africa https://iptv-org.github.io/iptv/regions/wafr.m3u
diff --git a/tests/__data__/input/data/cities.json b/tests/__data__/input/data/cities.json new file mode 100644 index 0000000000..2bf660f0ef --- /dev/null +++ b/tests/__data__/input/data/cities.json @@ -0,0 +1 @@ +[{"country":"AD","subdivision":"AD-02","code":"ADCAN","name":"Canillo","wikidata_id":"Q386802"},{"country":"CA","subdivision":"CA-ON","code":"CAAAC","name":"Ailsa Craig","wikidata_id":"Q65963197"},{"country":"HK","subdivision":null,"code":"HK9SK","name":"Sai Kung","wikidata_id":"Q206377"}] \ No newline at end of file diff --git a/tests/__data__/input/data/feeds.json b/tests/__data__/input/data/feeds.json index 7472d177a0..1c2ce8806c 100644 --- a/tests/__data__/input/data/feeds.json +++ b/tests/__data__/input/data/feeds.json @@ -5,7 +5,7 @@ "name": "SD", "is_main": true, "broadcast_area": [ - "c/AD" + "ct/ADCAN" ], "languages": [ "cat" @@ -37,7 +37,7 @@ "name": "SD", "is_main": true, "broadcast_area": [ - "r/INT" + "r/WW" ], "languages": [ "eng" @@ -180,7 +180,7 @@ "name": "SD", "is_main": true, "broadcast_area": [ - "r/INT" + "r/WW" ], "languages": [ "nld" @@ -805,7 +805,7 @@ "name": "SD", "is_main": true, "broadcast_area": [ - "r/INT" + "r/WW" ], "languages": [], "timezones": [ diff --git a/tests/__data__/input/data/regions.json b/tests/__data__/input/data/regions.json index 0741930a13..9646031669 100644 --- a/tests/__data__/input/data/regions.json +++ b/tests/__data__/input/data/regions.json @@ -1 +1 @@ -[{"code":"AFR","name":"Africa","countries":["AO","BF","BI","BJ","BW","CD","CF","CG","CI","CM","CV","DJ","DZ","EG","EH","ER","ET","GA","GH","GM","GN","GQ","GW","KE","KM","LR","LS","LY","MA","MG","ML","MR","MU","MW","MZ","NA","NE","NG","RE","RW","SC","SD","SH","SL","SN","SO","SS","ST","SZ","TD","TF","TG","TN","TZ","UG","YT","ZA","ZM","ZW"]},{"code":"AMER","name":"Americas","countries":["AG","AI","AR","AW","BB","BL","BM","BO","BR","BS","BV","BZ","CA","CL","CO","CR","CU","CW","DM","DO","EC","FK","GD","GF","GL","GP","GS","GT","GY","HN","HT","JM","KN","KY","LC","MF","MQ","MS","MX","NI","PA","PE","PM","PR","PY","SR","SV","SX","TC","TT","US","UY","VC","VE","VG","VI"]},{"code":"APAC","name":"Asia-Pacific","countries":["AF","AS","AU","BD","BN","BT","CK","CN","FJ","FM","GU","ID","IN","JP","KH","KI","KP","KR","LA","LK","MH","MM","MN","MP","MV","MY","NC","NF","NP","NR","NU","NZ","PF","PG","PH","PK","PN","PW","SB","SG","TH","TK","TL","TO","TV","TW","VN","VU","WF","WS"]},{"code":"ARAB","name":"Arab world","countries":["AE","BH","DJ","DZ","EG","IQ","JO","KM","KW","LB","LY","MA","MR","OM","PS","QA","SA","SD","SO","SY","TN","YE"]},{"code":"ASEAN","name":"Association of Southeast Asian Nations","countries":["BN","KH","ID","LA","MY","MM","PH","SG","TH","VN"]},{"code":"ASIA","name":"Asia","countries":["AE","AF","AM","AZ","BD","BH","BN","BT","CN","CY","GE","ID","IL","IN","IQ","IR","JO","JP","KG","KH","KP","KR","KW","KZ","LA","LB","LK","MM","MN","MV","MY","NP","OM","PH","PK","PS","QA","RU","SA","SG","SY","TH","TJ","TL","TM","TR","TW","UZ","VN","YE"]},{"code":"CARIB","name":"Caribbean","countries":["AG","AI","AW","BB","BL","BS","CU","CW","DM","DO","GD","GP","HT","JM","KN","KY","LC","MF","MQ","MS","PR","SX","TC","TT","VC","VG","VI"]},{"code":"CAS","name":"Central Asia","countries":["KG","KZ","TJ","TM","UZ"]},{"code":"CENAMER","name":"Central America","countries":["BZ","CR","SV","GT","HN","NI","PA"]},{"code":"CIS","name":"Commonwealth of Independent States","countries":["AM","AZ","BY","KG","KZ","MD","RU","TJ","UZ"]},{"code":"EMEA","name":"Europe, the Middle East and Africa","countries":["AD","AE","AL","AM","AO","AT","AZ","BA","BE","BF","BG","BH","BI","BJ","BW","BY","CD","CF","CG","CH","CI","CM","CV","CY","CZ","DE","DJ","DK","DZ","EE","EG","EH","ER","ES","ET","FI","FR","GA","GE","GH","GM","GN","GQ","GR","GW","HR","HU","IE","IQ","IR","IS","IT","JO","KE","KM","KW","KZ","LB","LI","LR","LS","LT","LU","LV","LY","MA","MC","MD","ME","MG","MK","ML","MR","MT","MU","MW","MZ","NA","NE","NG","NL","NO","OM","PL","PS","PT","QA","RE","RO","RS","RU","RW","SA","SC","SD","SE","SH","SI","SK","SL","SM","SN","SO","SS","ST","SY","SZ","TD","TF","TG","TN","TR","TZ","UA","UG","UK","VA","YE","YT","ZA","ZM","ZW"]},{"code":"EUR","name":"Europe","countries":["AD","AL","AM","AT","AZ","BA","BE","BG","BY","CH","CY","CZ","DE","DK","EE","ES","FI","FR","GE","GR","HR","HU","IE","IS","IT","KZ","LI","LT","LU","LV","MC","MD","ME","MK","MT","NL","NO","PL","PT","RO","RS","RU","SE","SI","SK","SM","TR","UA","UK","VA"]},{"code":"HISPAM","name":"Hispanic America","countries":["AR","BO","CL","CO","CR","CU","DO","EC","GT","HN","MX","NI","PA","PE","PR","PY","SV","UY","VE"]},{"code":"INT","name":"Worldwide","countries":["AD","AE","AF","AG","AI","AL","AM","AO","AQ","AR","AS","AT","AU","AW","AX","AZ","BA","BB","BD","BE","BF","BG","BH","BI","BJ","BL","BM","BN","BO","BQ","BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD","CF","CG","CH","CI","CK","CL","CM","CN","CO","CR","CU","CV","CW","CX","CY","CZ","DE","DJ","DK","DM","DO","DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ","FK","FM","FO","FR","GA","UK","GD","GE","GF","GG","GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT","GU","GW","GY","HK","HM","HN","HR","HT","HU","ID","IE","IL","IM","IN","IO","IQ","IR","IS","IT","JE","JM","JO","JP","KE","KG","KH","KI","KM","KN","KP","KR","KW","KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT","LU","LV","LY","MA","MC","MD","ME","MF","MG","MH","MK","ML","MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV","MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI","NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF","PG","PH","PK","PL","PM","PN","PR","PS","PT","PW","PY","QA","RE","RO","RS","RU","RW","SA","SB","SC","SD","SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO","SR","SS","ST","SV","SX","SY","SZ","TC","TD","TF","TG","TH","TJ","TK","TL","TM","TN","TO","TR","TT","TV","TW","TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE","VG","VI","VN","VU","WF","WS","XK","YE","YT","ZA","ZM","ZW"]},{"code":"LAC","name":"Latin America and the Caribbean","countries":["AG","AI","AR","AW","BB","BL","BO","BR","BS","CL","CO","CR","CU","CW","DM","DO","EC","GD","GF","GP","GT","HN","HT","JM","KN","KY","LC","MF","MQ","MS","MX","NI","PA","PE","PR","PY","SV","SX","TC","TT","UY","VC","VE","VG","VI"]},{"code":"LATAM","name":"Latin America","countries":["AR","BL","BO","BR","CL","CO","CR","CU","DO","EC","GF","GP","GT","HN","HT","MF","MQ","MX","NI","PA","PE","PR","PY","SV","UY","VE"]},{"code":"MAGHREB","name":"Maghreb","countries":["DZ","LY","MA","MR","TN"]},{"code":"MENA","name":"Middle East and North Africa","countries":["AE","BH","CY","DJ","DZ","EG","EH","IL","IQ","IR","JO","KW","LB","LY","MA","OM","PS","QA","SA","SD","SY","TN","TR","YE"]},{"code":"MIDEAST","name":"Middle East","countries":["AE","BH","CY","EG","IL","IQ","IR","JO","KW","LB","OM","PS","QA","SA","SY","TR","YE"]},{"code":"NAM","name":"Northern America","countries":["BM","CA","GL","PM","US"]},{"code":"NORAM","name":"North America","countries":["AG","AI","AW","BB","BL","BM","BS","BZ","CA","CR","CU","CW","DM","DO","GD","GL","GP","GT","HN","HT","JM","KN","KY","LC","MF","MQ","MS","MX","NI","PA","PM","PR","SV","SX","TC","TT","US","VC","VG","VI"]},{"code":"NORD","name":"Nordics","countries":["AX","DK","FO","FI","IS","NO","SE"]},{"code":"OCE","name":"Oceania","countries":["AS","AU","CK","FJ","FM","GU","KI","MH","MP","NC","NF","NR","NU","NZ","PF","PG","PN","PW","SB","TK","TO","TV","VU","WF","WS"]},{"code":"SAS","name":"South Asia","countries":["AF","BD","BT","IN","LK","MV","NP","PK"]},{"code":"SOUTHAM","name":"South America","countries":["AR","BO","BR","CL","CO","EC","PY","PE","UY","VE","BV","FK","GF","GY","GS","SR"]},{"code":"SSA","name":"Sub-Saharan Africa","countries":["AO","BF","BI","BJ","BW","CD","CF","CG","CI","CM","CV","DJ","ER","ET","GA","GH","GM","GN","GQ","GW","KE","KM","LR","LS","MG","ML","MR","MU","MW","MZ","NA","NE","NG","RW","SC","SD","SL","SN","SO","SS","ST","SZ","TD","TG","TZ","UG","ZA","ZM","ZW"]},{"code":"WAFR","name":"West Africa","countries":["BF","BJ","CI","CV","GH","GM","GN","GW","LR","ML","MR","NE","NG","SH","SL","SN","TG"]}] \ No newline at end of file +[{"code":"AFR","name":"Africa","countries":["AO","BF","BI","BJ","BW","CD","CF","CG","CI","CM","CV","DJ","DZ","EG","EH","ER","ET","GA","GH","GM","GN","GQ","GW","KE","KM","LR","LS","LY","MA","MG","ML","MR","MU","MW","MZ","NA","NE","NG","RE","RW","SC","SD","SH","SL","SN","SO","SS","ST","SZ","TD","TF","TG","TN","TZ","UG","YT","ZA","ZM","ZW"]},{"code":"AMER","name":"Americas","countries":["AG","AI","AR","AW","BB","BL","BM","BO","BR","BS","BV","BZ","CA","CL","CO","CR","CU","CW","DM","DO","EC","FK","GD","GF","GL","GP","GS","GT","GY","HN","HT","JM","KN","KY","LC","MF","MQ","MS","MX","NI","PA","PE","PM","PR","PY","SR","SV","SX","TC","TT","US","UY","VC","VE","VG","VI"]},{"code":"APAC","name":"Asia-Pacific","countries":["AF","AS","AU","BD","BN","BT","CK","CN","FJ","FM","GU","ID","IN","JP","KH","KI","KP","KR","LA","LK","MH","MM","MN","MP","MV","MY","NC","NF","NP","NR","NU","NZ","PF","PG","PH","PK","PN","PW","SB","SG","TH","TK","TL","TO","TV","TW","VN","VU","WF","WS"]},{"code":"ARAB","name":"Arab world","countries":["AE","BH","DJ","DZ","EG","IQ","JO","KM","KW","LB","LY","MA","MR","OM","PS","QA","SA","SD","SO","SY","TN","YE"]},{"code":"ASEAN","name":"Association of Southeast Asian Nations","countries":["BN","KH","ID","LA","MY","MM","PH","SG","TH","VN"]},{"code":"ASIA","name":"Asia","countries":["AE","AF","AM","AZ","BD","BH","BN","BT","CN","CY","GE","ID","IL","IN","IQ","IR","JO","JP","KG","KH","KP","KR","KW","KZ","LA","LB","LK","MM","MN","MV","MY","NP","OM","PH","PK","PS","QA","RU","SA","SG","SY","TH","TJ","TL","TM","TR","TW","UZ","VN","YE"]},{"code":"CARIB","name":"Caribbean","countries":["AG","AI","AW","BB","BL","BS","CU","CW","DM","DO","GD","GP","HT","JM","KN","KY","LC","MF","MQ","MS","PR","SX","TC","TT","VC","VG","VI"]},{"code":"CAS","name":"Central Asia","countries":["KG","KZ","TJ","TM","UZ"]},{"code":"CENAMER","name":"Central America","countries":["BZ","CR","SV","GT","HN","NI","PA"]},{"code":"CIS","name":"Commonwealth of Independent States","countries":["AM","AZ","BY","KG","KZ","MD","RU","TJ","UZ"]},{"code":"EMEA","name":"Europe, the Middle East and Africa","countries":["AD","AE","AL","AM","AO","AT","AZ","BA","BE","BF","BG","BH","BI","BJ","BW","BY","CD","CF","CG","CH","CI","CM","CV","CY","CZ","DE","DJ","DK","DZ","EE","EG","EH","ER","ES","ET","FI","FR","GA","GE","GH","GM","GN","GQ","GR","GW","HR","HU","IE","IQ","IR","IS","IT","JO","KE","KM","KW","KZ","LB","LI","LR","LS","LT","LU","LV","LY","MA","MC","MD","ME","MG","MK","ML","MR","MT","MU","MW","MZ","NA","NE","NG","NL","NO","OM","PL","PS","PT","QA","RE","RO","RS","RU","RW","SA","SC","SD","SE","SH","SI","SK","SL","SM","SN","SO","SS","ST","SY","SZ","TD","TF","TG","TN","TR","TZ","UA","UG","UK","VA","YE","YT","ZA","ZM","ZW"]},{"code":"WW","name":"Worldwide","countries":["AD","AE","AF","AG","AI","AL","AM","AO","AQ","AR","AS","AT","AU","AW","AX","AZ","BA","BB","BD","BE","BF","BG","BH","BI","BJ","BL","BM","BN","BO","BQ","BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD","CF","CG","CH","CI","CK","CL","CM","CN","CO","CR","CU","CV","CW","CX","CY","CZ","DE","DJ","DK","DM","DO","DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ","FK","FM","FO","FR","GA","UK","GD","GE","GF","GG","GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT","GU","GW","GY","HK","HM","HN","HR","HT","HU","ID","IE","IL","IM","IN","IO","IQ","IR","IS","IT","JE","JM","JO","JP","KE","KG","KH","KI","KM","KN","KP","KR","KW","KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT","LU","LV","LY","MA","MC","MD","ME","MF","MG","MH","MK","ML","MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV","MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI","NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF","PG","PH","PK","PL","PM","PN","PR","PS","PT","PW","PY","QA","RE","RO","RS","RU","RW","SA","SB","SC","SD","SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO","SR","SS","ST","SV","SX","SY","SZ","TC","TD","TF","TG","TH","TJ","TK","TL","TM","TN","TO","TR","TT","TV","TW","TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE","VG","VI","VN","VU","WF","WS","XK","YE","YT","ZA","ZM","ZW"]},{"code":"EUR","name":"Europe","countries":["AD","AL","AM","AT","AZ","BA","BE","BG","BY","CH","CY","CZ","DE","DK","EE","ES","FI","FR","GE","GR","HR","HU","IE","IS","IT","KZ","LI","LT","LU","LV","MC","MD","ME","MK","MT","NL","NO","PL","PT","RO","RS","RU","SE","SI","SK","SM","TR","UA","UK","VA"]},{"code":"HISPAM","name":"Hispanic America","countries":["AR","BO","CL","CO","CR","CU","DO","EC","GT","HN","MX","NI","PA","PE","PR","PY","SV","UY","VE"]},{"code":"LAC","name":"Latin America and the Caribbean","countries":["AG","AI","AR","AW","BB","BL","BO","BR","BS","CL","CO","CR","CU","CW","DM","DO","EC","GD","GF","GP","GT","HN","HT","JM","KN","KY","LC","MF","MQ","MS","MX","NI","PA","PE","PR","PY","SV","SX","TC","TT","UY","VC","VE","VG","VI"]},{"code":"LATAM","name":"Latin America","countries":["AR","BL","BO","BR","CL","CO","CR","CU","DO","EC","GF","GP","GT","HN","HT","MF","MQ","MX","NI","PA","PE","PR","PY","SV","UY","VE"]},{"code":"MAGHREB","name":"Maghreb","countries":["DZ","LY","MA","MR","TN"]},{"code":"MENA","name":"Middle East and North Africa","countries":["AE","BH","CY","DJ","DZ","EG","EH","IL","IQ","IR","JO","KW","LB","LY","MA","OM","PS","QA","SA","SD","SY","TN","TR","YE"]},{"code":"MIDEAST","name":"Middle East","countries":["AE","BH","CY","EG","IL","IQ","IR","JO","KW","LB","OM","PS","QA","SA","SY","TR","YE"]},{"code":"NAM","name":"Northern America","countries":["BM","CA","GL","PM","US"]},{"code":"NORAM","name":"North America","countries":["AG","AI","AW","BB","BL","BM","BS","BZ","CA","CR","CU","CW","DM","DO","GD","GL","GP","GT","HN","HT","JM","KN","KY","LC","MF","MQ","MS","MX","NI","PA","PM","PR","SV","SX","TC","TT","US","VC","VG","VI"]},{"code":"NORD","name":"Nordics","countries":["AX","DK","FO","FI","IS","NO","SE"]},{"code":"OCE","name":"Oceania","countries":["AS","AU","CK","FJ","FM","GU","KI","MH","MP","NC","NF","NR","NU","NZ","PF","PG","PN","PW","SB","TK","TO","TV","VU","WF","WS"]},{"code":"SAS","name":"South Asia","countries":["AF","BD","BT","IN","LK","MV","NP","PK"]},{"code":"SOUTHAM","name":"South America","countries":["AR","BO","BR","CL","CO","EC","PY","PE","UY","VE","BV","FK","GF","GY","GS","SR"]},{"code":"SSA","name":"Sub-Saharan Africa","countries":["AO","BF","BI","BJ","BW","CD","CF","CG","CI","CM","CV","DJ","ER","ET","GA","GH","GM","GN","GQ","GW","KE","KM","LR","LS","MG","ML","MR","MU","MW","MZ","NA","NE","NG","RW","SC","SD","SL","SN","SO","SS","ST","SZ","TD","TG","TZ","UG","ZA","ZM","ZW"]},{"code":"WAFR","name":"West Africa","countries":["BF","BJ","CI","CV","GH","GM","GN","GW","LR","ML","MR","NE","NG","SH","SL","SN","TG"]}] \ No newline at end of file diff --git a/tests/__data__/input/readme_update/.readme/config.json b/tests/__data__/input/readme_update/.readme/config.json deleted file mode 100644 index e02806b642..0000000000 --- a/tests/__data__/input/readme_update/.readme/config.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "build" : "tests/__data__/output/playlists.md", - "files" : ["tests/__data__/output/.readme/template.md"] -} \ No newline at end of file diff --git a/tests/__data__/input/readme_update/.readme/template.md b/tests/__data__/input/readme_update/.readme/template.md deleted file mode 100644 index d1291f2f49..0000000000 --- a/tests/__data__/input/readme_update/.readme/template.md +++ /dev/null @@ -1,110 +0,0 @@ -# Playlists - -### Grouped by category - -
-Expand -
- -Playlist in which each channel has its _category_ as a group title: - -``` -https://iptv-org.github.io/iptv/index.category.m3u -``` - -Same thing, but split up into separate files: - - -#include "tests/__data__/output/.readme/_categories.md" - -
- -### Grouped by language - -
-Expand -
- -Playlist in which each channel has its _language_ as a group title: - -``` -https://iptv-org.github.io/iptv/index.language.m3u -``` - -Same thing, but split up into separate files: - - -#include "tests/__data__/output/.readme/_languages.md" - -
- -### Grouped by country - -
-Expand -
- -Playlist in which each channel has its _country_ as a group title: - -``` -https://iptv-org.github.io/iptv/index.country.m3u -``` - -Same thing, but split up into separate files: - - -#include "tests/__data__/output/.readme/_countries.md" - -
- -### Grouped by subdivision - -
-Expand -
- - -#include "tests/__data__/output/.readme/_subdivisions.md" - -
- -### Grouped by region - -
-Expand -
- -Playlist in which each channel has its _region_ as a group title: - -``` -https://iptv-org.github.io/iptv/index.region.m3u -``` - -Same thing, but split up into separate files: - - -#include "tests/__data__/output/.readme/_regions.md" - -
- -### Grouped by sources - -Playlists in which channels are grouped by broadcast source. - -
-Expand -
- -To use the playlist, simply replace `` in the link below with the name of one of the files in the [streams](streams) folder. - -``` -https://iptv-org.github.io/iptv/sources/.m3u -``` - -
- -Also, any of our internal playlists are available in raw form (without any filtering or sorting) at this link: - -``` -https://iptv-org.github.io/iptv/raw/.m3u -``` diff --git a/tests/__data__/input/readme_update/generators.log b/tests/__data__/input/readme_update/generators.log index 27beaa3641..de76b7f764 100644 --- a/tests/__data__/input/readme_update/generators.log +++ b/tests/__data__/input/readme_update/generators.log @@ -38,9 +38,12 @@ {"type":"country","filepath":"countries/cg.m3u","count":1} {"type":"country","filepath":"countries/ro.m3u","count":1} {"type":"subdivision","filepath":"subdivisions/ca-on.m3u","count":1} +{"type":"city","filepath":"cities/adcan.m3u","count":1} +{"type":"city","filepath":"cities/hk9sk.m3u","count":1} {"type":"country","filepath":"countries/ru.m3u","count":2} {"type":"country","filepath":"countries/rw.m3u","count":1} {"type":"country","filepath":"countries/re.m3u","count":1} +{"type":"country","filepath":"countries/int.m3u","count":3} {"type":"country","filepath":"countries/undefined.m3u","count":2} {"type":"country","filepath":"countries/bl.m3u","count":1} {"type":"country","filepath":"countries/sh.m3u","count":1} @@ -74,7 +77,6 @@ {"type":"region","filepath":"regions/oce.m3u","count":0} {"type":"region","filepath":"regions/undefined.m3u","count":2} {"type":"region","filepath":"regions/sas.m3u","count":1} -{"type":"region","filepath":"regions/int.m3u","count":1} {"type":"region","filepath":"regions/southam.m3u","count":0} {"type":"region","filepath":"regions/ssa.m3u","count":0} {"type":"region","filepath":"regions/wafr.m3u","count":0} \ No newline at end of file diff --git a/tests/commands/playlist/generate.test.ts b/tests/commands/playlist/generate.test.ts index 5489e54caa..39f38a8f36 100644 --- a/tests/commands/playlist/generate.test.ts +++ b/tests/commands/playlist/generate.test.ts @@ -4,7 +4,8 @@ import { EOL } from 'node:os' import * as fs from 'fs-extra' import * as glob from 'glob' -const ENV_VAR = 'cross-env STREAMS_DIR=tests/__data__/input/playlist_generate DATA_DIR=tests/__data__/input/data PUBLIC_DIR=tests/__data__/output/.gh-pages LOGS_DIR=tests/__data__/output/logs' +const ENV_VAR = + 'cross-env STREAMS_DIR=tests/__data__/input/playlist_generate DATA_DIR=tests/__data__/input/data PUBLIC_DIR=tests/__data__/output/.gh-pages LOGS_DIR=tests/__data__/output/logs' beforeEach(() => { fs.emptyDirSync('tests/__data__/output') @@ -26,7 +27,7 @@ describe('playlist:generate', () => { }) playlists.forEach((filepath: string) => { - expect(content(`tests/__data__/output/${filepath}`)).toBe( + expect(content(`tests/__data__/output/${filepath}`), filepath).toBe( content(`tests/__data__/expected/playlist_generate/${filepath}`) ) }) diff --git a/tests/commands/readme/update.test.ts b/tests/commands/readme/update.test.ts index 87af269728..8031c8737e 100644 --- a/tests/commands/readme/update.test.ts +++ b/tests/commands/readme/update.test.ts @@ -2,19 +2,11 @@ import { pathToFileURL } from 'node:url' import { execSync } from 'child_process' import fs from 'fs-extra' -const ENV_VAR = 'cross-env DATA_DIR=tests/__data__/input/data LOGS_DIR=tests/__data__/input/readme_update README_DIR=tests/__data__/output/.readme' +const ENV_VAR = + 'cross-env DATA_DIR=tests/__data__/input/data LOGS_DIR=tests/__data__/input/readme_update ROOT_DIR=tests/__data__/output' beforeEach(() => { fs.emptyDirSync('tests/__data__/output') - fs.mkdirSync('tests/__data__/output/.readme') - fs.copyFileSync( - 'tests/__data__/input/readme_update/.readme/config.json', - 'tests/__data__/output/.readme/config.json' - ) - fs.copyFileSync( - 'tests/__data__/input/readme_update/.readme/template.md', - 'tests/__data__/output/.readme/template.md' - ) }) describe('readme:update', () => { @@ -23,8 +15,8 @@ describe('readme:update', () => { const stdout = execSync(cmd, { encoding: 'utf8' }) if (process.env.DEBUG === 'true') console.log(cmd, stdout) - expect(content('tests/__data__/output/playlists.md')).toEqual( - content('tests/__data__/expected/readme_update/playlists.md') + expect(content('tests/__data__/output/PLAYLISTS.md')).toEqual( + content('tests/__data__/expected/readme_update/PLAYLISTS.md') ) }) })