mirror of
https://github.com/iptv-org/iptv.git
synced 2025-05-12 18:10:04 -04:00
wip
This commit is contained in:
parent
d604f35ba1
commit
9a4a62fd10
45 changed files with 733 additions and 35060 deletions
|
@ -1,109 +1,90 @@
|
|||
const { db, logger, generator, file } = require('../core')
|
||||
const { create: createPlaylist } = require('../core/playlist')
|
||||
const { db, logger, generator, file, api } = require('../core')
|
||||
const _ = require('lodash')
|
||||
|
||||
let languages = []
|
||||
let countries = []
|
||||
let categories = []
|
||||
let regions = []
|
||||
|
||||
const LOGS_PATH = process.env.LOGS_PATH || 'scripts/logs'
|
||||
const PUBLIC_PATH = process.env.PUBLIC_PATH || '.gh-pages'
|
||||
|
||||
async function main() {
|
||||
await setUp()
|
||||
const streams = await loadStreams()
|
||||
|
||||
await generateCategories()
|
||||
await generateCountries()
|
||||
await generateLanguages()
|
||||
await generateRegions()
|
||||
await generateIndex()
|
||||
await generateIndexNSFW()
|
||||
await generateIndexCategory()
|
||||
await generateIndexCountry()
|
||||
await generateIndexLanguage()
|
||||
await generateIndexRegion()
|
||||
logger.info(`generating categories/...`)
|
||||
await generator.generate('categories', streams)
|
||||
|
||||
await generateChannelsJson()
|
||||
// await generateCountries(streams)
|
||||
// await generateLanguages()
|
||||
// await generateRegions()
|
||||
// await generateIndex()
|
||||
// await generateIndexNSFW()
|
||||
// await generateIndexCategory()
|
||||
// await generateIndexCountry()
|
||||
// await generateIndexLanguage()
|
||||
// await generateIndexRegion()
|
||||
|
||||
// await generateChannelsJson()
|
||||
|
||||
// await saveLogs()
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
async function generateCategories() {
|
||||
logger.info(`Generating categories/...`)
|
||||
|
||||
for (const category of categories) {
|
||||
const { count } = await generator.generate(
|
||||
`${PUBLIC_PATH}/categories/${category.slug}.m3u`,
|
||||
{ categories: { $elemMatch: category } },
|
||||
{ saveEmpty: true, includeNSFW: true }
|
||||
)
|
||||
|
||||
await log('categories', {
|
||||
name: category.name,
|
||||
slug: category.slug,
|
||||
count
|
||||
})
|
||||
}
|
||||
|
||||
const { count: otherCount } = await generator.generate(
|
||||
`${PUBLIC_PATH}/categories/other.m3u`,
|
||||
{ categories: { $size: 0 } },
|
||||
{
|
||||
saveEmpty: true,
|
||||
onLoad: function (items) {
|
||||
return items.map(item => {
|
||||
item.group_title = 'Other'
|
||||
return item
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
await log('categories', {
|
||||
name: 'Other',
|
||||
slug: 'other',
|
||||
count: otherCount
|
||||
})
|
||||
}
|
||||
|
||||
async function generateCountries() {
|
||||
logger.info(`Generating countries/...`)
|
||||
|
||||
async function generateCountries(streams) {
|
||||
logger.info(`generating countries/...`)
|
||||
const countries = await loadCountries()
|
||||
const regions = await loadRegions()
|
||||
for (const country of countries) {
|
||||
const { count } = await generator.generate(
|
||||
let areaCodes = _.filter(regions, { countries: [country.code] }).map(r => r.code)
|
||||
areaCodes.push(country.code)
|
||||
const { count, items } = await generator.generate(
|
||||
`${PUBLIC_PATH}/countries/${country.code.toLowerCase()}.m3u`,
|
||||
streams,
|
||||
{
|
||||
countries: { $elemMatch: country }
|
||||
public: true,
|
||||
filter: s => _.intersection(areaCodes, s.broadcast_area).length
|
||||
}
|
||||
)
|
||||
|
||||
await log('countries', {
|
||||
log.countries.push({
|
||||
name: country.name,
|
||||
code: country.code,
|
||||
count
|
||||
})
|
||||
}
|
||||
|
||||
const { count: undefinedCount } = await generator.generate(
|
||||
`${PUBLIC_PATH}/countries/undefined.m3u`,
|
||||
{
|
||||
countries: { $size: 0 }
|
||||
},
|
||||
{
|
||||
onLoad: function (items) {
|
||||
return items.map(item => {
|
||||
item.group_title = 'Undefined'
|
||||
return item
|
||||
})
|
||||
}
|
||||
const { count } = await generator.generate(`${PUBLIC_PATH}/countries/undefined.m3u`, streams, {
|
||||
public: true,
|
||||
filter: s => !s.broadcast_area.length,
|
||||
onLoad: items => {
|
||||
return items.map(item => {
|
||||
item.group_title = 'Undefined'
|
||||
return item
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
await log('countries', {
|
||||
name: 'Undefined',
|
||||
code: 'UNDEFINED',
|
||||
count: undefinedCount
|
||||
})
|
||||
|
||||
log.countries.push({
|
||||
name: 'Undefined',
|
||||
id: 'UNDEFINED',
|
||||
count
|
||||
})
|
||||
|
||||
// const { count: undefinedCount } = await generator.generate(
|
||||
// `${PUBLIC_PATH}/countries/undefined.m3u`,
|
||||
// {
|
||||
// countries: { $size: 0 }
|
||||
// },
|
||||
// {
|
||||
// onLoad: function (items) {
|
||||
// return items.map(item => {
|
||||
// item.group_title = 'Undefined'
|
||||
// return item
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
|
||||
// await log('countries', {
|
||||
// name: 'Undefined',
|
||||
// code: 'UNDEFINED',
|
||||
// count: undefinedCount
|
||||
// })
|
||||
}
|
||||
|
||||
async function generateLanguages() {
|
||||
|
@ -395,47 +376,44 @@ async function generateIndexRegion() {
|
|||
)
|
||||
}
|
||||
|
||||
async function generateChannelsJson() {
|
||||
logger.info('Generating channels.json...')
|
||||
async function loadStreams() {
|
||||
await api.channels.load()
|
||||
let channels = await api.channels.all()
|
||||
channels = _.keyBy(channels, 'id')
|
||||
|
||||
await generator.generate(
|
||||
`${PUBLIC_PATH}/channels.json`,
|
||||
{},
|
||||
{ format: 'json', includeNSFW: true, uniqBy: null }
|
||||
)
|
||||
}
|
||||
|
||||
async function setUp() {
|
||||
logger.info(`Loading database...`)
|
||||
const items = await db.find({})
|
||||
categories = _.sortBy(_.uniqBy(_.flatten(items.map(i => i.categories)), 'slug'), ['name']).filter(
|
||||
i => i
|
||||
)
|
||||
countries = _.sortBy(_.uniqBy(_.flatten(items.map(i => i.countries)), 'code'), ['name']).filter(
|
||||
i => i
|
||||
)
|
||||
languages = _.sortBy(_.uniqBy(_.flatten(items.map(i => i.languages)), 'code'), ['name']).filter(
|
||||
i => i
|
||||
)
|
||||
regions = _.sortBy(_.uniqBy(_.flatten(items.map(i => i.regions)), 'code'), ['name']).filter(
|
||||
i => i
|
||||
)
|
||||
|
||||
const categoriesLog = `${LOGS_PATH}/generate-playlists/categories.log`
|
||||
const countriesLog = `${LOGS_PATH}/generate-playlists/countries.log`
|
||||
const languagesLog = `${LOGS_PATH}/generate-playlists/languages.log`
|
||||
const regionsLog = `${LOGS_PATH}/generate-playlists/regions.log`
|
||||
|
||||
logger.info(`Creating '${categoriesLog}'...`)
|
||||
await file.create(categoriesLog)
|
||||
logger.info(`Creating '${countriesLog}'...`)
|
||||
await file.create(countriesLog)
|
||||
logger.info(`Creating '${languagesLog}'...`)
|
||||
await file.create(languagesLog)
|
||||
logger.info(`Creating '${regionsLog}'...`)
|
||||
await file.create(regionsLog)
|
||||
}
|
||||
|
||||
async function log(type, data) {
|
||||
await file.append(`${LOGS_PATH}/generate-playlists/${type}.log`, JSON.stringify(data) + '\n')
|
||||
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')
|
||||
|
||||
await api.languages.load()
|
||||
let languages = await api.languages.all()
|
||||
languages = _.keyBy(languages, '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
|
||||
stream.broadcast_area = channel
|
||||
? channel.broadcast_area.map(item => {
|
||||
const [_, code] = item.split('/')
|
||||
return code
|
||||
})
|
||||
: []
|
||||
stream.categories = channel ? channel.categories.map(id => categories[id]) : []
|
||||
stream.languages = channel ? channel.languages.map(code => languages[code]) : []
|
||||
stream.guides = guides[stream.channel_id] ? guides[stream.channel_id].map(g => g.url) : []
|
||||
|
||||
return stream
|
||||
})
|
||||
}
|
||||
|
|
|
@ -16,11 +16,25 @@ class API {
|
|||
find(query) {
|
||||
return _.find(this.collection, query)
|
||||
}
|
||||
|
||||
filter(query) {
|
||||
return _.filter(this.collection, query)
|
||||
}
|
||||
|
||||
all() {
|
||||
return this.collection
|
||||
}
|
||||
}
|
||||
|
||||
const api = {}
|
||||
|
||||
api.channels = new API(`${DATA_DIR}/channels.json`)
|
||||
api.countries = new API(`${DATA_DIR}/countries.json`)
|
||||
api.guides = new API(`${DATA_DIR}/guides.json`)
|
||||
api.categories = new API(`${DATA_DIR}/categories.json`)
|
||||
api.languages = new API(`${DATA_DIR}/languages.json`)
|
||||
api.regions = new API(`${DATA_DIR}/regions.json`)
|
||||
api.statuses = new API(`${DATA_DIR}/statuses.json`)
|
||||
api.blocklist = new API(`${DATA_DIR}/blocklist.json`)
|
||||
|
||||
module.exports = api
|
||||
|
|
|
@ -1,61 +1,75 @@
|
|||
const Database = require('nedb-promises')
|
||||
const nedb = require('nedb-promises')
|
||||
const file = require('./file')
|
||||
|
||||
const DB_FILEPATH = process.env.DB_FILEPATH || './scripts/channels.db'
|
||||
const DB_DIR = process.env.DB_DIR || './scripts/database'
|
||||
|
||||
const nedb = Database.create({
|
||||
filename: file.resolve(DB_FILEPATH),
|
||||
autoload: true,
|
||||
onload(err) {
|
||||
if (err) console.error(err)
|
||||
},
|
||||
compareStrings: (a, b) => {
|
||||
a = a.replace(/\s/g, '_')
|
||||
b = b.replace(/\s/g, '_')
|
||||
class Database {
|
||||
constructor(filepath) {
|
||||
this.filepath = filepath
|
||||
}
|
||||
|
||||
return a.localeCompare(b, undefined, {
|
||||
sensitivity: 'accent',
|
||||
numeric: true
|
||||
load() {
|
||||
this.db = nedb.create({
|
||||
filename: file.resolve(this.filepath),
|
||||
autoload: true,
|
||||
onload: err => {
|
||||
if (err) console.error(err)
|
||||
},
|
||||
compareStrings: (a, b) => {
|
||||
a = a.replace(/\s/g, '_')
|
||||
b = b.replace(/\s/g, '_')
|
||||
|
||||
return a.localeCompare(b, undefined, {
|
||||
sensitivity: 'accent',
|
||||
numeric: true
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
removeIndex(field) {
|
||||
return this.db.removeIndex(field)
|
||||
}
|
||||
|
||||
addIndex(options) {
|
||||
return this.db.ensureIndex(options)
|
||||
}
|
||||
|
||||
compact() {
|
||||
return this.db.persistence.compactDatafile()
|
||||
}
|
||||
|
||||
stopAutocompact() {
|
||||
return this.db.persistence.stopAutocompaction()
|
||||
}
|
||||
|
||||
reset() {
|
||||
return file.clear(this.filepath)
|
||||
}
|
||||
|
||||
count(query) {
|
||||
return this.db.count(query)
|
||||
}
|
||||
|
||||
insert(doc) {
|
||||
return this.db.insert(doc)
|
||||
}
|
||||
|
||||
update(query, update) {
|
||||
return this.db.update(query, update)
|
||||
}
|
||||
|
||||
find(query) {
|
||||
return this.db.find(query)
|
||||
}
|
||||
|
||||
remove(query, options) {
|
||||
return this.db.remove(query, options)
|
||||
}
|
||||
}
|
||||
|
||||
const db = {}
|
||||
|
||||
db.removeIndex = function (field) {
|
||||
return nedb.removeIndex(field)
|
||||
}
|
||||
|
||||
db.addIndex = function (options) {
|
||||
return nedb.ensureIndex(options)
|
||||
}
|
||||
|
||||
db.compact = function () {
|
||||
return nedb.persistence.compactDatafile()
|
||||
}
|
||||
|
||||
db.reset = function () {
|
||||
return file.clear(DB_FILEPATH)
|
||||
}
|
||||
|
||||
db.count = function (query) {
|
||||
return nedb.count(query)
|
||||
}
|
||||
|
||||
db.insert = function (doc) {
|
||||
return nedb.insert(doc)
|
||||
}
|
||||
|
||||
db.update = function (query, update) {
|
||||
return nedb.update(query, update)
|
||||
}
|
||||
|
||||
db.find = function (query) {
|
||||
return nedb.find(query)
|
||||
}
|
||||
|
||||
db.remove = function (query, options) {
|
||||
return nedb.remove(query, options)
|
||||
}
|
||||
db.streams = new Database(`${DB_DIR}/streams.db`)
|
||||
|
||||
module.exports = db
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
const { create: createPlaylist } = require('./playlist')
|
||||
const store = require('./store')
|
||||
const path = require('path')
|
||||
const glob = require('glob')
|
||||
const fs = require('mz/fs')
|
||||
const _ = require('lodash')
|
||||
|
||||
const file = {}
|
||||
|
||||
|
@ -64,4 +67,45 @@ file.basename = function (filepath) {
|
|||
return path.basename(filepath)
|
||||
}
|
||||
|
||||
// file.saveAsM3U = async function (filepath, items, options = {}) {
|
||||
// const playlist = createPlaylist(filepath)
|
||||
|
||||
// const header = {}
|
||||
// if (options.public) {
|
||||
// let guides = items.map(item => item.guides)
|
||||
// guides = _.uniq(_.flatten(guides)).sort().join(',')
|
||||
|
||||
// header['x-tvg-url'] = guides
|
||||
// }
|
||||
// playlist.setHeader(header)
|
||||
|
||||
// for (const item of items) {
|
||||
// const stream = store.create(item)
|
||||
|
||||
// let attrs
|
||||
// if (options.public) {
|
||||
// attrs = {
|
||||
// 'tvg-id': stream.get('tvg_id'),
|
||||
// 'tvg-country': stream.get('tvg_country'),
|
||||
// 'tvg-language': stream.get('tvg_language'),
|
||||
// 'tvg-logo': stream.get('tvg_logo'),
|
||||
// 'user-agent': stream.get('http.user-agent') || undefined,
|
||||
// 'group-title': stream.get('group_title')
|
||||
// }
|
||||
// } else {
|
||||
// attrs = {
|
||||
// 'tvg-id': stream.get('tvg_id'),
|
||||
// 'user-agent': stream.get('http.user-agent') || undefined
|
||||
// }
|
||||
// }
|
||||
|
||||
// playlist.add(stream.get('url'), stream.get('display_name'), attrs, {
|
||||
// 'http-referrer': stream.get('http.referrer') || undefined,
|
||||
// 'http-user-agent': stream.get('http.user-agent') || undefined
|
||||
// })
|
||||
// }
|
||||
|
||||
// return file.write(filepath, playlist.toString())
|
||||
// }
|
||||
|
||||
module.exports = file
|
||||
|
|
|
@ -1,119 +1,23 @@
|
|||
const { create: createPlaylist } = require('./playlist')
|
||||
const store = require('./store')
|
||||
const file = require('./file')
|
||||
const logger = require('./logger')
|
||||
const db = require('./db')
|
||||
const _ = require('lodash')
|
||||
const generators = require('../generators')
|
||||
|
||||
const LOGS_DIR = process.env.LOGS_DIR || 'scripts/logs/generators'
|
||||
|
||||
const generator = {}
|
||||
|
||||
generator.generate = async function (filepath, query = {}, options = {}) {
|
||||
options = {
|
||||
...{
|
||||
format: 'm3u',
|
||||
saveEmpty: false,
|
||||
includeNSFW: false,
|
||||
includeGuides: true,
|
||||
includeBroken: false,
|
||||
onLoad: r => r,
|
||||
uniqBy: item => item.id || _.uniqueId(),
|
||||
sortBy: null
|
||||
},
|
||||
...options
|
||||
}
|
||||
|
||||
query['is_nsfw'] = options.includeNSFW ? { $in: [true, false] } : false
|
||||
query['is_broken'] = options.includeBroken ? { $in: [true, false] } : false
|
||||
|
||||
let items = await db
|
||||
.find(query)
|
||||
.sort({ name: 1, 'status.level': 1, 'resolution.height': -1, url: 1 })
|
||||
|
||||
items = _.uniqBy(items, 'url')
|
||||
if (!options.saveEmpty && !items.length) return { filepath, query, options, count: 0 }
|
||||
if (options.uniqBy) items = _.uniqBy(items, options.uniqBy)
|
||||
|
||||
items = options.onLoad(items)
|
||||
|
||||
if (options.sortBy) items = _.sortBy(items, options.sortBy)
|
||||
|
||||
switch (options.format) {
|
||||
case 'json':
|
||||
await saveAsJSON(filepath, items, options)
|
||||
break
|
||||
case 'm3u':
|
||||
default:
|
||||
await saveAsM3U(filepath, items, options)
|
||||
break
|
||||
}
|
||||
|
||||
return { filepath, query, options, count: items.length }
|
||||
}
|
||||
|
||||
async function saveAsM3U(filepath, items, options = {}) {
|
||||
const playlist = await createPlaylist(filepath)
|
||||
|
||||
const header = {}
|
||||
if (options.public) {
|
||||
let guides = items.map(item => item.guides)
|
||||
guides = _.uniq(_.flatten(guides)).sort().join(',')
|
||||
|
||||
header['x-tvg-url'] = guides
|
||||
}
|
||||
|
||||
await playlist.header(header)
|
||||
for (const item of items) {
|
||||
const stream = store.create(item)
|
||||
|
||||
let attrs
|
||||
if (options.public) {
|
||||
attrs = {
|
||||
'tvg-id': stream.get('tvg_id'),
|
||||
'tvg-country': stream.get('tvg_country'),
|
||||
'tvg-language': stream.get('tvg_language'),
|
||||
'tvg-logo': stream.get('tvg_logo'),
|
||||
'user-agent': stream.get('http.user-agent') || undefined,
|
||||
'group-title': stream.get('group_title')
|
||||
}
|
||||
} else {
|
||||
attrs = {
|
||||
'tvg-id': stream.get('tvg_id'),
|
||||
'user-agent': stream.get('http.user-agent') || undefined
|
||||
}
|
||||
generator.generate = async function (name, items = []) {
|
||||
if (typeof generators[name] === 'function') {
|
||||
try {
|
||||
const logs = await generators[name].bind()(items)
|
||||
await file.create(`${LOGS_DIR}/${name}.log`, logs.map(toJSON).join('\n'))
|
||||
} catch (error) {
|
||||
logger.error(`generators/${name}.js: ${error.message}`)
|
||||
}
|
||||
|
||||
await playlist.link(stream.get('url'), stream.get('display_name'), attrs, {
|
||||
'http-referrer': stream.get('http.referrer') || undefined,
|
||||
'http-user-agent': stream.get('http.user-agent') || undefined
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function saveAsJSON(filepath, items, options) {
|
||||
const output = items.map(item => {
|
||||
const stream = store.create(item)
|
||||
const categories = stream.get('categories').map(c => ({ name: c.name, slug: c.slug }))
|
||||
const countries = stream.get('countries').map(c => ({ name: c.name, code: c.code }))
|
||||
|
||||
return {
|
||||
name: stream.get('name'),
|
||||
logo: stream.get('logo'),
|
||||
url: stream.get('url'),
|
||||
categories,
|
||||
countries,
|
||||
languages: stream.get('languages'),
|
||||
tvg: {
|
||||
id: stream.get('tvg_id'),
|
||||
name: stream.get('name'),
|
||||
url: stream.get('tvg_url')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await file.create(filepath, JSON.stringify(output))
|
||||
}
|
||||
|
||||
generator.saveAsM3U = saveAsM3U
|
||||
generator.saveAsJSON = saveAsJSON
|
||||
|
||||
module.exports = generator
|
||||
|
||||
function toJSON(item) {
|
||||
return JSON.stringify(item)
|
||||
}
|
||||
|
|
|
@ -1,49 +1,92 @@
|
|||
const file = require('./file')
|
||||
const store = require('./store')
|
||||
const _ = require('lodash')
|
||||
|
||||
const playlist = {}
|
||||
|
||||
playlist.create = async function (filepath) {
|
||||
playlist.filepath = filepath
|
||||
const dir = file.dirname(filepath)
|
||||
file.createDir(dir)
|
||||
await file.create(filepath, '')
|
||||
class Playlist {
|
||||
constructor() {
|
||||
this.links = []
|
||||
}
|
||||
|
||||
return playlist
|
||||
setHeader(attrs = {}) {
|
||||
this.header = attrs
|
||||
}
|
||||
|
||||
add(url, title, attrs, vlcOpts) {
|
||||
this.links.push({ url, title, attrs, vlcOpts })
|
||||
}
|
||||
|
||||
toString() {
|
||||
let output = `#EXTM3U`
|
||||
for (const attr in this.header) {
|
||||
const value = this.header[attr]
|
||||
output += ` ${attr}="${value}"`
|
||||
}
|
||||
output += `\n`
|
||||
|
||||
for (const link of this.links) {
|
||||
output += `#EXTINF:-1`
|
||||
for (const name in link.attrs) {
|
||||
const value = link.attrs[name]
|
||||
if (value !== undefined) {
|
||||
output += ` ${name}="${value}"`
|
||||
}
|
||||
}
|
||||
output += `,${link.title}\n`
|
||||
|
||||
for (const name in link.vlcOpts) {
|
||||
const value = link.vlcOpts[name]
|
||||
if (value !== undefined) {
|
||||
output += `#EXTVLCOPT:${name}=${value}\n`
|
||||
}
|
||||
}
|
||||
|
||||
output += `${link.url}\n`
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
}
|
||||
|
||||
playlist.header = async function (attrs) {
|
||||
let header = `#EXTM3U`
|
||||
for (const name in attrs) {
|
||||
const value = attrs[name]
|
||||
header += ` ${name}="${value}"`
|
||||
playlist.create = function (items = [], options = {}) {
|
||||
const p = new Playlist()
|
||||
|
||||
const header = {}
|
||||
if (options.public) {
|
||||
let guides = items.map(item => item.guides)
|
||||
guides = _.uniq(_.flatten(guides)).sort().join(',')
|
||||
|
||||
header['x-tvg-url'] = guides
|
||||
}
|
||||
header += `\n`
|
||||
p.setHeader(header)
|
||||
|
||||
await file.append(playlist.filepath, header)
|
||||
for (const item of items) {
|
||||
const stream = store.create(item)
|
||||
|
||||
return playlist
|
||||
}
|
||||
|
||||
playlist.link = async function (url, title, attrs, vlcOpts) {
|
||||
let link = `#EXTINF:-1`
|
||||
for (const name in attrs) {
|
||||
const value = attrs[name]
|
||||
if (value !== undefined) {
|
||||
link += ` ${name}="${value}"`
|
||||
let attrs
|
||||
if (options.public) {
|
||||
attrs = {
|
||||
'tvg-id': stream.get('tvg_id'),
|
||||
'tvg-country': stream.get('tvg_country'),
|
||||
'tvg-language': stream.get('tvg_language'),
|
||||
'tvg-logo': stream.get('tvg_logo'),
|
||||
'user-agent': stream.get('http.user-agent') || undefined,
|
||||
'group-title': stream.get('group_title')
|
||||
}
|
||||
} else {
|
||||
attrs = {
|
||||
'tvg-id': stream.get('tvg_id'),
|
||||
'user-agent': stream.get('http.user-agent') || undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
link += `,${title}\n`
|
||||
for (const name in vlcOpts) {
|
||||
const value = vlcOpts[name]
|
||||
if (value !== undefined) {
|
||||
link += `#EXTVLCOPT:${name}=${value}\n`
|
||||
}
|
||||
}
|
||||
link += `${url}\n`
|
||||
|
||||
await file.append(playlist.filepath, link)
|
||||
p.add(stream.get('url'), stream.get('title'), attrs, {
|
||||
'http-referrer': stream.get('http.referrer') || undefined,
|
||||
'http-user-agent': stream.get('http.user-agent') || undefined
|
||||
})
|
||||
}
|
||||
|
||||
return playlist
|
||||
return p
|
||||
}
|
||||
|
||||
module.exports = playlist
|
||||
|
|
1
scripts/data/.gitignore
vendored
1
scripts/data/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
codes.json
|
|
@ -1,147 +0,0 @@
|
|||
{
|
||||
"auto": {
|
||||
"name": "Auto",
|
||||
"slug": "auto",
|
||||
"nsfw": false
|
||||
},
|
||||
"animation": {
|
||||
"name": "Animation",
|
||||
"slug": "animation",
|
||||
"nsfw": false
|
||||
},
|
||||
"business": {
|
||||
"name": "Business",
|
||||
"slug": "business",
|
||||
"nsfw": false
|
||||
},
|
||||
"classic": {
|
||||
"name": "Classic",
|
||||
"slug": "classic",
|
||||
"nsfw": false
|
||||
},
|
||||
"comedy": {
|
||||
"name": "Comedy",
|
||||
"slug": "comedy",
|
||||
"nsfw": false
|
||||
},
|
||||
"cooking": {
|
||||
"name": "Cooking",
|
||||
"slug": "cooking",
|
||||
"nsfw": false
|
||||
},
|
||||
"culture": {
|
||||
"name": "Culture",
|
||||
"slug": "culture",
|
||||
"nsfw": false
|
||||
},
|
||||
"documentary": {
|
||||
"name": "Documentary",
|
||||
"slug": "documentary",
|
||||
"nsfw": false
|
||||
},
|
||||
"education": {
|
||||
"name": "Education",
|
||||
"slug": "education",
|
||||
"nsfw": false
|
||||
},
|
||||
"entertainment": {
|
||||
"name": "Entertainment",
|
||||
"slug": "entertainment",
|
||||
"nsfw": false
|
||||
},
|
||||
"family": {
|
||||
"name": "Family",
|
||||
"slug": "family",
|
||||
"nsfw": false
|
||||
},
|
||||
"general": {
|
||||
"name": "General",
|
||||
"slug": "general",
|
||||
"nsfw": false
|
||||
},
|
||||
"kids": {
|
||||
"name": "Kids",
|
||||
"slug": "kids",
|
||||
"nsfw": false
|
||||
},
|
||||
"legislative": {
|
||||
"name": "Legislative",
|
||||
"slug": "legislative",
|
||||
"nsfw": false
|
||||
},
|
||||
"lifestyle": {
|
||||
"name": "Lifestyle",
|
||||
"slug": "lifestyle",
|
||||
"nsfw": false
|
||||
},
|
||||
"local": {
|
||||
"name": "Local",
|
||||
"slug": "local",
|
||||
"nsfw": false
|
||||
},
|
||||
"movies": {
|
||||
"name": "Movies",
|
||||
"slug": "movies",
|
||||
"nsfw": false
|
||||
},
|
||||
"music": {
|
||||
"name": "Music",
|
||||
"slug": "music",
|
||||
"nsfw": false
|
||||
},
|
||||
"news": {
|
||||
"name": "News",
|
||||
"slug": "news",
|
||||
"nsfw": false
|
||||
},
|
||||
"outdoor": {
|
||||
"name": "Outdoor",
|
||||
"slug": "outdoor",
|
||||
"nsfw": false
|
||||
},
|
||||
"relax": {
|
||||
"name": "Relax",
|
||||
"slug": "relax",
|
||||
"nsfw": false
|
||||
},
|
||||
"religious": {
|
||||
"name": "Religious",
|
||||
"slug": "religious",
|
||||
"nsfw": false
|
||||
},
|
||||
"series": {
|
||||
"name": "Series",
|
||||
"slug": "series",
|
||||
"nsfw": false
|
||||
},
|
||||
"science": {
|
||||
"name": "Science",
|
||||
"slug": "science",
|
||||
"nsfw": false
|
||||
},
|
||||
"shop": {
|
||||
"name": "Shop",
|
||||
"slug": "shop",
|
||||
"nsfw": false
|
||||
},
|
||||
"sports": {
|
||||
"name": "Sports",
|
||||
"slug": "sports",
|
||||
"nsfw": false
|
||||
},
|
||||
"travel": {
|
||||
"name": "Travel",
|
||||
"slug": "travel",
|
||||
"nsfw": false
|
||||
},
|
||||
"weather": {
|
||||
"name": "Weather",
|
||||
"slug": "weather",
|
||||
"nsfw": false
|
||||
},
|
||||
"xxx": {
|
||||
"name": "XXX",
|
||||
"slug": "xxx",
|
||||
"nsfw": true
|
||||
}
|
||||
}
|
|
@ -1,264 +0,0 @@
|
|||
{
|
||||
"AD": { "name": "Andorra", "code": "AD", "lang": "cat" },
|
||||
"AE": { "name": "United Arab Emirates", "code": "AE", "lang": "ara" },
|
||||
"AF": { "name": "Afghanistan", "code": "AF", "lang": "pus" },
|
||||
"AG": { "name": "Antigua and Barbuda", "code": "AG", "lang": "eng" },
|
||||
"AI": { "name": "Anguilla", "code": "AI", "lang": "eng" },
|
||||
"AL": { "name": "Albania", "code": "AL", "lang": "sqi" },
|
||||
"AM": { "name": "Armenia", "code": "AM", "lang": "hye" },
|
||||
"AO": { "name": "Angola", "code": "AO", "lang": "por" },
|
||||
"AQ": { "name": "Antarctica", "code": "AQ", "lang": null },
|
||||
"AR": { "name": "Argentina", "code": "AR", "lang": "spa" },
|
||||
"AS": { "name": "American Samoa", "code": "AS", "lang": "eng" },
|
||||
"AT": { "name": "Austria", "code": "AT", "lang": "deu" },
|
||||
"AU": { "name": "Australia", "code": "AU", "lang": "eng" },
|
||||
"AW": { "name": "Aruba", "code": "AW", "lang": "nld" },
|
||||
"AX": { "name": "Åland", "code": "AX", "lang": "swe" },
|
||||
"AZ": { "name": "Azerbaijan", "code": "AZ", "lang": "aze" },
|
||||
"BA": { "name": "Bosnia and Herzegovina", "code": "BA", "lang": "bos" },
|
||||
"BB": { "name": "Barbados", "code": "BB", "lang": "eng" },
|
||||
"BD": { "name": "Bangladesh", "code": "BD", "lang": "ben" },
|
||||
"BE": { "name": "Belgium", "code": "BE", "lang": "nld" },
|
||||
"BF": { "name": "Burkina Faso", "code": "BF", "lang": "fra" },
|
||||
"BG": { "name": "Bulgaria", "code": "BG", "lang": "bul" },
|
||||
"BH": { "name": "Bahrain", "code": "BH", "lang": "ara" },
|
||||
"BI": { "name": "Burundi", "code": "BI", "lang": "fra" },
|
||||
"BJ": { "name": "Benin", "code": "BJ", "lang": "fra" },
|
||||
"BL": { "name": "Saint Barthélemy", "code": "BL", "lang": "fra" },
|
||||
"BM": { "name": "Bermuda", "code": "BM", "lang": "eng" },
|
||||
"BN": { "name": "Brunei", "code": "BN", "lang": "msa" },
|
||||
"BO": { "name": "Bolivia", "code": "BO", "lang": "spa" },
|
||||
"BQ": { "name": "Bonaire", "code": "BQ", "lang": "nld" },
|
||||
"BR": { "name": "Brazil", "code": "BR", "lang": "por" },
|
||||
"BS": { "name": "Bahamas", "code": "BS", "lang": "eng" },
|
||||
"BT": { "name": "Bhutan", "code": "BT", "lang": "dzo" },
|
||||
"BV": { "name": "Bouvet Island", "code": "BV", "lang": "nor" },
|
||||
"BW": { "name": "Botswana", "code": "BW", "lang": "eng" },
|
||||
"BY": { "name": "Belarus", "code": "BY", "lang": "bel" },
|
||||
"BZ": { "name": "Belize", "code": "BZ", "lang": "eng" },
|
||||
"CA": { "name": "Canada", "code": "CA", "lang": "eng" },
|
||||
"CC": { "name": "Cocos [Keeling] Islands", "code": "CC", "lang": "eng" },
|
||||
"CD": {
|
||||
"name": "Democratic Republic of the Congo",
|
||||
"code": "CD",
|
||||
"lang": "fra"
|
||||
},
|
||||
"CF": { "name": "Central African Republic", "code": "CF", "lang": "fra" },
|
||||
"CG": { "name": "Republic of the Congo", "code": "CG", "lang": "fra" },
|
||||
"CH": { "name": "Switzerland", "code": "CH", "lang": "deu" },
|
||||
"CI": { "name": "Ivory Coast", "code": "CI", "lang": "fra" },
|
||||
"CK": { "name": "Cook Islands", "code": "CK", "lang": "eng" },
|
||||
"CL": { "name": "Chile", "code": "CL", "lang": "spa" },
|
||||
"CM": { "name": "Cameroon", "code": "CM", "lang": "eng" },
|
||||
"CN": { "name": "China", "code": "CN", "lang": "zho" },
|
||||
"CO": { "name": "Colombia", "code": "CO", "lang": "spa" },
|
||||
"CR": { "name": "Costa Rica", "code": "CR", "lang": "spa" },
|
||||
"CU": { "name": "Cuba", "code": "CU", "lang": "spa" },
|
||||
"CV": { "name": "Cape Verde", "code": "CV", "lang": "por" },
|
||||
"CW": { "name": "Curacao", "code": "CW", "lang": "nld" },
|
||||
"CX": { "name": "Christmas Island", "code": "CX", "lang": "eng" },
|
||||
"CY": { "name": "Cyprus", "code": "CY", "lang": "ell" },
|
||||
"CZ": { "name": "Czech Republic", "code": "CZ", "lang": "ces" },
|
||||
"DE": { "name": "Germany", "code": "DE", "lang": "deu" },
|
||||
"DJ": { "name": "Djibouti", "code": "DJ", "lang": "fra" },
|
||||
"DK": { "name": "Denmark", "code": "DK", "lang": "dan" },
|
||||
"DM": { "name": "Dominica", "code": "DM", "lang": "eng" },
|
||||
"DO": { "name": "Dominican Republic", "code": "DO", "lang": "spa" },
|
||||
"DZ": { "name": "Algeria", "code": "DZ", "lang": "ara" },
|
||||
"EC": { "name": "Ecuador", "code": "EC", "lang": "spa" },
|
||||
"EE": { "name": "Estonia", "code": "EE", "lang": "est" },
|
||||
"EG": { "name": "Egypt", "code": "EG", "lang": "ara" },
|
||||
"EH": { "name": "Western Sahara", "code": "EH", "lang": "spa" },
|
||||
"ER": { "name": "Eritrea", "code": "ER", "lang": "tir" },
|
||||
"ES": { "name": "Spain", "code": "ES", "lang": "spa" },
|
||||
"ET": { "name": "Ethiopia", "code": "ET", "lang": "amh" },
|
||||
"FI": { "name": "Finland", "code": "FI", "lang": "fin" },
|
||||
"FJ": { "name": "Fiji", "code": "FJ", "lang": "eng" },
|
||||
"FK": { "name": "Falkland Islands", "code": "FK", "lang": "eng" },
|
||||
"FM": { "name": "Micronesia", "code": "FM", "lang": "eng" },
|
||||
"FO": { "name": "Faroe Islands", "code": "FO", "lang": "fao" },
|
||||
"FR": { "name": "France", "code": "FR", "lang": "fra" },
|
||||
"GA": { "name": "Gabon", "code": "GA", "lang": "fra" },
|
||||
"UK": { "name": "United Kingdom", "code": "UK", "lang": "eng" },
|
||||
"GD": { "name": "Grenada", "code": "GD", "lang": "eng" },
|
||||
"GE": { "name": "Georgia", "code": "GE", "lang": "kat" },
|
||||
"GF": { "name": "French Guiana", "code": "GF", "lang": "fra" },
|
||||
"GG": { "name": "Guernsey", "code": "GG", "lang": "eng" },
|
||||
"GH": { "name": "Ghana", "code": "GH", "lang": "eng" },
|
||||
"GI": { "name": "Gibraltar", "code": "GI", "lang": "eng" },
|
||||
"GL": { "name": "Greenland", "code": "GL", "lang": "kal" },
|
||||
"GM": { "name": "Gambia", "code": "GM", "lang": "eng" },
|
||||
"GN": { "name": "Guinea", "code": "GN", "lang": "fra" },
|
||||
"GP": { "name": "Guadeloupe", "code": "GP", "lang": "fra" },
|
||||
"GQ": { "name": "Equatorial Guinea", "code": "GQ", "lang": "spa" },
|
||||
"GR": { "name": "Greece", "code": "GR", "lang": "ell" },
|
||||
"GS": {
|
||||
"name": "South Georgia and the South Sandwich Islands",
|
||||
"code": "GS",
|
||||
"lang": "eng"
|
||||
},
|
||||
"GT": { "name": "Guatemala", "code": "GT", "lang": "spa" },
|
||||
"GU": { "name": "Guam", "code": "GU", "lang": "eng" },
|
||||
"GW": { "name": "Guinea-Bissau", "code": "GW", "lang": "por" },
|
||||
"GY": { "name": "Guyana", "code": "GY", "lang": "eng" },
|
||||
"HK": { "name": "Hong Kong", "code": "HK", "lang": "zho" },
|
||||
"HM": { "name": "Heard Island and McDonald Islands", "code": "HM", "lang": "eng" },
|
||||
"HN": { "name": "Honduras", "code": "HN", "lang": "spa" },
|
||||
"HR": { "name": "Croatia", "code": "HR", "lang": "hrv" },
|
||||
"HT": { "name": "Haiti", "code": "HT", "lang": "fra" },
|
||||
"HU": { "name": "Hungary", "code": "HU", "lang": "hun" },
|
||||
"ID": { "name": "Indonesia", "code": "ID", "lang": "ind" },
|
||||
"IE": { "name": "Ireland", "code": "IE", "lang": "gle" },
|
||||
"IL": { "name": "Israel", "code": "IL", "lang": "heb" },
|
||||
"IM": { "name": "Isle of Man", "code": "IM", "lang": "eng" },
|
||||
"IN": { "name": "India", "code": "IN", "lang": "hin" },
|
||||
"IO": { "name": "British Indian Ocean Territory", "code": "IO", "lang": "eng" },
|
||||
"IQ": { "name": "Iraq", "code": "IQ", "lang": "ara" },
|
||||
"IR": { "name": "Iran", "code": "IR", "lang": "fas" },
|
||||
"IS": { "name": "Iceland", "code": "IS", "lang": "isl" },
|
||||
"IT": { "name": "Italy", "code": "IT", "lang": "ita" },
|
||||
"JE": { "name": "Jersey", "code": "JE", "lang": "eng" },
|
||||
"JM": { "name": "Jamaica", "code": "JM", "lang": "eng" },
|
||||
"JO": { "name": "Jordan", "code": "JO", "lang": "ara" },
|
||||
"JP": { "name": "Japan", "code": "JP", "lang": "jpn" },
|
||||
"KE": { "name": "Kenya", "code": "KE", "lang": "eng" },
|
||||
"KG": { "name": "Kyrgyzstan", "code": "KG", "lang": "kir" },
|
||||
"KH": { "name": "Cambodia", "code": "KH", "lang": "khm" },
|
||||
"KI": { "name": "Kiribati", "code": "KI", "lang": "eng" },
|
||||
"KM": { "name": "Comoros", "code": "KM", "lang": "ara" },
|
||||
"KN": { "name": "Saint Kitts and Nevis", "code": "KN", "lang": "eng" },
|
||||
"KP": { "name": "North Korea", "code": "KP", "lang": "kor" },
|
||||
"KR": { "name": "South Korea", "code": "KR", "lang": "kor" },
|
||||
"KW": { "name": "Kuwait", "code": "KW", "lang": "ara" },
|
||||
"KY": { "name": "Cayman Islands", "code": "KY", "lang": "eng" },
|
||||
"KZ": { "name": "Kazakhstan", "code": "KZ", "lang": "kaz" },
|
||||
"LA": { "name": "Laos", "code": "LA", "lang": "lao" },
|
||||
"LB": { "name": "Lebanon", "code": "LB", "lang": "ara" },
|
||||
"LC": { "name": "Saint Lucia", "code": "LC", "lang": "eng" },
|
||||
"LI": { "name": "Liechtenstein", "code": "LI", "lang": "deu" },
|
||||
"LK": { "name": "Sri Lanka", "code": "LK", "lang": "sin" },
|
||||
"LR": { "name": "Liberia", "code": "LR", "lang": "eng" },
|
||||
"LS": { "name": "Lesotho", "code": "LS", "lang": "eng" },
|
||||
"LT": { "name": "Lithuania", "code": "LT", "lang": "lit" },
|
||||
"LU": { "name": "Luxembourg", "code": "LU", "lang": "fra" },
|
||||
"LV": { "name": "Latvia", "code": "LV", "lang": "lav" },
|
||||
"LY": { "name": "Libya", "code": "LY", "lang": "ara" },
|
||||
"MA": { "name": "Morocco", "code": "MA", "lang": "ara" },
|
||||
"MC": { "name": "Monaco", "code": "MC", "lang": "fra" },
|
||||
"MD": { "name": "Moldova", "code": "MD", "lang": "ron" },
|
||||
"ME": { "name": "Montenegro", "code": "ME", "lang": "srp" },
|
||||
"MF": { "name": "Saint Martin", "code": "MF", "lang": "eng" },
|
||||
"MG": { "name": "Madagascar", "code": "MG", "lang": "fra" },
|
||||
"MH": { "name": "Marshall Islands", "code": "MH", "lang": "eng" },
|
||||
"MK": { "name": "North Macedonia", "code": "MK", "lang": "mkd" },
|
||||
"ML": { "name": "Mali", "code": "ML", "lang": "fra" },
|
||||
"MM": { "name": "Myanmar [Burma]", "code": "MM", "lang": "mya" },
|
||||
"MN": { "name": "Mongolia", "code": "MN", "lang": "mon" },
|
||||
"MO": { "name": "Macao", "code": "MO", "lang": "zho" },
|
||||
"MP": { "name": "Northern Mariana Islands", "code": "MP", "lang": "eng" },
|
||||
"MQ": { "name": "Martinique", "code": "MQ", "lang": "fra" },
|
||||
"MR": { "name": "Mauritania", "code": "MR", "lang": "ara" },
|
||||
"MS": { "name": "Montserrat", "code": "MS", "lang": "eng" },
|
||||
"MT": { "name": "Malta", "code": "MT", "lang": "mlt" },
|
||||
"MU": { "name": "Mauritius", "code": "MU", "lang": "eng" },
|
||||
"MV": { "name": "Maldives", "code": "MV", "lang": "div" },
|
||||
"MW": { "name": "Malawi", "code": "MW", "lang": "eng" },
|
||||
"MX": { "name": "Mexico", "code": "MX", "lang": "spa" },
|
||||
"MY": { "name": "Malaysia", "code": "MY", "lang": "msa" },
|
||||
"MZ": { "name": "Mozambique", "code": "MZ", "lang": "por" },
|
||||
"NA": { "name": "Namibia", "code": "NA", "lang": "eng" },
|
||||
"NC": { "name": "New Caledonia", "code": "NC", "lang": "fra" },
|
||||
"NE": { "name": "Niger", "code": "NE", "lang": "fra" },
|
||||
"NF": { "name": "Norfolk Island", "code": "NF", "lang": "eng" },
|
||||
"NG": { "name": "Nigeria", "code": "NG", "lang": "eng" },
|
||||
"NI": { "name": "Nicaragua", "code": "NI", "lang": "spa" },
|
||||
"NL": { "name": "Netherlands", "code": "NL", "lang": "nld" },
|
||||
"NO": { "name": "Norway", "code": "NO", "lang": "nor" },
|
||||
"NP": { "name": "Nepal", "code": "NP", "lang": "nep" },
|
||||
"NR": { "name": "Nauru", "code": "NR", "lang": "eng" },
|
||||
"NU": { "name": "Niue", "code": "NU", "lang": "eng" },
|
||||
"NZ": { "name": "New Zealand", "code": "NZ", "lang": "eng" },
|
||||
"OM": { "name": "Oman", "code": "OM", "lang": "ara" },
|
||||
"PA": { "name": "Panama", "code": "PA", "lang": "spa" },
|
||||
"PE": { "name": "Peru", "code": "PE", "lang": "spa" },
|
||||
"PF": { "name": "French Polynesia", "code": "PF", "lang": "fra" },
|
||||
"PG": { "name": "Papua New Guinea", "code": "PG", "lang": "eng" },
|
||||
"PH": { "name": "Philippines", "code": "PH", "lang": "eng" },
|
||||
"PK": { "name": "Pakistan", "code": "PK", "lang": "eng" },
|
||||
"PL": { "name": "Poland", "code": "PL", "lang": "pol" },
|
||||
"PM": { "name": "Saint Pierre and Miquelon", "code": "PM", "lang": "fra" },
|
||||
"PN": { "name": "Pitcairn Islands", "code": "PN", "lang": "eng" },
|
||||
"PR": { "name": "Puerto Rico", "code": "PR", "lang": "spa" },
|
||||
"PS": { "name": "Palestine", "code": "PS", "lang": "ara" },
|
||||
"PT": { "name": "Portugal", "code": "PT", "lang": "por" },
|
||||
"PW": { "name": "Palau", "code": "PW", "lang": "eng" },
|
||||
"PY": { "name": "Paraguay", "code": "PY", "lang": "spa" },
|
||||
"QA": { "name": "Qatar", "code": "QA", "lang": "ara" },
|
||||
"RE": { "name": "Réunion", "code": "RE", "lang": "fra" },
|
||||
"RO": { "name": "Romania", "code": "RO", "lang": "ron" },
|
||||
"RS": { "name": "Serbia", "code": "RS", "lang": "srp" },
|
||||
"RU": { "name": "Russia", "code": "RU", "lang": "rus" },
|
||||
"RW": { "name": "Rwanda", "code": "RW", "lang": "kin" },
|
||||
"SA": { "name": "Saudi Arabia", "code": "SA", "lang": "ara" },
|
||||
"SB": { "name": "Solomon Islands", "code": "SB", "lang": "eng" },
|
||||
"SC": { "name": "Seychelles", "code": "SC", "lang": "fra" },
|
||||
"SD": { "name": "Sudan", "code": "SD", "lang": "ara" },
|
||||
"SE": { "name": "Sweden", "code": "SE", "lang": "swe" },
|
||||
"SG": { "name": "Singapore", "code": "SG", "lang": "eng" },
|
||||
"SH": { "name": "Saint Helena", "code": "SH", "lang": "eng" },
|
||||
"SI": { "name": "Slovenia", "code": "SI", "lang": "slv" },
|
||||
"SJ": { "name": "Svalbard and Jan Mayen", "code": "SJ", "lang": "nor" },
|
||||
"SK": { "name": "Slovakia", "code": "SK", "lang": "slk" },
|
||||
"SL": { "name": "Sierra Leone", "code": "SL", "lang": "eng" },
|
||||
"SM": { "name": "San Marino", "code": "SM", "lang": "ita" },
|
||||
"SN": { "name": "Senegal", "code": "SN", "lang": "fra" },
|
||||
"SO": { "name": "Somalia", "code": "SO", "lang": "som" },
|
||||
"SR": { "name": "Suriname", "code": "SR", "lang": "nld" },
|
||||
"SS": { "name": "South Sudan", "code": "SS", "lang": "eng" },
|
||||
"ST": { "name": "São Tomé and Príncipe", "code": "ST", "lang": "por" },
|
||||
"SV": { "name": "El Salvador", "code": "SV", "lang": "spa" },
|
||||
"SX": { "name": "Sint Maarten", "code": "SX", "lang": "nld" },
|
||||
"SY": { "name": "Syria", "code": "SY", "lang": "ara" },
|
||||
"SZ": { "name": "Swaziland", "code": "SZ", "lang": "eng" },
|
||||
"TC": { "name": "Turks and Caicos Islands", "code": "TC", "lang": "eng" },
|
||||
"TD": { "name": "Chad", "code": "TD", "lang": "fra" },
|
||||
"TF": { "name": "French Southern Territories", "code": "TF", "lang": "fra" },
|
||||
"TG": { "name": "Togo", "code": "TG", "lang": "fra" },
|
||||
"TH": { "name": "Thailand", "code": "TH", "lang": "tha" },
|
||||
"TJ": { "name": "Tajikistan", "code": "TJ", "lang": "tgk" },
|
||||
"TK": { "name": "Tokelau", "code": "TK", "lang": "eng" },
|
||||
"TL": { "name": "East Timor", "code": "TL", "lang": "por" },
|
||||
"TM": { "name": "Turkmenistan", "code": "TM", "lang": "tuk" },
|
||||
"TN": { "name": "Tunisia", "code": "TN", "lang": "ara" },
|
||||
"TO": { "name": "Tonga", "code": "TO", "lang": "eng" },
|
||||
"TR": { "name": "Turkey", "code": "TR", "lang": "tur" },
|
||||
"TT": { "name": "Trinidad and Tobago", "code": "TT", "lang": "eng" },
|
||||
"TV": { "name": "Tuvalu", "code": "TV", "lang": "eng" },
|
||||
"TW": { "name": "Taiwan", "code": "TW", "lang": "zho" },
|
||||
"TZ": { "name": "Tanzania", "code": "TZ", "lang": "swa" },
|
||||
"UA": { "name": "Ukraine", "code": "UA", "lang": "ukr" },
|
||||
"UG": { "name": "Uganda", "code": "UG", "lang": "eng" },
|
||||
"UM": { "name": "U.S. Minor Outlying Islands", "code": "UM", "lang": "eng" },
|
||||
"US": { "name": "United States", "code": "US", "lang": "eng" },
|
||||
"UY": { "name": "Uruguay", "code": "UY", "lang": "spa" },
|
||||
"UZ": { "name": "Uzbekistan", "code": "UZ", "lang": "uzb" },
|
||||
"VA": { "name": "Vatican City", "code": "VA", "lang": "ita" },
|
||||
"VC": { "name": "Saint Vincent and the Grenadines", "code": "VC", "lang": "eng" },
|
||||
"VE": { "name": "Venezuela", "code": "VE", "lang": "spa" },
|
||||
"VG": { "name": "British Virgin Islands", "code": "VG", "lang": "eng" },
|
||||
"VI": { "name": "U.S. Virgin Islands", "code": "VI", "lang": "eng" },
|
||||
"VN": { "name": "Vietnam", "code": "VN", "lang": "vie" },
|
||||
"VU": { "name": "Vanuatu", "code": "VU", "lang": "bis" },
|
||||
"WF": { "name": "Wallis and Futuna", "code": "WF", "lang": "fra" },
|
||||
"WS": { "name": "Samoa", "code": "WS", "lang": "smo" },
|
||||
"XK": { "name": "Kosovo", "code": "XK", "lang": "sqi" },
|
||||
"YE": { "name": "Yemen", "code": "YE", "lang": "ara" },
|
||||
"YT": { "name": "Mayotte", "code": "YT", "lang": "fra" },
|
||||
"ZA": {
|
||||
"name": "South Africa",
|
||||
"code": "ZA",
|
||||
"lang": "afr"
|
||||
},
|
||||
"ZM": { "name": "Zambia", "code": "ZM", "lang": "eng" },
|
||||
"ZW": { "name": "Zimbabwe", "code": "ZW", "lang": "eng" }
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
47
scripts/generators/categories.js
Normal file
47
scripts/generators/categories.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
const { create: createPlaylist } = require('../core/playlist')
|
||||
const api = require('../core/api')
|
||||
const file = require('../core/file')
|
||||
const _ = require('lodash')
|
||||
|
||||
const PUBLIC_DIR = process.env.PUBLIC_DIR || '.gh-pages'
|
||||
|
||||
module.exports = async function (streams = []) {
|
||||
const logs = []
|
||||
|
||||
await api.categories.load()
|
||||
const categories = await api.categories.all()
|
||||
|
||||
for (const category of categories) {
|
||||
let output = _.filter(streams, { channel: { categories: [category.id] } })
|
||||
output = _.orderBy(
|
||||
output,
|
||||
['channel.name', 'status.level', 'resolution.height'],
|
||||
['asc', 'asc', 'desc']
|
||||
)
|
||||
output = _.uniqBy(output, s => s.channel_id || _.uniqueId())
|
||||
|
||||
const playlist = createPlaylist(output, { public: true })
|
||||
await file.create(`${PUBLIC_DIR}/categories/${category.id}.m3u`, playlist.toString())
|
||||
|
||||
logs.push({ id: category.id, count: output.length })
|
||||
}
|
||||
|
||||
let output = _.filter(streams, s => !s.categories.length)
|
||||
output = _.orderBy(
|
||||
output,
|
||||
['channel.name', 'status.level', 'resolution.height'],
|
||||
['asc', 'asc', 'desc']
|
||||
)
|
||||
output = _.uniqBy(output, s => s.channel_id || _.uniqueId())
|
||||
output = output.map(item => {
|
||||
item.group_title = 'Other'
|
||||
return item
|
||||
})
|
||||
|
||||
const playlist = createPlaylist(output, { public: true })
|
||||
await file.create(`${PUBLIC_DIR}/categories/other.m3u`, playlist.toString())
|
||||
|
||||
logs.push({ id: 'other', count: output.length })
|
||||
|
||||
return logs
|
||||
}
|
1
scripts/generators/index.js
Normal file
1
scripts/generators/index.js
Normal file
|
@ -0,0 +1 @@
|
|||
exports.categories = require('./categories')
|
|
@ -1,5 +1,5 @@
|
|||
module.exports = function () {
|
||||
if (this.group_title) return this.group_title
|
||||
if (this.group_title !== undefined) return this.group_title
|
||||
|
||||
if (Array.isArray(this.categories)) {
|
||||
return this.categories
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
exports.group_title = require('./group_title')
|
||||
exports.display_name = require('./display_name')
|
||||
exports.title = require('./title')
|
||||
exports.tvg_country = require('./tvg_country')
|
||||
exports.tvg_id = require('./tvg_id')
|
||||
exports.tvg_language = require('./tvg_language')
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
module.exports = function () {
|
||||
let title = this.title
|
||||
let title = this.channel_name
|
||||
|
||||
if (this.resolution.height) {
|
||||
title += ` (${this.resolution.height}p)`
|
|
@ -1,5 +1,3 @@
|
|||
module.exports = function () {
|
||||
if (this.tvg_country) return this.tvg_country
|
||||
|
||||
return Array.isArray(this.countries) ? this.countries.map(i => i.code).join(';') : ''
|
||||
return Array.isArray(this.broadcast_area) ? this.broadcast_area.join(';') : ''
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module.exports = function () {
|
||||
return this.id || ''
|
||||
return this.channel_id || ''
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module.exports = function () {
|
||||
return this.logo || ''
|
||||
return this.channel && this.channel.logo ? this.channel.logo : ''
|
||||
}
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
const { parser } = require('../../core')
|
||||
|
||||
module.exports = function ({ title }) {
|
||||
return parser.parseChannelName(title)
|
||||
return title
|
||||
.trim()
|
||||
.split(' ')
|
||||
.map(s => s.trim())
|
||||
.filter(s => {
|
||||
return !/\[|\]/i.test(s) && !/\((\d+)P\)/i.test(s)
|
||||
})
|
||||
.join(' ')
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue