diff --git a/.github/workflows/cablego.com.pe.yml b/.github/workflows/cablego.com.pe.yml
new file mode 100644
index 00000000..d5737366
--- /dev/null
+++ b/.github/workflows/cablego.com.pe.yml
@@ -0,0 +1,17 @@
+name: cablego.com.pe
+on:
+ schedule:
+ - cron: '0 3 * * *'
+ workflow_dispatch:
+ workflow_run:
+ workflows: [_trigger]
+ types:
+ - completed
+jobs:
+ load:
+ uses: ./.github/workflows/_load.yml
+ with:
+ site: ${{github.workflow}}
+ secrets:
+ APP_ID: ${{ secrets.APP_ID }}
+ APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }}
diff --git a/sites/cablego.com.pe/__data__/content.json b/sites/cablego.com.pe/__data__/content.json
new file mode 100644
index 00000000..34ab546c
--- /dev/null
+++ b/sites/cablego.com.pe/__data__/content.json
@@ -0,0 +1 @@
+{"state":[],"snippets":{"snippet--channelGrid":"
\n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n \n 16:00 \n \n \n Elif\n \n\n\n \n \n \n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n\n
\n
\n","snippet--loadMore":" Show more \n"}}
\ No newline at end of file
diff --git a/sites/cablego.com.pe/__data__/no_content.json b/sites/cablego.com.pe/__data__/no_content.json
new file mode 100644
index 00000000..64c6171c
--- /dev/null
+++ b/sites/cablego.com.pe/__data__/no_content.json
@@ -0,0 +1 @@
+{"state":[],"snippets":{"snippet--channelGrid":" \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n \n
\n\n
\n
\n \n \n \n \n
\n \n \n
\n\n
\n
\n
\n Program Guide not available\n
\n
\n
\n\n
\n \n \n \n \n \n
\n
\n","snippet--loadMore":" Show more \n"}}
\ No newline at end of file
diff --git a/sites/cablego.com.pe/cablego.com.pe.config.js b/sites/cablego.com.pe/cablego.com.pe.config.js
new file mode 100644
index 00000000..3a270ef5
--- /dev/null
+++ b/sites/cablego.com.pe/cablego.com.pe.config.js
@@ -0,0 +1,108 @@
+const dayjs = require('dayjs')
+const axios = require('axios')
+const cheerio = require('cheerio')
+const utc = require('dayjs/plugin/utc')
+const timezone = require('dayjs/plugin/timezone')
+const customParseFormat = require('dayjs/plugin/customParseFormat')
+
+dayjs.extend(utc)
+dayjs.extend(timezone)
+dayjs.extend(customParseFormat)
+
+module.exports = {
+ site: 'cablego.com.pe',
+ request: {
+ method: 'POST',
+ headers: {
+ 'x-requested-with': 'XMLHttpRequest'
+ },
+ cache: {
+ ttl: 60 * 60 * 1000 // 1 hour
+ }
+ },
+ url({ channel, date }) {
+ const [page] = channel.site_id.split('#')
+
+ return `https://cablego.com.pe/epg/default/${date.format(
+ 'YYYY-MM-DD'
+ )}?page=${page}&do=loadPage`
+ },
+ parser: function ({ content, channel, date }) {
+ let programs = []
+ const items = parseItems(content, channel)
+ items.forEach(item => {
+ const $item = cheerio.load(item)
+ const prev = programs[programs.length - 1]
+ let start = parseStart($item, date)
+ if (!start) return
+ if (prev) {
+ if (start.isBefore(prev.start)) {
+ start = start.add(1, 'd')
+ date = date.add(1, 'd')
+ }
+ prev.stop = start
+ }
+ const stop = start.add(30, 'm')
+ programs.push({
+ title: parseTitle($item),
+ start,
+ stop
+ })
+ })
+
+ return programs
+ },
+ async channels() {
+ const promises = [0, 1, 2, 3, 4].map(page => {
+ return axios.post(
+ `https://cablego.com.pe/epg/default/2022-11-28?page=${page}&do=loadPage`,
+ null,
+ {
+ headers: {
+ 'x-requested-with': 'XMLHttpRequest'
+ }
+ }
+ )
+ })
+
+ const channels = []
+ await Promise.allSettled(promises).then(results => {
+ results.forEach((r, page) => {
+ if (r.status === 'fulfilled') {
+ const html = r.value.data.snippets['snippet--channelGrid']
+ const $ = cheerio.load(html)
+ $('.epg-channel-strip').each((i, el) => {
+ const channelId = $(el).find('.epg-channel-logo').attr('id')
+ channels.push({
+ lang: 'es',
+ site_id: `${page}#${channelId}`,
+ name: $(el).find('img').attr('alt')
+ })
+ })
+ }
+ })
+ })
+
+ return channels
+ }
+}
+
+function parseTitle($item) {
+ return $item('span:nth-child(2) > a').text().trim()
+}
+
+function parseStart($item, date) {
+ const time = $item('.epg-show-start').text().trim()
+
+ return dayjs.tz(`${date.format('YYYY-MM-DD')} ${time}`, 'YYYY-MM-DD HH:mm', 'America/Lima')
+}
+
+function parseItems(content, channel) {
+ const [, channelId] = channel.site_id.split('#')
+ const data = JSON.parse(content)
+ if (!data || !data.snippets || !data.snippets['snippet--channelGrid']) return []
+ const html = data.snippets['snippet--channelGrid']
+ const $ = cheerio.load(html)
+
+ return $(`#${channelId}`).parent().find('.epg-show').toArray()
+}
diff --git a/sites/cablego.com.pe/cablego.com.pe.test.js b/sites/cablego.com.pe/cablego.com.pe.test.js
new file mode 100644
index 00000000..3fa8c367
--- /dev/null
+++ b/sites/cablego.com.pe/cablego.com.pe.test.js
@@ -0,0 +1,54 @@
+// npm run channels:parse -- --config=./sites/cablego.com.pe/cablego.com.pe.config.js --output=./sites/cablego.com.pe/cablego.com.pe_pe.channels.xml
+// npx epg-grabber --config=sites/cablego.com.pe/cablego.com.pe.config.js --channels=sites/cablego.com.pe/cablego.com.pe_pe.channels.xml --output=guide.xml --days=2
+
+const { parser, url, request } = require('./cablego.com.pe.config.js')
+const fs = require('fs')
+const path = require('path')
+const dayjs = require('dayjs')
+const utc = require('dayjs/plugin/utc')
+const customParseFormat = require('dayjs/plugin/customParseFormat')
+dayjs.extend(customParseFormat)
+dayjs.extend(utc)
+
+const date = dayjs.utc('2022-11-28', 'YYYY-MM-DD').startOf('d')
+const channel = {
+ site_id: '0#LATINA',
+ xmltv_id: 'Latina.pe'
+}
+
+it('can generate valid url', () => {
+ expect(url({ channel, date })).toBe(
+ 'https://cablego.com.pe/epg/default/2022-11-28?page=0&do=loadPage'
+ )
+})
+
+it('can generate valid request method', () => {
+ expect(request.method).toBe('POST')
+})
+
+it('can generate valid request headers', () => {
+ expect(request.headers).toMatchObject({
+ 'x-requested-with': 'XMLHttpRequest'
+ })
+})
+
+it('can parse response', () => {
+ const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
+ let results = parser({ content, channel, date }).map(p => {
+ p.start = p.start.toJSON()
+ p.stop = p.stop.toJSON()
+ return p
+ })
+
+ expect(results[0]).toMatchObject({
+ start: '2022-11-28T05:00:00.000Z',
+ stop: '2022-11-28T06:30:00.000Z',
+ title: 'Especiales Qatar'
+ })
+})
+
+it('can handle empty guide', () => {
+ const content = fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
+ const result = parser({ content, channel, date })
+ expect(result).toMatchObject([])
+})
diff --git a/sites/cablego.com.pe/cablego.com.pe_pe.channels.xml b/sites/cablego.com.pe/cablego.com.pe_pe.channels.xml
new file mode 100644
index 00000000..46622ec7
--- /dev/null
+++ b/sites/cablego.com.pe/cablego.com.pe_pe.channels.xml
@@ -0,0 +1,101 @@
+
+
+
+ AMERICA TV
+ ATV
+ ATV+
+ BHTV
+ CONECTA2 TV
+ CONGRESO TV
+ DE PELICULA
+ DISTRITO COMEDIA
+ ECUADOR TV
+ EUROPA EUROPA
+ EXITOSA TV
+ GLOBAL
+ GOLDEN EDGE
+ KARIBEÑA
+ LATINA
+ NATIVA
+ OVACION
+ PANAMERICANA TV
+ PASIONES
+ PBO
+ TV PERU
+ USMP TV
+ VENUS
+ WILLAX
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+