From 1c0e6250b75911922816c7919b47a43b76a63200 Mon Sep 17 00:00:00 2001 From: freearhey Date: Fri, 29 Jan 2021 21:30:54 +0300 Subject: [PATCH 01/36] Update format.js Pass playlist to createChannel() --- scripts/format.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/format.js b/scripts/format.js index 8edd4682cb..10c9fa981e 100644 --- a/scripts/format.js +++ b/scripts/format.js @@ -68,7 +68,7 @@ async function loadPlaylist(url) { playlist.url = url playlist.items = playlist.items .map(item => { - return helper.createChannel(item) + return helper.createChannel(item, playlist) }) .filter(i => i.url) From 93302ce7846d713b12f60818163ec2ce8951619d Mon Sep 17 00:00:00 2001 From: freearhey Date: Fri, 29 Jan 2021 21:30:58 +0300 Subject: [PATCH 02/36] Update generate.js --- scripts/generate.js | 91 ++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 47 deletions(-) diff --git a/scripts/generate.js b/scripts/generate.js index 9c42b54b60..89b1c8e4ac 100644 --- a/scripts/generate.js +++ b/scripts/generate.js @@ -54,60 +54,57 @@ function createNoJekyllFile() { function parseIndex() { const root = helper.parsePlaylist('index.m3u') - let countries = {} - let languages = {} - let categories = {} - for (let rootItem of root.items) { const playlist = helper.parsePlaylist(rootItem.url) - const countryCode = helper.getBasename(rootItem.url).toLowerCase() - const countryName = rootItem.name - for (let item of playlist.items) { - const channel = helper.createChannel(item) + const channel = helper.createChannel(item, playlist) if (!channel.url) continue - channel.country.code = countryCode - channel.country.name = countryName - channel.tvg.url = playlist.header.attrs['x-tvg-url'] || '' // all list.all.push(channel) // country - if (!countries[countryCode]) { - countries[countryCode] = [] + if (!channel.countries.length) { + const countryCode = 'undefined' + if (!list.countries[countryCode]) { + list.countries[countryCode] = [] + } + list.countries[countryCode].push(channel) + } else { + for (let country of channel.countries) { + const countryCode = country.code || 'undefined' + if (!list.countries[countryCode]) { + list.countries[countryCode] = [] + } + list.countries[countryCode].push(channel) + } } - countries[countryCode].push(channel) // language if (!channel.language.length) { const languageCode = 'undefined' - if (!languages[languageCode]) { - languages[languageCode] = [] + if (!list.languages[languageCode]) { + list.languages[languageCode] = [] } - languages[languageCode].push(channel) + list.languages[languageCode].push(channel) } else { for (let language of channel.language) { const languageCode = language.code || 'undefined' - if (!languages[languageCode]) { - languages[languageCode] = [] + if (!list.languages[languageCode]) { + list.languages[languageCode] = [] } - languages[languageCode].push(channel) + list.languages[languageCode].push(channel) } } // category const categoryCode = channel.category ? channel.category.toLowerCase() : 'other' - if (!categories[categoryCode]) { - categories[categoryCode] = [] + if (!list.categories[categoryCode]) { + list.categories[categoryCode] = [] } - categories[categoryCode].push(channel) + list.categories[categoryCode].push(channel) } } - - list.countries = countries - list.languages = languages - list.categories = categories } function generateIndex() { @@ -142,10 +139,10 @@ function generateCountryIndex() { const filename = `${ROOT_DIR}/index.country.m3u` helper.createFile(filename, '#EXTM3U\n') - const channels = helper.sortBy(list.all, ['country.name', 'name', 'url']) + const channels = helper.sortBy(list.all, ['countryName', 'name', 'url']) for (let channel of channels) { const category = channel.category - channel.category = channel.country.name + channel.category = channel.countries.map(c => c.name).join(';') helper.appendToFile(filename, channel.toString()) channel.category = category } @@ -155,10 +152,10 @@ function generateLanguageIndex() { const filename = `${ROOT_DIR}/index.language.m3u` helper.createFile(filename, '#EXTM3U\n') - const channels = helper.sortBy(list.all, ['language.name', 'name', 'url']) + const channels = helper.sortBy(list.all, ['languageName', 'name', 'url']) for (let channel of channels) { const category = channel.category - channel.category = channel.language.map(l => l.name).join(';') + channel.category = channel.getLanguageAttribute() helper.appendToFile(filename, channel.toString()) channel.category = category } @@ -190,6 +187,22 @@ function generateCountries() { } } +function generateLanguages() { + const outputDir = `${ROOT_DIR}/languages` + helper.createDir(outputDir) + + for (let lid in list.languages) { + let language = list.languages[lid] + const filename = `${outputDir}/${lid}.m3u` + helper.createFile(filename, '#EXTM3U\n') + + const channels = helper.sortBy(Object.values(language), ['name', 'url']) + for (let channel of channels) { + helper.appendToFile(filename, channel.toString()) + } + } +} + function generateCategories() { const outputDir = `${ROOT_DIR}/categories` helper.createDir(outputDir) @@ -207,20 +220,4 @@ function generateCategories() { } } -function generateLanguages() { - const outputDir = `${ROOT_DIR}/languages` - helper.createDir(outputDir) - - for (let lid in list.languages) { - let language = list.languages[lid] - const filename = `${outputDir}/${lid}.m3u` - helper.createFile(filename, '#EXTM3U\n') - - const channels = helper.sortBy(Object.values(language), ['name', 'url']) - for (let channel of channels) { - helper.appendToFile(filename, channel.toString()) - } - } -} - main() From 4543a25bd7b60c0050d8b83962fa1b0b6f95aa1d Mon Sep 17 00:00:00 2001 From: freearhey Date: Fri, 29 Jan 2021 21:31:00 +0300 Subject: [PATCH 03/36] Update helper.js --- scripts/helper.js | 85 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 23 deletions(-) diff --git a/scripts/helper.js b/scripts/helper.js index fedc1eed92..883fb3c53f 100644 --- a/scripts/helper.js +++ b/scripts/helper.js @@ -8,6 +8,10 @@ const urlParser = require('url') const escapeStringRegexp = require('escape-string-regexp') const markdownInclude = require('markdown-include') const iso6393 = require('iso-639-3') +const intlDisplayNames = new Intl.DisplayNames(['en'], { + style: 'long', + type: 'region' +}) let helper = {} @@ -105,14 +109,15 @@ helper.getISO6391Code = function (name) { helper.parsePlaylist = function (filename) { const content = this.readFile(filename) const result = playlistParser.parse(content) + const playlist = new Playlist(result) + playlist.url = filename - return new Playlist(result) + return playlist } helper.parseEPG = async function (url) { return this.getEPG(url).then(content => { const result = epgParser.parse(content) - console.log('wo') const channels = {} for (let channel of result.channels) { channels[channel.id] = channel @@ -211,8 +216,8 @@ helper.generateTable = function (data, options) { return output } -helper.createChannel = function (data) { - return new Channel(data) +helper.createChannel = function (data, parent) { + return new Channel(data, parent) } helper.writeToLog = function (country, msg, url) { @@ -282,6 +287,17 @@ helper.sleep = function (ms) { } } +helper.code2country = function (code) { + code = code ? code.toLowerCase() : '' + if (code === 'int') { + return { code: 'int', name: 'International' } + } else if (code === 'unsorted') { + return null + } + + return { code, name: intlDisplayNames.of(code.toUpperCase()) } +} + class Playlist { constructor(data) { this.header = data.header @@ -302,11 +318,12 @@ class Playlist { } class Channel { - constructor(data) { - this.parseData(data) + constructor(data, parent) { + this.parseData(data, parent) } - parseData(data) { + parseData(data, parent) { + this.source = helper.getBasename(parent.url) this.logo = data.tvg.logo this.category = helper.filterGroup(data.group.title) this.url = data.url @@ -314,21 +331,34 @@ class Channel { this.status = this.parseStatus(data.name) this.http = data.http this.tvg = data.tvg - this.country = { - code: null, - name: null - } + this.tvg.url = parent.header.attrs['x-tvg-url'] || '' + this.countries = this.parseCountries(data.tvg.country) this.resolution = this.parseResolution(data.name) - - this.setLanguage(data.tvg.language) + this.language = this.parseLanguage(data.tvg.language) } - get ['language.name']() { + get languageName() { return this.language[0] ? this.language[0].name : null } - get ['country.name']() { - return this.country.name || null + get countryName() { + return this.countries[0] ? this.countries[0].name : null + } + + get countryCode() { + return this.countries[0] ? this.countries[0].code : null + } + + parseCountries(value) { + if (!value) { + const country = helper.code2country(this.source) + return country ? [country] : [] + } + + return value + .split(';') + .filter(i => i) + .map(helper.code2country) } parseName(title) { @@ -359,8 +389,8 @@ class Channel { } } - setLanguage(lang) { - this.language = lang + parseLanguage(lang) { + return lang .split(';') .map(name => { const code = name ? helper.getISO6391Code(name) : null @@ -374,10 +404,18 @@ class Channel { .filter(l => l) } + getCountryAttribute() { + return this.countries.map(c => c.code.toUpperCase()).join(';') + } + + getLanguageAttribute() { + return this.language.map(l => l.name).join(';') + } + toString() { - const country = this.country.code ? this.country.code.toUpperCase() : '' + const country = this.getCountryAttribute() + const language = this.getLanguageAttribute() const tvgUrl = (this.tvg.id || this.tvg.name) && this.tvg.url ? this.tvg.url : '' - const language = this.language.map(l => l.name).join(';') const resolution = this.resolution.height ? ` (${this.resolution.height}p)` : '' const status = this.status ? ` [${this.status}]` : '' @@ -395,11 +433,12 @@ class Channel { } toShortString() { - const language = this.language.map(l => l.name).join(';') + const country = this.getCountryAttribute() + const language = this.getLanguageAttribute() const resolution = this.resolution.height ? ` (${this.resolution.height}p)` : '' const status = this.status ? ` [${this.status}]` : '' - let info = `-1 tvg-id="${this.tvg.id}" tvg-name="${this.tvg.name}" tvg-language="${language}" tvg-logo="${this.logo}" group-title="${this.category}",${this.name}${resolution}${status}` + let info = `-1 tvg-id="${this.tvg.id}" tvg-name="${this.tvg.name}" tvg-language="${language}" tvg-logo="${this.logo}" tvg-country="${country}" group-title="${this.category}",${this.name}${resolution}${status}` if (this.http['referrer']) { info += `\n#EXTVLCOPT:http-referrer=${this.http['referrer']}` @@ -419,7 +458,7 @@ class Channel { url: this.url, category: this.category || null, language: this.language, - country: this.country, + countries: this.countries, tvg: { id: this.tvg.id || null, name: this.tvg.name || null, From 47d03d7f58412f8b0f1f72b666e1dd9ce08e67b3 Mon Sep 17 00:00:00 2001 From: freearhey Date: Fri, 29 Jan 2021 21:35:20 +0300 Subject: [PATCH 04/36] Update index.m3u Removed link to int.m3u --- index.m3u | 2 -- 1 file changed, 2 deletions(-) diff --git a/index.m3u b/index.m3u index d727ae7264..f034a2845b 100644 --- a/index.m3u +++ b/index.m3u @@ -135,8 +135,6 @@ channels/is.m3u channels/in.m3u #EXTINF:-1,Indonesia channels/id.m3u -#EXTINF:-1,International -channels/int.m3u #EXTINF:-1,Iran channels/ir.m3u #EXTINF:-1,Iraq From f1bebbdf1458f29d610cd7e5a6e92a905f673595 Mon Sep 17 00:00:00 2001 From: freearhey Date: Fri, 29 Jan 2021 21:38:02 +0300 Subject: [PATCH 05/36] Update unsorted.m3u Moved the contents of int.m3u to unsorted.m3u --- channels/unsorted.m3u | 144 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/channels/unsorted.m3u b/channels/unsorted.m3u index 48aab1fe76..dba1f58a1c 100644 --- a/channels/unsorted.m3u +++ b/channels/unsorted.m3u @@ -417,3 +417,147 @@ https://www.livestreamcdn.net:444/ExtremaTV/_definst_/ExtremaTV/chunklist_w75593 https://y5w8j4a9.ssl.hwcdn.net/mundohd/tracks-v1a1/index.m3u8 #EXTINF:-1 tvg-id="" tvg-name="" tvg-language="" tvg-logo="" group-title="",Дорама http://sc.id-tv.kz:80/dorama_hd_34_35.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Anal" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Anal +http://cdn.adultiptv.net/anal.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Asian" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Asian +http://cdn.adultiptv.net/asian.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Big Ass" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Big Ass +http://cdn.adultiptv.net/bigass.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Big Dick" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Big Dick +http://cdn.adultiptv.net/bigdick.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Big Tits" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Big Tits +http://cdn.adultiptv.net/bigtits.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Blonde" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Blonde +http://cdn.adultiptv.net/blonde.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Blowjob" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Blowjob +http://cdn.adultiptv.net/blowjob.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Brunette" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Brunette +http://cdn.adultiptv.net/brunette.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Compilation" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Compilation +http://cdn.adultiptv.net/compilation.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Cuckold" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Cuckold +http://cdn.adultiptv.net/cuckold.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Fetish" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Fetish +http://cdn.adultiptv.net/fetish.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Gangbang" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Gangbang +http://cdn.adultiptv.net/gangbang.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Gay" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Gay +http://cdn.adultiptv.net/gay.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Hardcore" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Hardcore +http://cdn.adultiptv.net/hardcore.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Interracial" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Interracial +http://cdn.adultiptv.net/interracial.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Latina" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Latina +http://cdn.adultiptv.net/latina.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Lesbian" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Lesbian +http://cdn.adultiptv.net/lesbian.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Live Cams" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Live Cams +http://cdn.adultiptv.net/livecams.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net MILF" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net MILF +http://cdn.adultiptv.net/milf.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Pornstar" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Pornstar +http://cdn.adultiptv.net/pornstar.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net POV" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net POV +http://cdn.adultiptv.net/pov.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Rough" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Rough +http://cdn.adultiptv.net/rough.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Russian" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Russian +http://cdn.adultiptv.net/russian.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Teen" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Teen +http://cdn.adultiptv.net/teen.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Threesome" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Threesome +http://cdn.adultiptv.net/threesome.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/HL7fwzt.png" group-title="Sport",Adventure Sports TV (360p) +https://gizmeon.s.llnwi.net/channellivev3/live/master.m3u8?channel=275 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/HL7fwzt.png" group-title="",Afrobeats +https://stream.ecable.tv/afrobeats/tracks-v1a1/mono.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",ANAL +http://nruxmzi.ojswi5dsmftgm2ldfz4hs6q.cmle.ru/anal.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 1 (HD) +https://www.ast.tv/stream/1/ultra.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 1 (HQ) +https://www.ast.tv/stream/1/high.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 1 (LQ) +https://www.ast.tv/stream/1/normal.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 1 (PC) (1080p) +http://www.ast.tv/stream/1/master.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 1 (Phone) +http://www.ast.tv/stream/1/cellular.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 2 (Cellular) +http://www.ast.tv/stream/2/cellular.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 2 (HD) +https://www.ast.tv/stream/2/ultra.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 2 (HQ) +https://www.ast.tv/stream/2/high.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 2 (LQ) +https://www.ast.tv/stream/2/normal.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 2 (PC) (1080p) +http://www.ast.tv/stream/2/master.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="Arabic" tvg-logo="https://i.imgur.com/4s1NlRf.jpg" group-title="Religious",Chaine Nord Africaine (360p) +https://live.creacast.com/cna/smil:cna.smil/chunklist.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/tXTjWgP.png" group-title="Religious",Christian Youth Channel (1080p) +http://media.smc-host.com:1935/cycnow.com/cyc2/playlist.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",Nyx Media +https://5a2a51fc4cfde.streamlock.net/free/_definst_/Stream1/chunklist_w805691612.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="Red Bull TV" tvg-language="English" tvg-logo="https://i.imgur.com/7NeBmWX.jpg" group-title="Sport",Red Bull TV (1080p) +https://dms.redbull.tv/v3/linear-borb/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjYXRlZ29yeSI6InBlcnNvbmFsX2NvbXB1dGVyIiwiY291bnRyeV9jb2RlIjoidXMiLCJleHBpcmVzIjoiMjAxNy0wOS0xNlQxNzo0NjowMy45NjM0NjI4NDJaIiwib3NfZmFtaWx5IjoiaHR0cCIsInJlbW90ZV9pcCI6IjEwLjE1Ny4xMTIuMTQ4IiwidWEiOiJNb3ppbGxhLzUuMCAoTWFjaW50b3NoOyBJbnRlbCBNYWMgT1MgWCAxMF8xMl81KSBBcHBsZVdlYktpdC82MDMuMi40IChLSFRNTCwgbGlrZSBHZWNrbykgVmVyc2lvbi8xMC4xLjEgU2FmYXJpLzYwMy4yLjQiLCJ1aWQiOiJkOGZiZWYzMC0yZDhhLTQwYTUtOGNjNy0wNzgxNGJhMTliNzMifQ.Q_38FNpW3so5yrA5FQt9qBuix3dTulKpb6uQ0dRjrtY/playlist.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="Red Bull TV" tvg-language="English" tvg-logo="https://i.imgur.com/7NeBmWX.jpg" group-title="Sport",Red Bull TV (1080p) +https://rbmn-live.akamaized.net/hls/live/590964/BoRB-AT/master.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="Sport",Red Bull TV +https://rbmn-live.akamaized.net/hls/live/590964/BoRB-AT/master_1660.m3u8?xtreamiptv.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="Sport",Red Bull TV +https://rbmn-live.akamaized.net/hls/live/590964/BoRB-AT/master_3360.m3u8?denmstv.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="Red Bull TV" tvg-language="English" tvg-logo="https://i.imgur.com/7NeBmWX.jpg" group-title="Sport",Red Bull TV (Canberra / AU) (1080p) +https://i.mjh.nz/au/Canberra/tv.redbull.tv.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="Red Bull TV" tvg-language="English" tvg-logo="https://i.imgur.com/7NeBmWX.jpg" group-title="Sport",Red Bull TV (Melbourne / AU) (1080p) +https://i.mjh.nz/au/Melbourne/tv.redbull.tv.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="Red Bull TV" tvg-language="English" tvg-logo="https://i.imgur.com/7NeBmWX.jpg" group-title="Sport",Red Bull TV (NZ) (1080p) +https://i.mjh.nz/nz/tv.redbull.tv.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Big Ass +http://live.redtraffic.xyz/bigass.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Big Dick +http://live.redtraffic.xyz/bigdick.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Big Tits +http://live.redtraffic.xyz/bigtits.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Blowjob +http://live.redtraffic.xyz/blowjob.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Cuckold +http://live.redtraffic.xyz/cuckold.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Fetish +http://live.redtraffic.xyz/fetish.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Gangbang +http://live.redtraffic.net/gangbang.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Hardcore +http://live.redtraffic.xyz/hardcore.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Interracial +http://live.redtraffic.xyz/interracial.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Latina +http://live.redtraffic.xyz/latina.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Lesbian +http://live.redtraffic.xyz/lesbian.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Milf +http://live.redtraffic.xyz/milf.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Pornstars +http://live.redtraffic.xyz/pornstar.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic POV +http://live.redtraffic.xyz/pov.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Russian +http://live.redtraffic.xyz/russian.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Teen +http://live.redtraffic.xyz/teen.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Threesome +http://live.redtraffic.xyz/threesome.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Woman +http://live.redtraffic.net/woman.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/826gz7r.jpg" group-title="",Silence TV (720p) +http://93.190.140.42:8081/SilenceTV/live/playlist.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/ygkBFYT.jpg" group-title="",Swamiji TV (720p) +https://stream.swamiji.tv/YogaIPTV/smil:YogaStream.smil/playlist.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/5uIXfol.jpg" group-title="",The Boat Show +https://a.jsrdn.com/broadcast/22706/+0000/hi/c.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/lPyJhBN.png" group-title="News",UN Web TV (540p) +https://bcliveunivsecure-lh.akamaihd.net/i/un150_A1_1@575439/master.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/Ll6GlqY.png" group-title="Music",V2BEAT TV (720p) +https://de1se01.v2beat.live/playlist.m3u8 +#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="Persian" tvg-logo="https://i.imgur.com/x6vlBzd.jpg" group-title="",YourTime TV +https://hls.yourtime.live/hls/stream.m3u8 From b0c8741746be773ee89e3bf8d69d5797fb78f3c4 Mon Sep 17 00:00:00 2001 From: freearhey Date: Fri, 29 Jan 2021 21:38:05 +0300 Subject: [PATCH 06/36] Delete int.m3u --- channels/int.m3u | 145 ----------------------------------------------- 1 file changed, 145 deletions(-) delete mode 100644 channels/int.m3u diff --git a/channels/int.m3u b/channels/int.m3u deleted file mode 100644 index b3b83de647..0000000000 --- a/channels/int.m3u +++ /dev/null @@ -1,145 +0,0 @@ -#EXTM3U -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Anal" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Anal -http://cdn.adultiptv.net/anal.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Asian" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Asian -http://cdn.adultiptv.net/asian.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Big Ass" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Big Ass -http://cdn.adultiptv.net/bigass.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Big Dick" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Big Dick -http://cdn.adultiptv.net/bigdick.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Big Tits" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Big Tits -http://cdn.adultiptv.net/bigtits.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Blonde" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Blonde -http://cdn.adultiptv.net/blonde.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Blowjob" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Blowjob -http://cdn.adultiptv.net/blowjob.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Brunette" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Brunette -http://cdn.adultiptv.net/brunette.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Compilation" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Compilation -http://cdn.adultiptv.net/compilation.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Cuckold" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Cuckold -http://cdn.adultiptv.net/cuckold.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Fetish" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Fetish -http://cdn.adultiptv.net/fetish.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Gangbang" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Gangbang -http://cdn.adultiptv.net/gangbang.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Gay" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Gay -http://cdn.adultiptv.net/gay.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Hardcore" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Hardcore -http://cdn.adultiptv.net/hardcore.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Interracial" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Interracial -http://cdn.adultiptv.net/interracial.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Latina" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Latina -http://cdn.adultiptv.net/latina.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Lesbian" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Lesbian -http://cdn.adultiptv.net/lesbian.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Live Cams" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Live Cams -http://cdn.adultiptv.net/livecams.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net MILF" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net MILF -http://cdn.adultiptv.net/milf.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Pornstar" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Pornstar -http://cdn.adultiptv.net/pornstar.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net POV" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net POV -http://cdn.adultiptv.net/pov.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Rough" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Rough -http://cdn.adultiptv.net/rough.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Russian" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Russian -http://cdn.adultiptv.net/russian.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Teen" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Teen -http://cdn.adultiptv.net/teen.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="AdultIPTV.net Threesome" tvg-language="English" tvg-logo="https://files.adultiptv.net/adultiptvnet.jpg" group-title="XXX",AdultIPTV.net Threesome -http://cdn.adultiptv.net/threesome.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/HL7fwzt.png" group-title="Sport",Adventure Sports TV (360p) -https://gizmeon.s.llnwi.net/channellivev3/live/master.m3u8?channel=275 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/HL7fwzt.png" group-title="",Afrobeats -https://stream.ecable.tv/afrobeats/tracks-v1a1/mono.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",ANAL -http://nruxmzi.ojswi5dsmftgm2ldfz4hs6q.cmle.ru/anal.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 1 (HD) -https://www.ast.tv/stream/1/ultra.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 1 (HQ) -https://www.ast.tv/stream/1/high.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 1 (LQ) -https://www.ast.tv/stream/1/normal.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 1 (PC) (1080p) -http://www.ast.tv/stream/1/master.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 1 (Phone) -http://www.ast.tv/stream/1/cellular.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 2 (Cellular) -http://www.ast.tv/stream/2/cellular.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 2 (HD) -https://www.ast.tv/stream/2/ultra.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 2 (HQ) -https://www.ast.tv/stream/2/high.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 2 (LQ) -https://www.ast.tv/stream/2/normal.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/KmokZz8.jpg" group-title="XXX",AST TV 2 (PC) (1080p) -http://www.ast.tv/stream/2/master.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="Arabic" tvg-logo="https://i.imgur.com/4s1NlRf.jpg" group-title="Religious",Chaine Nord Africaine (360p) -https://live.creacast.com/cna/smil:cna.smil/chunklist.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/tXTjWgP.png" group-title="Religious",Christian Youth Channel (1080p) -http://media.smc-host.com:1935/cycnow.com/cyc2/playlist.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",Nyx Media -https://5a2a51fc4cfde.streamlock.net/free/_definst_/Stream1/chunklist_w805691612.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="Red Bull TV" tvg-language="English" tvg-logo="https://i.imgur.com/7NeBmWX.jpg" group-title="Sport",Red Bull TV (1080p) -https://dms.redbull.tv/v3/linear-borb/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjYXRlZ29yeSI6InBlcnNvbmFsX2NvbXB1dGVyIiwiY291bnRyeV9jb2RlIjoidXMiLCJleHBpcmVzIjoiMjAxNy0wOS0xNlQxNzo0NjowMy45NjM0NjI4NDJaIiwib3NfZmFtaWx5IjoiaHR0cCIsInJlbW90ZV9pcCI6IjEwLjE1Ny4xMTIuMTQ4IiwidWEiOiJNb3ppbGxhLzUuMCAoTWFjaW50b3NoOyBJbnRlbCBNYWMgT1MgWCAxMF8xMl81KSBBcHBsZVdlYktpdC82MDMuMi40IChLSFRNTCwgbGlrZSBHZWNrbykgVmVyc2lvbi8xMC4xLjEgU2FmYXJpLzYwMy4yLjQiLCJ1aWQiOiJkOGZiZWYzMC0yZDhhLTQwYTUtOGNjNy0wNzgxNGJhMTliNzMifQ.Q_38FNpW3so5yrA5FQt9qBuix3dTulKpb6uQ0dRjrtY/playlist.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="Red Bull TV" tvg-language="English" tvg-logo="https://i.imgur.com/7NeBmWX.jpg" group-title="Sport",Red Bull TV (1080p) -https://rbmn-live.akamaized.net/hls/live/590964/BoRB-AT/master.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="Sport",Red Bull TV -https://rbmn-live.akamaized.net/hls/live/590964/BoRB-AT/master_1660.m3u8?xtreamiptv.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="Sport",Red Bull TV -https://rbmn-live.akamaized.net/hls/live/590964/BoRB-AT/master_3360.m3u8?denmstv.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="Red Bull TV" tvg-language="English" tvg-logo="https://i.imgur.com/7NeBmWX.jpg" group-title="Sport",Red Bull TV (Canberra / AU) (1080p) -https://i.mjh.nz/au/Canberra/tv.redbull.tv.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="Red Bull TV" tvg-language="English" tvg-logo="https://i.imgur.com/7NeBmWX.jpg" group-title="Sport",Red Bull TV (Melbourne / AU) (1080p) -https://i.mjh.nz/au/Melbourne/tv.redbull.tv.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="Red Bull TV" tvg-language="English" tvg-logo="https://i.imgur.com/7NeBmWX.jpg" group-title="Sport",Red Bull TV (NZ) (1080p) -https://i.mjh.nz/nz/tv.redbull.tv.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Big Ass -http://live.redtraffic.xyz/bigass.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Big Dick -http://live.redtraffic.xyz/bigdick.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Big Tits -http://live.redtraffic.xyz/bigtits.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Blowjob -http://live.redtraffic.xyz/blowjob.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Cuckold -http://live.redtraffic.xyz/cuckold.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Fetish -http://live.redtraffic.xyz/fetish.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Gangbang -http://live.redtraffic.net/gangbang.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Hardcore -http://live.redtraffic.xyz/hardcore.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Interracial -http://live.redtraffic.xyz/interracial.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Latina -http://live.redtraffic.xyz/latina.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Lesbian -http://live.redtraffic.xyz/lesbian.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Milf -http://live.redtraffic.xyz/milf.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Pornstars -http://live.redtraffic.xyz/pornstar.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic POV -http://live.redtraffic.xyz/pov.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Russian -http://live.redtraffic.xyz/russian.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Teen -http://live.redtraffic.xyz/teen.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Threesome -http://live.redtraffic.xyz/threesome.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="" group-title="XXX",RedTraffic Woman -http://live.redtraffic.net/woman.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/826gz7r.jpg" group-title="",Silence TV (720p) -http://93.190.140.42:8081/SilenceTV/live/playlist.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/ygkBFYT.jpg" group-title="",Swamiji TV (720p) -https://stream.swamiji.tv/YogaIPTV/smil:YogaStream.smil/playlist.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/5uIXfol.jpg" group-title="",The Boat Show -https://a.jsrdn.com/broadcast/22706/+0000/hi/c.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/lPyJhBN.png" group-title="News",UN Web TV (540p) -https://bcliveunivsecure-lh.akamaihd.net/i/un150_A1_1@575439/master.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="English" tvg-logo="https://i.imgur.com/Ll6GlqY.png" group-title="Music",V2BEAT TV (720p) -https://de1se01.v2beat.live/playlist.m3u8 -#EXTINF:-1 tvg-id="" tvg-name="" tvg-language="Persian" tvg-logo="https://i.imgur.com/x6vlBzd.jpg" group-title="",YourTime TV -https://hls.yourtime.live/hls/stream.m3u8 From ee90fcb3d22fab2282ddfc4ad1271082b9fe1c50 Mon Sep 17 00:00:00 2001 From: freearhey Date: Fri, 29 Jan 2021 22:16:18 +0300 Subject: [PATCH 07/36] Update format.js --- scripts/format.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/format.js b/scripts/format.js index 10c9fa981e..3466df4412 100644 --- a/scripts/format.js +++ b/scripts/format.js @@ -172,8 +172,8 @@ async function updateFromEPG(playlist) { if (!channel.tvg.name && epgItem.name.length) { channel.tvg.name = epgItem.name[0].value } - if (!channel.language.length && epgItem.name.length && epgItem.name[0].lang) { - channel.setLanguage(epgItem.name[0].lang) + if (!channel.languages.length && epgItem.name.length && epgItem.name[0].lang) { + channel.languages = helper.parseLanguages(epgItem.name[0].lang) } if (!channel.logo && epgItem.icon.length) { channel.logo = epgItem.icon[0] From c0711e3196ecfc85287159e0c749c04efd375090 Mon Sep 17 00:00:00 2001 From: freearhey Date: Fri, 29 Jan 2021 22:16:33 +0300 Subject: [PATCH 08/36] Update generate.js --- scripts/generate.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/generate.js b/scripts/generate.js index 89b1c8e4ac..f8a6d55aef 100644 --- a/scripts/generate.js +++ b/scripts/generate.js @@ -81,14 +81,14 @@ function parseIndex() { } // language - if (!channel.language.length) { + if (!channel.languages.length) { const languageCode = 'undefined' if (!list.languages[languageCode]) { list.languages[languageCode] = [] } list.languages[languageCode].push(channel) } else { - for (let language of channel.language) { + for (let language of channel.languages) { const languageCode = language.code || 'undefined' if (!list.languages[languageCode]) { list.languages[languageCode] = [] @@ -139,7 +139,7 @@ function generateCountryIndex() { const filename = `${ROOT_DIR}/index.country.m3u` helper.createFile(filename, '#EXTM3U\n') - const channels = helper.sortBy(list.all, ['countryName', 'name', 'url']) + const channels = helper.sortBy(list.all, ['countryAttribute', 'name', 'url']) for (let channel of channels) { const category = channel.category channel.category = channel.countries.map(c => c.name).join(';') @@ -152,7 +152,7 @@ function generateLanguageIndex() { const filename = `${ROOT_DIR}/index.language.m3u` helper.createFile(filename, '#EXTM3U\n') - const channels = helper.sortBy(list.all, ['languageName', 'name', 'url']) + const channels = helper.sortBy(list.all, ['languageAttribute', 'name', 'url']) for (let channel of channels) { const category = channel.category channel.category = channel.getLanguageAttribute() From 094dc1f52f4d396c110a66f2459da5a37f64f703 Mon Sep 17 00:00:00 2001 From: freearhey Date: Fri, 29 Jan 2021 22:16:40 +0300 Subject: [PATCH 09/36] Update helper.js --- scripts/helper.js | 136 ++++++++++++++++++++++------------------------ 1 file changed, 66 insertions(+), 70 deletions(-) diff --git a/scripts/helper.js b/scripts/helper.js index 883fb3c53f..209b04d825 100644 --- a/scripts/helper.js +++ b/scripts/helper.js @@ -298,6 +298,61 @@ helper.code2country = function (code) { return { code, name: intlDisplayNames.of(code.toUpperCase()) } } +helper.parseCountries = function (value, source) { + if (!value) { + const country = helper.code2country(source) + return country ? [country] : [] + } + + return value + .split(';') + .filter(i => i) + .map(helper.code2country) +} + +helper.parseName = function (title) { + return title + .trim() + .split(' ') + .map(s => s.trim()) + .filter(s => { + return !/\[|\]/i.test(s) && !/\((\d+)P\)/i.test(s) + }) + .join(' ') +} + +helper.parseStatus = function (title) { + const regex = /\[(.*)\]/i + const match = title.match(regex) + + return match ? match[1] : null +} + +helper.parseResolution = function (title) { + const regex = /\((\d+)P\)/i + const match = title.match(regex) + + return { + width: null, + height: match ? parseInt(match[1]) : null + } +} + +helper.parseLanguages = function (lang) { + return lang + .split(';') + .map(name => { + const code = name ? helper.getISO6391Code(name) : null + if (!code) return null + + return { + code, + name + } + }) + .filter(l => l) +} + class Playlist { constructor(data) { this.header = data.header @@ -327,81 +382,22 @@ class Channel { this.logo = data.tvg.logo this.category = helper.filterGroup(data.group.title) this.url = data.url - this.name = this.parseName(data.name) - this.status = this.parseStatus(data.name) + this.name = helper.parseName(data.name) + this.status = helper.parseStatus(data.name) this.http = data.http this.tvg = data.tvg this.tvg.url = parent.header.attrs['x-tvg-url'] || '' - this.countries = this.parseCountries(data.tvg.country) - this.resolution = this.parseResolution(data.name) - this.language = this.parseLanguage(data.tvg.language) + this.countries = helper.parseCountries(data.tvg.country, this.source) + this.resolution = helper.parseResolution(data.name) + this.languages = helper.parseLanguages(data.tvg.language) } - get languageName() { - return this.language[0] ? this.language[0].name : null + get languageAttribute() { + return this.getLanguageAttribute() } - get countryName() { - return this.countries[0] ? this.countries[0].name : null - } - - get countryCode() { - return this.countries[0] ? this.countries[0].code : null - } - - parseCountries(value) { - if (!value) { - const country = helper.code2country(this.source) - return country ? [country] : [] - } - - return value - .split(';') - .filter(i => i) - .map(helper.code2country) - } - - parseName(title) { - return title - .trim() - .split(' ') - .map(s => s.trim()) - .filter(s => { - return !/\[|\]/i.test(s) && !/\((\d+)P\)/i.test(s) - }) - .join(' ') - } - - parseStatus(title) { - const regex = /\[(.*)\]/i - const match = title.match(regex) - - return match ? match[1] : null - } - - parseResolution(title) { - const regex = /\((\d+)P\)/i - const match = title.match(regex) - - return { - width: null, - height: match ? parseInt(match[1]) : null - } - } - - parseLanguage(lang) { - return lang - .split(';') - .map(name => { - const code = name ? helper.getISO6391Code(name) : null - if (!code) return null - - return { - code, - name - } - }) - .filter(l => l) + get countryAttribute() { + return this.getCountryAttribute() } getCountryAttribute() { @@ -409,7 +405,7 @@ class Channel { } getLanguageAttribute() { - return this.language.map(l => l.name).join(';') + return this.languages.map(l => l.name).join(';') } toString() { @@ -457,7 +453,7 @@ class Channel { logo: this.logo || null, url: this.url, category: this.category || null, - language: this.language, + languages: this.languages, countries: this.countries, tvg: { id: this.tvg.id || null, From 9e033378a390917eb87b6569444f3cc765e90642 Mon Sep 17 00:00:00 2001 From: freearhey Date: Fri, 29 Jan 2021 22:19:44 +0300 Subject: [PATCH 10/36] Update template.md --- .readme/template.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.readme/template.md b/.readme/template.md index 92031dabcb..3211b66679 100644 --- a/.readme/template.md +++ b/.readme/template.md @@ -53,16 +53,22 @@ If successful, you should get the following response: "logo": "https://i.imgur.com/ilZJT5s.png", "url": "http://ott-cdn.ucom.am/s27/index.m3u8", "category": "News", - "language": [ + "languages": [ { "code": "eng", "name": "English" } ], - "country": { - "code": "us", - "name": "United States" - }, + "countries": [ + { + "code": "us", + "name": "United States" + }, + { + "code": "ca", + "name": "Canada" + } + ], "tvg": { "id": "cnn.us", "name": "CNN", From 80256e204c3d0fde16310b5f2ceff6fd862546ce Mon Sep 17 00:00:00 2001 From: freearhey Date: Sat, 30 Jan 2021 01:58:52 +0300 Subject: [PATCH 11/36] Update helper.js --- scripts/helper.js | 360 ++++++++-------------------------------------- 1 file changed, 57 insertions(+), 303 deletions(-) diff --git a/scripts/helper.js b/scripts/helper.js index 209b04d825..27e9b25fc5 100644 --- a/scripts/helper.js +++ b/scripts/helper.js @@ -1,53 +1,14 @@ const fs = require('fs') const path = require('path') -const playlistParser = require('iptv-playlist-parser') const axios = require('axios') const zlib = require('zlib') -const epgParser = require('epg-parser') const urlParser = require('url') const escapeStringRegexp = require('escape-string-regexp') const markdownInclude = require('markdown-include') const iso6393 = require('iso-639-3') -const intlDisplayNames = new Intl.DisplayNames(['en'], { - style: 'long', - type: 'region' -}) let helper = {} -helper.supportedCategories = { - auto: 'Auto', - business: 'Business', - classic: 'Classic', - comedy: 'Comedy', - documentary: 'Documentary', - education: 'Education', - entertainment: 'Entertainment', - family: 'Family', - fashion: 'Fashion', - food: 'Food', - general: 'General', - health: 'Health', - history: 'History', - hobby: 'Hobby', - kids: 'Kids', - legislative: 'Legislative', - lifestyle: 'Lifestyle', - local: 'Local', - movies: 'Movies', - music: 'Music', - news: 'News', - quiz: 'Quiz', - religious: 'Religious', - 'sci-fi': 'Sci-Fi', - shop: 'Shop', - sport: 'Sport', - travel: 'Travel', - weather: 'Weather', - xxx: 'XXX', - other: 'Other' -} - helper.code2flag = function (code) { switch (code) { case 'uk': @@ -63,6 +24,25 @@ helper.code2flag = function (code) { } } +helper.code2name = function (code) { + const intlDisplayNames = new Intl.DisplayNames(['en'], { + style: 'long', + type: 'region' + }) + + try { + return intlDisplayNames.of(code.toUpperCase()) + } catch (e) { + return null + } +} + +helper.language2code = function (name) { + const lang = iso6393.find(l => l.name === name) + + return lang && lang.iso6393 ? lang.iso6393 : null +} + helper.sortBy = function (arr, fields) { return arr.sort((a, b) => { for (let field of fields) { @@ -80,54 +60,7 @@ helper.sortBy = function (arr, fields) { }) } -helper.createDir = function (dir) { - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir) - } -} - -helper.compileMarkdown = function (filepath) { - return markdownInclude.compileFiles(path.resolve(__dirname, filepath)) -} - -helper.escapeStringRegexp = function (scring) { - return escapeStringRegexp(string) -} - -helper.getISO6391Name = function (code) { - const lang = iso6393.find(l => l.iso6393 === code.toLowerCase()) - - return lang && lang.name ? lang.name : null -} - -helper.getISO6391Code = function (name) { - const lang = iso6393.find(l => l.name === name) - - return lang && lang.iso6393 ? lang.iso6393 : null -} - -helper.parsePlaylist = function (filename) { - const content = this.readFile(filename) - const result = playlistParser.parse(content) - const playlist = new Playlist(result) - playlist.url = filename - - return playlist -} - -helper.parseEPG = async function (url) { - return this.getEPG(url).then(content => { - const result = epgParser.parse(content) - const channels = {} - for (let channel of result.channels) { - channels[channel.id] = channel - } - - return { url, channels } - }) -} - -helper.getEPG = function (url) { +helper.loadEPG = function (url) { return new Promise((resolve, reject) => { var buffer = [] axios({ @@ -163,28 +96,24 @@ helper.getEPG = function (url) { }) } -helper.readFile = function (filename) { - return fs.readFileSync(path.resolve(__dirname) + `/../${filename}`, { encoding: 'utf8' }) -} - -helper.appendToFile = function (filename, data) { - fs.appendFileSync(path.resolve(__dirname) + '/../' + filename, data) -} - -helper.createFile = function (filename, data = '') { - fs.writeFileSync(path.resolve(__dirname) + '/../' + filename, data) -} - helper.getBasename = function (filename) { return path.basename(filename, path.extname(filename)) } -helper.getUrlPath = function (u) { - let parsed = urlParser.parse(u) - let searchQuery = parsed.search || '' - let path = parsed.host + parsed.pathname + searchQuery +helper.filterPlaylists = function (arr, include = '', exclude = '') { + if (include) { + const included = include.split(',').map(filename => `channels/${filename}.m3u`) - return path.toLowerCase() + return arr.filter(i => included.indexOf(i.url) > -1) + } + + if (exclude) { + const excluded = exclude.split(',').map(filename => `channels/${filename}.m3u`) + + return arr.filter(i => excluded.indexOf(i.url) === -1) + } + + return arr } helper.generateTable = function (data, options) { @@ -216,8 +145,30 @@ helper.generateTable = function (data, options) { return output } -helper.createChannel = function (data, parent) { - return new Channel(data, parent) +helper.createDir = function (dir) { + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir) + } +} + +helper.readFile = function (filename) { + return fs.readFileSync(path.resolve(__dirname) + `/../${filename}`, { encoding: 'utf8' }) +} + +helper.appendToFile = function (filename, data) { + fs.appendFileSync(path.resolve(__dirname) + '/../' + filename, data) +} + +helper.compileMarkdown = function (filepath) { + return markdownInclude.compileFiles(path.resolve(__dirname, filepath)) +} + +helper.escapeStringRegexp = function (scring) { + return escapeStringRegexp(string) +} + +helper.createFile = function (filename, data = '') { + fs.writeFileSync(path.resolve(__dirname) + '/../' + filename, data) } helper.writeToLog = function (country, msg, url) { @@ -226,26 +177,6 @@ helper.writeToLog = function (country, msg, url) { this.appendToFile('error.log', now.toISOString() + ' ' + line + '\n') } -helper.filterPlaylists = function (arr, include = '', exclude = '') { - if (include) { - const included = include.split(',').map(filename => `channels/${filename}.m3u`) - - return arr.filter(i => included.indexOf(i.url) > -1) - } - - if (exclude) { - const excluded = exclude.split(',').map(filename => `channels/${filename}.m3u`) - - return arr.filter(i => excluded.indexOf(i.url) === -1) - } - - return arr -} - -helper.filterGroup = function (groupTitle) { - return this.supportedCategories[groupTitle.toLowerCase()] || '' -} - helper.filterNSFW = function (arr) { const sfwCategories = [ 'Auto', @@ -287,181 +218,4 @@ helper.sleep = function (ms) { } } -helper.code2country = function (code) { - code = code ? code.toLowerCase() : '' - if (code === 'int') { - return { code: 'int', name: 'International' } - } else if (code === 'unsorted') { - return null - } - - return { code, name: intlDisplayNames.of(code.toUpperCase()) } -} - -helper.parseCountries = function (value, source) { - if (!value) { - const country = helper.code2country(source) - return country ? [country] : [] - } - - return value - .split(';') - .filter(i => i) - .map(helper.code2country) -} - -helper.parseName = function (title) { - return title - .trim() - .split(' ') - .map(s => s.trim()) - .filter(s => { - return !/\[|\]/i.test(s) && !/\((\d+)P\)/i.test(s) - }) - .join(' ') -} - -helper.parseStatus = function (title) { - const regex = /\[(.*)\]/i - const match = title.match(regex) - - return match ? match[1] : null -} - -helper.parseResolution = function (title) { - const regex = /\((\d+)P\)/i - const match = title.match(regex) - - return { - width: null, - height: match ? parseInt(match[1]) : null - } -} - -helper.parseLanguages = function (lang) { - return lang - .split(';') - .map(name => { - const code = name ? helper.getISO6391Code(name) : null - if (!code) return null - - return { - code, - name - } - }) - .filter(l => l) -} - -class Playlist { - constructor(data) { - this.header = data.header - this.items = data.items - } - - getHeader() { - let parts = ['#EXTM3U'] - for (let key in this.header.attrs) { - let value = this.header.attrs[key] - if (value) { - parts.push(`${key}="${value}"`) - } - } - - return `${parts.join(' ')}\n` - } -} - -class Channel { - constructor(data, parent) { - this.parseData(data, parent) - } - - parseData(data, parent) { - this.source = helper.getBasename(parent.url) - this.logo = data.tvg.logo - this.category = helper.filterGroup(data.group.title) - this.url = data.url - this.name = helper.parseName(data.name) - this.status = helper.parseStatus(data.name) - this.http = data.http - this.tvg = data.tvg - this.tvg.url = parent.header.attrs['x-tvg-url'] || '' - this.countries = helper.parseCountries(data.tvg.country, this.source) - this.resolution = helper.parseResolution(data.name) - this.languages = helper.parseLanguages(data.tvg.language) - } - - get languageAttribute() { - return this.getLanguageAttribute() - } - - get countryAttribute() { - return this.getCountryAttribute() - } - - getCountryAttribute() { - return this.countries.map(c => c.code.toUpperCase()).join(';') - } - - getLanguageAttribute() { - return this.languages.map(l => l.name).join(';') - } - - toString() { - const country = this.getCountryAttribute() - const language = this.getLanguageAttribute() - const tvgUrl = (this.tvg.id || this.tvg.name) && this.tvg.url ? this.tvg.url : '' - const resolution = this.resolution.height ? ` (${this.resolution.height}p)` : '' - const status = this.status ? ` [${this.status}]` : '' - - let info = `-1 tvg-id="${this.tvg.id}" tvg-name="${this.tvg.name}" tvg-language="${language}" tvg-logo="${this.logo}" tvg-country="${country}" tvg-url="${tvgUrl}" group-title="${this.category}",${this.name}${resolution}${status}` - - if (this.http['referrer']) { - info += `\n#EXTVLCOPT:http-referrer=${this.http['referrer']}` - } - - if (this.http['user-agent']) { - info += `\n#EXTVLCOPT:http-user-agent=${this.http['user-agent']}` - } - - return '#EXTINF:' + info + '\n' + this.url + '\n' - } - - toShortString() { - const country = this.getCountryAttribute() - const language = this.getLanguageAttribute() - const resolution = this.resolution.height ? ` (${this.resolution.height}p)` : '' - const status = this.status ? ` [${this.status}]` : '' - - let info = `-1 tvg-id="${this.tvg.id}" tvg-name="${this.tvg.name}" tvg-language="${language}" tvg-logo="${this.logo}" tvg-country="${country}" group-title="${this.category}",${this.name}${resolution}${status}` - - if (this.http['referrer']) { - info += `\n#EXTVLCOPT:http-referrer=${this.http['referrer']}` - } - - if (this.http['user-agent']) { - info += `\n#EXTVLCOPT:http-user-agent=${this.http['user-agent']}` - } - - return '#EXTINF:' + info + '\n' + this.url + '\n' - } - - toJSON() { - return { - name: this.name, - logo: this.logo || null, - url: this.url, - category: this.category || null, - languages: this.languages, - countries: this.countries, - tvg: { - id: this.tvg.id || null, - name: this.tvg.name || null, - url: this.tvg.url || null - } - } - } -} - module.exports = helper From 385de935a1ab8e12d47ee7afa01c47c61f813c88 Mon Sep 17 00:00:00 2001 From: freearhey Date: Sat, 30 Jan 2021 02:01:01 +0300 Subject: [PATCH 12/36] Rename helper.js to utils.js --- scripts/{helper.js => utils.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename scripts/{helper.js => utils.js} (100%) diff --git a/scripts/helper.js b/scripts/utils.js similarity index 100% rename from scripts/helper.js rename to scripts/utils.js From 287ca1d113ff02ffcb0729d367c80814b50a2e2b Mon Sep 17 00:00:00 2001 From: freearhey Date: Sat, 30 Jan 2021 02:26:20 +0300 Subject: [PATCH 13/36] Update format.js --- scripts/format.js | 74 ++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/scripts/format.js b/scripts/format.js index 3466df4412..4d3e4e0968 100644 --- a/scripts/format.js +++ b/scripts/format.js @@ -1,5 +1,6 @@ const { program } = require('commander') -const helper = require('./helper') +const parser = require('./parser') +const utils = require('./utils') const axios = require('axios') const ProgressBar = require('progress') const https = require('https') @@ -28,9 +29,10 @@ const instance = axios.create({ let globalBuffer = [] async function main() { - const index = parseIndex() - for (const item of index.items) { - await loadPlaylist(item.url) + const playlists = parseIndex() + + for (const playlist of playlists) { + await loadPlaylist(playlist.url) .then(addToBuffer) .then(sortChannels) .then(removeDuplicates) @@ -40,7 +42,7 @@ async function main() { .then(done) } - if (index.items.length) { + if (playlists.length) { await loadPlaylist('channels/unsorted.m3u') .then(removeUnsortedDuplicates) .then(sortChannels) @@ -53,38 +55,30 @@ async function main() { function parseIndex() { console.info(`Parsing 'index.m3u'...`) - const playlist = helper.parsePlaylist('index.m3u') - playlist.items = helper - .filterPlaylists(playlist.items, config.country, config.exclude) + let playlists = parser.parseIndex() + playlists = utils + .filterPlaylists(playlists, config.country, config.exclude) .filter(i => i.url !== 'channels/unsorted.m3u') - console.info(`Found ${playlist.items.length} playlist(s)\n`) + console.info(`Found ${playlists.length} playlist(s)\n`) - return playlist + return playlists } async function loadPlaylist(url) { console.info(`Processing '${url}'...`) - const playlist = helper.parsePlaylist(url) - playlist.url = url - playlist.items = playlist.items - .map(item => { - return helper.createChannel(item, playlist) - }) - .filter(i => i.url) - - return playlist + return parser.parsePlaylist(url) } async function addToBuffer(playlist) { if (playlist.url === 'channels/unsorted.m3u') return playlist - globalBuffer = globalBuffer.concat(playlist.items) + globalBuffer = globalBuffer.concat(playlist.channels) return playlist } async function sortChannels(playlist) { console.info(` Sorting channels...`) - playlist.items = helper.sortBy(playlist.items, ['name', 'url']) + playlist.channels = utils.sortBy(playlist.channels, ['name', 'url']) return playlist } @@ -92,7 +86,7 @@ async function sortChannels(playlist) { async function removeDuplicates(playlist) { console.info(` Looking for duplicates...`) let buffer = {} - const items = playlist.items.filter(i => { + const channels = playlist.channels.filter(i => { const result = typeof buffer[i.url] === 'undefined' if (result) { buffer[i.url] = true @@ -101,7 +95,7 @@ async function removeDuplicates(playlist) { return result }) - playlist.items = items + playlist.channels = channels return playlist } @@ -109,31 +103,31 @@ async function removeDuplicates(playlist) { async function detectResolution(playlist) { if (!config.resolution) return playlist const bar = new ProgressBar(' Detecting resolution: [:bar] :current/:total (:percent) ', { - total: playlist.items.length + total: playlist.channels.length }) const results = [] - for (const item of playlist.items) { + for (const channel of playlist.channels) { bar.tick() - const url = item.url + const url = channel.url const response = await instance .get(url) - .then(helper.sleep(config.delay)) + .then(utils.sleep(config.delay)) .catch(err => {}) if (response) { if (response.status === 200) { if (/^#EXTM3U/.test(response.data)) { const resolution = parseResolution(response.data) if (resolution) { - item.resolution = resolution + channel.resolution = resolution } } } } - results.push(item) + results.push(channel) } - playlist.items = results + playlist.channels = results return playlist } @@ -160,12 +154,12 @@ async function updateFromEPG(playlist) { console.info(` Adding data from '${tvgUrl}'...`) - return helper + return utils .parseEPG(tvgUrl) .then(epg => { if (!epg) return playlist - playlist.items.map(channel => { + playlist.channels.map(channel => { if (!channel.tvg.id) return channel const epgItem = epg.channels[channel.tvg.id] if (!epgItem) return channel @@ -173,7 +167,7 @@ async function updateFromEPG(playlist) { channel.tvg.name = epgItem.name[0].value } if (!channel.languages.length && epgItem.name.length && epgItem.name[0].lang) { - channel.languages = helper.parseLanguages(epgItem.name[0].lang) + channel.languages = utils.parseLanguages(epgItem.name[0].lang) } if (!channel.logo && epgItem.icon.length) { channel.logo = epgItem.icon[0] @@ -190,25 +184,25 @@ async function updateFromEPG(playlist) { async function removeUnsortedDuplicates(playlist) { console.info(` Looking for duplicates...`) const urls = globalBuffer.map(i => i.url) - const items = playlist.items.filter(i => !urls.includes(i.url)) - if (items.length === playlist.items.length) return playlist - playlist.items = items + const channels = playlist.channels.filter(i => !urls.includes(i.url)) + if (channels.length === playlist.channels.length) return playlist + playlist.channels = channels return playlist } async function updatePlaylist(playlist) { - const original = helper.readFile(playlist.url) + const original = utils.readFile(playlist.url) let output = playlist.getHeader() - for (let channel of playlist.items) { - output += channel.toShortString() + for (let channel of playlist.channels) { + output += channel.toString(true) } if (original === output) { console.info(`No changes have been made.`) return false } else { - helper.createFile(playlist.url, output) + utils.createFile(playlist.url, output) console.info(`Playlist has been updated.`) } From da687ac7442f9763dd03180e29113af7bf26129d Mon Sep 17 00:00:00 2001 From: freearhey Date: Sat, 30 Jan 2021 02:26:23 +0300 Subject: [PATCH 14/36] Update generate.js --- scripts/generate.js | 132 ++++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 65 deletions(-) diff --git a/scripts/generate.js b/scripts/generate.js index f8a6d55aef..0e12090846 100644 --- a/scripts/generate.js +++ b/scripts/generate.js @@ -1,4 +1,5 @@ -const helper = require('./helper') +const utils = require('./utils') +const parser = require('./parser') const ROOT_DIR = './.gh-pages' @@ -10,56 +11,38 @@ let list = { } function main() { - console.log(`Parsing index...`) parseIndex() - console.log('Creating root directory...') createRootDirectory() - console.log('Creating .nojekyll...') createNoJekyllFile() - console.log('Generating index.m3u...') generateIndex() - console.log('Generating index.sfw.m3u...') generateSFWIndex() - console.log('Generating channels.json...') - generateChannels() - console.log('Generating index.country.m3u...') + generateChannelsJson() generateCountryIndex() - console.log('Generating index.language.m3u...') generateLanguageIndex() - console.log('Generating index.category.m3u...') generateCategoryIndex() - console.log('Generating /countries...') generateCountries() - console.log('Generating /categories...') - generateCategories() - console.log('Generating /languages...') generateLanguages() - console.log('Done.\n') - - console.log( - `Countries: ${Object.values(list.countries).length}. Languages: ${ - Object.values(list.languages).length - }. Categories: ${Object.values(list.categories).length}. Channels: ${list.all.length}.` - ) + generateCategories() + finish() } function createRootDirectory() { - helper.createDir(ROOT_DIR) + console.log('Creating root directory...') + utils.createDir(ROOT_DIR) } function createNoJekyllFile() { - helper.createFile(`${ROOT_DIR}/.nojekyll`) + console.log('Creating .nojekyll...') + utils.createFile(`${ROOT_DIR}/.nojekyll`) } function parseIndex() { - const root = helper.parsePlaylist('index.m3u') - - for (let rootItem of root.items) { - const playlist = helper.parsePlaylist(rootItem.url) - for (let item of playlist.items) { - const channel = helper.createChannel(item, playlist) - if (!channel.url) continue + console.log(`Parsing index...`) + const items = parser.parseIndex() + for (let item of items) { + const playlist = parser.parsePlaylist(item.url) + for (let channel of playlist.channels) { // all list.all.push(channel) @@ -108,116 +91,135 @@ function parseIndex() { } function generateIndex() { + console.log('Generating index.m3u...') const filename = `${ROOT_DIR}/index.m3u` - helper.createFile(filename, '#EXTM3U\n') + utils.createFile(filename, '#EXTM3U\n') - const channels = helper.sortBy(list.all, ['name', 'url']) + const channels = utils.sortBy(list.all, ['name', 'url']) for (let channel of channels) { - helper.appendToFile(filename, channel.toString()) + utils.appendToFile(filename, channel.toString()) } } function generateSFWIndex() { + console.log('Generating index.sfw.m3u...') const filename = `${ROOT_DIR}/index.sfw.m3u` - helper.createFile(filename, '#EXTM3U\n') + utils.createFile(filename, '#EXTM3U\n') - const sorted = helper.sortBy(list.all, ['name', 'url']) - const channels = helper.filterNSFW(sorted) + const sorted = utils.sortBy(list.all, ['name', 'url']) + const channels = utils.filterNSFW(sorted) for (let channel of channels) { - helper.appendToFile(filename, channel.toString()) + utils.appendToFile(filename, channel.toString()) } } -function generateChannels() { +function generateChannelsJson() { + console.log('Generating channels.json...') const filename = `${ROOT_DIR}/channels.json` - const sorted = helper.sortBy(list.all, ['name', 'url']) + const sorted = utils.sortBy(list.all, ['name', 'url']) const channels = sorted.map(c => c.toJSON()) - helper.createFile(filename, JSON.stringify(channels)) + utils.createFile(filename, JSON.stringify(channels)) } function generateCountryIndex() { + console.log('Generating index.country.m3u...') const filename = `${ROOT_DIR}/index.country.m3u` - helper.createFile(filename, '#EXTM3U\n') + utils.createFile(filename, '#EXTM3U\n') - const channels = helper.sortBy(list.all, ['countryAttribute', 'name', 'url']) + const channels = utils.sortBy(list.all, ['tvgCountry', 'name', 'url']) for (let channel of channels) { const category = channel.category - channel.category = channel.countries.map(c => c.name).join(';') - helper.appendToFile(filename, channel.toString()) + channel.category = channel.tvgCountry + utils.appendToFile(filename, channel.toString()) channel.category = category } } function generateLanguageIndex() { + console.log('Generating index.language.m3u...') const filename = `${ROOT_DIR}/index.language.m3u` - helper.createFile(filename, '#EXTM3U\n') + utils.createFile(filename, '#EXTM3U\n') - const channels = helper.sortBy(list.all, ['languageAttribute', 'name', 'url']) + const channels = utils.sortBy(list.all, ['tvgLanguage', 'name', 'url']) for (let channel of channels) { const category = channel.category - channel.category = channel.getLanguageAttribute() - helper.appendToFile(filename, channel.toString()) + channel.category = channel.tvgLanguage + utils.appendToFile(filename, channel.toString()) channel.category = category } } function generateCategoryIndex() { + console.log('Generating index.category.m3u...') const filename = `${ROOT_DIR}/index.category.m3u` - helper.createFile(filename, '#EXTM3U\n') + utils.createFile(filename, '#EXTM3U\n') - const channels = helper.sortBy(list.all, ['category', 'name', 'url']) + const channels = utils.sortBy(list.all, ['category', 'name', 'url']) for (let channel of channels) { - helper.appendToFile(filename, channel.toString()) + utils.appendToFile(filename, channel.toString()) } } function generateCountries() { + console.log('Generating /countries...') const outputDir = `${ROOT_DIR}/countries` - helper.createDir(outputDir) + utils.createDir(outputDir) for (let cid in list.countries) { let country = list.countries[cid] const filename = `${outputDir}/${cid}.m3u` - helper.createFile(filename, '#EXTM3U\n') + utils.createFile(filename, '#EXTM3U\n') - const channels = helper.sortBy(Object.values(country), ['name', 'url']) + const channels = utils.sortBy(Object.values(country), ['name', 'url']) for (let channel of channels) { - helper.appendToFile(filename, channel.toString()) + utils.appendToFile(filename, channel.toString()) } } } function generateLanguages() { + console.log('Generating /languages...') const outputDir = `${ROOT_DIR}/languages` - helper.createDir(outputDir) + utils.createDir(outputDir) for (let lid in list.languages) { let language = list.languages[lid] const filename = `${outputDir}/${lid}.m3u` - helper.createFile(filename, '#EXTM3U\n') + utils.createFile(filename, '#EXTM3U\n') - const channels = helper.sortBy(Object.values(language), ['name', 'url']) + const channels = utils.sortBy(Object.values(language), ['name', 'url']) for (let channel of channels) { - helper.appendToFile(filename, channel.toString()) + utils.appendToFile(filename, channel.toString()) } } } function generateCategories() { + console.log('Generating /categories...') const outputDir = `${ROOT_DIR}/categories` - helper.createDir(outputDir) + utils.createDir(outputDir) - for (let cid in helper.supportedCategories) { + for (let cid in utils.supportedCategories) { let category = list.categories[cid] const filename = `${outputDir}/${cid}.m3u` - helper.createFile(filename, '#EXTM3U\n') + utils.createFile(filename, '#EXTM3U\n') if (!category) continue - const channels = helper.sortBy(Object.values(category), ['name', 'url']) + const channels = utils.sortBy(Object.values(category), ['name', 'url']) for (let channel of channels) { - helper.appendToFile(filename, channel.toString()) + utils.appendToFile(filename, channel.toString()) } } } +function finish() { + console.log('Done.\n') + + console.log( + `Countries: ${Object.values(list.countries).length}. Languages: ${ + Object.values(list.languages).length + }. Categories: ${Object.values(list.categories).length}. Channels: ${list.all.length}.` + ) +} + main() From bfcc6047edb61c12cae975126dd2770972d1e4e2 Mon Sep 17 00:00:00 2001 From: freearhey Date: Sat, 30 Jan 2021 02:26:29 +0300 Subject: [PATCH 15/36] Create parser.js --- scripts/parser.js | 227 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 scripts/parser.js diff --git a/scripts/parser.js b/scripts/parser.js new file mode 100644 index 0000000000..a31be1f2b2 --- /dev/null +++ b/scripts/parser.js @@ -0,0 +1,227 @@ +const playlistParser = require('iptv-playlist-parser') +const epgParser = require('epg-parser') +const utils = require('./utils') +const supportedCategories = { + auto: 'Auto', + business: 'Business', + classic: 'Classic', + comedy: 'Comedy', + documentary: 'Documentary', + education: 'Education', + entertainment: 'Entertainment', + family: 'Family', + fashion: 'Fashion', + food: 'Food', + general: 'General', + health: 'Health', + history: 'History', + hobby: 'Hobby', + kids: 'Kids', + legislative: 'Legislative', + lifestyle: 'Lifestyle', + local: 'Local', + movies: 'Movies', + music: 'Music', + news: 'News', + quiz: 'Quiz', + religious: 'Religious', + 'sci-fi': 'Sci-Fi', + shop: 'Shop', + sport: 'Sport', + travel: 'Travel', + weather: 'Weather', + xxx: 'XXX', + other: 'Other' +} + +const parser = {} + +parser.parseIndex = function () { + const content = utils.readFile('index.m3u') + const result = playlistParser.parse(content) + + return result.items +} + +parser.parsePlaylist = function (filename) { + const content = utils.readFile(filename) + const result = playlistParser.parse(content) + + return new Playlist({ header: result.header, items: result.items, url: filename }) +} + +parser.parseCountries = function (string) { + return string + .split(';') + .filter(i => i) + .map(code => { + code = code ? code.toLowerCase() : '' + if (code === 'int') { + return { code: 'int', name: 'International' } + } else if (code === 'unsorted') { + return null + } + + return { code, name: utils.code2name(code) } + }) +} + +parser.parseLanguages = function (string) { + return string + .split(';') + .map(name => { + const code = name ? utils.language2code(name) : null + if (!code) return null + + return { + code, + name + } + }) + .filter(l => l) +} + +parser.parseCategory = function (string) { + return supportedCategories[string.toLowerCase()] || '' +} + +parser.parseTitle = function (title) { + const channelName = title + .trim() + .split(' ') + .map(s => s.trim()) + .filter(s => { + return !/\[|\]/i.test(s) && !/\((\d+)P\)/i.test(s) + }) + .join(' ') + + const streamStatusMatch = title.match(/\[(.*)\]/i) + const streamStatus = streamStatusMatch ? streamStatusMatch[1] : null + + const streamResolutionMatch = title.match(/\((\d+)P\)/i) + const streamResolutionHeight = streamResolutionMatch ? parseInt(streamResolutionMatch[1]) : null + const streamResolution = { width: null, height: streamResolutionHeight } + + return { channelName, streamStatus, streamResolution } +} + +parser.parseEPG = async function (url) { + return utils.loadEPG(url).then(content => { + const result = epgParser.parse(content) + const channels = {} + for (let channel of result.channels) { + channels[channel.id] = channel + } + + return { url, channels } + }) +} + +class Playlist { + constructor({ header, items, url }) { + this.url = url + this.header = header + this.channels = items + .map(item => new Channel({ data: item, header, sourceUrl: url })) + .filter(channel => channel.url) + } + + getHeader() { + let parts = ['#EXTM3U'] + for (let key in this.header.attrs) { + let value = this.header.attrs[key] + if (value) { + parts.push(`${key}="${value}"`) + } + } + + return `${parts.join(' ')}\n` + } +} + +class Channel { + constructor({ data, header, sourceUrl }) { + this.parseData(data) + + if (!this.countries.length) { + const filename = utils.getBasename(sourceUrl) + const countryName = utils.code2name(filename) + this.countries = countryName ? [{ code: filename.toLowerCase(), name: countryName }] : [] + } + + this.tvg.url = header.attrs['x-tvg-url'] || '' + } + + parseData(data) { + const title = parser.parseTitle(data.name) + + this.tvg = data.tvg + this.http = data.http + this.url = data.url + this.logo = data.tvg.logo + this.name = title.channelName + this.status = title.streamStatus + this.resolution = title.streamResolution + this.countries = parser.parseCountries(data.tvg.country) + this.languages = parser.parseLanguages(data.tvg.language) + this.category = parser.parseCategory(data.group.title) + } + + get tvgCountry() { + return this.countries.map(c => c.code.toUpperCase()).join(';') + } + + get tvgLanguage() { + return this.languages.map(l => l.name).join(';') + } + + get tvgUrl() { + return (this.tvg.id || this.tvg.name) && this.tvg.url ? this.tvg.url : '' + } + + toString(short = false) { + let info = `-1 tvg-id="${this.tvg.id}" tvg-name="${this.tvg.name}" tvg-language="${this.tvgLanguage}" tvg-logo="${this.logo}" tvg-country="${this.tvgCountry}"` + + if (!short) { + info += ` tvg-url="${this.tvgUrl}"` + } + + info += ` group-title="${this.category}",${this.name}` + + if (this.resolution.height) { + info += ` (${this.resolution.height}p)` + } + + if (this.status) { + info += ` [${this.status}]` + } + + if (this.http['referrer']) { + info += `\n#EXTVLCOPT:http-referrer=${this.http['referrer']}` + } + + if (this.http['user-agent']) { + info += `\n#EXTVLCOPT:http-user-agent=${this.http['user-agent']}` + } + + return '#EXTINF:' + info + '\n' + this.url + '\n' + } + + toJSON() { + return { + name: this.name, + logo: this.logo || null, + url: this.url, + category: this.category || null, + languages: this.languages, + countries: this.countries, + tvg: { + id: this.tvg.id || null, + name: this.tvg.name || null, + url: this.tvg.url || null + } + } + } +} + +module.exports = parser From 1edad82ef42fb521d6463a0a5f8983a1195fa082 Mon Sep 17 00:00:00 2001 From: freearhey Date: Sat, 30 Jan 2021 06:16:44 +0300 Subject: [PATCH 16/36] Update utils.js --- scripts/utils.js | 242 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 192 insertions(+), 50 deletions(-) diff --git a/scripts/utils.js b/scripts/utils.js index 27e9b25fc5..063f3e3aeb 100644 --- a/scripts/utils.js +++ b/scripts/utils.js @@ -7,9 +7,157 @@ const escapeStringRegexp = require('escape-string-regexp') const markdownInclude = require('markdown-include') const iso6393 = require('iso-639-3') -let helper = {} +const utils = {} -helper.code2flag = function (code) { +utils.supportedCategories = [ + { + name: 'Auto', + id: 'auto', + nsfw: false + }, + { + name: 'Business', + id: 'business', + nsfw: false + }, + { + name: 'Classic', + id: 'classic', + nsfw: false + }, + { + name: 'Comedy', + id: 'comedy', + nsfw: false + }, + { + name: 'Documentary', + id: 'documentary', + nsfw: false + }, + { + name: 'Education', + id: 'education', + nsfw: false + }, + { + name: 'Entertainment', + id: 'entertainment', + nsfw: false + }, + { + name: 'Family', + id: 'family', + nsfw: false + }, + { + name: 'Fashion', + id: 'fashion', + nsfw: false + }, + { + name: 'Food', + id: 'food', + nsfw: false + }, + { + name: 'General', + id: 'general', + nsfw: false + }, + { + name: 'Health', + id: 'health', + nsfw: false + }, + { + name: 'History', + id: 'history', + nsfw: false + }, + { + name: 'Hobby', + id: 'hobby', + nsfw: false + }, + { + name: 'Kids', + id: 'kids', + nsfw: false + }, + { + name: 'Legislative', + id: 'legislative', + nsfw: false + }, + { + name: 'Lifestyle', + id: 'lifestyle', + nsfw: false + }, + { + name: 'Local', + id: 'local', + nsfw: false + }, + { + name: 'Movies', + id: 'movies', + nsfw: false + }, + { + name: 'Music', + id: 'music', + nsfw: false + }, + { + name: 'News', + id: 'news', + nsfw: false + }, + { + name: 'Quiz', + id: 'quiz', + nsfw: false + }, + { + name: 'Religious', + id: 'religious', + nsfw: false + }, + { + name: 'Sci-Fi', + id: 'sci-fi', + nsfw: false + }, + { + name: 'Shop', + id: 'shop', + nsfw: false + }, + { + name: 'Sport', + id: 'sport', + nsfw: false + }, + { + name: 'Travel', + id: 'travel', + nsfw: false + }, + { + name: 'Weather', + id: 'weather', + nsfw: false + }, + { + name: 'XXX', + id: 'xxx', + nsfw: true + } +] + +utils.code2flag = function (code) { switch (code) { case 'uk': return '🇬🇧' @@ -24,9 +172,16 @@ helper.code2flag = function (code) { } } -helper.code2name = function (code) { +utils.code2name = function (code) { + switch (code.toLowerCase()) { + case 'int': + return 'International' + case 'us': + return 'United States' + } + const intlDisplayNames = new Intl.DisplayNames(['en'], { - style: 'long', + style: 'narrow', type: 'region' }) @@ -37,18 +192,34 @@ helper.code2name = function (code) { } } -helper.language2code = function (name) { +utils.language2code = function (name) { const lang = iso6393.find(l => l.name === name) return lang && lang.iso6393 ? lang.iso6393 : null } -helper.sortBy = function (arr, fields) { +utils.sortBy = function (arr, fields) { return arr.sort((a, b) => { for (let field of fields) { let propA = a[field] ? a[field].toLowerCase() : '' let propB = b[field] ? b[field].toLowerCase() : '' + if (propA === 'undefined') { + return 1 + } + + if (propB === 'undefined') { + return -1 + } + + if (propA === 'other') { + return 1 + } + + if (propB === 'other') { + return -1 + } + if (propA < propB) { return -1 } @@ -60,7 +231,7 @@ helper.sortBy = function (arr, fields) { }) } -helper.loadEPG = function (url) { +utils.loadEPG = function (url) { return new Promise((resolve, reject) => { var buffer = [] axios({ @@ -96,11 +267,11 @@ helper.loadEPG = function (url) { }) } -helper.getBasename = function (filename) { +utils.getBasename = function (filename) { return path.basename(filename, path.extname(filename)) } -helper.filterPlaylists = function (arr, include = '', exclude = '') { +utils.filterPlaylists = function (arr, include = '', exclude = '') { if (include) { const included = include.split(',').map(filename => `channels/${filename}.m3u`) @@ -116,7 +287,7 @@ helper.filterPlaylists = function (arr, include = '', exclude = '') { return arr } -helper.generateTable = function (data, options) { +utils.generateTable = function (data, options) { let output = '\n' output += '\t\n\t\t' @@ -145,77 +316,48 @@ helper.generateTable = function (data, options) { return output } -helper.createDir = function (dir) { +utils.createDir = function (dir) { if (!fs.existsSync(dir)) { fs.mkdirSync(dir) } } -helper.readFile = function (filename) { +utils.readFile = function (filename) { return fs.readFileSync(path.resolve(__dirname) + `/../${filename}`, { encoding: 'utf8' }) } -helper.appendToFile = function (filename, data) { +utils.appendToFile = function (filename, data) { fs.appendFileSync(path.resolve(__dirname) + '/../' + filename, data) } -helper.compileMarkdown = function (filepath) { +utils.compileMarkdown = function (filepath) { return markdownInclude.compileFiles(path.resolve(__dirname, filepath)) } -helper.escapeStringRegexp = function (scring) { +utils.escapeStringRegexp = function (scring) { return escapeStringRegexp(string) } -helper.createFile = function (filename, data = '') { +utils.createFile = function (filename, data = '') { fs.writeFileSync(path.resolve(__dirname) + '/../' + filename, data) } -helper.writeToLog = function (country, msg, url) { +utils.writeToLog = function (country, msg, url) { var now = new Date() var line = `${country}: ${msg} '${url}'` this.appendToFile('error.log', now.toISOString() + ' ' + line + '\n') } -helper.filterNSFW = function (arr) { - const sfwCategories = [ - 'Auto', - 'Business', - 'Classic', - 'Comedy', - 'Documentary', - 'Education', - 'Entertainment', - 'Family', - 'Fashion', - 'Food', - 'General', - 'Health', - 'History', - 'Hobby', - 'Kids', - 'Legislative', - 'Lifestyle', - 'Local', - 'Movies', - 'Music', - 'News', - 'Quiz', - 'Religious', - 'Sci-Fi', - 'Shop', - 'Sport', - 'Travel', - 'Weather' - ] +utils.filterNSFW = function (arr) { + const sfwCategories = utils.supportedCategories.filter(c => !c.nsfw).map(c => c.name) return arr.filter(i => sfwCategories.includes(i.category)) } -helper.sleep = function (ms) { +utils.sleep = function (ms) { return function (x) { return new Promise(resolve => setTimeout(() => resolve(x), ms)) } } -module.exports = helper +module.exports = utils From 8b35d234919e49c26a00ed9c45f70d0b3bfe8af6 Mon Sep 17 00:00:00 2001 From: freearhey Date: Sat, 30 Jan 2021 06:18:21 +0300 Subject: [PATCH 17/36] Update generate.js --- scripts/generate.js | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/scripts/generate.js b/scripts/generate.js index 0e12090846..8a52d200c6 100644 --- a/scripts/generate.js +++ b/scripts/generate.js @@ -40,6 +40,11 @@ function parseIndex() { console.log(`Parsing index...`) const items = parser.parseIndex() + for (const category of utils.supportedCategories) { + list.categories[category.id] = [] + } + list.categories['other'] = [] + for (let item of items) { const playlist = parser.parsePlaylist(item.url) for (let channel of playlist.channels) { @@ -81,11 +86,12 @@ function parseIndex() { } // category - const categoryCode = channel.category ? channel.category.toLowerCase() : 'other' - if (!list.categories[categoryCode]) { - list.categories[categoryCode] = [] + const categoryId = channel.category.toLowerCase() + if (!list.categories[categoryId]) { + list.categories['other'].push(channel) + } else { + list.categories[categoryId].push(channel) } - list.categories[categoryCode].push(channel) } } } @@ -165,13 +171,13 @@ function generateCountries() { const outputDir = `${ROOT_DIR}/countries` utils.createDir(outputDir) - for (let cid in list.countries) { - let country = list.countries[cid] - const filename = `${outputDir}/${cid}.m3u` + for (const countryId in list.countries) { + const filename = `${outputDir}/${countryId}.m3u` utils.createFile(filename, '#EXTM3U\n') - const channels = utils.sortBy(Object.values(country), ['name', 'url']) - for (let channel of channels) { + let channels = Object.values(list.countries[countryId]) + channels = utils.sortBy(channels, ['name', 'url']) + for (const channel of channels) { utils.appendToFile(filename, channel.toString()) } } @@ -182,13 +188,13 @@ function generateLanguages() { const outputDir = `${ROOT_DIR}/languages` utils.createDir(outputDir) - for (let lid in list.languages) { - let language = list.languages[lid] - const filename = `${outputDir}/${lid}.m3u` + for (const languageId in list.languages) { + const filename = `${outputDir}/${languageId}.m3u` utils.createFile(filename, '#EXTM3U\n') - const channels = utils.sortBy(Object.values(language), ['name', 'url']) - for (let channel of channels) { + let channels = Object.values(list.languages[languageId]) + channels = utils.sortBy(channels, ['name', 'url']) + for (const channel of channels) { utils.appendToFile(filename, channel.toString()) } } @@ -199,14 +205,13 @@ function generateCategories() { const outputDir = `${ROOT_DIR}/categories` utils.createDir(outputDir) - for (let cid in utils.supportedCategories) { - let category = list.categories[cid] - const filename = `${outputDir}/${cid}.m3u` + for (const category of utils.supportedCategories) { + const filename = `${outputDir}/${category.id}.m3u` utils.createFile(filename, '#EXTM3U\n') - if (!category) continue - const channels = utils.sortBy(Object.values(category), ['name', 'url']) - for (let channel of channels) { + let channels = Object.values(list.categories[category.id]) + channels = utils.sortBy(channels, ['name', 'url']) + for (const channel of channels) { utils.appendToFile(filename, channel.toString()) } } From 5b10af9862cdf081771cd436603a07bff81eb4a4 Mon Sep 17 00:00:00 2001 From: freearhey Date: Sat, 30 Jan 2021 06:18:43 +0300 Subject: [PATCH 18/36] Update parser.js --- scripts/parser.js | 47 ++++------------------------------------------- 1 file changed, 4 insertions(+), 43 deletions(-) diff --git a/scripts/parser.js b/scripts/parser.js index a31be1f2b2..419f8f1916 100644 --- a/scripts/parser.js +++ b/scripts/parser.js @@ -1,38 +1,6 @@ const playlistParser = require('iptv-playlist-parser') const epgParser = require('epg-parser') const utils = require('./utils') -const supportedCategories = { - auto: 'Auto', - business: 'Business', - classic: 'Classic', - comedy: 'Comedy', - documentary: 'Documentary', - education: 'Education', - entertainment: 'Entertainment', - family: 'Family', - fashion: 'Fashion', - food: 'Food', - general: 'General', - health: 'Health', - history: 'History', - hobby: 'Hobby', - kids: 'Kids', - legislative: 'Legislative', - lifestyle: 'Lifestyle', - local: 'Local', - movies: 'Movies', - music: 'Music', - news: 'News', - quiz: 'Quiz', - religious: 'Religious', - 'sci-fi': 'Sci-Fi', - shop: 'Shop', - sport: 'Sport', - travel: 'Travel', - weather: 'Weather', - xxx: 'XXX', - other: 'Other' -} const parser = {} @@ -54,16 +22,7 @@ parser.parseCountries = function (string) { return string .split(';') .filter(i => i) - .map(code => { - code = code ? code.toLowerCase() : '' - if (code === 'int') { - return { code: 'int', name: 'International' } - } else if (code === 'unsorted') { - return null - } - - return { code, name: utils.code2name(code) } - }) + .map(code => ({ code: code.toLowerCase(), name: utils.code2name(code) })) } parser.parseLanguages = function (string) { @@ -82,7 +41,9 @@ parser.parseLanguages = function (string) { } parser.parseCategory = function (string) { - return supportedCategories[string.toLowerCase()] || '' + const category = utils.supportedCategories.find(c => c.id === string.toLowerCase()) + + return category ? category.name : '' } parser.parseTitle = function (title) { From f93b21b4521e3dca490833c0be86a969683d416d Mon Sep 17 00:00:00 2001 From: freearhey Date: Sat, 30 Jan 2021 06:26:15 +0300 Subject: [PATCH 19/36] Update update-readme.js --- scripts/update-readme.js | 190 +++++++++++++++++++-------------------- 1 file changed, 94 insertions(+), 96 deletions(-) diff --git a/scripts/update-readme.js b/scripts/update-readme.js index fdea7885d9..268b35a37e 100644 --- a/scripts/update-readme.js +++ b/scripts/update-readme.js @@ -1,99 +1,120 @@ -const helper = require('./helper') +const utils = require('./utils') +const parser = require('./parser') -let output = { +const list = { countries: [], languages: [], categories: [] } function main() { - console.log(`Parsing index...`) parseIndex() - console.log(`Generating countries table...`) generateCountriesTable() - console.log(`Generating languages table...`) generateLanguagesTable() - console.log(`Generating categories table...`) generateCategoriesTable() - console.log(`Generating README.md...`) generateReadme() - console.log(`Done.`) + finish() } function parseIndex() { - const root = helper.parsePlaylist('index.m3u') + console.log(`Parsing index...`) + const items = parser.parseIndex() - let countries = {} - let languages = {} - let categories = {} + const countries = {} + const languages = {} + const categories = {} - for (let categoryCode in helper.supportedCategories) { - categories[categoryCode] = { - category: helper.supportedCategories[categoryCode], - channels: 0, - playlist: `https://iptv-org.github.io/iptv/categories/${categoryCode}.m3u` - } + countries['undefined'] = { + country: 'Undefined', + channels: 0, + playlist: `https://iptv-org.github.io/iptv/countries/undefined.m3u`, + epg: '', + name: 'Undefined' } - for (let rootItem of root.items) { - const playlist = helper.parsePlaylist(rootItem.url) - const countryName = rootItem.name - const countryCode = helper.getBasename(rootItem.url).toLowerCase() - const countryEpg = playlist.header.attrs['x-tvg-url'] - ? `${playlist.header.attrs['x-tvg-url']}` - : '' + languages['undefined'] = { + language: 'Undefined', + channels: 0, + playlist: `https://iptv-org.github.io/iptv/languages/undefined.m3u` + } - for (let item of playlist.items) { + for (const category of utils.supportedCategories) { + categories[category.id] = { + category: category.name, + channels: 0, + playlist: `https://iptv-org.github.io/iptv/categories/${category.id}.m3u` + } + } + categories['other'] = { + category: 'Other', + channels: 0, + playlist: `https://iptv-org.github.io/iptv/categories/other.m3u` + } + + for (const item of items) { + const playlist = parser.parsePlaylist(item.url) + for (let channel of playlist.channels) { // countries - if (countries[countryCode]) { - countries[countryCode].channels++ + if (!channel.countries.length) { + countries['undefined'].channels++ } else { - let flag = helper.code2flag(countryCode) - - countries[countryCode] = { - country: flag + ' ' + countryName, - channels: 1, - playlist: `https://iptv-org.github.io/iptv/countries/${countryCode}.m3u`, - epg: countryEpg + for (let country of channel.countries) { + if (countries[country.code]) { + countries[country.code].channels++ + } else { + let flag = utils.code2flag(country.code) + countries[country.code] = { + country: flag + ' ' + country.name, + channels: 1, + playlist: `https://iptv-org.github.io/iptv/countries/${country.code}.m3u`, + epg: playlist.header.attrs['x-tvg-url'] + ? `${playlist.header.attrs['x-tvg-url']}` + : '', + name: country.name + } + } } } // languages - const languageNames = item.tvg.language || 'Undefined' - for (let languageName of languageNames.split(';')) { - let languageCode = 'undefined' - if (languageName !== 'Undefined') { - languageCode = helper.getISO6391Code(languageName) - if (!languageCode) continue - } - - if (languages[languageCode]) { - languages[languageCode].channels++ - } else { - languages[languageCode] = { - language: languageName, - channels: 1, - playlist: `https://iptv-org.github.io/iptv/languages/${languageCode}.m3u` + if (!channel.languages.length) { + languages['undefined'].channels++ + } else { + for (let language of channel.languages) { + if (languages[language.code]) { + languages[language.code].channels++ + } else { + languages[language.code] = { + language: language.name, + channels: 1, + playlist: `https://iptv-org.github.io/iptv/languages/${language.code}.m3u` + } } } } // categories - const categoryName = helper.filterGroup(item.group.title) || 'Other' - const categoryCode = categoryName.toLowerCase() - if (categories[categoryCode]) { - categories[categoryCode].channels++ + const categoryId = channel.category.toLowerCase() + if (!categoryId) { + categories['other'].channels++ + } else if (categories[categoryId]) { + categories[categoryId].channels++ } } } - output.countries = Object.values(countries) - output.languages = Object.values(languages) - output.categories = Object.values(categories) + list.countries = Object.values(countries) + list.languages = Object.values(languages) + list.categories = Object.values(categories) } function generateCountriesTable() { - const table = helper.generateTable(output.countries, { + console.log(`Generating countries table...`) + list.countries = utils.sortBy(list.countries, ['name']) + list.countries.forEach(function (i) { + delete i.name + }) + const table = utils.generateTable(list.countries, { columns: [ { name: 'Country', align: 'left' }, { name: 'Channels', align: 'right' }, @@ -102,27 +123,13 @@ function generateCountriesTable() { ] }) - helper.createFile('./.readme/_countries.md', table) + utils.createFile('./.readme/_countries.md', table) } function generateLanguagesTable() { - output.languages.sort((a, b) => { - if (a.language === 'Undefined') { - return 1 - } - if (b.language === 'Undefined') { - return -1 - } - if (a.language < b.language) { - return -1 - } - if (a.language > b.language) { - return 1 - } - return 0 - }) - - const table = helper.generateTable(output.languages, { + console.log(`Generating languages table...`) + list.languages = utils.sortBy(list.languages, ['language']) + const table = utils.generateTable(list.languages, { columns: [ { name: 'Language', align: 'left' }, { name: 'Channels', align: 'right' }, @@ -130,27 +137,13 @@ function generateLanguagesTable() { ] }) - helper.createFile('./.readme/_languages.md', table) + utils.createFile('./.readme/_languages.md', table) } function generateCategoriesTable() { - output.categories.sort((a, b) => { - if (a.category === 'Other') { - return 1 - } - if (b.category === 'Other') { - return -1 - } - if (a.category < b.category) { - return -1 - } - if (a.category > b.category) { - return 1 - } - return 0 - }) - - const table = helper.generateTable(output.categories, { + console.log(`Generating categories table...`) + list.categories = utils.sortBy(list.categories, ['category']) + const table = utils.generateTable(list.categories, { columns: [ { name: 'Category', align: 'left' }, { name: 'Channels', align: 'right' }, @@ -158,11 +151,16 @@ function generateCategoriesTable() { ] }) - helper.createFile('./.readme/_categories.md', table) + utils.createFile('./.readme/_categories.md', table) } function generateReadme() { - helper.compileMarkdown('../.readme/config.json') + console.log(`Generating README.md...`) + utils.compileMarkdown('../.readme/config.json') +} + +function finish() { + console.log(`Done.`) } main() From 44846b8eaa36d1b6c6dee68c83220261497f403e Mon Sep 17 00:00:00 2001 From: freearhey Date: Sat, 30 Jan 2021 06:41:19 +0300 Subject: [PATCH 20/36] Update test.js --- scripts/test.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/scripts/test.js b/scripts/test.js index 1f0ec90870..fca3de471a 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -1,5 +1,6 @@ const { program } = require('commander') -const helper = require('./helper') +const utils = require('./utils') +const parser = require('./parser') const axios = require('axios') const https = require('https') const ProgressBar = require('progress') @@ -30,28 +31,27 @@ let stats = { } async function test() { - const playlist = helper.parsePlaylist('index.m3u') + let items = parser.parseIndex() + items = utils.filterPlaylists(items, config.country, config.exclude) - const countries = helper.filterPlaylists(playlist.items, config.country, config.exclude) - - for (let country of countries) { - const playlist = helper.parsePlaylist(country.url) - const bar = new ProgressBar(`Processing '${country.url}'...:current/:total\n`, { - total: playlist.items.length + for (const item of items) { + const playlist = parser.parsePlaylist(item.url) + const bar = new ProgressBar(`Processing '${item.url}'...:current/:total`, { + total: playlist.channels.length }) stats.playlists++ - for (let channel of playlist.items) { + for (let channel of playlist.channels) { bar.tick() stats.channels++ await instance .get(channel.url) - .then(helper.sleep(config.delay)) + .then(utils.sleep(config.delay)) .catch(error => { if (error.response) { stats.failures++ - helper.writeToLog(country.url, error.message, channel.url) + utils.writeToLog(country.url, error.message, channel.url) console.log(`Error: ${error.message} '${channel.url}'`) } }) From 6d7fd69269397d213bdc9820fb9f5da780e48bcb Mon Sep 17 00:00:00 2001 From: freearhey Date: Sat, 30 Jan 2021 07:18:06 +0300 Subject: [PATCH 21/36] Update format.js --- scripts/format.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/scripts/format.js b/scripts/format.js index 4d3e4e0968..0a69b878c7 100644 --- a/scripts/format.js +++ b/scripts/format.js @@ -38,7 +38,7 @@ async function main() { .then(removeDuplicates) .then(detectResolution) .then(updateFromEPG) - .then(updatePlaylist) + .then(savePlaylist) .then(done) } @@ -46,7 +46,7 @@ async function main() { await loadPlaylist('channels/unsorted.m3u') .then(removeUnsortedDuplicates) .then(sortChannels) - .then(updatePlaylist) + .then(savePlaylist) .then(done) } @@ -191,12 +191,9 @@ async function removeUnsortedDuplicates(playlist) { return playlist } -async function updatePlaylist(playlist) { +async function savePlaylist(playlist) { const original = utils.readFile(playlist.url) - let output = playlist.getHeader() - for (let channel of playlist.channels) { - output += channel.toString(true) - } + const output = playlist.toString(true) if (original === output) { console.info(`No changes have been made.`) From ad9f6e81682da15ac6d6f831d76315b21616544c Mon Sep 17 00:00:00 2001 From: freearhey Date: Sat, 30 Jan 2021 07:19:17 +0300 Subject: [PATCH 22/36] Update parser.js --- scripts/parser.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/parser.js b/scripts/parser.js index 419f8f1916..a3164f80fc 100644 --- a/scripts/parser.js +++ b/scripts/parser.js @@ -87,7 +87,7 @@ class Playlist { .filter(channel => channel.url) } - getHeader() { + toString(short = false) { let parts = ['#EXTM3U'] for (let key in this.header.attrs) { let value = this.header.attrs[key] @@ -96,7 +96,12 @@ class Playlist { } } - return `${parts.join(' ')}\n` + let output = `${parts.join(' ')}\n` + for (let channel of this.channels) { + output += channel.toString(short) + } + + return output } } From 70e81b719745e2e9ca8c682045abdd4720319009 Mon Sep 17 00:00:00 2001 From: freearhey Date: Sat, 30 Jan 2021 07:32:27 +0300 Subject: [PATCH 23/36] Update parser.js --- scripts/parser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/parser.js b/scripts/parser.js index a3164f80fc..086a90b559 100644 --- a/scripts/parser.js +++ b/scripts/parser.js @@ -21,7 +21,7 @@ parser.parsePlaylist = function (filename) { parser.parseCountries = function (string) { return string .split(';') - .filter(i => i) + .filter(code => code && utils.codeIsValid(code)) .map(code => ({ code: code.toLowerCase(), name: utils.code2name(code) })) } From 57353c6fd8d64602ccd17b37b1ab1748fb5b4649 Mon Sep 17 00:00:00 2001 From: freearhey Date: Sat, 30 Jan 2021 07:32:31 +0300 Subject: [PATCH 24/36] Update utils.js --- scripts/utils.js | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/scripts/utils.js b/scripts/utils.js index 063f3e3aeb..6981caa2cf 100644 --- a/scripts/utils.js +++ b/scripts/utils.js @@ -6,6 +6,10 @@ const urlParser = require('url') const escapeStringRegexp = require('escape-string-regexp') const markdownInclude = require('markdown-include') const iso6393 = require('iso-639-3') +const intlDisplayNames = new Intl.DisplayNames(['en'], { + style: 'narrow', + type: 'region' +}) const utils = {} @@ -180,11 +184,6 @@ utils.code2name = function (code) { return 'United States' } - const intlDisplayNames = new Intl.DisplayNames(['en'], { - style: 'narrow', - type: 'region' - }) - try { return intlDisplayNames.of(code.toUpperCase()) } catch (e) { @@ -192,6 +191,23 @@ utils.code2name = function (code) { } } +utils.codeIsValid = function (code) { + switch (code.toLowerCase()) { + case 'int': + return true + case 'us': + return true + } + + try { + intlDisplayNames.of(code.toUpperCase()) + + return true + } catch (e) { + return false + } +} + utils.language2code = function (name) { const lang = iso6393.find(l => l.name === name) From bfed3dbc81377e29f8e55fa24fbe11ecc77ab433 Mon Sep 17 00:00:00 2001 From: freearhey Date: Sun, 31 Jan 2021 20:11:41 +0300 Subject: [PATCH 25/36] Create categories.js --- scripts/categories.js | 147 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 scripts/categories.js diff --git a/scripts/categories.js b/scripts/categories.js new file mode 100644 index 0000000000..ef737a7fdf --- /dev/null +++ b/scripts/categories.js @@ -0,0 +1,147 @@ +module.exports = [ + { + name: 'Auto', + id: 'auto', + nsfw: false + }, + { + name: 'Business', + id: 'business', + nsfw: false + }, + { + name: 'Classic', + id: 'classic', + nsfw: false + }, + { + name: 'Comedy', + id: 'comedy', + nsfw: false + }, + { + name: 'Documentary', + id: 'documentary', + nsfw: false + }, + { + name: 'Education', + id: 'education', + nsfw: false + }, + { + name: 'Entertainment', + id: 'entertainment', + nsfw: false + }, + { + name: 'Family', + id: 'family', + nsfw: false + }, + { + name: 'Fashion', + id: 'fashion', + nsfw: false + }, + { + name: 'Food', + id: 'food', + nsfw: false + }, + { + name: 'General', + id: 'general', + nsfw: false + }, + { + name: 'Health', + id: 'health', + nsfw: false + }, + { + name: 'History', + id: 'history', + nsfw: false + }, + { + name: 'Hobby', + id: 'hobby', + nsfw: false + }, + { + name: 'Kids', + id: 'kids', + nsfw: false + }, + { + name: 'Legislative', + id: 'legislative', + nsfw: false + }, + { + name: 'Lifestyle', + id: 'lifestyle', + nsfw: false + }, + { + name: 'Local', + id: 'local', + nsfw: false + }, + { + name: 'Movies', + id: 'movies', + nsfw: false + }, + { + name: 'Music', + id: 'music', + nsfw: false + }, + { + name: 'News', + id: 'news', + nsfw: false + }, + { + name: 'Quiz', + id: 'quiz', + nsfw: false + }, + { + name: 'Religious', + id: 'religious', + nsfw: false + }, + { + name: 'Sci-Fi', + id: 'sci-fi', + nsfw: false + }, + { + name: 'Shop', + id: 'shop', + nsfw: false + }, + { + name: 'Sport', + id: 'sport', + nsfw: false + }, + { + name: 'Travel', + id: 'travel', + nsfw: false + }, + { + name: 'Weather', + id: 'weather', + nsfw: false + }, + { + name: 'XXX', + id: 'xxx', + nsfw: true + } +] From 47caeba6228699a8ed0c9bc883b2bdcdec39b58a Mon Sep 17 00:00:00 2001 From: freearhey Date: Sun, 31 Jan 2021 20:11:47 +0300 Subject: [PATCH 26/36] Create regions.js --- scripts/regions.js | 258 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 scripts/regions.js diff --git a/scripts/regions.js b/scripts/regions.js new file mode 100644 index 0000000000..ecf69898b8 --- /dev/null +++ b/scripts/regions.js @@ -0,0 +1,258 @@ +module.exports = { + AFR: { name: 'Africa', codes: [] }, + MENA: { name: 'Middle East and North Africa', codes: [] }, + INT: { + name: 'International', + codes: [ + 'AF', + 'AX', + 'AL', + 'DZ', + 'AS', + 'AD', + 'AO', + 'AI', + 'AQ', + 'AG', + 'AR', + 'AM', + 'AW', + 'AU', + 'AT', + 'AZ', + 'BS', + 'BH', + 'BD', + 'BB', + 'BY', + 'BE', + 'BZ', + 'BJ', + 'BM', + 'BT', + 'BO', + 'BQ', + 'BA', + 'BW', + 'BV', + 'BR', + 'IO', + 'BN', + 'BG', + 'BF', + 'BI', + 'KH', + 'CM', + 'CA', + 'CV', + 'KY', + 'CF', + 'TD', + 'CL', + 'CN', + 'CX', + 'CC', + 'CO', + 'KM', + 'CG', + 'CD', + 'CK', + 'CR', + 'CI', + 'HR', + 'CU', + 'CW', + 'CY', + 'CZ', + 'DK', + 'DJ', + 'DM', + 'DO', + 'EC', + 'EG', + 'SV', + 'GQ', + 'ER', + 'EE', + 'ET', + 'FK', + 'FO', + 'FJ', + 'FI', + 'FR', + 'GF', + 'PF', + 'TF', + 'GA', + 'GM', + 'GE', + 'DE', + 'GH', + 'GI', + 'GR', + 'GL', + 'GD', + 'GP', + 'GU', + 'GT', + 'GG', + 'GN', + 'GW', + 'GY', + 'HT', + 'HM', + 'VA', + 'HN', + 'HK', + 'HU', + 'IS', + 'IN', + 'ID', + 'IR', + 'IQ', + 'IE', + 'IM', + 'IL', + 'IT', + 'JM', + 'JP', + 'JE', + 'JO', + 'KZ', + 'KE', + 'KI', + 'KP', + 'KR', + 'KW', + 'KG', + 'LA', + 'LV', + 'LB', + 'LS', + 'LR', + 'LY', + 'LI', + 'LT', + 'LU', + 'MO', + 'MK', + 'MG', + 'MW', + 'MY', + 'MV', + 'ML', + 'MT', + 'MH', + 'MQ', + 'MR', + 'MU', + 'YT', + 'MX', + 'FM', + 'MD', + 'MC', + 'MN', + 'ME', + 'MS', + 'MA', + 'MZ', + 'MM', + 'NA', + 'NR', + 'NP', + 'NL', + 'NC', + 'NZ', + 'NI', + 'NE', + 'NG', + 'NU', + 'NF', + 'MP', + 'NO', + 'OM', + 'PK', + 'PW', + 'PS', + 'PA', + 'PG', + 'PY', + 'PE', + 'PH', + 'PN', + 'PL', + 'PT', + 'PR', + 'QA', + 'RE', + 'RO', + 'RU', + 'RW', + 'BL', + 'SH', + 'KN', + 'LC', + 'MF', + 'PM', + 'VC', + 'WS', + 'SM', + 'ST', + 'SA', + 'SN', + 'RS', + 'SC', + 'SL', + 'SG', + 'SX', + 'SK', + 'SI', + 'SB', + 'SO', + 'ZA', + 'GS', + 'SS', + 'ES', + 'LK', + 'SD', + 'SR', + 'SJ', + 'SZ', + 'SE', + 'CH', + 'SY', + 'TW', + 'TJ', + 'TZ', + 'TH', + 'TL', + 'TG', + 'TK', + 'TO', + 'TT', + 'TN', + 'TR', + 'TM', + 'TC', + 'TV', + 'UG', + 'UA', + 'AE', + 'GB', + 'US', + 'UM', + 'UY', + 'UZ', + 'VU', + 'VE', + 'VN', + 'VG', + 'VI', + 'WF', + 'EH', + 'YE', + 'ZM', + 'ZW' + ] + } +} From fa2654be283fc3f8eaea963af5da55f76fcdd681 Mon Sep 17 00:00:00 2001 From: freearhey Date: Sun, 31 Jan 2021 20:11:52 +0300 Subject: [PATCH 27/36] Update generate.js --- scripts/generate.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/generate.js b/scripts/generate.js index 8a52d200c6..7cb05722f9 100644 --- a/scripts/generate.js +++ b/scripts/generate.js @@ -1,5 +1,6 @@ const utils = require('./utils') const parser = require('./parser') +const categories = require('./categories') const ROOT_DIR = './.gh-pages' @@ -40,7 +41,7 @@ function parseIndex() { console.log(`Parsing index...`) const items = parser.parseIndex() - for (const category of utils.supportedCategories) { + for (const category of categories) { list.categories[category.id] = [] } list.categories['other'] = [] @@ -205,7 +206,7 @@ function generateCategories() { const outputDir = `${ROOT_DIR}/categories` utils.createDir(outputDir) - for (const category of utils.supportedCategories) { + for (const category of categories) { const filename = `${outputDir}/${category.id}.m3u` utils.createFile(filename, '#EXTM3U\n') From 28fae67450c3421c2287785d9cd34853d72cf773 Mon Sep 17 00:00:00 2001 From: freearhey Date: Sun, 31 Jan 2021 20:11:56 +0300 Subject: [PATCH 28/36] Update parser.js --- scripts/parser.js | 134 +++++++++++++++++++++++++++------------------- 1 file changed, 79 insertions(+), 55 deletions(-) diff --git a/scripts/parser.js b/scripts/parser.js index 086a90b559..15ddc09afb 100644 --- a/scripts/parser.js +++ b/scripts/parser.js @@ -1,6 +1,7 @@ const playlistParser = require('iptv-playlist-parser') const epgParser = require('epg-parser') const utils = require('./utils') +const categories = require('./categories') const parser = {} @@ -18,54 +19,6 @@ parser.parsePlaylist = function (filename) { return new Playlist({ header: result.header, items: result.items, url: filename }) } -parser.parseCountries = function (string) { - return string - .split(';') - .filter(code => code && utils.codeIsValid(code)) - .map(code => ({ code: code.toLowerCase(), name: utils.code2name(code) })) -} - -parser.parseLanguages = function (string) { - return string - .split(';') - .map(name => { - const code = name ? utils.language2code(name) : null - if (!code) return null - - return { - code, - name - } - }) - .filter(l => l) -} - -parser.parseCategory = function (string) { - const category = utils.supportedCategories.find(c => c.id === string.toLowerCase()) - - return category ? category.name : '' -} - -parser.parseTitle = function (title) { - const channelName = title - .trim() - .split(' ') - .map(s => s.trim()) - .filter(s => { - return !/\[|\]/i.test(s) && !/\((\d+)P\)/i.test(s) - }) - .join(' ') - - const streamStatusMatch = title.match(/\[(.*)\]/i) - const streamStatus = streamStatusMatch ? streamStatusMatch[1] : null - - const streamResolutionMatch = title.match(/\((\d+)P\)/i) - const streamResolutionHeight = streamResolutionMatch ? parseInt(streamResolutionMatch[1]) : null - const streamResolution = { width: null, height: streamResolutionHeight } - - return { channelName, streamStatus, streamResolution } -} - parser.parseEPG = async function (url) { return utils.loadEPG(url).then(content => { const result = epgParser.parse(content) @@ -113,13 +66,14 @@ class Channel { const filename = utils.getBasename(sourceUrl) const countryName = utils.code2name(filename) this.countries = countryName ? [{ code: filename.toLowerCase(), name: countryName }] : [] + this.tvg.country = this.countries.map(c => c.code.toUpperCase()).join(';') } this.tvg.url = header.attrs['x-tvg-url'] || '' } parseData(data) { - const title = parser.parseTitle(data.name) + const title = this.parseTitle(data.name) this.tvg = data.tvg this.http = data.http @@ -128,17 +82,85 @@ class Channel { this.name = title.channelName this.status = title.streamStatus this.resolution = title.streamResolution - this.countries = parser.parseCountries(data.tvg.country) - this.languages = parser.parseLanguages(data.tvg.language) - this.category = parser.parseCategory(data.group.title) + this.countries = this.parseCountries(data.tvg.country) + this.languages = this.parseLanguages(data.tvg.language) + this.category = this.parseCategory(data.group.title) + } + + parseCountries(string) { + let arr = string + .split(';') + .reduce((acc, curr) => { + const codes = utils.region2codes(curr) + if (codes.length) { + for (let code of codes) { + if (!acc.includes(code)) { + acc.push(code) + } + } + } else { + acc.push(curr) + } + + return acc + }, []) + .filter(code => code && utils.code2name(code)) + + return arr.map(code => { + return { code: code.toLowerCase(), name: utils.code2name(code) } + }) + } + + parseLanguages(string) { + return string + .split(';') + .map(name => { + const code = name ? utils.language2code(name) : null + if (!code) return null + + return { + code, + name + } + }) + .filter(l => l) + } + + parseCategory(string) { + const category = categories.find(c => c.id === string.toLowerCase()) + + return category ? category.name : '' + } + + parseTitle(title) { + const channelName = title + .trim() + .split(' ') + .map(s => s.trim()) + .filter(s => { + return !/\[|\]/i.test(s) && !/\((\d+)P\)/i.test(s) + }) + .join(' ') + + const streamStatusMatch = title.match(/\[(.*)\]/i) + const streamStatus = streamStatusMatch ? streamStatusMatch[1] : null + + const streamResolutionMatch = title.match(/\((\d+)P\)/i) + const streamResolutionHeight = streamResolutionMatch ? parseInt(streamResolutionMatch[1]) : null + const streamResolution = { width: null, height: streamResolutionHeight } + + return { channelName, streamStatus, streamResolution } } get tvgCountry() { - return this.countries.map(c => c.code.toUpperCase()).join(';') + return this.tvg.country + .split(';') + .map(code => utils.code2name(code)) + .join(';') } get tvgLanguage() { - return this.languages.map(l => l.name).join(';') + return this.tvg.language } get tvgUrl() { @@ -146,7 +168,9 @@ class Channel { } toString(short = false) { - let info = `-1 tvg-id="${this.tvg.id}" tvg-name="${this.tvg.name}" tvg-language="${this.tvgLanguage}" tvg-logo="${this.logo}" tvg-country="${this.tvgCountry}"` + this.tvg.country = this.tvg.country.toUpperCase() + + let info = `-1 tvg-id="${this.tvg.id}" tvg-name="${this.tvg.name}" tvg-language="${this.tvg.language}" tvg-logo="${this.logo}" tvg-country="${this.tvg.country}"` if (!short) { info += ` tvg-url="${this.tvgUrl}"` From 275d699c081037dbf584794706b170cca477623a Mon Sep 17 00:00:00 2001 From: freearhey Date: Sun, 31 Jan 2021 20:11:59 +0300 Subject: [PATCH 29/36] Update utils.js --- scripts/utils.js | 198 ++++------------------------------------------- 1 file changed, 17 insertions(+), 181 deletions(-) diff --git a/scripts/utils.js b/scripts/utils.js index 6981caa2cf..f48e79474e 100644 --- a/scripts/utils.js +++ b/scripts/utils.js @@ -6,6 +6,8 @@ const urlParser = require('url') const escapeStringRegexp = require('escape-string-regexp') const markdownInclude = require('markdown-include') const iso6393 = require('iso-639-3') +const regions = require('./regions') +const categories = require('./categories') const intlDisplayNames = new Intl.DisplayNames(['en'], { style: 'narrow', type: 'region' @@ -13,201 +15,35 @@ const intlDisplayNames = new Intl.DisplayNames(['en'], { const utils = {} -utils.supportedCategories = [ - { - name: 'Auto', - id: 'auto', - nsfw: false - }, - { - name: 'Business', - id: 'business', - nsfw: false - }, - { - name: 'Classic', - id: 'classic', - nsfw: false - }, - { - name: 'Comedy', - id: 'comedy', - nsfw: false - }, - { - name: 'Documentary', - id: 'documentary', - nsfw: false - }, - { - name: 'Education', - id: 'education', - nsfw: false - }, - { - name: 'Entertainment', - id: 'entertainment', - nsfw: false - }, - { - name: 'Family', - id: 'family', - nsfw: false - }, - { - name: 'Fashion', - id: 'fashion', - nsfw: false - }, - { - name: 'Food', - id: 'food', - nsfw: false - }, - { - name: 'General', - id: 'general', - nsfw: false - }, - { - name: 'Health', - id: 'health', - nsfw: false - }, - { - name: 'History', - id: 'history', - nsfw: false - }, - { - name: 'Hobby', - id: 'hobby', - nsfw: false - }, - { - name: 'Kids', - id: 'kids', - nsfw: false - }, - { - name: 'Legislative', - id: 'legislative', - nsfw: false - }, - { - name: 'Lifestyle', - id: 'lifestyle', - nsfw: false - }, - { - name: 'Local', - id: 'local', - nsfw: false - }, - { - name: 'Movies', - id: 'movies', - nsfw: false - }, - { - name: 'Music', - id: 'music', - nsfw: false - }, - { - name: 'News', - id: 'news', - nsfw: false - }, - { - name: 'Quiz', - id: 'quiz', - nsfw: false - }, - { - name: 'Religious', - id: 'religious', - nsfw: false - }, - { - name: 'Sci-Fi', - id: 'sci-fi', - nsfw: false - }, - { - name: 'Shop', - id: 'shop', - nsfw: false - }, - { - name: 'Sport', - id: 'sport', - nsfw: false - }, - { - name: 'Travel', - id: 'travel', - nsfw: false - }, - { - name: 'Weather', - id: 'weather', - nsfw: false - }, - { - name: 'XXX', - id: 'xxx', - nsfw: true - } -] - utils.code2flag = function (code) { + code = code.toUpperCase() switch (code) { - case 'uk': + case 'UK': return '🇬🇧' - case 'int': - return '🌎' - case 'unsorted': + case 'UNSORTED': return '' default: - return code - .toUpperCase() - .replace(/./g, char => String.fromCodePoint(char.charCodeAt(0) + 127397)) + return code.replace(/./g, char => String.fromCodePoint(char.charCodeAt(0) + 127397)) } } +utils.region2codes = function (region) { + region = region.toUpperCase() + + return regions[region] ? regions[region].codes : [] +} + utils.code2name = function (code) { - switch (code.toLowerCase()) { - case 'int': - return 'International' - case 'us': - return 'United States' - } - try { - return intlDisplayNames.of(code.toUpperCase()) + code = code.toUpperCase() + if (regions[code]) return regions[code].name + if (code === 'US') return 'United States' + return intlDisplayNames.of(code) } catch (e) { return null } } -utils.codeIsValid = function (code) { - switch (code.toLowerCase()) { - case 'int': - return true - case 'us': - return true - } - - try { - intlDisplayNames.of(code.toUpperCase()) - - return true - } catch (e) { - return false - } -} - utils.language2code = function (name) { const lang = iso6393.find(l => l.name === name) @@ -365,7 +201,7 @@ utils.writeToLog = function (country, msg, url) { } utils.filterNSFW = function (arr) { - const sfwCategories = utils.supportedCategories.filter(c => !c.nsfw).map(c => c.name) + const sfwCategories = categories.filter(c => !c.nsfw).map(c => c.name) return arr.filter(i => sfwCategories.includes(i.category)) } From 223ea9990b4abfa49e81182a75da8142d295c560 Mon Sep 17 00:00:00 2001 From: freearhey Date: Sun, 31 Jan 2021 20:19:01 +0300 Subject: [PATCH 30/36] Update update-readme.js --- scripts/update-readme.js | 49 +++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/scripts/update-readme.js b/scripts/update-readme.js index 268b35a37e..bc38c0d933 100644 --- a/scripts/update-readme.js +++ b/scripts/update-readme.js @@ -1,10 +1,11 @@ const utils = require('./utils') const parser = require('./parser') +const categories = require('./categories') const list = { - countries: [], - languages: [], - categories: [] + countries: {}, + languages: {}, + categories: {} } function main() { @@ -20,11 +21,7 @@ function parseIndex() { console.log(`Parsing index...`) const items = parser.parseIndex() - const countries = {} - const languages = {} - const categories = {} - - countries['undefined'] = { + list.countries['undefined'] = { country: 'Undefined', channels: 0, playlist: `https://iptv-org.github.io/iptv/countries/undefined.m3u`, @@ -32,20 +29,20 @@ function parseIndex() { name: 'Undefined' } - languages['undefined'] = { + list.languages['undefined'] = { language: 'Undefined', channels: 0, playlist: `https://iptv-org.github.io/iptv/languages/undefined.m3u` } - for (const category of utils.supportedCategories) { - categories[category.id] = { + for (const category of categories) { + list.categories[category.id] = { category: category.name, channels: 0, playlist: `https://iptv-org.github.io/iptv/categories/${category.id}.m3u` } } - categories['other'] = { + list.categories['other'] = { category: 'Other', channels: 0, playlist: `https://iptv-org.github.io/iptv/categories/other.m3u` @@ -56,14 +53,14 @@ function parseIndex() { for (let channel of playlist.channels) { // countries if (!channel.countries.length) { - countries['undefined'].channels++ + list.countries['undefined'].channels++ } else { for (let country of channel.countries) { - if (countries[country.code]) { - countries[country.code].channels++ + if (list.countries[country.code]) { + list.countries[country.code].channels++ } else { let flag = utils.code2flag(country.code) - countries[country.code] = { + list.countries[country.code] = { country: flag + ' ' + country.name, channels: 1, playlist: `https://iptv-org.github.io/iptv/countries/${country.code}.m3u`, @@ -78,13 +75,13 @@ function parseIndex() { // languages if (!channel.languages.length) { - languages['undefined'].channels++ + list.languages['undefined'].channels++ } else { for (let language of channel.languages) { - if (languages[language.code]) { - languages[language.code].channels++ + if (list.languages[language.code]) { + list.languages[language.code].channels++ } else { - languages[language.code] = { + list.languages[language.code] = { language: language.name, channels: 1, playlist: `https://iptv-org.github.io/iptv/languages/${language.code}.m3u` @@ -96,16 +93,16 @@ function parseIndex() { // categories const categoryId = channel.category.toLowerCase() if (!categoryId) { - categories['other'].channels++ - } else if (categories[categoryId]) { - categories[categoryId].channels++ + list.categories['other'].channels++ + } else if (list.categories[categoryId]) { + list.categories[categoryId].channels++ } } } - list.countries = Object.values(countries) - list.languages = Object.values(languages) - list.categories = Object.values(categories) + list.countries = Object.values(list.countries) + list.languages = Object.values(list.languages) + list.categories = Object.values(list.categories) } function generateCountriesTable() { From e35ad8731766cf2742703b64e173878add09917a Mon Sep 17 00:00:00 2001 From: freearhey Date: Sun, 31 Jan 2021 22:01:34 +0300 Subject: [PATCH 31/36] Convert categories.js to json --- scripts/categories.js | 147 ---------------------------------------- scripts/categories.json | 147 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 147 deletions(-) delete mode 100644 scripts/categories.js create mode 100644 scripts/categories.json diff --git a/scripts/categories.js b/scripts/categories.js deleted file mode 100644 index ef737a7fdf..0000000000 --- a/scripts/categories.js +++ /dev/null @@ -1,147 +0,0 @@ -module.exports = [ - { - name: 'Auto', - id: 'auto', - nsfw: false - }, - { - name: 'Business', - id: 'business', - nsfw: false - }, - { - name: 'Classic', - id: 'classic', - nsfw: false - }, - { - name: 'Comedy', - id: 'comedy', - nsfw: false - }, - { - name: 'Documentary', - id: 'documentary', - nsfw: false - }, - { - name: 'Education', - id: 'education', - nsfw: false - }, - { - name: 'Entertainment', - id: 'entertainment', - nsfw: false - }, - { - name: 'Family', - id: 'family', - nsfw: false - }, - { - name: 'Fashion', - id: 'fashion', - nsfw: false - }, - { - name: 'Food', - id: 'food', - nsfw: false - }, - { - name: 'General', - id: 'general', - nsfw: false - }, - { - name: 'Health', - id: 'health', - nsfw: false - }, - { - name: 'History', - id: 'history', - nsfw: false - }, - { - name: 'Hobby', - id: 'hobby', - nsfw: false - }, - { - name: 'Kids', - id: 'kids', - nsfw: false - }, - { - name: 'Legislative', - id: 'legislative', - nsfw: false - }, - { - name: 'Lifestyle', - id: 'lifestyle', - nsfw: false - }, - { - name: 'Local', - id: 'local', - nsfw: false - }, - { - name: 'Movies', - id: 'movies', - nsfw: false - }, - { - name: 'Music', - id: 'music', - nsfw: false - }, - { - name: 'News', - id: 'news', - nsfw: false - }, - { - name: 'Quiz', - id: 'quiz', - nsfw: false - }, - { - name: 'Religious', - id: 'religious', - nsfw: false - }, - { - name: 'Sci-Fi', - id: 'sci-fi', - nsfw: false - }, - { - name: 'Shop', - id: 'shop', - nsfw: false - }, - { - name: 'Sport', - id: 'sport', - nsfw: false - }, - { - name: 'Travel', - id: 'travel', - nsfw: false - }, - { - name: 'Weather', - id: 'weather', - nsfw: false - }, - { - name: 'XXX', - id: 'xxx', - nsfw: true - } -] diff --git a/scripts/categories.json b/scripts/categories.json new file mode 100644 index 0000000000..8c016cef66 --- /dev/null +++ b/scripts/categories.json @@ -0,0 +1,147 @@ +[ + { + "name": "Auto", + "id": "auto", + "nsfw": false + }, + { + "name": "Business", + "id": "business", + "nsfw": false + }, + { + "name": "Classic", + "id": "classic", + "nsfw": false + }, + { + "name": "Comedy", + "id": "comedy", + "nsfw": false + }, + { + "name": "Documentary", + "id": "documentary", + "nsfw": false + }, + { + "name": "Education", + "id": "education", + "nsfw": false + }, + { + "name": "Entertainment", + "id": "entertainment", + "nsfw": false + }, + { + "name": "Family", + "id": "family", + "nsfw": false + }, + { + "name": "Fashion", + "id": "fashion", + "nsfw": false + }, + { + "name": "Food", + "id": "food", + "nsfw": false + }, + { + "name": "General", + "id": "general", + "nsfw": false + }, + { + "name": "Health", + "id": "health", + "nsfw": false + }, + { + "name": "History", + "id": "history", + "nsfw": false + }, + { + "name": "Hobby", + "id": "hobby", + "nsfw": false + }, + { + "name": "Kids", + "id": "kids", + "nsfw": false + }, + { + "name": "Legislative", + "id": "legislative", + "nsfw": false + }, + { + "name": "Lifestyle", + "id": "lifestyle", + "nsfw": false + }, + { + "name": "Local", + "id": "local", + "nsfw": false + }, + { + "name": "Movies", + "id": "movies", + "nsfw": false + }, + { + "name": "Music", + "id": "music", + "nsfw": false + }, + { + "name": "News", + "id": "news", + "nsfw": false + }, + { + "name": "Quiz", + "id": "quiz", + "nsfw": false + }, + { + "name": "Religious", + "id": "religious", + "nsfw": false + }, + { + "name": "Sci-Fi", + "id": "sci-fi", + "nsfw": false + }, + { + "name": "Shop", + "id": "shop", + "nsfw": false + }, + { + "name": "Sport", + "id": "sport", + "nsfw": false + }, + { + "name": "Travel", + "id": "travel", + "nsfw": false + }, + { + "name": "Weather", + "id": "weather", + "nsfw": false + }, + { + "name": "XXX", + "id": "xxx", + "nsfw": true + } +] From 8a267c79d48ce5a97880390d0342c18f0cada221 Mon Sep 17 00:00:00 2001 From: freearhey Date: Sun, 31 Jan 2021 22:01:46 +0300 Subject: [PATCH 32/36] Convert regions.js to json --- scripts/regions.js | 258 ------------------------ scripts/regions.json | 455 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 455 insertions(+), 258 deletions(-) delete mode 100644 scripts/regions.js create mode 100644 scripts/regions.json diff --git a/scripts/regions.js b/scripts/regions.js deleted file mode 100644 index ecf69898b8..0000000000 --- a/scripts/regions.js +++ /dev/null @@ -1,258 +0,0 @@ -module.exports = { - AFR: { name: 'Africa', codes: [] }, - MENA: { name: 'Middle East and North Africa', codes: [] }, - INT: { - name: 'International', - codes: [ - 'AF', - 'AX', - 'AL', - 'DZ', - 'AS', - 'AD', - 'AO', - 'AI', - 'AQ', - 'AG', - 'AR', - 'AM', - 'AW', - 'AU', - 'AT', - 'AZ', - 'BS', - 'BH', - 'BD', - 'BB', - 'BY', - 'BE', - 'BZ', - 'BJ', - 'BM', - 'BT', - 'BO', - 'BQ', - 'BA', - 'BW', - 'BV', - 'BR', - 'IO', - 'BN', - 'BG', - 'BF', - 'BI', - 'KH', - 'CM', - 'CA', - 'CV', - 'KY', - 'CF', - 'TD', - 'CL', - 'CN', - 'CX', - 'CC', - 'CO', - 'KM', - 'CG', - 'CD', - 'CK', - 'CR', - 'CI', - 'HR', - 'CU', - 'CW', - 'CY', - 'CZ', - 'DK', - 'DJ', - 'DM', - 'DO', - 'EC', - 'EG', - 'SV', - 'GQ', - 'ER', - 'EE', - 'ET', - 'FK', - 'FO', - 'FJ', - 'FI', - 'FR', - 'GF', - 'PF', - 'TF', - 'GA', - 'GM', - 'GE', - 'DE', - 'GH', - 'GI', - 'GR', - 'GL', - 'GD', - 'GP', - 'GU', - 'GT', - 'GG', - 'GN', - 'GW', - 'GY', - 'HT', - 'HM', - 'VA', - 'HN', - 'HK', - 'HU', - 'IS', - 'IN', - 'ID', - 'IR', - 'IQ', - 'IE', - 'IM', - 'IL', - 'IT', - 'JM', - 'JP', - 'JE', - 'JO', - 'KZ', - 'KE', - 'KI', - 'KP', - 'KR', - 'KW', - 'KG', - 'LA', - 'LV', - 'LB', - 'LS', - 'LR', - 'LY', - 'LI', - 'LT', - 'LU', - 'MO', - 'MK', - 'MG', - 'MW', - 'MY', - 'MV', - 'ML', - 'MT', - 'MH', - 'MQ', - 'MR', - 'MU', - 'YT', - 'MX', - 'FM', - 'MD', - 'MC', - 'MN', - 'ME', - 'MS', - 'MA', - 'MZ', - 'MM', - 'NA', - 'NR', - 'NP', - 'NL', - 'NC', - 'NZ', - 'NI', - 'NE', - 'NG', - 'NU', - 'NF', - 'MP', - 'NO', - 'OM', - 'PK', - 'PW', - 'PS', - 'PA', - 'PG', - 'PY', - 'PE', - 'PH', - 'PN', - 'PL', - 'PT', - 'PR', - 'QA', - 'RE', - 'RO', - 'RU', - 'RW', - 'BL', - 'SH', - 'KN', - 'LC', - 'MF', - 'PM', - 'VC', - 'WS', - 'SM', - 'ST', - 'SA', - 'SN', - 'RS', - 'SC', - 'SL', - 'SG', - 'SX', - 'SK', - 'SI', - 'SB', - 'SO', - 'ZA', - 'GS', - 'SS', - 'ES', - 'LK', - 'SD', - 'SR', - 'SJ', - 'SZ', - 'SE', - 'CH', - 'SY', - 'TW', - 'TJ', - 'TZ', - 'TH', - 'TL', - 'TG', - 'TK', - 'TO', - 'TT', - 'TN', - 'TR', - 'TM', - 'TC', - 'TV', - 'UG', - 'UA', - 'AE', - 'GB', - 'US', - 'UM', - 'UY', - 'UZ', - 'VU', - 'VE', - 'VN', - 'VG', - 'VI', - 'WF', - 'EH', - 'YE', - 'ZM', - 'ZW' - ] - } -} diff --git a/scripts/regions.json b/scripts/regions.json new file mode 100644 index 0000000000..863379a782 --- /dev/null +++ b/scripts/regions.json @@ -0,0 +1,455 @@ +{ + "ASIA": { + "name": "Asia", + "codes": [ + "AF", + "AM", + "AZ", + "BH", + "BD", + "BT", + "BN", + "KH", + "CN", + "CY", + "TL", + "GE", + "IN", + "ID", + "IR", + "IQ", + "IL", + "JP", + "JO", + "KZ", + "KW", + "KG", + "LA", + "LB", + "MY", + "MV", + "MN", + "MM", + "NP", + "KP", + "OM", + "PK", + "PS", + "PH", + "QA", + "RU", + "SA", + "SG", + "KR", + "LK", + "SY", + "TW", + "TJ", + "TH", + "TR", + "TM", + "AE", + "UZ", + "VN", + "YE" + ] + }, + "AFR": { + "name": "Africa", + "codes": [ + "AO", + "BI", + "CD", + "CM", + "CF", + "TD", + "CG", + "GQ", + "GA", + "KE", + "NG", + "RW", + "ST", + "TZ", + "UG", + "SD", + "SS", + "DJ", + "ER", + "ET", + "SO", + "BW", + "KM", + "LS", + "MG", + "MW", + "MU", + "MZ", + "NA", + "SC", + "ZA", + "SZ", + "ZM", + "ZW", + "BJ", + "ML", + "BF", + "CV", + "CI", + "GM", + "GH", + "GN", + "GW", + "LR", + "MR", + "NE", + "SN", + "SL", + "TG", + "TN", + "EH", + "EG", + "TF", + "LY", + "YT", + "MA", + "RE", + "SH", + "DZ" + ] + }, + "SSA": { + "name": "Sub-Saharan Africa", + "codes": [ + "AO", + "BI", + "CD", + "CM", + "CF", + "TD", + "CG", + "GQ", + "GA", + "KE", + "NG", + "RW", + "ST", + "TZ", + "UG", + "SD", + "SS", + "DJ", + "ER", + "ET", + "SO", + "BW", + "KM", + "LS", + "MG", + "MW", + "MU", + "MZ", + "NA", + "SC", + "ZA", + "SZ", + "ZM", + "ZW", + "BJ", + "ML", + "BF", + "CV", + "CI", + "GM", + "GH", + "GN", + "GW", + "LR", + "MR", + "NE", + "SN", + "SL", + "TG" + ] + }, + "MENA": { + "name": "Middle East and North Africa", + "codes": [ + "DZ", + "BH", + "DJ", + "EG", + "IR", + "IQ", + "JO", + "KW", + "LB", + "LY", + "MA", + "OM", + "PS", + "QA", + "SA", + "SD", + "SY", + "TN", + "AE", + "EH", + "YE" + ] + }, + "INT": { + "name": "International", + "codes": [ + "AF", + "AX", + "AL", + "DZ", + "AS", + "AD", + "AO", + "AI", + "AQ", + "AG", + "AR", + "AM", + "AW", + "AU", + "AT", + "AZ", + "BS", + "BH", + "BD", + "BB", + "BY", + "BE", + "BZ", + "BJ", + "BM", + "BT", + "BO", + "BQ", + "BA", + "BW", + "BV", + "BR", + "IO", + "BN", + "BG", + "BF", + "BI", + "KH", + "CM", + "CA", + "CV", + "KY", + "CF", + "TD", + "CL", + "CN", + "CX", + "CC", + "CO", + "KM", + "CG", + "CD", + "CK", + "CR", + "CI", + "HR", + "CU", + "CW", + "CY", + "CZ", + "DK", + "DJ", + "DM", + "DO", + "EC", + "EG", + "SV", + "GQ", + "ER", + "EE", + "ET", + "FK", + "FO", + "FJ", + "FI", + "FR", + "GF", + "PF", + "TF", + "GA", + "GM", + "GE", + "DE", + "GH", + "GI", + "GR", + "GL", + "GD", + "GP", + "GU", + "GT", + "GG", + "GN", + "GW", + "GY", + "HT", + "HM", + "VA", + "HN", + "HK", + "HU", + "IS", + "IN", + "ID", + "IR", + "IQ", + "IE", + "IM", + "IL", + "IT", + "JM", + "JP", + "JE", + "JO", + "KZ", + "KE", + "KI", + "KP", + "KR", + "KW", + "KG", + "LA", + "LV", + "LB", + "LS", + "LR", + "LY", + "LI", + "LT", + "LU", + "MO", + "MK", + "MG", + "MW", + "MY", + "MV", + "ML", + "MT", + "MH", + "MQ", + "MR", + "MU", + "YT", + "MX", + "FM", + "MD", + "MC", + "MN", + "ME", + "MS", + "MA", + "MZ", + "MM", + "NA", + "NR", + "NP", + "NL", + "NC", + "NZ", + "NI", + "NE", + "NG", + "NU", + "NF", + "MP", + "NO", + "OM", + "PK", + "PW", + "PS", + "PA", + "PG", + "PY", + "PE", + "PH", + "PN", + "PL", + "PT", + "PR", + "QA", + "RE", + "RO", + "RU", + "RW", + "BL", + "SH", + "KN", + "LC", + "MF", + "PM", + "VC", + "WS", + "SM", + "ST", + "SA", + "SN", + "RS", + "SC", + "SL", + "SG", + "SX", + "SK", + "SI", + "SB", + "SO", + "ZA", + "GS", + "SS", + "ES", + "LK", + "SD", + "SR", + "SJ", + "SZ", + "SE", + "CH", + "SY", + "TW", + "TJ", + "TZ", + "TH", + "TL", + "TG", + "TK", + "TO", + "TT", + "TN", + "TR", + "TM", + "TC", + "TV", + "UG", + "UA", + "AE", + "GB", + "US", + "UM", + "UY", + "UZ", + "VU", + "VE", + "VN", + "VG", + "VI", + "WF", + "EH", + "YE", + "ZM", + "ZW" + ] + } +} From 0c87eb8da5e74c04581226b09cda2afc08f73354 Mon Sep 17 00:00:00 2001 From: freearhey Date: Sun, 31 Jan 2021 22:04:55 +0300 Subject: [PATCH 33/36] Sort the codes --- scripts/regions.json | 506 +++++++++++++++++++++---------------------- 1 file changed, 253 insertions(+), 253 deletions(-) diff --git a/scripts/regions.json b/scripts/regions.json index 863379a782..d7f5e976e2 100644 --- a/scripts/regions.json +++ b/scripts/regions.json @@ -2,53 +2,53 @@ "ASIA": { "name": "Asia", "codes": [ + "AE", "AF", "AM", "AZ", - "BH", "BD", - "BT", + "BH", "BN", - "KH", + "BT", "CN", "CY", - "TL", "GE", - "IN", "ID", - "IR", - "IQ", "IL", - "JP", + "IN", + "IQ", + "IR", "JO", - "KZ", - "KW", + "JP", "KG", + "KH", + "KP", + "KR", + "KW", + "KZ", "LA", "LB", - "MY", - "MV", - "MN", + "LK", "MM", + "MN", + "MV", + "MY", "NP", - "KP", "OM", + "PH", "PK", "PS", - "PH", "QA", "RU", "SA", "SG", - "KR", - "LK", "SY", - "TW", - "TJ", "TH", - "TR", + "TJ", + "TL", "TM", - "AE", + "TR", + "TW", "UZ", "VN", "YE" @@ -58,129 +58,131 @@ "name": "Africa", "codes": [ "AO", + "BF", "BI", + "BJ", + "BW", "CD", - "CM", "CF", - "TD", "CG", - "GQ", - "GA", - "KE", - "NG", - "RW", - "ST", - "TZ", - "UG", - "SD", - "SS", + "CI", + "CM", + "CV", "DJ", + "DZ", + "EG", + "EH", "ER", "ET", - "SO", - "BW", + "GA", + "GH", + "GM", + "GN", + "GQ", + "GW", + "KE", "KM", + "LR", "LS", + "LY", + "MA", "MG", - "MW", + "ML", + "MR", "MU", + "MW", "MZ", "NA", - "SC", - "ZA", - "SZ", - "ZM", - "ZW", - "BJ", - "ML", - "BF", - "CV", - "CI", - "GM", - "GH", - "GN", - "GW", - "LR", - "MR", "NE", - "SN", + "NG", + "RE", + "RW", + "SC", + "SD", + "SH", "SL", + "SN", + "SO", + "SS", + "ST", + "SZ", + "TD", + "TF", "TG", "TN", - "EH", - "EG", - "TF", - "LY", + "TZ", + "UG", "YT", - "MA", - "RE", - "SH", - "DZ" + "ZA", + "ZM", + "ZW" ] }, "SSA": { "name": "Sub-Saharan Africa", "codes": [ "AO", + "BF", "BI", + "BJ", + "BW", "CD", - "CM", "CF", - "TD", "CG", - "GQ", - "GA", - "KE", - "NG", - "RW", - "ST", - "TZ", - "UG", - "SD", - "SS", + "CI", + "CM", + "CV", "DJ", "ER", "ET", - "SO", - "BW", + "GA", + "GH", + "GM", + "GN", + "GQ", + "GW", + "KE", "KM", + "LR", "LS", "MG", - "MW", + "ML", + "MR", "MU", + "MW", "MZ", "NA", - "SC", - "ZA", - "SZ", - "ZM", - "ZW", - "BJ", - "ML", - "BF", - "CV", - "CI", - "GM", - "GH", - "GN", - "GW", - "LR", - "MR", "NE", - "SN", + "NG", + "RW", + "SC", + "SD", "SL", - "TG" + "SN", + "SO", + "SS", + "ST", + "SZ", + "TD", + "TG", + "TZ", + "UG", + "ZA", + "ZM", + "ZW" ] }, "MENA": { "name": "Middle East and North Africa", "codes": [ - "DZ", + "AE", "BH", "DJ", + "DZ", "EG", - "IR", + "EH", "IQ", + "IR", "JO", "KW", "LB", @@ -193,261 +195,259 @@ "SD", "SY", "TN", - "AE", - "EH", "YE" ] }, "INT": { "name": "International", "codes": [ - "AF", - "AX", - "AL", - "DZ", - "AS", "AD", - "AO", - "AI", - "AQ", + "AE", + "AF", "AG", - "AR", + "AI", + "AL", "AM", - "AW", - "AU", + "AO", + "AQ", + "AR", + "AS", "AT", + "AU", + "AW", + "AX", "AZ", - "BS", - "BH", - "BD", + "BA", "BB", - "BY", + "BD", "BE", - "BZ", + "BF", + "BG", + "BH", + "BI", "BJ", + "BL", "BM", - "BT", + "BN", "BO", "BQ", - "BA", - "BW", - "BV", "BR", - "IO", - "BN", - "BG", - "BF", - "BI", - "KH", - "CM", + "BS", + "BT", + "BV", + "BW", + "BY", + "BZ", "CA", - "CV", - "KY", - "CF", - "TD", - "CL", - "CN", - "CX", "CC", - "CO", - "KM", - "CG", "CD", - "CK", - "CR", + "CF", + "CG", + "CH", "CI", - "HR", + "CK", + "CL", + "CM", + "CN", + "CO", + "CR", "CU", + "CV", "CW", + "CX", "CY", "CZ", - "DK", + "DE", "DJ", + "DK", "DM", "DO", + "DZ", "EC", - "EG", - "SV", - "GQ", - "ER", "EE", + "EG", + "EH", + "ER", + "ES", "ET", - "FK", - "FO", - "FJ", "FI", + "FJ", + "FK", + "FM", + "FO", "FR", - "GF", - "PF", - "TF", "GA", - "GM", + "GB", + "GD", "GE", - "DE", + "GF", + "GG", "GH", "GI", - "GR", "GL", - "GD", - "GP", - "GU", - "GT", - "GG", + "GM", "GN", + "GP", + "GQ", + "GR", + "GS", + "GT", + "GU", "GW", "GY", - "HT", - "HM", - "VA", - "HN", "HK", + "HM", + "HN", + "HR", + "HT", "HU", - "IS", - "IN", "ID", - "IR", - "IQ", "IE", - "IM", "IL", + "IM", + "IN", + "IO", + "IQ", + "IR", + "IS", "IT", - "JM", - "JP", "JE", + "JM", "JO", - "KZ", + "JP", "KE", + "KG", + "KH", "KI", + "KM", + "KN", "KP", "KR", "KW", - "KG", + "KY", + "KZ", "LA", - "LV", "LB", - "LS", - "LR", - "LY", + "LC", "LI", + "LK", + "LR", + "LS", "LT", "LU", - "MO", - "MK", + "LV", + "LY", + "MA", + "MC", + "MD", + "ME", + "MF", "MG", - "MW", - "MY", - "MV", - "ML", - "MT", "MH", + "MK", + "ML", + "MM", + "MN", + "MO", + "MP", "MQ", "MR", - "MU", - "YT", - "MX", - "FM", - "MD", - "MC", - "MN", - "ME", "MS", - "MA", + "MT", + "MU", + "MV", + "MW", + "MX", + "MY", "MZ", - "MM", "NA", - "NR", - "NP", - "NL", "NC", - "NZ", - "NI", "NE", - "NG", - "NU", "NF", - "MP", + "NG", + "NI", + "NL", "NO", + "NP", + "NR", + "NU", + "NZ", "OM", - "PK", - "PW", - "PS", "PA", - "PG", - "PY", "PE", + "PF", + "PG", "PH", - "PN", + "PK", "PL", - "PT", + "PM", + "PN", "PR", + "PS", + "PT", + "PW", + "PY", "QA", "RE", "RO", + "RS", "RU", "RW", - "BL", - "SH", - "KN", - "LC", - "MF", - "PM", - "VC", - "WS", - "SM", - "ST", "SA", - "SN", - "RS", - "SC", - "SL", - "SG", - "SX", - "SK", - "SI", "SB", - "SO", - "ZA", - "GS", - "SS", - "ES", - "LK", + "SC", "SD", - "SR", - "SJ", - "SZ", "SE", - "CH", + "SG", + "SH", + "SI", + "SJ", + "SK", + "SL", + "SM", + "SN", + "SO", + "SR", + "SS", + "ST", + "SV", + "SX", "SY", - "TW", - "TJ", - "TZ", - "TH", - "TL", - "TG", - "TK", - "TO", - "TT", - "TN", - "TR", - "TM", + "SZ", "TC", + "TD", + "TF", + "TG", + "TH", + "TJ", + "TK", + "TL", + "TM", + "TN", + "TO", + "TR", + "TT", "TV", - "UG", + "TW", + "TZ", "UA", - "AE", - "GB", - "US", + "UG", "UM", + "US", "UY", "UZ", - "VU", + "VA", + "VC", "VE", - "VN", "VG", "VI", + "VN", + "VU", "WF", - "EH", + "WS", "YE", + "YT", + "ZA", "ZM", "ZW" ] From fe847b2549cad9dcd6cf2d4bb067759eb3967054 Mon Sep 17 00:00:00 2001 From: freearhey Date: Mon, 1 Feb 2021 07:28:40 +0300 Subject: [PATCH 34/36] Update regions.json --- scripts/regions.json | 594 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 514 insertions(+), 80 deletions(-) diff --git a/scripts/regions.json b/scripts/regions.json index d7f5e976e2..3ecc3e707f 100644 --- a/scripts/regions.json +++ b/scripts/regions.json @@ -1,59 +1,4 @@ { - "ASIA": { - "name": "Asia", - "codes": [ - "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" - ] - }, "AFR": { "name": "Africa", "codes": [ @@ -118,84 +63,382 @@ "ZW" ] }, - "SSA": { - "name": "Sub-Saharan Africa", + "AMER": { + "name": "Americas", "codes": [ + "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" + ] + }, + "APAC": { + "name": "Asia-Pacific", + "codes": [ + "AE", + "AF", + "AM", + "AS", + "AU", + "AZ", + "BD", + "BH", + "BN", + "BT", + "CK", + "CN", + "CY", + "FJ", + "FM", + "GE", + "GU", + "ID", + "IL", + "IN", + "IQ", + "IR", + "JO", + "JP", + "KG", + "KH", + "KI", + "KP", + "KR", + "KW", + "KZ", + "LA", + "LB", + "LK", + "MH", + "MM", + "MN", + "MP", + "MV", + "MY", + "NC", + "NF", + "NP", + "NR", + "NU", + "NZ", + "OM", + "PF", + "PG", + "PH", + "PK", + "PN", + "PS", + "PW", + "QA", + "RU", + "SA", + "SB", + "SG", + "SY", + "TH", + "TJ", + "TK", + "TL", + "TM", + "TO", + "TR", + "TV", + "TW", + "UZ", + "VN", + "VU", + "WF", + "WS", + "YE" + ] + }, + "ASIA": { + "name": "Asia", + "codes": [ + "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" + ] + }, + "EMEA": { + "name": "Europe, Middle East and Africa", + "codes": [ + "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", + "GB", + "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", + "VA", + "YE", + "YT", "ZA", "ZM", "ZW" ] }, - "MENA": { - "name": "Middle East and North Africa", + "EUR": { + "name": "Europe", "codes": [ - "AE", - "BH", - "DJ", - "DZ", - "EG", - "EH", - "IQ", - "IR", - "JO", - "KW", - "LB", - "LY", - "MA", - "OM", - "PS", - "QA", - "SA", - "SD", - "SY", - "TN", - "YE" + "AD", + "AL", + "AM", + "AT", + "AZ", + "BA", + "BE", + "BG", + "BY", + "CH", + "CY", + "CZ", + "DE", + "DK", + "EE", + "ES", + "FI", + "FR", + "GB", + "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", + "VA" ] }, "INT": { @@ -451,5 +694,196 @@ "ZM", "ZW" ] + }, + "MEA": { + "name": "Middle East and Africa", + "codes": [ + "AE", + "AO", + "BF", + "BH", + "BI", + "BJ", + "BW", + "CD", + "CF", + "CG", + "CI", + "CM", + "CV", + "DJ", + "DZ", + "EG", + "EH", + "ER", + "ET", + "GA", + "GH", + "GM", + "GN", + "GQ", + "GW", + "IQ", + "IR", + "JO", + "KE", + "KM", + "KW", + "LB", + "LR", + "LS", + "LY", + "MA", + "MG", + "ML", + "MR", + "MU", + "MW", + "MZ", + "NA", + "NE", + "NG", + "OM", + "PS", + "QA", + "RE", + "RW", + "SA", + "SC", + "SD", + "SH", + "SL", + "SN", + "SO", + "SS", + "ST", + "SY", + "SZ", + "TD", + "TF", + "TG", + "TN", + "TZ", + "UG", + "YE", + "YT", + "ZA", + "ZM", + "ZW" + ] + }, + "MENA": { + "name": "Middle East and North Africa", + "codes": [ + "AE", + "BH", + "DJ", + "DZ", + "EG", + "EH", + "IQ", + "IR", + "JO", + "KW", + "LB", + "LY", + "MA", + "OM", + "PS", + "QA", + "SA", + "SD", + "SY", + "TN", + "YE" + ] + }, + "NORD": { + "name": "Nordics", + "codes": ["AX", "DK", "FO", "FI", "IS", "NO", "SE"] + }, + "OCE": { + "name": "Oceania", + "codes": [ + "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" + ] + }, + "SSA": { + "name": "Sub-Saharan Africa", + "codes": [ + "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" + ] } } From b70cbd8fe789da0bcbb23b50500874d0164b127c Mon Sep 17 00:00:00 2001 From: freearhey Date: Sun, 7 Feb 2021 04:51:12 +0300 Subject: [PATCH 35/36] Added LATAM, MIDEAST, NORAM and SAS --- scripts/regions.json | 102 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/scripts/regions.json b/scripts/regions.json index 3ecc3e707f..6084e09698 100644 --- a/scripts/regions.json +++ b/scripts/regions.json @@ -695,6 +695,37 @@ "ZW" ] }, + "LATAM": { + "name": "Latin America", + "codes": [ + "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" + ] + }, "MEA": { "name": "Middle East and Africa", "codes": [ @@ -832,6 +863,77 @@ "WS" ] }, + "MIDEAST": { + "name": "Middle East", + "codes": [ + "AE", + "BH", + "CY", + "EG", + "IL", + "IQ", + "IR", + "JO", + "KW", + "LB", + "OM", + "PS", + "QA", + "SA", + "SY", + "TR", + "YE" + ] + }, + "NORAM": { + "name": "North America", + "codes": [ + "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" + ] + }, + "SAS": { + "name": "South Asia", + "codes": ["AF", "BD", "BT", "IN", "LK", "MV", "NP", "PK"] + }, "SSA": { "name": "Sub-Saharan Africa", "codes": [ From d61777d1325dc1ace50ad68bd88adfaaea8976cc Mon Sep 17 00:00:00 2001 From: freearhey Date: Sun, 7 Feb 2021 05:17:35 +0300 Subject: [PATCH 36/36] Added CARIB codes --- scripts/regions.json | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/scripts/regions.json b/scripts/regions.json index 6084e09698..a3626d2c06 100644 --- a/scripts/regions.json +++ b/scripts/regions.json @@ -259,6 +259,38 @@ "YE" ] }, + "CARIB": { + "name": "Caribbean", + "codes": [ + "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" + ] + }, "EMEA": { "name": "Europe, Middle East and Africa", "codes": [