const { db, api, logger, file, zip } = require('../../core') const { generateXMLTV, Program, Channel } = require('epg-grabber') const _ = require('lodash') const langs = require('langs') const PUBLIC_DIR = process.env.PUBLIC_DIR || '.gh-pages' const LOGS_DIR = process.env.LOGS_DIR || 'scripts/logs' const CURR_DATE = process.env.CURR_DATE || new Date() const logPath = `${LOGS_DIR}/guides/update.log` async function main() { logger.info(`starting...`) logger.info('loading API data...') await api.countries.load() await api.channels.load() await api.regions.load() await api.subdivisions.load() let countries = await api.countries.all() let api_channels = await api.channels.all() let channels_dic = {} api_channels.forEach(channel => { channels_dic[channel.id] = channel }) let api_regions = await api.regions.all() let api_subdivisions = await api.subdivisions.all() logger.info('loading database/programs.db...') await db.programs.load() let db_programs = await db.programs.find({}) db_programs = db_programs .map(p => { if (p.titles.length) { p.score = calcScore(p) p.lang = p.titles[0].lang return p } return null }) .filter(Boolean) logger.info(`found ${db_programs.length} programs`) logger.info(`creating ${logPath}...`) await file.create(logPath) for (let country of countries) { let countryBroadcastCode = `c/${country.code}` let countryRegions = api_regions .filter(r => r.countries.includes(country.code)) .map(r => `r/${r.code}`) let countrySubdivisions = api_subdivisions .filter(s => s.country === country.code) .map(s => `s/${s.code}`) let broadcastCodes = [countryBroadcastCode, ...countryRegions, ...countrySubdivisions] let countryChannels = api_channels.filter( c => _.intersection(c.broadcast_area, broadcastCodes).length ) countryChannels = countryChannels.map(c => c.id) let countryPrograms = db_programs.filter(p => countryChannels.includes(p.channel)) let langGroups = _.groupBy(countryPrograms, 'lang') let countryLanguages = _.uniq([...country.languages, 'eng']) let programs = {} for (let langCode of countryLanguages) { const lang = convertLangCode(langCode, '3', '1') if (!lang) continue let langPrograms = langGroups[lang] if (!langPrograms || !langPrograms.length) continue let channelGroups = _.groupBy(langPrograms, 'channel') for (let channel in channelGroups) { if (programs[channel]) continue let groupedPrograms = channelGroups[channel] let channelPrograms = getChannelPrograms(groupedPrograms) if (!channelPrograms.length) continue programs[channel] = channelPrograms } } programs = _.flatten(Object.values(programs)) if (!programs.length) continue let channels = programs.map(p => { let c = channels_dic[p.channel] c.site = p.site c.lang = p.lang return new Channel(c) }) channels = _.sortBy(channels, 'id') channels = _.uniqBy(channels, 'id') programs = _.sortBy(programs, ['channel', 'start']) programs = programs.map(p => new Program(p, new Channel(channels_dic[p.channel]))) programs = _.uniqBy(programs, p => p.channel + p.start) const filename = country.code.toLowerCase() const xmlFilepath = `${PUBLIC_DIR}/guides/${filename}.xml` const gzFilepath = `${PUBLIC_DIR}/guides/${filename}.xml.gz` const jsonFilepath = `${PUBLIC_DIR}/guides/${filename}.json` logger.info(`creating ${xmlFilepath}...`) const xmltv = generateXMLTV({ channels, programs, date: CURR_DATE }) await file.create(xmlFilepath, xmltv) logger.info(`creating ${gzFilepath}...`) const compressed = await zip.compress(xmltv) await file.create(gzFilepath, compressed) logger.info(`creating ${jsonFilepath}...`) await file.create(jsonFilepath, JSON.stringify({ channels, programs })) for (let channel of channels) { let result = { country: country.code, lang: channel.lang, site: channel.site, channel: channel.id, filename } await file.append(logPath, JSON.stringify(result) + '\r\n') } } } main() function convertLangCode(code, from, to) { let found = langs.where(from, code) return found ? found[to] : null } function getChannelPrograms(programs) { let sites = _.groupBy(programs, 'site') let topScore = 0 let selected for (let site in sites) { let sitePrograms = sites[site] let siteScore = _.sumBy(sitePrograms, 'score') if (siteScore > topScore) { selected = site topScore = siteScore } } return sites[selected] || [] } function calcScore(program) { let score = 0 let values = Object.values(program) for (let value of values) { if (Array.isArray(value) && value.length) { score++ } else if (typeof value === 'string' && value) { score++ } else if (value && typeof value === 'object' && Object.values(value).map(Boolean).length) { score++ } } return score }