Update generate-playlists.js
This commit is contained in:
parent
96403d463e
commit
62ce78bbdf
|
@ -19,6 +19,7 @@
|
|||
"m3u-linter": "^0.3.0",
|
||||
"markdown-include": "^0.4.3",
|
||||
"mz": "^2.7.0",
|
||||
"natural-orderby": "^2.0.3",
|
||||
"nedb-promises": "^5.0.2",
|
||||
"normalize-url": "^6.1.0",
|
||||
"transliteration": "^2.2.0",
|
||||
|
@ -3180,6 +3181,14 @@
|
|||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc="
|
||||
},
|
||||
"node_modules/natural-orderby": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/natural-orderby/-/natural-orderby-2.0.3.tgz",
|
||||
"integrity": "sha512-p7KTHxU0CUrcOXe62Zfrb5Z13nLvPhSWR/so3kFulUQU0sgUll2Z0LwpsLN351eOOD+hRGu/F1g+6xDfPeD++Q==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/nedb-promises": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/nedb-promises/-/nedb-promises-5.0.2.tgz",
|
||||
|
@ -6665,6 +6674,11 @@
|
|||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc="
|
||||
},
|
||||
"natural-orderby": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/natural-orderby/-/natural-orderby-2.0.3.tgz",
|
||||
"integrity": "sha512-p7KTHxU0CUrcOXe62Zfrb5Z13nLvPhSWR/so3kFulUQU0sgUll2Z0LwpsLN351eOOD+hRGu/F1g+6xDfPeD++Q=="
|
||||
},
|
||||
"nedb-promises": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/nedb-promises/-/nedb-promises-5.0.2.tgz",
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
"m3u-linter": "^0.3.0",
|
||||
"markdown-include": "^0.4.3",
|
||||
"mz": "^2.7.0",
|
||||
"natural-orderby": "^2.0.3",
|
||||
"nedb-promises": "^5.0.2",
|
||||
"normalize-url": "^6.1.0",
|
||||
"transliteration": "^2.2.0",
|
||||
|
|
|
@ -1,32 +1,41 @@
|
|||
const { db, generator, api } = require('../core')
|
||||
const { db, generator, api, logger } = require('../core')
|
||||
const _ = require('lodash')
|
||||
|
||||
async function main() {
|
||||
const streams = await loadStreams()
|
||||
|
||||
logger.info('generating categories/...')
|
||||
await generator.generate('categories', streams)
|
||||
logger.info('generating countries/...')
|
||||
await generator.generate('countries', streams)
|
||||
logger.info('generating languages/...')
|
||||
await generator.generate('languages', streams)
|
||||
logger.info('generating regions/...')
|
||||
await generator.generate('regions', streams)
|
||||
logger.info('generating index.category.m3u...')
|
||||
await generator.generate('index_category_m3u', streams)
|
||||
logger.info('generating index.country.m3u...')
|
||||
await generator.generate('index_country_m3u', streams)
|
||||
logger.info('generating index.language.m3u...')
|
||||
await generator.generate('index_language_m3u', streams)
|
||||
logger.info('generating index.m3u...')
|
||||
await generator.generate('index_m3u', streams)
|
||||
logger.info('generating index.nsfw.m3u...')
|
||||
await generator.generate('index_nsfw_m3u', streams)
|
||||
logger.info('generating index.region.m3u...')
|
||||
await generator.generate('index_region_m3u', streams)
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
async function loadStreams() {
|
||||
await db.streams.load()
|
||||
let streams = await db.streams.find({})
|
||||
|
||||
await api.channels.load()
|
||||
let channels = await api.channels.all()
|
||||
channels = _.keyBy(channels, 'id')
|
||||
|
||||
await api.countries.load()
|
||||
let countries = await api.countries.all()
|
||||
countries = _.keyBy(countries, 'code')
|
||||
|
||||
await api.categories.load()
|
||||
let categories = await api.categories.all()
|
||||
categories = _.keyBy(categories, 'id')
|
||||
|
@ -35,55 +44,36 @@ async function loadStreams() {
|
|||
let languages = await api.languages.all()
|
||||
languages = _.keyBy(languages, 'code')
|
||||
|
||||
await api.regions.load()
|
||||
let regions = await api.regions.all()
|
||||
regions = _.keyBy(regions, 'code')
|
||||
|
||||
await api.guides.load()
|
||||
let guides = await api.guides.all()
|
||||
guides = _.groupBy(guides, 'channel')
|
||||
|
||||
await db.streams.load()
|
||||
let streams = await db.streams.find({})
|
||||
|
||||
return streams.map(stream => {
|
||||
const channel = channels[stream.channel_id] || null
|
||||
|
||||
stream.channel = channel
|
||||
if (channel) {
|
||||
stream.broadcast_area = channel.broadcast_area.map(item => {
|
||||
stream.group_title = channel.categories
|
||||
.map(id => (categories[id] ? categories[id].name : null))
|
||||
.filter(i => i)
|
||||
.sort()
|
||||
.join(';')
|
||||
stream.tvg_language = channel.languages
|
||||
.map(code => (languages[code] ? languages[code].name : ''))
|
||||
.filter(i => i)
|
||||
.sort()
|
||||
.join(';')
|
||||
stream.tvg_country = channel.broadcast_area
|
||||
.map(item => {
|
||||
const [_, code] = item.split('/')
|
||||
return code
|
||||
})
|
||||
stream.regions = channel.broadcast_area
|
||||
.reduce((acc, item) => {
|
||||
const [type, code] = item.split('/')
|
||||
switch (type) {
|
||||
case 'r':
|
||||
acc.push(regions[code])
|
||||
break
|
||||
case 's':
|
||||
const [c] = item.split('-')
|
||||
const r1 = _.filter(regions, { countries: [c] })
|
||||
acc = acc.concat(r1)
|
||||
break
|
||||
case 'c':
|
||||
const r2 = _.filter(regions, { countries: [code] })
|
||||
acc = acc.concat(r2)
|
||||
break
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
.filter(i => i)
|
||||
stream.categories = channel.categories.map(id => categories[id])
|
||||
stream.languages = channel.languages.map(code => languages[code])
|
||||
stream.guides = guides[stream.channel_id] ? guides[stream.channel_id].map(g => g.url) : []
|
||||
} else {
|
||||
stream.broadcast_area = []
|
||||
stream.categories = []
|
||||
stream.languages = []
|
||||
stream.regions = []
|
||||
stream.guides = []
|
||||
.sort()
|
||||
.join(';')
|
||||
stream.tvg_logo = channel.logo
|
||||
stream.tvg_url =
|
||||
guides[channel.id] && guides[channel.id].length ? guides[channel.id][0].url : null
|
||||
stream.channel = channel
|
||||
}
|
||||
|
||||
return stream
|
||||
|
|
|
@ -3,22 +3,23 @@ const logger = require('./logger')
|
|||
const file = require('./file')
|
||||
const generators = require('../generators')
|
||||
const _ = require('lodash')
|
||||
const { orderBy } = require('natural-orderby')
|
||||
|
||||
const PUBLIC_DIR = process.env.PUBLIC_DIR || '.gh-pages'
|
||||
const LOGS_DIR = process.env.LOGS_DIR || 'scripts/logs/generators'
|
||||
|
||||
const generator = {}
|
||||
|
||||
generator.generate = async function (name, items = []) {
|
||||
generator.generate = async function (name, streams = []) {
|
||||
if (typeof generators[name] === 'function') {
|
||||
try {
|
||||
items = _.orderBy(
|
||||
items,
|
||||
streams = orderBy(
|
||||
streams,
|
||||
['channel_name', 'status.level', 'resolution.height'],
|
||||
['asc', 'asc', 'desc']
|
||||
)
|
||||
items = _.uniqBy(items, s => s.channel_id || _.uniqueId())
|
||||
let output = await generators[name].bind()(items)
|
||||
streams = _.uniqBy(streams, stream => stream.channel_id || _.uniqueId())
|
||||
let output = await generators[name].bind()(streams)
|
||||
output = Array.isArray(output) ? output : [output]
|
||||
for (const type of output) {
|
||||
const playlist = createPlaylist(type.items, { public: true })
|
||||
|
|
|
@ -53,10 +53,8 @@ playlist.create = function (items = [], options = {}) {
|
|||
|
||||
const header = {}
|
||||
if (options.public) {
|
||||
let guides = items.map(item => item.guides)
|
||||
guides = _.uniq(_.flatten(guides)).sort().join(',')
|
||||
|
||||
header['x-tvg-url'] = guides
|
||||
let guides = items.map(item => item.tvg_url).filter(i => i)
|
||||
header['x-tvg-url'] = _.uniq(guides).sort().join(',')
|
||||
}
|
||||
p.setHeader(header)
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ module.exports = async function (streams = []) {
|
|||
output.push({ filepath: `categories/${category.id}.m3u`, items })
|
||||
}
|
||||
|
||||
let items = _.filter(streams, s => !s.categories.length)
|
||||
let items = _.filter(streams, stream => !stream.channel || !stream.channel.categories.length)
|
||||
output.push({ filepath: 'categories/undefined.m3u', items })
|
||||
|
||||
return output
|
||||
|
|
|
@ -2,20 +2,28 @@ const api = require('../core/api')
|
|||
const _ = require('lodash')
|
||||
|
||||
module.exports = async function (streams = []) {
|
||||
const output = []
|
||||
streams = _.filter(streams, stream => !stream.channel || stream.channel.is_nsfw === false)
|
||||
|
||||
await api.countries.load()
|
||||
const countries = await api.countries.all()
|
||||
await api.regions.load()
|
||||
const regions = await api.regions.all()
|
||||
streams = _.filter(streams, s => !s.channel || s.channel.is_nsfw === false)
|
||||
|
||||
const output = []
|
||||
for (const country of countries) {
|
||||
const areaCodes = _.filter(regions, { countries: [country.code] }).map(r => r.code)
|
||||
areaCodes.push(country.code)
|
||||
let items = _.filter(streams, s => _.intersection(areaCodes, s.broadcast_area).length)
|
||||
const countryAreaCodes = _.filter(regions, { countries: [country.code] }).map(
|
||||
r => `r/${r.code}`
|
||||
)
|
||||
countryAreaCodes.push(`c/${country.code}`)
|
||||
let items = _.filter(
|
||||
streams,
|
||||
stream =>
|
||||
stream.channel && _.intersection(stream.channel.broadcast_area, countryAreaCodes).length
|
||||
)
|
||||
output.push({ filepath: `countries/${country.code.toLowerCase()}.m3u`, items })
|
||||
}
|
||||
|
||||
let items = _.filter(streams, s => !s.broadcast_area.length)
|
||||
let items = _.filter(streams, stream => !stream.channel || !stream.channel.broadcast_area.length)
|
||||
output.push({ filepath: 'countries/undefined.m3u', items })
|
||||
|
||||
return output
|
||||
|
|
|
@ -3,19 +3,32 @@ const _ = require('lodash')
|
|||
|
||||
module.exports = async function (streams = []) {
|
||||
streams = _.filter(streams, s => !s.channel || s.channel.is_nsfw === false)
|
||||
|
||||
await api.categories.load()
|
||||
let categories = await api.categories.all()
|
||||
categories = _.keyBy(categories, 'id')
|
||||
|
||||
let items = []
|
||||
streams.forEach(stream => {
|
||||
if (!stream.categories.length) return items.push(stream)
|
||||
|
||||
stream.categories.forEach(category => {
|
||||
if (!stream.channel || !stream.channel.categories.length) {
|
||||
const item = _.cloneDeep(stream)
|
||||
item.group_title = category.name
|
||||
item.group_title = null
|
||||
items.push(item)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
stream.channel.categories.forEach(id => {
|
||||
const item = _.cloneDeep(stream)
|
||||
item.group_title = categories[id] ? categories[id].name : null
|
||||
items.push(item)
|
||||
})
|
||||
})
|
||||
items = _.sortBy(items, i => {
|
||||
if (i.group_title === 'Undefined') return '_'
|
||||
return i.group_title
|
||||
|
||||
items = _.sortBy(items, item => {
|
||||
if (!item.group_title) return ''
|
||||
|
||||
return item.group_title
|
||||
})
|
||||
|
||||
return { filepath: 'index.category.m3u', items }
|
||||
|
|
|
@ -2,6 +2,8 @@ const api = require('../core/api')
|
|||
const _ = require('lodash')
|
||||
|
||||
module.exports = async function (streams = []) {
|
||||
streams = _.filter(streams, s => !s.channel || s.channel.is_nsfw === false)
|
||||
|
||||
await api.regions.load()
|
||||
let regions = await api.regions.all()
|
||||
regions = _.keyBy(regions, 'code')
|
||||
|
@ -10,10 +12,14 @@ module.exports = async function (streams = []) {
|
|||
let countries = await api.countries.all()
|
||||
countries = _.keyBy(countries, 'code')
|
||||
|
||||
streams = _.filter(streams, s => !s.channel || s.channel.is_nsfw === false)
|
||||
let items = []
|
||||
streams.forEach(stream => {
|
||||
if (!stream.channel) return items.push(stream)
|
||||
if (!stream.channel || !stream.channel.broadcast_area.length) {
|
||||
const item = _.cloneDeep(stream)
|
||||
item.group_title = null
|
||||
items.push(item)
|
||||
return
|
||||
}
|
||||
|
||||
getBroadcastCountries(stream.channel, { countries, regions }).forEach(country => {
|
||||
const item = _.cloneDeep(stream)
|
||||
|
@ -21,9 +27,10 @@ module.exports = async function (streams = []) {
|
|||
items.push(item)
|
||||
})
|
||||
})
|
||||
items = _.sortBy(items, i => {
|
||||
if (i.group_title === 'Undefined') return '_'
|
||||
return i.group_title
|
||||
|
||||
items = _.sortBy(items, item => {
|
||||
if (!item.group_title) return false
|
||||
return item.group_title
|
||||
})
|
||||
|
||||
return { filepath: 'index.country.m3u', items }
|
||||
|
|
|
@ -3,18 +3,28 @@ const _ = require('lodash')
|
|||
|
||||
module.exports = async function (streams = []) {
|
||||
streams = _.filter(streams, s => !s.channel || s.channel.is_nsfw === false)
|
||||
|
||||
await api.languages.load()
|
||||
let languages = await api.languages.all()
|
||||
languages = _.keyBy(languages, 'code')
|
||||
|
||||
let items = []
|
||||
streams.forEach(stream => {
|
||||
if (!stream.languages.length) return items.push(stream)
|
||||
|
||||
stream.languages.forEach(language => {
|
||||
if (!stream.channel || !stream.channel.languages.length) {
|
||||
const item = _.cloneDeep(stream)
|
||||
item.group_title = language.name
|
||||
item.group_title = null
|
||||
items.push(stream)
|
||||
return
|
||||
}
|
||||
|
||||
stream.channel.languages.forEach(code => {
|
||||
const item = _.cloneDeep(stream)
|
||||
item.group_title = languages[code] ? languages[code].name : null
|
||||
items.push(item)
|
||||
})
|
||||
})
|
||||
items = _.sortBy(items, i => {
|
||||
if (i.group_title === 'Undefined') return '_'
|
||||
if (!i.group_title) return ''
|
||||
return i.group_title
|
||||
})
|
||||
|
||||
|
|
|
@ -2,21 +2,55 @@ const api = require('../core/api')
|
|||
const _ = require('lodash')
|
||||
|
||||
module.exports = async function (streams = []) {
|
||||
streams = _.filter(streams, s => !s.channel || s.channel.is_nsfw === false)
|
||||
streams = _.filter(streams, stream => !stream.channel || stream.channel.is_nsfw === false)
|
||||
|
||||
await api.regions.load()
|
||||
let regions = await api.regions.all()
|
||||
regions = _.keyBy(regions, 'code')
|
||||
|
||||
let items = []
|
||||
streams.forEach(stream => {
|
||||
if (!stream.regions.length) return items.push(stream)
|
||||
if (!stream.channel || !stream.channel.broadcast_area.length) {
|
||||
const item = _.cloneDeep(stream)
|
||||
item.group_title = null
|
||||
items.push(item)
|
||||
return
|
||||
}
|
||||
|
||||
stream.regions.forEach(region => {
|
||||
getChannelRegions(stream.channel, { regions }).forEach(region => {
|
||||
const item = _.cloneDeep(stream)
|
||||
item.group_title = region.name
|
||||
items.push(item)
|
||||
})
|
||||
})
|
||||
|
||||
items = _.sortBy(items, i => {
|
||||
if (i.group_title === 'Undefined') return '_'
|
||||
if (!i.group_title) return ''
|
||||
return i.group_title
|
||||
})
|
||||
|
||||
return { filepath: 'index.region.m3u', items }
|
||||
}
|
||||
|
||||
function getChannelRegions(channel, { regions }) {
|
||||
return channel.broadcast_area
|
||||
.reduce((acc, item) => {
|
||||
const [type, code] = item.split('/')
|
||||
switch (type) {
|
||||
case 'r':
|
||||
acc.push(regions[code])
|
||||
break
|
||||
case 's':
|
||||
const [c] = item.split('-')
|
||||
const r1 = _.filter(regions, { countries: [c] })
|
||||
acc = acc.concat(r1)
|
||||
break
|
||||
case 'c':
|
||||
const r2 = _.filter(regions, { countries: [code] })
|
||||
acc = acc.concat(r2)
|
||||
break
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
.filter(i => i)
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ module.exports = async function (streams = []) {
|
|||
}
|
||||
}
|
||||
|
||||
let items = _.filter(streams, s => !s.languages.length)
|
||||
let items = _.filter(streams, stream => !stream.channel || !stream.channel.languages.length)
|
||||
output.push({ filepath: 'languages/undefined.m3u', items })
|
||||
|
||||
return output
|
||||
|
|
|
@ -5,15 +5,18 @@ module.exports = async function (streams = []) {
|
|||
const output = []
|
||||
await api.regions.load()
|
||||
const regions = await api.regions.all()
|
||||
streams = _.filter(streams, s => !s.channel || s.channel.is_nsfw === false)
|
||||
streams = _.filter(streams, stream => !stream.channel || stream.channel.is_nsfw === false)
|
||||
for (const region of regions) {
|
||||
const areaCodes = region.countries
|
||||
areaCodes.push(region.code)
|
||||
let items = _.filter(streams, s => _.intersection(areaCodes, s.broadcast_area).length)
|
||||
const areaCodes = region.countries.map(code => `c/${code}`)
|
||||
areaCodes.push(`r/${region.code}`)
|
||||
let items = _.filter(
|
||||
streams,
|
||||
stream => stream.channel && _.intersection(stream.channel.broadcast_area, areaCodes).length
|
||||
)
|
||||
output.push({ filepath: `regions/${region.code.toLowerCase()}.m3u`, items })
|
||||
}
|
||||
|
||||
let items = _.filter(streams, s => !s.broadcast_area.length)
|
||||
let items = _.filter(streams, stream => !stream.channel || !stream.channel.broadcast_area.length)
|
||||
output.push({ filepath: 'regions/undefined.m3u', items })
|
||||
|
||||
return output
|
||||
|
|
|
@ -1,12 +1,3 @@
|
|||
module.exports = function () {
|
||||
if (this.group_title !== undefined) return this.group_title
|
||||
|
||||
if (Array.isArray(this.categories) && this.categories.length) {
|
||||
return this.categories
|
||||
.map(i => i.name)
|
||||
.sort()
|
||||
.join(';')
|
||||
}
|
||||
|
||||
return 'Undefined'
|
||||
return this.group_title || 'Undefined'
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
exports.group_title = require('./group_title')
|
||||
exports.title = require('./title')
|
||||
exports.tvg_country = require('./tvg_country')
|
||||
exports.tvg_id = require('./tvg_id')
|
||||
exports.tvg_language = require('./tvg_language')
|
||||
exports.tvg_logo = require('./tvg_logo')
|
||||
exports.tvg_url = require('./tvg_url')
|
||||
exports.tvg_country = require('./tvg_country')
|
||||
exports.tvg_language = require('./tvg_language')
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module.exports = function () {
|
||||
return Array.isArray(this.broadcast_area) ? this.broadcast_area.join(';') : ''
|
||||
return this.tvg_country || ''
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module.exports = function () {
|
||||
return Array.isArray(this.languages) ? this.languages.map(i => i.name).join(';') : ''
|
||||
return this.tvg_language || ''
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module.exports = function () {
|
||||
return this.channel && this.channel.logo ? this.channel.logo : ''
|
||||
return this.tvg_logo || ''
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module.exports = function () {
|
||||
return this.guides.length ? this.guides[0] : ''
|
||||
return this.tvg_url || ''
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ch/tv.blue.ch.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml,https://iptv-org.github.io/epg/guides/uk/sky.com.epg.xml"
|
||||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml"
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-country="INT" tvg-language="English" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD (720p) [Not 24/7]
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-country="RU" tvg-language="Russian" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="General",ЛДПР ТВ (1080p)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ch/tv.blue.ch.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml,https://iptv-org.github.io/epg/guides/uk/sky.com.epg.xml"
|
||||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml"
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-country="INT" tvg-language="English" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD (720p) [Not 24/7]
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/playlist.m3u8
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ch/tv.blue.ch.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml,https://iptv-org.github.io/epg/guides/uk/sky.com.epg.xml"
|
||||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml"
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-country="INT" tvg-language="English" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD (720p) [Not 24/7]
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-country="CA" tvg-language="French" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Weather",Meteomedia
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ch/tv.blue.ch.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml,https://iptv-org.github.io/epg/guides/uk/sky.com.epg.xml"
|
||||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml"
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-country="INT" tvg-language="English" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD (720p) [Not 24/7]
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-country="RU" tvg-language="Russian" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="General",ЛДПР ТВ (1080p)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ch/tv.blue.ch.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml,https://iptv-org.github.io/epg/guides/uk/sky.com.epg.xml"
|
||||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml"
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-country="INT" tvg-language="English" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD (720p) [Not 24/7]
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/playlist.m3u8
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ad/andorradifusio.ad.epg.xml,https://iptv-org.github.io/epg/guides/ch/tv.blue.ch.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml,https://iptv-org.github.io/epg/guides/uk/sky.com.epg.xml"
|
||||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ad/andorradifusio.ad.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml"
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-country="INT" tvg-language="English" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General",BBC News HD (720p) [Not 24/7]
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-country="RU" tvg-language="Russian" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="General",ЛДПР ТВ (1080p)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ad/andorradifusio.ad.epg.xml,https://iptv-org.github.io/epg/guides/ch/tv.blue.ch.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml,https://iptv-org.github.io/epg/guides/uk/sky.com.epg.xml"
|
||||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ad/andorradifusio.ad.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml"
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-country="INT" tvg-language="English" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Afghanistan",BBC News HD (720p) [Not 24/7]
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-country="INT" tvg-language="English" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="Albania",BBC News HD (720p) [Not 24/7]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ad/andorradifusio.ad.epg.xml,https://iptv-org.github.io/epg/guides/ch/tv.blue.ch.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml,https://iptv-org.github.io/epg/guides/uk/sky.com.epg.xml"
|
||||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ad/andorradifusio.ad.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml"
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-country="INT" tvg-language="English" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="English",BBC News HD (720p) [Not 24/7]
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-country="CA" tvg-language="French" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="French",Meteomedia
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ad/andorradifusio.ad.epg.xml,https://iptv-org.github.io/epg/guides/ch/tv.blue.ch.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml,https://iptv-org.github.io/epg/guides/uk/sky.com.epg.xml"
|
||||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ad/andorradifusio.ad.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml"
|
||||
#EXTINF:-1 tvg-id="AndorraTV.ad" tvg-country="AD" tvg-language="Valencian" tvg-logo="" group-title="Undefined",ATV (720p) [Offline]
|
||||
https://iptv-all.lanesh4d0w.repl.co/andorra/atv
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-country="INT" tvg-language="English" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD (720p) [Not 24/7]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ad/andorradifusio.ad.epg.xml,https://iptv-org.github.io/epg/guides/ch/tv.blue.ch.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml,https://iptv-org.github.io/epg/guides/uk/sky.com.epg.xml"
|
||||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ad/andorradifusio.ad.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml"
|
||||
#EXTINF:-1 tvg-id="AndorraTV.ad" tvg-country="AD" tvg-language="Valencian" tvg-logo="" group-title="Undefined",ATV (720p) [Offline]
|
||||
https://iptv-all.lanesh4d0w.repl.co/andorra/atv
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-country="INT" tvg-language="English" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD (720p) [Not 24/7]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ad/andorradifusio.ad.epg.xml,https://iptv-org.github.io/epg/guides/ch/tv.blue.ch.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml,https://iptv-org.github.io/epg/guides/uk/sky.com.epg.xml"
|
||||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ad/andorradifusio.ad.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml"
|
||||
#EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-country="CA" tvg-language="French" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Americas",Meteomedia
|
||||
http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-country="RU" tvg-language="Russian" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="Asia",ЛДПР ТВ (1080p)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ch/tv.blue.ch.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml,https://iptv-org.github.io/epg/guides/uk/sky.com.epg.xml"
|
||||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml"
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-country="INT" tvg-language="English" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD (720p) [Not 24/7]
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/playlist.m3u8
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ad/andorradifusio.ad.epg.xml,https://iptv-org.github.io/epg/guides/ch/tv.blue.ch.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml,https://iptv-org.github.io/epg/guides/uk/sky.com.epg.xml"
|
||||
#EXTM3U x-tvg-url="https://iptv-org.github.io/epg/guides/ad/andorradifusio.ad.epg.xml,https://iptv-org.github.io/epg/guides/ru/tv.yandex.ru.epg.xml,https://iptv-org.github.io/epg/guides/uk/ontvtonight.com.epg.xml"
|
||||
#EXTINF:-1 tvg-id="AndorraTV.ad" tvg-country="AD" tvg-language="Valencian" tvg-logo="" group-title="Undefined",ATV (720p) [Offline]
|
||||
https://iptv-all.lanesh4d0w.repl.co/andorra/atv
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-country="INT" tvg-language="English" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD (720p) [Not 24/7]
|
||||
|
|
Loading…
Reference in New Issue