From 2a1eb57c05f126cd5913aa91018866b724c33722 Mon Sep 17 00:00:00 2001 From: Aleksandr Statciuk Date: Thu, 16 Sep 2021 03:30:52 +0300 Subject: [PATCH 1/9] Update Playlist.js --- scripts/helpers/Playlist.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/scripts/helpers/Playlist.js b/scripts/helpers/Playlist.js index 6b797c96c..0df181a2d 100644 --- a/scripts/helpers/Playlist.js +++ b/scripts/helpers/Playlist.js @@ -11,17 +11,21 @@ module.exports = class Playlist { this.updated = false } - toString(options = {}) { - const config = { raw: false, ...options } - let parts = ['#EXTM3U'] + getHeader() { + let header = ['#EXTM3U'] for (let key in this.header.attrs) { let value = this.header.attrs[key] if (value) { - parts.push(`${key}="${value}"`) + header.push(`${key}="${value}"`) } } - let output = `${parts.join(' ')}\n` + return header.join(' ') + } + + toString(options = {}) { + const config = { raw: false, ...options } + let output = `${this.getHeader()}\n` for (let channel of this.channels) { output += channel.toString(config.raw) } From d7f3998a3d74ed6c995e5a6d8b097827a7d0e404 Mon Sep 17 00:00:00 2001 From: Aleksandr Statciuk Date: Thu, 16 Sep 2021 03:53:03 +0300 Subject: [PATCH 2/9] Install axios package --- package-lock.json | 57 ++++++++++++++++++++++++++++------------------- package.json | 1 + 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index d377bf1b2..ebcda9db2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,9 +4,11 @@ "requires": true, "packages": { "": { + "name": "iptv", "license": "MIT", "dependencies": { "@freearhey/iso-639-3": "^1.0.0", + "axios": "^0.21.4", "commander": "^7.0.0", "iptv-checker": "^0.21.0", "iptv-playlist-parser": "^0.5.4", @@ -1046,19 +1048,11 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "node_modules/axios": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", - "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", "dependencies": { - "follow-redirects": "^1.10.0" - } - }, - "node_modules/axios/node_modules/follow-redirects": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz", - "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==", - "engines": { - "node": ">=4.0" + "follow-redirects": "^1.14.0" } }, "node_modules/babel-jest": { @@ -1679,6 +1673,25 @@ "node": ">=8" } }, + "node_modules/follow-redirects": { + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", + "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/form-data": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", @@ -4615,18 +4628,11 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "axios": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", - "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", "requires": { - "follow-redirects": "^1.10.0" - }, - "dependencies": { - "follow-redirects": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz", - "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==" - } + "follow-redirects": "^1.14.0" } }, "babel-jest": { @@ -5091,6 +5097,11 @@ "path-exists": "^4.0.0" } }, + "follow-redirects": { + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", + "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==" + }, "form-data": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", diff --git a/package.json b/package.json index dff30960a..b2eb86fad 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "license": "MIT", "dependencies": { "@freearhey/iso-639-3": "^1.0.0", + "axios": "^0.21.4", "commander": "^7.0.0", "iptv-checker": "^0.21.0", "iptv-playlist-parser": "^0.5.4", From 7f2c5b36c975d0cb7c6473c5369076e43e1293c0 Mon Sep 17 00:00:00 2001 From: Aleksandr Statciuk Date: Thu, 16 Sep 2021 03:53:06 +0300 Subject: [PATCH 3/9] Create epg.js --- scripts/helpers/epg.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 scripts/helpers/epg.js diff --git a/scripts/helpers/epg.js b/scripts/helpers/epg.js new file mode 100644 index 000000000..202a89e89 --- /dev/null +++ b/scripts/helpers/epg.js @@ -0,0 +1,12 @@ +const axios = require('axios') + +module.exports = { + codes: { + async load() { + return await axios + .get('https://iptv-org.github.io/epg/codes.json') + .then(r => r.data) + .catch(console.log) + } + } +} From 7e811f4c33402cd7a97c90a7a10b6a1d213d8c25 Mon Sep 17 00:00:00 2001 From: Aleksandr Statciuk Date: Thu, 16 Sep 2021 04:26:25 +0300 Subject: [PATCH 4/9] Update db.js --- scripts/helpers/db.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/scripts/helpers/db.js b/scripts/helpers/db.js index 859a41576..20c8ff7f1 100644 --- a/scripts/helpers/db.js +++ b/scripts/helpers/db.js @@ -2,15 +2,22 @@ const categories = require('../data/categories') const parser = require('./parser') const utils = require('./utils') const file = require('./file') +const epg = require('./epg') const db = {} db.load = async function () { - let files = await file.list() + const files = await file.list() + const codes = await epg.codes.load() for (const file of files) { const playlist = await parser.parsePlaylist(file) - db.playlists.add(playlist) + let guides = [] for (const channel of playlist.channels) { + const code = codes.find(ch => ch['tvg_id'] === channel.tvg.id) + if (code && Array.isArray(code.guides)) { + guides = [...guides, ...code.guides] + } + db.channels.add(channel) for (const country of channel.countries) { @@ -25,6 +32,10 @@ db.load = async function () { } } } + + if (guides.length) playlist.header.attrs['url-tvg'] = guides.join(',') + + db.playlists.add(playlist) } } From b4c430a5101b93508c308a560686c933edcaf069 Mon Sep 17 00:00:00 2001 From: Aleksandr Statciuk Date: Fri, 17 Sep 2021 14:22:25 +0300 Subject: [PATCH 5/9] Update format.js --- scripts/format.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/format.js b/scripts/format.js index f70d11b39..99f9643bf 100644 --- a/scripts/format.js +++ b/scripts/format.js @@ -187,10 +187,6 @@ function parseRequests(requests) { function updateDescription(channel, playlist) { const code = playlist.country.code - // tvg-name - if (!channel.tvg.name && channel.name) { - channel.tvg.name = channel.name.replace(/\"/gi, '') - } // tvg-id if (!channel.tvg.id && channel.tvg.name) { const id = utils.name2id(channel.tvg.name) From 52e8e617e19ae23e0c7c251ded6f417e20fe11b3 Mon Sep 17 00:00:00 2001 From: Aleksandr Statciuk Date: Fri, 17 Sep 2021 14:22:29 +0300 Subject: [PATCH 6/9] Update Channel.js --- scripts/helpers/Channel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/helpers/Channel.js b/scripts/helpers/Channel.js index d938c2bb1..aa10bc880 100644 --- a/scripts/helpers/Channel.js +++ b/scripts/helpers/Channel.js @@ -148,7 +148,7 @@ module.exports = class Channel { countries: this.countries, tvg: { id: this.tvg.id || null, - name: this.tvg.name || null, + name: this.tvg.name || this.name.replace(/\"/gi, ''), url: this.tvg.url || null } } From 11cc75fa2ad0a7756d058366766f9e6a5c41c413 Mon Sep 17 00:00:00 2001 From: Aleksandr Statciuk Date: Fri, 17 Sep 2021 14:24:50 +0300 Subject: [PATCH 7/9] Update db.js --- scripts/helpers/db.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/scripts/helpers/db.js b/scripts/helpers/db.js index 20c8ff7f1..0545a6c73 100644 --- a/scripts/helpers/db.js +++ b/scripts/helpers/db.js @@ -11,11 +11,10 @@ db.load = async function () { const codes = await epg.codes.load() for (const file of files) { const playlist = await parser.parsePlaylist(file) - let guides = [] for (const channel of playlist.channels) { const code = codes.find(ch => ch['tvg_id'] === channel.tvg.id) - if (code && Array.isArray(code.guides)) { - guides = [...guides, ...code.guides] + if (code && Array.isArray(code.guides) && code.guides.length) { + channel.tvg.url = code.guides[0] } db.channels.add(channel) @@ -33,8 +32,6 @@ db.load = async function () { } } - if (guides.length) playlist.header.attrs['url-tvg'] = guides.join(',') - db.playlists.add(playlist) } } From fb427d5bd3e54973ff8947ecb57d9b13aaac90ad Mon Sep 17 00:00:00 2001 From: Aleksandr Statciuk Date: Fri, 17 Sep 2021 14:25:23 +0300 Subject: [PATCH 8/9] Update generate.js --- scripts/generate.js | 91 +++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 33 deletions(-) diff --git a/scripts/generate.js b/scripts/generate.js index 3a2e6a7a3..4b50ec3c1 100644 --- a/scripts/generate.js +++ b/scripts/generate.js @@ -36,13 +36,16 @@ function createNoJekyllFile() { function generateIndex() { log.print('Generating index.m3u...\n') + const channels = db.channels.sortBy(['name', 'url']).removeDuplicates().removeOffline().get() + const guides = channels.map(channel => channel.tvg.url) + const filename = `${ROOT_DIR}/index.m3u` - file.create(filename, '#EXTM3U\n') + const urlTvg = generateUrlTvg(guides) + file.create(filename, `#EXTM3U url-tvg="${urlTvg}"\n`) const nsfwFilename = `${ROOT_DIR}/index.nsfw.m3u` - file.create(nsfwFilename, '#EXTM3U\n') + file.create(nsfwFilename, `#EXTM3U url-tvg="${urlTvg}"\n`) - const channels = db.channels.sortBy(['name', 'url']).removeDuplicates().removeOffline().get() for (const channel of channels) { if (!channel.isNSFW()) { file.append(filename, channel.toString()) @@ -53,14 +56,17 @@ function generateIndex() { function generateCategoryIndex() { log.print('Generating index.category.m3u...\n') - const filename = `${ROOT_DIR}/index.category.m3u` - file.create(filename, '#EXTM3U\n') - const channels = db.channels .sortBy(['category', 'name', 'url']) .removeDuplicates() .removeOffline() .get() + const guides = channels.map(channel => channel.tvg.url) + + const filename = `${ROOT_DIR}/index.category.m3u` + const urlTvg = generateUrlTvg(guides) + file.create(filename, `#EXTM3U url-tvg="${urlTvg}"\n`) + for (const channel of channels) { file.append(filename, channel.toString()) } @@ -68,50 +74,56 @@ function generateCategoryIndex() { function generateCountryIndex() { log.print('Generating index.country.m3u...\n') - const filename = `${ROOT_DIR}/index.country.m3u` - file.create(filename, '#EXTM3U\n') + const guides = [] + const lines = [] for (const country of [{ code: 'undefined' }, ...db.countries.sortBy(['name']).all()]) { const channels = db.channels .sortBy(['name', 'url']) .forCountry(country) .removeDuplicates() + .removeNSFW() .removeOffline() .get() for (const channel of channels) { const groupTitle = channel.group.title - const nsfw = channel.isNSFW() channel.group.title = country.name || '' - if (!nsfw) { - file.append(filename, channel.toString()) - } + lines.push(channel.toString()) channel.group.title = groupTitle + guides.push(channel.tvg.url) } } + + const filename = `${ROOT_DIR}/index.country.m3u` + const urlTvg = generateUrlTvg(guides) + file.create(filename, `#EXTM3U url-tvg="${urlTvg}"\n${lines.join('')}`) } function generateLanguageIndex() { log.print('Generating index.language.m3u...\n') - const filename = `${ROOT_DIR}/index.language.m3u` - file.create(filename, '#EXTM3U\n') + const guides = [] + const lines = [] for (const language of [{ code: 'undefined' }, ...db.languages.sortBy(['name']).all()]) { const channels = db.channels .sortBy(['name', 'url']) .forLanguage(language) .removeDuplicates() + .removeNSFW() .removeOffline() .get() for (const channel of channels) { const groupTitle = channel.group.title - const nsfw = channel.isNSFW() channel.group.title = language.name || '' - if (!nsfw) { - file.append(filename, channel.toString()) - } + lines.push(channel.toString()) channel.group.title = groupTitle + guides.push(channel.tvg.url) } } + + const filename = `${ROOT_DIR}/index.language.m3u` + const urlTvg = generateUrlTvg(guides) + file.create(filename, `#EXTM3U url-tvg="${urlTvg}"\n${lines.join('')}`) } function generateCategories() { @@ -120,15 +132,17 @@ function generateCategories() { file.createDir(outputDir) for (const category of [...db.categories.all(), { id: 'other' }]) { - const filename = `${outputDir}/${category.id}.m3u` - file.create(filename, '#EXTM3U\n') - const channels = db.channels .sortBy(['name', 'url']) .forCategory(category) .removeDuplicates() .removeOffline() .get() + const guides = channels.map(channel => channel.tvg.url) + + const filename = `${outputDir}/${category.id}.m3u` + const urlTvg = generateUrlTvg(guides) + file.create(filename, `#EXTM3U url-tvg="${urlTvg}"\n`) for (const channel of channels) { file.append(filename, channel.toString()) } @@ -141,19 +155,20 @@ function generateCountries() { file.createDir(outputDir) for (const country of [...db.countries.all(), { code: 'undefined' }]) { - const filename = `${outputDir}/${country.code}.m3u` - file.create(filename, '#EXTM3U\n') - const channels = db.channels .sortBy(['name', 'url']) .forCountry(country) .removeDuplicates() .removeOffline() + .removeNSFW() .get() + const guides = channels.map(channel => channel.tvg.url) + + const filename = `${outputDir}/${country.code}.m3u` + const urlTvg = generateUrlTvg(guides) + file.create(filename, `#EXTM3U url-tvg="${urlTvg}"\n`) for (const channel of channels) { - if (!channel.isNSFW()) { - file.append(filename, channel.toString()) - } + file.append(filename, channel.toString()) } } } @@ -164,19 +179,20 @@ function generateLanguages() { file.createDir(outputDir) for (const language of [...db.languages.all(), { code: 'undefined' }]) { - const filename = `${outputDir}/${language.code}.m3u` - file.create(filename, '#EXTM3U\n') - const channels = db.channels .sortBy(['name', 'url']) .forLanguage(language) .removeDuplicates() .removeOffline() + .removeNSFW() .get() + const guides = channels.map(channel => channel.tvg.url) + + const filename = `${outputDir}/${language.code}.m3u` + const urlTvg = generateUrlTvg(guides) + file.create(filename, `#EXTM3U url-tvg="${urlTvg}"\n`) for (const channel of channels) { - if (!channel.isNSFW()) { - file.append(filename, channel.toString()) - } + file.append(filename, channel.toString()) } } } @@ -197,4 +213,13 @@ function showResults() { ) } +function generateUrlTvg(guides) { + const output = guides.reduce((acc, curr) => { + if (curr && !acc.includes(curr)) acc.push(curr) + return acc + }, []) + + return output.sort().join(',') +} + main() From e8e85371b77df2e59b440df951891be09dc6a391 Mon Sep 17 00:00:00 2001 From: Shadix A Date: Fri, 17 Sep 2021 17:27:51 +0200 Subject: [PATCH 9/9] AE : Add alternatives for MBC2, Max, Action --- channels/ae.m3u | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/channels/ae.m3u b/channels/ae.m3u index b2de53bdb..88e298fe2 100644 --- a/channels/ae.m3u +++ b/channels/ae.m3u @@ -83,6 +83,8 @@ https://shls-mbc1ksa-prod-dub.shahid.net/out/v1/451b666db1fb41c7a4bbecf7b4865107 https://shls-mbc1-usa-prod.shahid.net/out/v1/1b559e832c3f40f996c1984245b3b24b/index.m3u8 #EXTINF:-1 tvg-id="MBC2.ae" tvg-country="ARAB" tvg-language="Arabic" tvg-logo="https://i.imgur.com/KXuzL1u.png" group-title="Movies",MBC 2 (1080p) https://shls-mbc2-prod-dub.shahid.net/out/v1/b4befe19798745fe986f5a9bfba62126/index.m3u8 +#EXTINF:-1 tvg-id="MBC2.ae" tvg-country="ARAB" tvg-language="Arabic" tvg-logo="https://i.imgur.com/KXuzL1u.png" group-title="Movies",MBC 2 (720p) +https://blogs.livehdchanel.live/mbc-222/index.m3u8 #EXTINF:-1 tvg-id="MBC3.ae" tvg-country="ARAB" tvg-language="Arabic" tvg-logo="https://i.imgur.com/FVNVC73.png" group-title="Kids",MBC 3 (1080p) https://shls-mbc3-prod-dub.shahid.net/out/v1/d5bbe570e1514d3d9a142657d33d85e6/index.m3u8 #EXTINF:-1 tvg-id="MBC3EUR.ae" tvg-country="ARAB" tvg-language="Arabic" tvg-logo="https://i.imgur.com/FVNVC73.png" group-title="Kids",MBC 3 EUR (1080p) @@ -95,6 +97,8 @@ https://shls-mbc4-prod-dub.shahid.net/out/v1/c08681f81775496ab4afa2bac7ae7638/in https://shls-mbc5-prod-dub.shahid.net/out/v1/2720564b6a4641658fdfb6884b160da2/index.m3u8 #EXTINF:-1 tvg-id="MBCAction.ae" tvg-country="ARAB" tvg-language="Arabic" tvg-logo="https://i.imgur.com/n3TgfP0.png" group-title="Movies",MBC Action (1080p) https://shls-mbcaction-prod-dub.shahid.net/out/v1/68dd761538e5460096c42422199d050b/index.m3u8 +#EXTINF:-1 tvg-id="MBCAction.ae" tvg-country="ARAB" tvg-language="Arabic" tvg-logo="https://i.imgur.com/n3TgfP0.png" group-title="Movies",MBC Action (576p) +https://blogs.livehdchanel.live/action2/index.m3u8 #EXTINF:-1 tvg-id="MBCBollywood.ae" tvg-country="ARAB" tvg-language="Arabic" tvg-logo="https://i.imgur.com/fMjhK06.png" group-title="General",MBC Bollywood (1080p) https://shls-mbcbollywood-prod-dub.shahid.net/out/v1/a79c9d7ef2a64a54a64d5c4567b3462a/index.m3u8 #EXTINF:-1 tvg-id="MBCDrama.ae" tvg-country="ARAB" tvg-language="Arabic" tvg-logo="https://i.imgur.com/F5ER0we.png" group-title="General",MBC Drama KSA (1080p) @@ -113,6 +117,8 @@ https://shls-mbc-masr-usa-prod.shahid.net/out/v1/d4fded7d5df04b88b9ea1db61d00f09 https://shls-masr2-prod-dub.shahid.net/out/v1/f683685242b549f48ea8a5171e3e993a/index.m3u8 #EXTINF:-1 tvg-id="MBCMax.ae" tvg-country="ARAB" tvg-language="Arabic" tvg-logo="https://i.imgur.com/X6EliFm.png" group-title="Movies",MBC Max (1080p) https://shls-mbcmax-prod-dub.shahid.net/out/v1/13815a7cda864c249a88c38e66a2e653/index.m3u8 +#EXTINF:-1 tvg-id="MBCMax.ae" tvg-country="ARAB" tvg-language="Arabic" tvg-logo="https://i.imgur.com/X6EliFm.png" group-title="Movies",MBC Max (576p) +https://blogs.livehdchanel.live/max/index.m3u8 #EXTINF:-1 tvg-id="MBCPersia.ae" tvg-country="IR" tvg-language="Persian" tvg-logo="https://upload.wikimedia.org/wikipedia/commons/8/8f/MBC_Persia_Logo.png" group-title="General",MBC Persia (1080p) https://shls-mbcpersia-prod-dub.shahid.net/out/v1/bdc7cd0d990e4c54808632a52c396946/index.m3u8 #EXTINF:-1 tvg-id="MBCDramaPlus.ae" tvg-country="ARAB" tvg-language="Arabic" tvg-logo="https://i.imgur.com/F5ER0we.png" group-title="Movies",MBC Plus Drama (1080p)