Initial Commit

This commit is contained in:
2023-09-10 21:48:48 +02:00
commit 227cca7d31
791 changed files with 165200 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="9tv.co.il">
<channels>
<channel lang="ru" xmltv_id="Channel9.il" site_id="#">9 канал</channel>
</channels>
</site>

View File

@@ -0,0 +1,69 @@
const cheerio = require('cheerio')
const dayjs = require('dayjs')
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: '9tv.co.il',
days: 2,
url: function ({ date }) {
return `https://www.9tv.co.il/BroadcastSchedule/getBrodcastSchedule?date=${date.format(
'DD/MM/YYYY 00:00:00'
)}`
},
parser: function ({ content, date }) {
const programs = []
const items = parseItems(content)
items.forEach(item => {
const prev = programs[programs.length - 1]
const $item = cheerio.load(item)
const start = parseStart($item, date)
if (prev) prev.stop = start
const stop = start.add(1, 'h')
programs.push({
title: parseTitle($item),
icon: parseIcon($item),
description: parseDescription($item),
start,
stop
})
})
return programs
}
}
function parseStart($item, date) {
let time = $item('a > div.guide_list_time').text().trim()
return dayjs.tz(`${date.format('YYYY-MM-DD')} ${time}`, 'YYYY-MM-DD HH:mm', 'Asia/Jerusalem')
}
function parseIcon($item) {
const backgroundImage = $item('a > div.guide_info_group > div.guide_info_pict').css(
'background-image'
)
if (!backgroundImage) return null
const [_, relativePath] = backgroundImage.match(/url\((.*)\)/) || [null, null]
return relativePath ? `https://www.9tv.co.il${relativePath}` : null
}
function parseDescription($item) {
return $item('a > div.guide_info_group > div.guide_txt_group > div').text().trim()
}
function parseTitle($item) {
return $item('a > div.guide_info_group > div.guide_txt_group > h3').text().trim()
}
function parseItems(content) {
const $ = cheerio.load(content)
return $('li').toArray()
}

View File

@@ -0,0 +1,56 @@
// npx epg-grabber --config=sites/9tv.co.il/9tv.co.il.config.js --channels=sites/9tv.co.il/9tv.co.il.channels.xml --output=guide.xml --days=2
const { parser, url } = require('./9tv.co.il.config.js')
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-03-06', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: '#',
xmltv_id: 'Channel9.il'
}
it('can generate valid url', () => {
expect(url({ date })).toBe(
'https://www.9tv.co.il/BroadcastSchedule/getBrodcastSchedule?date=06/03/2022 00:00:00'
)
})
it('can parse response', () => {
const content = `<li> <a href="#" class="guide_list_link w-inline-block"> <div class="guide_list_time">06:30</div><div class="guide_info_group"> <div class="guide_info_pict" style="background-image: url(/download/pictures/img_id=8484.jpg);"></div><div class="guide_txt_group"> <h3 class="guide_info_title">Слепая</h3> <div>Она не очень любит говорить о себе или о том, кто и зачем к ней обращается. Живет уединенно, в глуши. Но тех, кто приходит -принимает. Она видит судьбы.&#160;</div></div></div></a></li><li> <a href="#" class="guide_list_link even w-inline-block"> <div class="guide_list_time">09:10</div><div class="guide_info_group"> <div class="guide_info_pict" style="background-image: url(/download/pictures/img_id=23694.jpg);"></div><div class="guide_txt_group"> <h3 class="guide_info_title">Орел и решка. Морской сезон</h3> <div>Орел и решка. Морской сезон. Ведущие -Алина Астровская и Коля Серга.</div></div></div></a></li>`
const result = parser({ content, date }).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2022-03-06T04:30:00.000Z',
stop: '2022-03-06T07:10:00.000Z',
title: `Слепая`,
icon: 'https://www.9tv.co.il/download/pictures/img_id=8484.jpg',
description:
'Она не очень любит говорить о себе или о том, кто и зачем к ней обращается. Живет уединенно, в глуши. Но тех, кто приходит -принимает. Она видит судьбы.'
},
{
start: '2022-03-06T07:10:00.000Z',
stop: '2022-03-06T08:10:00.000Z',
icon: 'https://www.9tv.co.il/download/pictures/img_id=23694.jpg',
title: `Орел и решка. Морской сезон`,
description: 'Орел и решка. Морской сезон. Ведущие -Алина Астровская и Коля Серга.'
}
])
})
it('can handle empty guide', () => {
const result = parser({
date,
channel,
content: `<!DOCTYPE html><html><head></head><body></body></html>`
})
expect(result).toMatchObject([])
})

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="abc.net.au">
<channels>
<channel lang="en" xmltv_id="10Bold.au" site_id="ONE">10 Bold</channel>
<channel lang="en" xmltv_id="10Peach.au" site_id="11">10 Peach</channel>
<channel lang="en" xmltv_id="10Shake.au" site_id="SHAKE">10 Shake</channel>
<channel lang="en" xmltv_id="7flix.au" site_id="7flix">7flix</channel>
<channel lang="en" xmltv_id="7mate.au" site_id="7MATE">7mate</channel>
<channel lang="en" xmltv_id="7two.au" site_id="7TWO">7two</channel>
<channel lang="en" xmltv_id="9Gem.au" site_id="GEM">9 Gem</channel>
<channel lang="en" xmltv_id="9Go.au" site_id="GO">9 Go!</channel>
<channel lang="en" xmltv_id="9Life.au" site_id="9Life">9 Life</channel>
<channel lang="en" xmltv_id="9Rush.au" site_id="9Rush">9 Rush</channel>
<channel lang="en" xmltv_id="ABCKids.au" site_id="ABC4KIDS">ABC Kids</channel>
<channel lang="en" xmltv_id="ABCMe.au" site_id="ABC3">ABC ME</channel>
<channel lang="en" xmltv_id="ABCNewsAustralia.au" site_id="ABCN">ABC News</channel>
<channel lang="en" xmltv_id="ABCTV.au" site_id="ABC1">ABC TV</channel>
<channel lang="en" xmltv_id="ABCTVPlus.au" site_id="ABC2">ABC TV Plus</channel>
<channel lang="en" xmltv_id="Channel10.au" site_id="10">Channel 10</channel>
<channel lang="en" xmltv_id="Channel7.au" site_id="7">Channel 7</channel>
<channel lang="en" xmltv_id="Channel9.au" site_id="9">Channel 9</channel>
<channel lang="en" xmltv_id="NITV.au" site_id="NITV">NITV</channel>
<channel lang="en" xmltv_id="Racingcom.au" site_id="RTV">Racing.com</channel>
<channel lang="en" xmltv_id="SBS.au" site_id="SBS">SBS One</channel>
<channel lang="en" xmltv_id="SBSFood.au" site_id="SBS3">SBS Food</channel>
<channel lang="en" xmltv_id="SBSViceland.au" site_id="VICHD">SBS Viceland</channel>
<channel lang="en" xmltv_id="SBSWorldMovies.au" site_id="SBS2">SBS World Movies</channel>
<channel lang="en" xmltv_id="SBSWorldWatch.au" site_id="SBSWW">SBS World Watch</channel>
<channel lang="en" xmltv_id="SpreeTV.au" site_id="SPREE">Spree TV</channel>
<channel lang="en" xmltv_id="TVSN.au" site_id="TVSN">TSVN</channel>
<!-- <channel lang="en" xmltv_id="ABCTV.au" site_id="ABCHD">ABC TV HD</channel> -->
<!-- <channel lang="en" xmltv_id="Channel10.au" site_id="TENHD">Channel 10 HD</channel> -->
<!-- <channel lang="en" xmltv_id="Channel7.au" site_id="7HD">Channel 7 HD</channel> -->
<!-- <channel lang="en" xmltv_id="Channel9.au" site_id="9HD">Channel 9 HD</channel> -->
<!-- <channel lang="en" xmltv_id="SBS.au" site_id="SBSHD">SBS HD</channel> -->
</channels>
</site>

View File

@@ -0,0 +1,77 @@
const dayjs = require('dayjs')
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: 'abc.net.au',
days: 3,
request: {
cache: {
ttl: 60 * 60 * 1000 // 1 hour
}
},
url({ date }) {
return `https://epg.abctv.net.au/processed/Sydney_${date.format('YYYY-MM-DD')}.json`
},
parser({ content, channel }) {
let programs = []
const items = parseItems(content, channel)
items.forEach(item => {
programs.push({
title: item.title,
sub_title: item.episode_title,
category: item.genres,
description: item.description,
season: parseSeason(item),
episode: parseEpisode(item),
rating: parseRating(item),
icon: parseIcon(item),
start: parseTime(item.start_time),
stop: parseTime(item.end_time)
})
})
return programs
}
}
function parseItems(content, channel) {
try {
const data = JSON.parse(content)
if (!data) return []
if (!Array.isArray(data.schedule)) return []
const channelData = data.schedule.find(i => i.channel == channel.site_id)
return channelData.listing && Array.isArray(channelData.listing) ? channelData.listing : []
} catch (err) {
return []
}
}
function parseSeason(item) {
return item.series_num || null
}
function parseEpisode(item) {
return item.episode_num || null
}
function parseTime(time) {
return dayjs.tz(time, 'YYYY-MM-DD HH:mm', 'Australia/Sydney')
}
function parseIcon(item) {
return item.image_file
? `https://www.abc.net.au/tv/common/images/publicity/${item.image_file}`
: null
}
function parseRating(item) {
return item.rating
? {
system: 'ACB',
value: item.rating
}
: null
}

View File

@@ -0,0 +1,53 @@
// npx epg-grabber --config=sites/abc.net.au/abc.net.au.config.js --channels=sites/abc.net.au/abc.net.au.channels.xml --output=guide.xml --days=2
const { parser, url } = require('./abc.net.au.config.js')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
dayjs.extend(utc)
const date = dayjs.utc('2022-12-22', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: 'ABC1',
xmltv_id: 'ABCTV.au'
}
it('can generate valid url', () => {
expect(url({ date })).toBe('https://epg.abctv.net.au/processed/Sydney_2022-12-22.json')
})
it('can parse response', () => {
const content = `{"date":"2022-12-22","region":"Sydney","schedule":[{"channel":"ABC1","listing":[{"consumer_advice":"Adult Themes, Drug Use, Violence","rating":"M","show_id":912747,"repeat":true,"description":"When tragedy strikes close to home, it puts head teacher Noah Taylor on a collision course with the criminals responsible. Can the Lyell team help him stop the cycle of violence?","title":"Silent Witness","crid":"ZW2178A004S00","start_time":"2022-12-22T00:46:00","series-crid":"ZW2178A","live":false,"captioning":true,"show_type":"Episode","series_num":22,"episode_title":"Lift Up Your Hearts (part Two)","length":58,"onair_title":"Silent Witness","end_time":"2022-12-22T01:44:00","genres":["Entertainment"],"image_file":"ZW2178A004S00_460.jpg","prog_slug":"silent-witness","episode_num":4}]}]}`
const result = parser({ content, channel }).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
title: 'Silent Witness',
sub_title: 'Lift Up Your Hearts (part Two)',
description: `When tragedy strikes close to home, it puts head teacher Noah Taylor on a collision course with the criminals responsible. Can the Lyell team help him stop the cycle of violence?`,
category: ['Entertainment'],
rating: {
system: 'ACB',
value: 'M'
},
season: 22,
episode: 4,
icon: 'https://www.abc.net.au/tv/common/images/publicity/ZW2178A004S00_460.jpg',
start: '2022-12-21T13:46:00.000Z',
stop: '2022-12-21T14:44:00.000Z'
}
])
})
it('can handle empty guide', () => {
const result = parser(
{
content: `<Error><Code>NoSuchKey</Code><Message>The specified key does not exist.</Message><Key>processed/Sydney_2023-01-17.json</Key><RequestId>6MRHX5TJ12X39B3Y</RequestId><HostId>59rH6XRMrmkFywg8Kv58iqpI6O1fuOCuEbKa1HRRYa4buByXMBTvAhz8zuAK7X5D+ZN9ZuWxyGs=</HostId></Error>`
},
channel
)
expect(result).toMatchObject([])
})

View File

@@ -0,0 +1,63 @@
const axios = require('axios')
const dayjs = require('dayjs')
module.exports = {
site: 'allente.se',
days: 2,
url({ date, channel }) {
const [country] = channel.site_id.split('#')
return `https://cs-vcb.allente.${country}/epg/events?date=${date.format('YYYY-MM-DD')}`
},
parser({ content, channel }) {
let programs = []
const items = parseItems(content, channel)
items.forEach(item => {
if (!item.details) return
const start = dayjs(item.time)
const stop = start.add(item.details.duration, 'm')
programs.push({
title: item.title,
category: item.details.categories,
description: item.details.description,
icon: item.details.image,
season: parseSeason(item),
episode: parseEpisode(item),
start,
stop
})
})
return programs
},
async channels({ country, lang }) {
const data = await axios
.get(`https://cs-vcb.allente.${country}/epg/events?date=2021-11-17`)
.then(r => r.data)
.catch(console.log)
return data.channels.map(item => {
return {
lang,
site_id: `${country}#${item.id}`,
name: item.name
}
})
}
}
function parseItems(content, channel) {
const [_, channelId] = channel.site_id.split('#')
const data = JSON.parse(content)
if (!data || !Array.isArray(data.channels)) return []
const channelData = data.channels.find(i => i.id === channelId)
return channelData && Array.isArray(channelData.events) ? channelData.events : []
}
function parseSeason(item) {
return item.details.season || null
}
function parseEpisode(item) {
return item.details.episode || null
}

View File

@@ -0,0 +1,60 @@
// node ./scripts/channels.js --config=./sites/allente.se/allente.se.config.js --output=./sites/allente.se/allente.se_se.channels.xml --set=country:se --set=lang:sv
// node ./scripts/channels.js --config=./sites/allente.se/allente.se.config.js --output=./sites/allente.se/allente.se_fi.channels.xml --set=country:fi --set=lang:fi
// node ./scripts/channels.js --config=./sites/allente.se/allente.se.config.js --output=./sites/allente.se/allente.se_no.channels.xml --set=country:no --set=lang:no
// node ./scripts/channels.js --config=./sites/allente.se/allente.se.config.js --output=./sites/allente.se/allente.se_dk.channels.xml --set=country:dk --set=lang:da
// npx epg-grabber --config=sites/allente.se/allente.se.config.js --channels=sites/allente.se/allente.se_se.channels.xml --output=guide.xml --days=2
const { parser, url } = require('./allente.se.config.js')
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('2021-11-17', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: 'se#0148',
xmltv_id: 'SVT1.se'
}
it('can generate valid url', () => {
expect(url({ date, channel })).toBe('https://cs-vcb.allente.se/epg/events?date=2021-11-17')
})
it('can generate valid url for different country', () => {
const dkChannel = { site_id: 'dk#0148' }
expect(url({ date, channel: dkChannel })).toBe(
'https://cs-vcb.allente.dk/epg/events?date=2021-11-17'
)
})
it('can parse response', () => {
const content = `{"channels":[{"id":"0148","icon":"//images.ctfassets.net/989y85n5kcxs/5uT9g9pdQWRZeDPQXVI9g6/9cc44da567f591822ed645c99ecdcb64/SVT_1_black_new__2_.png","name":"SVT1 HD (T)","events":[{"id":"0086202208220710","live":false,"time":"2022-08-22T07:10:00Z","title":"Hemmagympa med Sofia","details":{"title":"Hemmagympa med Sofia","image":"https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440","description":"Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.","season":4,"episode":1,"categories":["other"],"duration":"20"}}]}]}`
const result = parser({ content, channel }).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2022-08-22T07:10:00.000Z',
stop: '2022-08-22T07:30:00.000Z',
title: `Hemmagympa med Sofia`,
category: ['other'],
description: `Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.`,
icon: 'https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440',
season: 4,
episode: 1
}
])
})
it('can handle empty guide', () => {
const result = parser({
date,
channel,
content: `{"date":"2001-11-17","categories":[],"channels":[]}`
})
expect(result).toMatchObject([])
})

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="allente.se">
<channels>
<channel lang="da" xmltv_id="6eren.dk" site_id="dk#568">6&apos;eren</channel>
<channel lang="da" xmltv_id="BoomerangNordic.uk" site_id="dk#0017">Boomerang Nordic</channel>
<channel lang="da" xmltv_id="Canal9.dk" site_id="dk#0368">Canal 9</channel>
<channel lang="da" xmltv_id="CartoonNetworkScandinavia.uk" site_id="dk#0028">Cartoon Network Nordic</channel>
<channel lang="da" xmltv_id="CMoreFirst.se" site_id="dk#968">C More First</channel>
<channel lang="da" xmltv_id="CMoreHits.se" site_id="dk#969">C More Hits</channel>
<channel lang="da" xmltv_id="CMoreSeries.se" site_id="dk#971">C More Series</channel>
<channel lang="da" xmltv_id="CMoreStars.se" site_id="dk#970">C More Stars</channel>
<channel lang="da" xmltv_id="DisneyChannelScandinavia.uk" site_id="dk#0037">Disney Channel Scandinavia</channel>
<channel lang="da" xmltv_id="DisneyJuniorScandinavia.uk" site_id="dk#0307">Disney Junior Scandinavia</channel>
<channel lang="da" xmltv_id="dk4.dk" site_id="dk#0376">DK 4</channel>
<channel lang="da" xmltv_id="DR1.dk" site_id="dk#452">DR 1</channel>
<channel lang="da" xmltv_id="DR2.dk" site_id="dk#0051">DR 2</channel>
<channel lang="da" xmltv_id="DRRamasjang.dk" site_id="dk#0048">DR Ramasjang</channel>
<channel lang="da" xmltv_id="EEurope.us" site_id="dk#0052">E! Europe</channel>
<channel lang="da" xmltv_id="EuronewsEnglish.fr" site_id="dk#0281">EuroNews English</channel>
<channel lang="da" xmltv_id="Eurosport2Danmark.dk" site_id="dk#0367">Eurosport 2 Danmark</channel>
<channel lang="da" xmltv_id="GodTV.uk" site_id="dk#0058">God TV Scandinavia</channel>
<channel lang="da" xmltv_id="Kanal4.dk" site_id="dk#0064">Kanal 4</channel>
<channel lang="da" xmltv_id="Kanal5.dk" site_id="dk#0065">Kanal 5</channel>
<channel lang="da" xmltv_id="MTV00s.uk" site_id="dk#0246">MTV 00s</channel>
<channel lang="da" xmltv_id="MTV80s.uk" site_id="dk#604">MTV 80s</channel>
<channel lang="da" xmltv_id="MTVGlobal.uk" site_id="dk#0076">MTV Nordic</channel>
<channel lang="da" xmltv_id="MTVHitsEurope.uk" site_id="dk#0077">MTV Hits Europe</channel>
<channel lang="da" xmltv_id="NationalGeographicDenmark.dk" site_id="dk#0317">National Geographic Danmark</channel>
<channel lang="da" xmltv_id="NationalGeographicWildDenmark.dk" site_id="dk#0082">National Geographic Wild Europe</channel>
<channel lang="da" xmltv_id="NickelodeonDenmark.dk" site_id="dk#0087">Nickelodeon Danmark</channel>
<channel lang="da" xmltv_id="NickJrScandinavia.nl" site_id="dk#0088">Nick Jr Scandinavia</channel>
<channel lang="da" xmltv_id="NicktoonsScandinavia.nl" site_id="dk#570">Nicktoons Scandinavia</channel>
<channel lang="da" xmltv_id="NRK1.no" site_id="dk#0090">NRK1</channel>
<channel lang="da" xmltv_id="ParamountNetworkDenmark.dk" site_id="dk#450">Paramount Network Danmark</channel>
<channel lang="da" xmltv_id="SFkanalen.se" site_id="dk#972">SF-kanalen</channel>
<channel lang="da" xmltv_id="SkyNewsInternational.uk" site_id="dk#0008">Sky News International</channel>
<channel lang="da" xmltv_id="SVT1.se" site_id="dk#0121">SVT 1</channel>
<channel lang="da" xmltv_id="TV2.dk" site_id="dk#0297">TV 2</channel>
<channel lang="da" xmltv_id="TV2Charlie.dk" site_id="dk#0180">TV 2 Charlie</channel>
<channel lang="da" xmltv_id="TV2Fri.dk" site_id="dk#0378">TV 2 Fri</channel>
<channel lang="da" xmltv_id="TV2News.dk" site_id="dk#0190">TV 2 News</channel>
<channel lang="da" xmltv_id="TV2Sport.dk" site_id="dk#454">TV 2 Sport</channel>
<channel lang="da" xmltv_id="TV2Zulu.dk" site_id="dk#0209">TV 2 Zulu</channel>
<channel lang="da" xmltv_id="TV3Danmark.dk" site_id="dk#0359">TV 3 Danmark</channel>
<channel lang="da" xmltv_id="TV3Max.dk" site_id="dk#0374">TV 3 Max</channel>
<channel lang="da" xmltv_id="TV3Plus.dk" site_id="dk#0248">TV3+</channel>
<channel lang="da" xmltv_id="TV3Puls.dk" site_id="dk#665">TV 3 Puls</channel>
<channel lang="da" xmltv_id="TV3SportDenmark.dk" site_id="dk#0200">TV 3 Sport</channel>
<channel lang="da" xmltv_id="TV4.se" site_id="dk#0227">TV 4</channel>
<channel lang="da" xmltv_id="VFilmAction.se" site_id="dk#0299">V Film Action</channel>
<channel lang="da" xmltv_id="VFilmFamily.se" site_id="dk#0308">V Film Family</channel>
<channel lang="da" xmltv_id="VFilmHits.se" site_id="dk#0322">V Film Hits</channel>
<channel lang="da" xmltv_id="VFilmPremiere.se" site_id="dk#0321">V Film Premiere</channel>
<channel lang="da" xmltv_id="ViasatExplore.se" site_id="dk#0358">Viasat Explore</channel>
<channel lang="da" xmltv_id="ViasatHistory.se" site_id="dk#0357">Viasat History HD</channel>
<channel lang="da" xmltv_id="ViasatNature.se" site_id="dk#0250">Viasat Nature</channel>
<channel lang="da" xmltv_id="VSeries.se" site_id="dk#0320">V Series</channel>
<channel lang="da" xmltv_id="VSportGolf.se" site_id="dk#0364">V Sport Golf</channel>
<channel lang="da" xmltv_id="VSportUltraHD.se" site_id="dk#418">V Sport Ultra HD</channel>
<channel lang="da" xmltv_id="Xee.dk" site_id="dk#707">Xee</channel>
<channel lang="en" xmltv_id="AlJazeeraEnglish.qa" site_id="dk#0344">Aljazeera English</channel>
<channel lang="en" xmltv_id="BBCWorldNewsEurope.uk" site_id="dk#0016">BBC World News Europe</channel>
<channel lang="en" xmltv_id="CNBCEurope.uk" site_id="dk#0032">CNBC Europe</channel>
<channel lang="en" xmltv_id="CNNInternationalEurope.us" site_id="dk#0033">CNN International Europe</channel>
</channels>
</site>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="allente.se">
<channels>
<channel lang="fi" xmltv_id="BoomerangNordic.uk" site_id="fi#0017">Boomerang</channel>
<channel lang="fi" xmltv_id="CartoonNetworkScandinavia.uk" site_id="fi#0028">Cartoon Network</channel>
<channel lang="fi" xmltv_id="CNBCEurope.uk" site_id="fi#0032">CNBC</channel>
<channel lang="fi" xmltv_id="CNNInternationalEurope.us" site_id="fi#0033">CNN</channel>
<channel lang="fi" xmltv_id="DisneyChannelScandinavia.uk" site_id="fi#0037">Disney Channel</channel>
<channel lang="fi" xmltv_id="DisneyJuniorScandinavia.uk" site_id="fi#0307">Disney Junior</channel>
<channel lang="fi" xmltv_id="EEurope.us" site_id="fi#0052">E!</channel>
<channel lang="fi" xmltv_id="MTV00s.uk" site_id="fi#0246">MTV 00s</channel>
<channel lang="fi" xmltv_id="MTVGlobal.uk" site_id="fi#0080">MTV</channel>
<channel lang="fi" xmltv_id="NationalGeographicFinland.fi" site_id="fi#0084">National Geographic</channel>
<channel lang="fi" xmltv_id="NationalGeographicWildFinland.fi" site_id="fi#558">National Geographic Wild</channel>
<channel lang="fi" xmltv_id="NickJrScandinavia.nl" site_id="fi#0088">Nick Jr</channel>
<channel lang="fi" xmltv_id="TV3.se" site_id="fi#0290">TV 3 Sverige</channel>
<channel lang="fi" xmltv_id="TV6Sweden.se" site_id="fi#0360">TV 6 Sverige</channel>
<channel lang="fi" xmltv_id="VFilmAction.se" site_id="fi#0299">V Film Action</channel>
<channel lang="fi" xmltv_id="VFilmFamily.se" site_id="fi#0308">V Film Family</channel>
<channel lang="fi" xmltv_id="VFilmHits.se" site_id="fi#0322">V Film Hits</channel>
<channel lang="fi" xmltv_id="VFilmPremiere.se" site_id="fi#0321">V Film Premiere</channel>
<channel lang="fi" xmltv_id="ViasatExplore.se" site_id="fi#0252">Viasat Explore</channel>
<channel lang="fi" xmltv_id="ViasatHistory.se" site_id="fi#0263">Viasat History HD</channel>
<channel lang="fi" xmltv_id="ViasatNature.se" site_id="fi#0250">Viasat Nature</channel>
<channel lang="fi" xmltv_id="VSport1Finland.fi" site_id="fi#0159">V Sport 1 Suomi</channel>
<channel lang="fi" xmltv_id="VSport1Sweden.se" site_id="fi#0362">V Sport 1 Sverige</channel>
<channel lang="fi" xmltv_id="VSport2Finland.fi" site_id="fi#488">V Sport 2 Suomi</channel>
<channel lang="fi" xmltv_id="VSportFootball.se" site_id="fi#0269">V Sport Football</channel>
<channel lang="fi" xmltv_id="VSportGolf.se" site_id="fi#0364">V Sport Golf</channel>
<channel lang="fi" xmltv_id="VSportLive1.se" site_id="fi#0255">V Sport Live 1</channel>
<channel lang="fi" xmltv_id="VSportLive2.se" site_id="fi#0256">V Sport Live 2</channel>
<channel lang="fi" xmltv_id="VSportLive3.se" site_id="fi#0257">V Sport Live 3</channel>
<channel lang="fi" xmltv_id="VSportLive4.se" site_id="fi#0258">V Sport Live 4</channel>
<channel lang="fi" xmltv_id="VSportLive5.se" site_id="fi#0259">V Sport Live 5</channel>
<channel lang="fi" xmltv_id="VSportPlusFinland.fi" site_id="fi#0369">V Sport + Suomi</channel>
<channel lang="fi" xmltv_id="VSportPremium.se" site_id="fi#527">V Sport Premium</channel>
<channel lang="fi" xmltv_id="VSportUltraHD.se" site_id="fi#418">V Sport Ultra HD</channel>
<channel lang="fi" xmltv_id="VSportVinter.se" site_id="fi#0363">V Sport Vinter</channel>
</channels>
</site>

View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="allente.se">
<channels>
<channel lang="no" xmltv_id="AlJazeeraEnglish.qa" site_id="no#0344">Aljazeera</channel>
<channel lang="no" xmltv_id="BBCWorldNewsEurope.uk" site_id="no#0016">BBC World News</channel>
<channel lang="no" xmltv_id="CartoonNetworkScandinavia.uk" site_id="no#0028">Cartoon Network</channel>
<channel lang="no" xmltv_id="CNBCEurope.uk" site_id="no#0032">CNBC</channel>
<channel lang="no" xmltv_id="CNNInternationalEurope.us" site_id="no#0033">CNN</channel>
<channel lang="no" xmltv_id="DiscoveryChannelNorway.no" site_id="no#532">Discovery Channel</channel>
<channel lang="no" xmltv_id="DisneyChannelScandinavia.uk" site_id="no#0037">Disney Channel</channel>
<channel lang="no" xmltv_id="DisneyJuniorScandinavia.uk" site_id="no#0307">Disney Junior</channel>
<channel lang="no" xmltv_id="DR2.dk" site_id="no#0051">DR 2</channel>
<channel lang="no" xmltv_id="EEurope.us" site_id="no#0052">E!</channel>
<channel lang="no" xmltv_id="EuronewsEnglish.fr" site_id="no#0281">EuroNews</channel>
<channel lang="no" xmltv_id="Eurosport1Norway.no" site_id="no#531">Eurosport 1</channel>
<channel lang="no" xmltv_id="EurosportNorway.no" site_id="no#530">Eurosport</channel>
<channel lang="no" xmltv_id="FEM.no" site_id="no#0056">FEM</channel>
<channel lang="no" xmltv_id="Kunskapskanalen.se" site_id="no#0149">Kunskapskanalen</channel>
<channel lang="no" xmltv_id="Matkanalen.no" site_id="no#565">Matkanalen</channel>
<channel lang="no" xmltv_id="MAX.no" site_id="no#533">Max</channel>
<channel lang="no" xmltv_id="MTV00s.uk" site_id="no#0246">MTV 00s</channel>
<channel lang="no" xmltv_id="MTV80s.uk" site_id="no#604">MTV 80s</channel>
<channel lang="no" xmltv_id="MTVHitsEurope.uk" site_id="no#0077">MTV Hits</channel>
<channel lang="no" xmltv_id="MTVGlobal.uk" site_id="no#0080">MTV Nordic</channel>
<channel lang="no" xmltv_id="NationalGeographicNorway.no" site_id="no#0316">National Geographic</channel>
<channel lang="no" xmltv_id="NationalGeographicWildNorway.no" site_id="no#558">National Geographic Wild</channel>
<channel lang="no" xmltv_id="NFLNetwork.us" site_id="no#556">NFL Network</channel>
<channel lang="no" xmltv_id="NickelodeonNorway.no" site_id="no#0087">Nickelodeon</channel>
<channel lang="no" xmltv_id="NickJrScandinavia.nl" site_id="no#0088">Nick Jr</channel>
<channel lang="no" xmltv_id="NicktoonsScandinavia.nl" site_id="no#570">Nicktoons</channel>
<channel lang="no" xmltv_id="NRK1.no" site_id="no#0090">NRK1</channel>
<channel lang="no" xmltv_id="NRK2.no" site_id="no#0288">NRK2</channel>
<channel lang="no" xmltv_id="NRK3.no" site_id="no#0289">NRK3</channel>
<channel lang="no" xmltv_id="SkyNewsInternational.uk" site_id="no#0008">Sky News International</channel>
<channel lang="no" xmltv_id="SVT1.se" site_id="no#0121">SVT 1</channel>
<channel lang="no" xmltv_id="SVT2.se" site_id="no#0141">SVT 2</channel>
<channel lang="no" xmltv_id="SVT24.se" site_id="no#598">SVT 24</channel>
<channel lang="no" xmltv_id="SVTBarn.se" site_id="no#0147">SVT Barn</channel>
<channel lang="no" xmltv_id="TV2.dk" site_id="no#0188">TV 2</channel>
<channel lang="no" xmltv_id="TV2.no" site_id="no#0187">TV 2</channel>
<channel lang="no" xmltv_id="TV2Livsstil.no" site_id="no#0277">TV 2 Livsstil</channel>
<channel lang="no" xmltv_id="TV2Nyhetskanalen.no" site_id="no#457">TV 2 Nyhetskanalen</channel>
<channel lang="no" xmltv_id="TV2Sport1.no" site_id="no#0199">TV 2 Sport 1</channel>
<channel lang="no" xmltv_id="TV2Sport2.no" site_id="no#0406">TV 2 Sport 2</channel>
<channel lang="no" xmltv_id="TV2SportPremium.no" site_id="no#0197">TV 2 Sport Premium</channel>
<channel lang="no" xmltv_id="TV2Zebra.no" site_id="no#0405">TV 2 Zebra</channel>
<channel lang="no" xmltv_id="TV3Danmark.dk" site_id="no#0359">TV 3 Danmark</channel>
<channel lang="no" xmltv_id="TV3Norway.no" site_id="no#0298">TV 3 Norge</channel>
<channel lang="no" xmltv_id="TV3.se" site_id="no#0222">TV 3 Sverige</channel>
<channel lang="no" xmltv_id="TV6Norway.no" site_id="no#0206">TV 6 Norge</channel>
<channel lang="no" xmltv_id="TV6Sweden.se" site_id="no#0360">TV 6 Sverige</channel>
<channel lang="no" xmltv_id="TVNorge.no" site_id="no#534">TV Norge</channel>
<channel lang="no" xmltv_id="V4.no" site_id="no#0361">V 4</channel>
<channel lang="no" xmltv_id="VFilmAction.se" site_id="no#0299">V Film Action</channel>
<channel lang="no" xmltv_id="VFilmFamily.se" site_id="no#0308">V Film Family</channel>
<channel lang="no" xmltv_id="VFilmHits.se" site_id="no#0322">V Film Hits</channel>
<channel lang="no" xmltv_id="VFilmPremiere.se" site_id="no#0321">V Film Premiere</channel>
<channel lang="no" xmltv_id="ViasatExplore.se" site_id="no#0358">Viasat Explore</channel>
<channel lang="no" xmltv_id="ViasatHistory.se" site_id="no#0357">Viasat History HD</channel>
<channel lang="no" xmltv_id="ViasatNature.se" site_id="no#0250">Viasat Nature</channel>
<channel lang="no" xmltv_id="VOX.no" site_id="no#535">Vox</channel>
<channel lang="no" xmltv_id="VSeries.se" site_id="no#0320">V Series</channel>
<channel lang="no" xmltv_id="VSport1Norway.no" site_id="no#0365">V Sport 1</channel>
<channel lang="no" xmltv_id="VSport2.no" site_id="no#608">V Sport 2</channel>
<channel lang="no" xmltv_id="VSport3.no" site_id="no#609">V Sport 3</channel>
<channel lang="no" xmltv_id="VSportGolf.se" site_id="no#0364">V Sport Golf</channel>
<channel lang="no" xmltv_id="VSportLive1.se" site_id="no#0255">V Sport Live 1</channel>
<channel lang="no" xmltv_id="VSportLive2.se" site_id="no#0256">V Sport Live 2</channel>
<channel lang="no" xmltv_id="VSportLive3.se" site_id="no#0257">V Sport Live 3</channel>
<channel lang="no" xmltv_id="VSportLive4.se" site_id="no#0258">V Sport Live 4</channel>
<channel lang="no" xmltv_id="VSportLive5.se" site_id="no#0259">V Sport Live 5</channel>
<channel lang="no" xmltv_id="VSportPlus.no" site_id="no#0271">V Sport +</channel>
<channel lang="no" xmltv_id="VSportUltraHD.se" site_id="no#418">V Sport Ultra HD</channel>
</channels>
</site>

View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="allente.se">
<channels>
<channel lang="sv" xmltv_id="AlJazeeraEnglish.qa" site_id="se#0344">Aljazeera</channel>
<channel lang="sv" xmltv_id="AnimalPlanetSweden.se" site_id="se#1005">Animal Planet Sverige</channel>
<channel lang="sv" xmltv_id="ATGLive.se" site_id="se#1000">ATG Live</channel>
<channel lang="sv" xmltv_id="BBCEarthNordic.uk" site_id="se#1018">BBC Earth HD</channel>
<channel lang="sv" xmltv_id="BBCBritNordic.uk" site_id="se#1016">BBC Brit HD</channel>
<channel lang="sv" xmltv_id="BBCWorldNewsEurope.uk" site_id="se#0016">BBC World News</channel>
<channel lang="sv" xmltv_id="BloombergTVEurope.uk" site_id="se#1008">Bloomberg TV</channel>
<channel lang="sv" xmltv_id="BoomerangNordic.uk" site_id="se#0017">Boomerang</channel>
<channel lang="sv" xmltv_id="CartoonNetworkScandinavia.uk" site_id="se#0028">Cartoon Network</channel>
<channel lang="sv" xmltv_id="CMoreFirst.se" site_id="se#968">C More First</channel>
<channel lang="sv" xmltv_id="CMoreFotboll.se" site_id="se#657">C More Fotboll</channel>
<channel lang="sv" xmltv_id="CMoreHits.se" site_id="se#969">C More Hits</channel>
<channel lang="sv" xmltv_id="CMoreHockey.se" site_id="se#656">C More Hockey</channel>
<channel lang="sv" xmltv_id="CMoreLive.se" site_id="se#659">C More Live</channel>
<channel lang="sv" xmltv_id="CMoreLive2.se" site_id="se#660">C More Live 2</channel>
<channel lang="sv" xmltv_id="CMoreLive3.se" site_id="se#661">C More Live 3</channel>
<channel lang="sv" xmltv_id="CMoreLive4.se" site_id="se#662">C More Live 4</channel>
<channel lang="sv" xmltv_id="CMoreLive5.se" site_id="se#663">C More Live 5</channel>
<channel lang="sv" xmltv_id="CMoreMix.se" site_id="se#658">C More Mix</channel>
<channel lang="sv" xmltv_id="CMoreSeries.se" site_id="se#971">C More Series</channel>
<channel lang="sv" xmltv_id="CMoreStars.se" site_id="se#970">C More Stars</channel>
<channel lang="sv" xmltv_id="CNBCEurope.uk" site_id="se#0032">CNBC</channel>
<channel lang="sv" xmltv_id="CNNInternationalEurope.us" site_id="se#0033">CNN</channel>
<channel lang="sv" xmltv_id="DiscoveryChannelSweden.se" site_id="se#493">Discovery Channel Sverige</channel>
<channel lang="sv" xmltv_id="DiscoveryScienceSweden.se" site_id="se#1006">Discovery Science Sverige</channel>
<channel lang="sv" xmltv_id="DisneyChannelScandinavia.uk" site_id="se#0037">Disney Channel</channel>
<channel lang="sv" xmltv_id="DisneyJuniorScandinavia.uk" site_id="se#0307">Disney Junior</channel>
<channel lang="sv" xmltv_id="DiscoveryPlusExtra1.se" site_id="se#637">Discovery+ Extra 1</channel>
<channel lang="sv" xmltv_id="DiscoveryPlusExtra2.se" site_id="se#638">Discovery+ Extra 2</channel>
<channel lang="sv" xmltv_id="DiscoveryPlusExtra3.se" site_id="se#639">Discovery+ Extra 3</channel>
<channel lang="sv" xmltv_id="DiscoveryPlusExtra4.se" site_id="se#640">Discovery+ Extra 4</channel>
<channel lang="sv" xmltv_id="DiscoveryPlusExtra5.se" site_id="se#641">Discovery+ Extra 5</channel>
<channel lang="sv" xmltv_id="DiscoveryPlusExtra6.se" site_id="se#642">Discovery+ Extra 6</channel>
<channel lang="sv" xmltv_id="DiscoveryPlusExtra7.se" site_id="se#643">Discovery+ Extra 7</channel>
<channel lang="sv" xmltv_id="DiscoveryPlusExtra8.se" site_id="se#644">Discovery+ Extra 8</channel>
<channel lang="sv" xmltv_id="DR1.dk" site_id="se#452">DR 1</channel>
<channel lang="sv" xmltv_id="DR2.dk" site_id="se#0051">DR 2</channel>
<channel lang="sv" xmltv_id="DRRamasjang.dk" site_id="se#0048">DR Ramasjang</channel>
<channel lang="sv" xmltv_id="EEurope.us" site_id="se#0052">E!</channel>
<channel lang="sv" xmltv_id="EuronewsEnglish.fr" site_id="se#0281">EuroNews</channel>
<channel lang="sv" xmltv_id="Eurosport1.fr" site_id="se#1023">Eurosport 1</channel>
<channel lang="sv" xmltv_id="Eurosport2.fr" site_id="se#1024">Eurosport 2</channel>
<channel lang="sv" xmltv_id="Godare.se" site_id="se#722">Godare</channel>
<channel lang="sv" xmltv_id="GodTV.uk" site_id="se#0058">God TV</channel>
<channel lang="sv" xmltv_id="HistorySweden.se" site_id="se#652">History</channel>
<channel lang="sv" xmltv_id="History2Nordic.us" site_id="se#1004">H2</channel>
<channel lang="sv" xmltv_id="HorseCountryTV.uk" site_id="se#668">Horse &amp; Country TV</channel>
<channel lang="sv" xmltv_id="InvestigationDiscoverySweden.se" site_id="se#1039">Investigation Discovery Sverige</channel>
<channel lang="sv" xmltv_id="Kanal5.se" site_id="se#0279">Kanal 5</channel>
<channel lang="sv" xmltv_id="Kanal9.se" site_id="se#474">Kanal 9</channel>
<channel lang="sv" xmltv_id="Kanal11.se" site_id="se#0235">Kanal 11</channel>
<channel lang="sv" xmltv_id="Kunskapskanalen.se" site_id="se#0149">Kunskapskanalen</channel>
<channel lang="sv" xmltv_id="MTV00s.uk" site_id="se#0246">MTV 00s</channel>
<channel lang="sv" xmltv_id="MTV80s.uk" site_id="se#0099">MTV 80s</channel>
<channel lang="sv" xmltv_id="MTVHitsEurope.uk" site_id="se#0077">MTV Hits</channel>
<channel lang="sv" xmltv_id="MTVGlobal.uk" site_id="se#0080">MTV Nordic</channel>
<channel lang="sv" xmltv_id="MotorvisionTV.de" site_id="se#1009">Motorvision</channel>
<channel lang="sv" xmltv_id="NationalGeographicSweden.se" site_id="se#0084">National Geographic</channel>
<channel lang="sv" xmltv_id="NationalGeographicWildSweden.se" site_id="se#0082">National Geographic Wild</channel>
<channel lang="sv" xmltv_id="NFLNetwork.us" site_id="se#569">NFL Network</channel>
<channel lang="sv" xmltv_id="NickelodeonScandinavia.nl" site_id="se#0086">Nickelodeon</channel>
<channel lang="sv" xmltv_id="NickJrScandinavia.nl" site_id="se#0088">Nick Jr</channel>
<channel lang="sv" xmltv_id="NicktoonsScandinavia.nl" site_id="se#570">Nicktoons</channel>
<channel lang="sv" xmltv_id="NRK1.no" site_id="se#0090">NRK1</channel>
<channel lang="sv" xmltv_id="NRK2.no" site_id="se#0288">NRK2</channel>
<channel lang="sv" xmltv_id="NRK3.no" site_id="se#0289">NRK3</channel>
<channel lang="sv" xmltv_id="ParamountNetworkSweden.se" site_id="se#0034">Paramount Network</channel>
<channel lang="sv" xmltv_id="ParamountPlusMovies.se" site_id="se#1001">Paramount+ Movies</channel>
<channel lang="sv" xmltv_id="ParamountPlusSeries.se" site_id="se#1002">Paramount+ Series</channel>
<channel lang="sv" xmltv_id="SFkanalen.se" site_id="se#972">SF-kanalen</channel>
<channel lang="sv" xmltv_id="Sjuan.se" site_id="se#0232">Sjuan</channel>
<channel lang="sv" xmltv_id="SkyNewsInternational.uk" site_id="se#596">Sky News International</channel>
<channel lang="sv" xmltv_id="Sportkanalen.se" site_id="se#0325">Sportkanalen</channel>
<channel lang="sv" xmltv_id="SVT1.se" site_id="se#0148">SVT 1</channel>
<channel lang="sv" xmltv_id="SVT2.se" site_id="se#0282">SVT 2</channel>
<channel lang="sv" xmltv_id="SVT24.se" site_id="se#146">SVT 24</channel>
<channel lang="sv" xmltv_id="SVTBarn.se" site_id="se#0147">SVT Barn</channel>
<channel lang="sv" xmltv_id="TLCSweden.se" site_id="se#1038">TLC Sverige</channel>
<channel lang="sv" xmltv_id="TV2.dk" site_id="se#0297">TV 2</channel>
<channel lang="sv" xmltv_id="TV3.se" site_id="se#0290">TV 3</channel>
<channel lang="sv" xmltv_id="TV4.se" site_id="se#0227">TV 4</channel>
<channel lang="sv" xmltv_id="TV4Fakta.se" site_id="se#0228">TV 4 Fakta</channel>
<channel lang="sv" xmltv_id="TV4Film.se" site_id="se#0229">TV 4 Film</channel>
<channel lang="sv" xmltv_id="TV4Guld.se" site_id="se#0230">TV 4 Guld</channel>
<channel lang="sv" xmltv_id="TV6Sweden.se" site_id="se#0360">TV 6</channel>
<channel lang="sv" xmltv_id="TV8Sweden.se" site_id="se#666">TV 8</channel>
<channel lang="sv" xmltv_id="TV10.se" site_id="se#667">TV 10</channel>
<channel lang="sv" xmltv_id="TV12.se" site_id="se#664">TV 12</channel>
<channel lang="sv" xmltv_id="VFilmAction.se" site_id="se#0299">V Film Action</channel>
<channel lang="sv" xmltv_id="VFilmFamily.se" site_id="se#0308">V Film Family</channel>
<channel lang="sv" xmltv_id="VFilmHits.se" site_id="se#0322">V Film Hits</channel>
<channel lang="sv" xmltv_id="VFilmPremiere.se" site_id="se#0321">V Film Premiere</channel>
<channel lang="sv" xmltv_id="ViasatExplore.se" site_id="se#0358">Viasat Explore</channel>
<channel lang="sv" xmltv_id="ViasatHistory.se" site_id="se#0357">Viasat History HD</channel>
<channel lang="sv" xmltv_id="ViasatNature.se" site_id="se#0356">Viasat Nature</channel>
<channel lang="sv" xmltv_id="VSeries.se" site_id="se#0320">V Series</channel>
<channel lang="sv" xmltv_id="VSport1Sweden.se" site_id="se#0362">V Sport 1</channel>
<channel lang="sv" xmltv_id="VSportExtra.se" site_id="se#715">V Sport Extra</channel>
<channel lang="sv" xmltv_id="VSportFootball.se" site_id="se#0269">V Sport Football</channel>
<channel lang="sv" xmltv_id="VSportGolf.se" site_id="se#0364">V Sport Golf</channel>
<channel lang="sv" xmltv_id="VSportLive1.se" site_id="se#0255">V Sport Live 1</channel>
<channel lang="sv" xmltv_id="VSportLive2.se" site_id="se#0256">V Sport Live 2</channel>
<channel lang="sv" xmltv_id="VSportLive3.se" site_id="se#0257">V Sport Live 3</channel>
<channel lang="sv" xmltv_id="VSportLive4.se" site_id="se#0258">V Sport Live 4</channel>
<channel lang="sv" xmltv_id="VSportLive5.se" site_id="se#0259">V Sport Live 5</channel>
<channel lang="sv" xmltv_id="VSportMotor.se" site_id="se#0292">V Sport Motor</channel>
<channel lang="sv" xmltv_id="VSportPremium.se" site_id="se#527">V Sport Premium</channel>
<channel lang="sv" xmltv_id="VSportUltraHD.se" site_id="se#418">V Sport Ultra HD</channel>
<channel lang="sv" xmltv_id="VSportVinter.se" site_id="se#0363">V Sport Vinter</channel>
</channels>
</site>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="andorradifusio.ad">
<channels>
<channel lang="ca" xmltv_id="AndorraTV.ad" site_id="atv">Andorra TV</channel>
</channels>
</site>

View File

@@ -0,0 +1,66 @@
const cheerio = require('cheerio')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const timezone = require('dayjs/plugin/timezone')
const customParseFormat = require('dayjs/plugin/customParseFormat')
require('dayjs/locale/ca')
dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.extend(customParseFormat)
module.exports = {
site: 'andorradifusio.ad',
days: 2,
url({ channel }) {
return `https://www.andorradifusio.ad/programacio/${channel.site_id}`
},
parser({ content, date }) {
const programs = []
const items = parseItems(content, date)
items.forEach(item => {
const prev = programs[programs.length - 1]
let start = parseStart(item, date)
if (prev) {
if (start.isBefore(prev.start)) {
start = start.add(1, 'd')
date = date.add(1, 'd')
}
prev.stop = start
}
const stop = start.add(1, 'h')
programs.push({
title: item.title,
start,
stop
})
})
return programs
}
}
function parseStart(item, date) {
const dateString = `${date.format('MM/DD/YYYY')} ${item.time}`
return dayjs.tz(dateString, 'MM/DD/YYYY HH:mm', 'Europe/Madrid')
}
function parseItems(content, date) {
const $ = cheerio.load(content)
const dayOfWeek = dayjs(date).locale('ca').format('dddd').toLowerCase()
const column = $('.programacio-dia > h3')
.filter((i, el) => $(el).text().startsWith(dayOfWeek))
.first()
.parent()
const items = []
const titles = column.find(`p`).toArray()
column.find(`h4`).each((i, time) => {
items.push({
time: $(time).text(),
title: $(titles[i]).text()
})
})
return items
}

View File

@@ -0,0 +1,54 @@
// npx epg-grabber --config=sites/andorradifusio.ad/andorradifusio.ad.config.js --channels=sites/andorradifusio.ad/andorradifusio.ad.channels.xml --output=guide.xml --days=2
const { parser, url } = require('./andorradifusio.ad.config.js')
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('2021-11-24', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: 'atv',
xmltv_id: 'AndorraTV.ad'
}
it('can generate valid url', () => {
expect(url({ channel })).toBe('https://www.andorradifusio.ad/programacio/atv')
})
it('can parse response', () => {
const content = `<!DOCTYPE html><html lang="ca"> <head></head> <body id="rtvabody"> <div class="container"> <div class="row"> <div class="col-sm-12"> <div class="programacio-dia"> <h3>dimecres <span class="dia">24 nov.</span></h3> <h4>07:00</h4> <p>Club Piolet</p><h4>23:30</h4> <p>Informatiu vespre</p><h4>01:00</h4> <p>&#192;rea Andorra Difusi&#243;</p></div><div class="programacio-dia"> <h3>dijous <span class="dia">25 nov.</span></h3> <h4>07:00</h4> <p>Club Piolet</p></div></div></div></div></body></html>`
const result = parser({ content, date }).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2021-11-24T06:00:00.000Z',
stop: '2021-11-24T22:30:00.000Z',
title: `Club Piolet`
},
{
start: '2021-11-24T22:30:00.000Z',
stop: '2021-11-25T00:00:00.000Z',
title: `Informatiu vespre`
},
{
start: '2021-11-25T00:00:00.000Z',
stop: '2021-11-25T01:00:00.000Z',
title: `Àrea Andorra Difusió`
}
])
})
it('can handle empty guide', () => {
const result = parser({
date,
channel,
content: `<!DOCTYPE html><html><head></head><body></body></html>`
})
expect(result).toMatchObject([])
})

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="arianaafgtv.com">
<channels>
<channel lang="en" xmltv_id="ArianaAfghanistanInternationalTV.us" site_id="#">Ariana Afghanistan International TV</channel>
</channels>
</site>

View File

@@ -0,0 +1,84 @@
const cheerio = require('cheerio')
const dayjs = require('dayjs')
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: 'arianaafgtv.com',
days: 2,
url() {
return `https://www.arianaafgtv.com/index.html`
},
parser({ content, date }) {
const programs = []
const items = parseItems(content, date)
items.forEach(item => {
const title = item.title
const start = parseStart(item, date)
const stop = parseStop(item, date)
programs.push({
title,
start,
stop
})
})
return programs
}
}
function parseStop(item, date) {
const time = `${date.format('MM/DD/YYYY')} ${item.end.toUpperCase()}`
return dayjs.tz(time, 'MM/DD/YYYY hh:mm A', 'Asia/Kabul')
}
function parseStart(item, date) {
const time = `${date.format('MM/DD/YYYY')} ${item.start.toUpperCase()}`
return dayjs.tz(time, 'MM/DD/YYYY hh:mm A', 'Asia/Kabul')
}
function parseItems(content, date) {
const $ = cheerio.load(content)
const dayOfWeek = date.format('dddd')
const column = $('.H4')
.filter((i, el) => {
return $(el).text() === dayOfWeek
})
.first()
.parent()
const rows = column
.find('.Paragraph')
.map((i, el) => {
return $(el).html()
})
.toArray()
.map(r => (r === '&nbsp;' ? '|' : r))
.join(' ')
.split('|')
const items = []
rows.forEach(row => {
row = row.trim()
if (row) {
const found = row.match(/(\d+(|:\d+)(a|p)m-\d+(|:\d+)(a|p)m)/gi)
if (!found) return
const time = found[0]
let start = time.match(/(\d+(|:\d+)(a|p)m)-/i)[1]
start = dayjs(start.toUpperCase(), ['hh:mmA', 'h:mmA', 'hA']).format('hh:mm A')
let end = time.match(/-(\d+(|:\d+)(a|p)m)/i)[1]
end = dayjs(end.toUpperCase(), ['hh:mmA', 'h:mmA', 'hA']).format('hh:mm A')
const title = row.replace(time, '').replace('&nbsp;', '').trim()
items.push({ start, end, title })
}
})
return items
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="arianatelevision.com">
<channels>
<channel lang="en" xmltv_id="ArianaTVNational.af" site_id="#">Ariana TV National</channel>
</channels>
</site>

View File

@@ -0,0 +1,69 @@
const cheerio = require('cheerio')
const dayjs = require('dayjs')
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: 'arianatelevision.com',
days: 2,
url: `https://www.arianatelevision.com/program-schedule/`,
parser({ content, date }) {
const programs = []
const items = parseItems(content, date)
items.forEach(item => {
const prev = programs[programs.length - 1]
let start = parseStart(item, date)
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: item.title,
start,
stop
})
})
return programs
}
}
function parseStart(item, date) {
const time = `${date.format('YYYY-MM-DD')} ${item.start}`
return dayjs.tz(time, 'YYYY-MM-DD H:mm', 'Asia/Kabul')
}
function parseItems(content, date) {
const items = []
const col = date.day()
const $ = cheerio.load(content)
const settings = $('#jtrt_table_settings_508').text()
if (!settings) return []
const data = JSON.parse(settings)
if (!data || !Array.isArray(data)) return []
let rows = data[0]
rows.shift()
const output = []
rows.forEach(row => {
let day = date.day() + 2
if (day > 7) day = 1
if (!row[0] || !row[day]) return
output.push({
start: row[0].trim(),
title: row[day].trim()
})
})
return output
}

View File

@@ -0,0 +1,59 @@
// npx epg-grabber --config=sites/arianatelevision.com/arianatelevision.com.config.js --channels=sites/arianatelevision.com/arianatelevision.com.channels.xml --output=guide.xml --days=2
const { parser, url } = require('./arianatelevision.com.config.js')
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('2021-11-27', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: '#',
xmltv_id: 'ArianaTVNational.af'
}
it('can generate valid url', () => {
expect(url).toBe('https://www.arianatelevision.com/program-schedule/')
})
it('can parse response', () => {
const content = `<!DOCTYPE html><html><head></head><body><textarea data-jtrt-table-id="508" id="jtrt_table_settings_508" cols="30" rows="10">[[["Start","Saturday","Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","",""],["7:00","City Report","ICC T20 Highlights","ICC T20 Highlights","ICC T20 Highlights","ICC T20 Highlights","ICC T20 Highlights","ICC T20 Highlights","",""],["7:30","ICC T20 Highlights","Sport ","Sport ","Sport ","Sport ","Sport ","Sport ","",""],["15:00","ICC T20 World Cup","ICC T20 World Cup","ICC T20 World Cup","ICC T20 World Cup","ICC T20 World Cup","ICC T20 World Cup","ICC T20 World Cup","",""],["6:30","Quran and Hadis ","Falah","Falah","Falah","Falah","Falah","Falah","",""],["","\\n","","","","","","","",""]]]</textarea></body></html>`
const result = parser({ content, date }).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2021-11-27T02:30:00.000Z',
stop: '2021-11-27T03:00:00.000Z',
title: `City Report`
},
{
start: '2021-11-27T03:00:00.000Z',
stop: '2021-11-27T10:30:00.000Z',
title: `ICC T20 Highlights`
},
{
start: '2021-11-27T10:30:00.000Z',
stop: '2021-11-28T02:00:00.000Z',
title: `ICC T20 World Cup`
},
{
start: '2021-11-28T02:00:00.000Z',
stop: '2021-11-28T02:30:00.000Z',
title: `Quran and Hadis`
}
])
})
it('can handle empty guide', () => {
const result = parser({
date,
channel,
content: `<!DOCTYPE html><html><head></head><body><textarea data-jtrt-table-id="508" id="jtrt_table_settings_508" cols="30" rows="10"></textarea></body></html>`
})
expect(result).toMatchObject([])
})

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="artonline.tv">
<channels>
<channel lang="ar" xmltv_id="ARTAflam1.sa" site_id="">ART Aflam 1</channel>
<channel lang="ar" xmltv_id="ARTAflam2.sa" site_id="Aflam2">ART Aflam 2</channel>
<channel lang="ar" xmltv_id="ARTCinema.sa" site_id="Cinema">ART Cinema</channel>
<channel lang="ar" xmltv_id="ARTHekayat.sa" site_id="Hekayat">ART Hekayat</channel>
<channel lang="ar" xmltv_id="ARTHekayat2.sa" site_id="Hekayat2">ART Hekayat 2</channel>
</channels>
</site>

View File

@@ -0,0 +1,68 @@
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0
const customParseFormat = require('dayjs/plugin/customParseFormat')
const timezone = require('dayjs/plugin/timezone')
const utc = require('dayjs/plugin/utc')
const dayjs = require('dayjs')
dayjs.extend(customParseFormat)
dayjs.extend(timezone)
dayjs.extend(utc)
module.exports = {
site: 'artonline.tv',
days: 2,
url: function ({ channel }) {
return `https://www.artonline.tv/Home/Tvlist${channel.site_id}`
},
request: {
method: 'POST',
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
data: function ({ date }) {
const diff = date.diff(dayjs.utc().startOf('d'), 'd')
const params = new URLSearchParams()
params.append('objId', diff)
return params
}
},
parser: function ({ content }) {
const programs = []
if (!content) return programs
const items = JSON.parse(content)
items.forEach(item => {
const icon = parseIcon(item)
const start = parseStart(item)
const duration = parseDuration(item)
const stop = start.add(duration, 's')
programs.push({
title: item.title,
description: item.description,
icon,
start,
stop
})
})
return programs
}
}
function parseStart(item) {
const [_, M, D, YYYY] = item.adddate.match(/(\d+)\/(\d+)\/(\d+) /)
const [HH, mm] = item.start_Time.split(':')
return dayjs.tz(`${YYYY}-${M}-${D}T${HH}:${mm}:00`, 'YYYY-M-DTHH:mm:ss', 'Asia/Riyadh')
}
function parseDuration(item) {
const [__, HH, mm, ss] = item.duration.match(/(\d+):(\d+):(\d+)/)
return parseInt(HH) * 3600 + parseInt(mm) * 60 + parseInt(ss)
}
function parseIcon(item) {
return item.thumbnail ? `https://www.artonline.tv${item.thumbnail}` : null
}

View File

@@ -0,0 +1,66 @@
// npx epg-grabber --config=sites/artonline.tv/artonline.tv.config.js --channels=sites/artonline.tv/artonline.tv.channels.xml --output=guide.xml --days=2
const { parser, url, request } = require('./artonline.tv.config.js')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const customParseFormat = require('dayjs/plugin/customParseFormat')
dayjs.extend(customParseFormat)
dayjs.extend(utc)
const channel = {
site_id: 'Aflam2',
xmltv_id: 'ARTAflam2.sa'
}
it('can generate valid url', () => {
expect(url({ channel })).toBe('https://www.artonline.tv/Home/TvlistAflam2')
})
it('can generate valid request method', () => {
expect(request.method).toBe('POST')
})
it('can generate valid request headers', () => {
expect(request.headers).toMatchObject({
'content-type': 'application/x-www-form-urlencoded'
})
})
it('can generate valid request data for today', () => {
const date = dayjs.utc().startOf('d')
const data = request.data({ date })
expect(data.get('objId')).toBe('0')
})
it('can generate valid request data for tomorrow', () => {
const date = dayjs.utc().startOf('d').add(1, 'd')
const data = request.data({ date })
expect(data.get('objId')).toBe('1')
})
it('can parse response', () => {
const content = `[{"id":158963,"eventid":null,"duration":"01:34:00","lang":"Arabic","title":"الراقصه و السياسي","description":"تقرر الراقصه سونيا انشاء دار حضانه للأطفال اليتامى و عندما تتقدم بمشورعها للمسئول يرفض فتتحداه ، تلجأ للوزير عبد الحميد رأفت تربطه بها علاقة قديمة ، يخشى على مركزه و يرفض مساعدتها فتقرر كتابة مذكراتها بمساعدة أحد الصحفيين ، يتخوف عبد الحميد و المسئولين ثم يفاجأ عبد الحميد بحصول سونيا على الموافقه للمشورع و البدء في تنفيذه و ذلك لعلاقتها بأحد كبار المسئولين .","thumbnail":"/UploadImages/Channel/ARTAFLAM1/03/AlRaqesaWaAlSeyasi.jpg","image":"0","start_Time":"00:30","adddate":"3/4/2022 12:00:00 AM","repeat1":null,"iD_genre":0,"iD_Show_Type":0,"iD_Channel":77,"iD_country":0,"iD_rating":0,"end_time":"02:04","season_Number":0,"epoisode_Number":0,"hasCatchup":0,"cmsid":0,"containerID":0,"imagePath":"../../UploadImages/Channel/ARTAFLAM1/3/","youtube":"0","published_at":"0","directed_by":"0","composition":"0","cast":"0","timeShow":null,"short_description":"تقرر الراقصه سونيا انشاء دار حضانه للأطفال اليتامى و عندما تتقدم بمشورعها للمسئول يرفض فتتحداه ، تلجأ للوزير عبد الحميد رأفت تربطه بها علاقة قديمة ، يخشى على مركزه و يرفض مساعدتها فتقرر كتابة مذكراتها بمساعدة أحد الصحفيين ، يتخوف عبد الحميد و المسئولين ثم يفاجأ عبد الحميد بحصول سونيا على الموافقه للمشورع و البدء في تنفيذه و ذلك لعلاقتها بأحد كبار المسئولين .","seOdescription":null,"tagseo":null,"channel_name":null,"pathimage":null,"pathThumbnail":null}]`
const result = parser({ content }).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2022-03-03T21:30:00.000Z',
stop: '2022-03-03T23:04:00.000Z',
title: 'الراقصه و السياسي',
description:
'تقرر الراقصه سونيا انشاء دار حضانه للأطفال اليتامى و عندما تتقدم بمشورعها للمسئول يرفض فتتحداه ، تلجأ للوزير عبد الحميد رأفت تربطه بها علاقة قديمة ، يخشى على مركزه و يرفض مساعدتها فتقرر كتابة مذكراتها بمساعدة أحد الصحفيين ، يتخوف عبد الحميد و المسئولين ثم يفاجأ عبد الحميد بحصول سونيا على الموافقه للمشورع و البدء في تنفيذه و ذلك لعلاقتها بأحد كبار المسئولين .',
icon: 'https://www.artonline.tv/UploadImages/Channel/ARTAFLAM1/03/AlRaqesaWaAlSeyasi.jpg'
}
])
})
it('can handle empty guide', () => {
const result = parser({
content: ''
})
expect(result).toMatchObject([])
})

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>PYWWJ0TM0RSWSX09</RequestId><HostId>WU2+m2j4IPZtj2j5k2C9NB41iM2QaK+LqVlBk2kLCNDrddFBXPkjCFLBiALXw8xTPF4xIPTZOWs=</HostId></Error>

View File

@@ -0,0 +1,27 @@
{
"responseCode": 200,
"responseMessage": "Linear Asset Detail",
"response": {
"eventId": "40609678",
"channelId": 425,
"channelStbNumber": "305",
"isHd": true,
"imageUrl": "https://s3-ap-southeast-1.amazonaws.com/ams-astro/production/images/1035X328883.jpg",
"title": "Triumph in the Skies Ep06",
"programmeId": "328827",
"episodeId": "328883",
"datetime": "2022-10-31 00:10:00.0",
"datetimeInUtc": "2022-10-30 16:10:00.0",
"duration": "00:52:00",
"siTrafficKey": "1:10000526:47979653",
"certification": "U",
"shortSynopsis": "This classic drama depicts the many aspects of two complicated relationships set against an airline company. Will those involved ever find true love?",
"longSynopsis": null,
"cast": "Francis Ng Chun Yu,Joe Ma Tak Chung,Flora Chan Wai San",
"director": "Joe Ma Tak Chung",
"filter": "Filter/71",
"subFilter": [
"Filter/24"
]
}
}

View File

@@ -0,0 +1,143 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="astro.com.my">
<channels>
<channel lang="ms" xmltv_id="8TV.my" site_id="115">8TV</channel>
<!-- <channel lang="ms" xmltv_id="" site_id="461">ABC</channel> -->
<channel lang="ms" xmltv_id="AdithyaTV.in" site_id="67">Adithya TV</channel>
<channel lang="ms" xmltv_id="AlJazeeraEnglish.qa" site_id="374">Aljazeera</channel>
<channel lang="ms" xmltv_id="AnimalPlanetMalaysia.my" site_id="377">Animal Planet</channel>
<channel lang="ms" xmltv_id="AsianFoodNetwork.sg" site_id="91">Asian Food Network</channel>
<channel lang="ms" xmltv_id="AstroAEC.my" site_id="182">Astro AEC</channel>
<channel lang="ms" xmltv_id="AstroAOD311.my" site_id="172">Astro AOD 311</channel>
<channel lang="ms" xmltv_id="AstroAOD352.my" site_id="87">Astro AOD 352</channel>
<channel lang="ms" xmltv_id="AstroAOD353.my" site_id="114">Astro AOD 353</channel>
<channel lang="ms" xmltv_id="AstroAOD354.my" site_id="65">Astro AOD 354</channel>
<channel lang="ms" xmltv_id="AstroAOD355.my" site_id="66">Astro AOD 355</channel>
<channel lang="ms" xmltv_id="AstroArena.my" site_id="235">Astro Arena</channel>
<channel lang="ms" xmltv_id="AstroArena2.my" site_id="457">Astro Arena 2</channel>
<channel lang="ms" xmltv_id="AstroAura.my" site_id="400">Astro Aura</channel>
<channel lang="ms" xmltv_id="AstroAwani.my" site_id="436">Astro Awani</channel>
<channel lang="ms" xmltv_id="AstroBollyOneHD.my" site_id="178">Astro BollyOne HD</channel>
<channel lang="ms" xmltv_id="AstroBoxOfficeTayanganHebat.my" site_id="176">Astro Box Office Tayangan Hebat</channel>
<channel lang="ms" xmltv_id="AstroBoxOfficeThangathirai.my" site_id="177">Astro Box Office Thangathirai</channel>
<channel lang="ms" xmltv_id="AstroCeria.my" site_id="386">Astro Ceria</channel>
<channel lang="ms" xmltv_id="AstroCh100.my" site_id="471">Gemilang</channel>
<channel lang="ms" xmltv_id="AstroCitra.my" site_id="301">Astro Citra</channel>
<channel lang="ms" xmltv_id="AstroCricket.my" site_id="197">Astro Cricket</channel>
<channel lang="ms" xmltv_id="AstroHuaHeeDai.my" site_id="162">Astro Hua Hee Dai</channel>
<channel lang="ms" xmltv_id="AstroOasis.my" site_id="315">Astro Oasis</channel>
<channel lang="ms" xmltv_id="AstroPrima.my" site_id="316">Astro Prima</channel>
<channel lang="ms" xmltv_id="AstroQuanJiaHD.my" site_id="158">Astro Quan Jia HD</channel>
<channel lang="ms" xmltv_id="AstroRania.my" site_id="401">Astro Rania</channel>
<channel lang="ms" xmltv_id="AstroRia.my" site_id="193">Astro Ria</channel>
<channel lang="ms" xmltv_id="AstroShuangXing.my" site_id="183">Astro Shuang Xing</channel>
<channel lang="ms" xmltv_id="AstroSuperSport.my" site_id="154">Astro SuperSport</channel>
<channel lang="ms" xmltv_id="AstroSuperSport2.my" site_id="138">Astro SuperSport 2</channel>
<channel lang="ms" xmltv_id="AstroSuperSport3.my" site_id="164">Astro SuperSport 3</channel>
<channel lang="ms" xmltv_id="AstroSuperSport4.my" site_id="241">Astro SuperSport 4</channel>
<channel lang="ms" xmltv_id="AstroSuperSport5.my" site_id="455">Astro SuperSport 5</channel>
<channel lang="ms" xmltv_id="AstroTutorTVPT3.my" site_id="410">Astro Tutor TV PT3</channel>
<channel lang="ms" xmltv_id="AstroTutorTVSPM.my" site_id="411">Astro Tutor TV SPM</channel>
<channel lang="ms" xmltv_id="AstroTutorTVUPSR.my" site_id="412">Astro Tutor TV UPSR</channel>
<channel lang="ms" xmltv_id="AstroUHD.my" site_id="308">Astro UHD</channel>
<channel lang="ms" xmltv_id="AstroVaanavil.my" site_id="397">Astro Vaanavil</channel>
<channel lang="ms" xmltv_id="AstroVellithirai.my" site_id="399">Astro Vellithirai</channel>
<channel lang="ms" xmltv_id="AstroVinmeenHD.my" site_id="167">Astro Vinmeen HD</channel>
<channel lang="ms" xmltv_id="AstroWahLaiToi.my" site_id="129">Astro Wah Lai Toi</channel>
<channel lang="ms" xmltv_id="AstroWarna.my" site_id="272">Astro Warna</channel>
<channel lang="ms" xmltv_id="AstroXiaoTaiYang.my" site_id="387">Astro Xiao Tai Yang</channel>
<channel lang="ms" xmltv_id="AwesomeTV.my" site_id="433">Awesome TV</channel>
<channel lang="ms" xmltv_id="AXNMalaysia.my" site_id="131">AXN</channel>
<channel lang="ms" xmltv_id="BBCEarthAsia.uk" site_id="452">BBC Earth</channel>
<channel lang="ms" xmltv_id="BBCFirstAsia.uk" site_id="458">BBC First</channel>
<channel lang="ms" xmltv_id="BBCLifestyleAsia.uk" site_id="451">BBC Lifestyle</channel>
<channel lang="ms" xmltv_id="BBCWorldNewsAsiaPacific.uk" site_id="366">BBC World News</channel>
<channel lang="ms" xmltv_id="beINSports.qa" site_id="236">beIN Sports HD</channel>
<channel lang="ms" xmltv_id="beINSports2.qa" site_id="466">beIN Sports 2</channel>
<channel lang="ms" xmltv_id="beINSports3.qa" site_id="313">beIN Sports 3</channel>
<channel lang="ms" xmltv_id="BernamaTV.my" site_id="160">Bernama TV</channel>
<channel lang="ms" xmltv_id="BloombergTVAsia.hk" site_id="422">Bloomberg TV</channel>
<channel lang="ms" xmltv_id="Boo.my" site_id="251">Boo</channel>
<channel lang="ms" xmltv_id="BoomerangSoutheastAsia.us" site_id="430">Boomerang</channel>
<channel lang="ms" xmltv_id="CartoonNetworkAsia.sg" site_id="371">Cartoon Network HD</channel>
<channel lang="ms" xmltv_id="CCTV4Asia.cn" site_id="385">CCTV 4</channel>
<channel lang="ms" xmltv_id="CCM.hk" site_id="187">Celestial Classic Movies</channel>
<channel lang="ms" xmltv_id="CelestialMoviesMalaysia.my" site_id="134">Celestial Movies</channel>
<channel lang="ms" xmltv_id="CGTN.cn" site_id="426">CGTN</channel>
<channel lang="ms" xmltv_id="ChuttiTVMalaysia.my" site_id="51">Chutti TV</channel>
<channel lang="ms" xmltv_id="CinemaxAsia.sg" site_id="337">Cinemax</channel>
<channel lang="ms" xmltv_id="CNA.sg" site_id="295">CNA</channel>
<channel lang="ms" xmltv_id="CNBCAsia.sg" site_id="423">CNBC Asia-Pacific</channel>
<channel lang="ms" xmltv_id="CNNInternationalAsiaPacific.hk" site_id="336">CNN</channel>
<channel lang="ms" xmltv_id="Colors.in" site_id="365">Colors</channel>
<channel lang="ms" xmltv_id="ColorsTamil.in" site_id="298">Colors Tamil</channel>
<channel lang="ms" xmltv_id="CrimePlusInvestigationAsia.sg" site_id="369">Crime + Investigation</channel>
<channel lang="ms" xmltv_id="CTiAsia.tw" site_id="424">CTI TV</channel>
<channel lang="ms" xmltv_id="DiscoveryAsia.sg" site_id="136">Discovery Asia</channel>
<channel lang="ms" xmltv_id="DiscoveryChannelIndonesia.id" site_id="376">Discovery Channel</channel>
<channel lang="ms" xmltv_id="DMAXSoutheastAsia.sg" site_id="367">DMAX</channel>
<channel lang="ms" xmltv_id="DWEnglish.de" site_id="287">DW English</channel>
<channel lang="ms" xmltv_id="eGGNetwork.my" site_id="206">Egg Network</channel>
<channel lang="ms" xmltv_id="EurosportAsia.fr" site_id="339">Eurosport</channel>
<channel lang="ms" xmltv_id="FoodNetworkAsia.sg" site_id="153">Food Network</channel>
<channel lang="ms" xmltv_id="France24English.fr" site_id="289">France 24 English</channel>
<channel lang="ms" xmltv_id="GolfChannelMalaysia.my" site_id="189">Golf Channel</channel>
<channel lang="ms" xmltv_id="GoShopChinese.my" site_id="202">Go Shop Chinese</channel>
<channel lang="ms" xmltv_id="GoShopMalay111.my" site_id="403">Go Shop Malay 111</channel>
<channel lang="ms" xmltv_id="GoShopMalay118.my" site_id="192">Go Shop Malay 118</channel>
<channel lang="ms" xmltv_id="GoShopMalay120.my" site_id="294">Go Shop Malay 120</channel>
<channel lang="ms" xmltv_id="HBOAsia.sg" site_id="143">HBO</channel>
<channel lang="ms" xmltv_id="HBOFamilyAsia.sg" site_id="450">HBO Family</channel>
<channel lang="ms" xmltv_id="HBOHitsAsia.sg" site_id="449">HBO Hits</channel>
<channel lang="ms" xmltv_id="HGTVAsia.us" site_id="198">HGTV</channel>
<channel lang="ms" xmltv_id="HistoryAsia.us" site_id="144">History</channel>
<channel lang="ms" xmltv_id="HITS.sg" site_id="179">Hits</channel>
<channel lang="ms" xmltv_id="HITSMovies.sg" site_id="391">Hits Movies</channel>
<channel lang="ms" xmltv_id="iQIYI.cn" site_id="355">Iqiyi</channel>
<channel lang="ms" xmltv_id="KBSWorld.kr" site_id="161">KBS World</channel>
<channel lang="ms" xmltv_id="KIX.hk" site_id="157">Kix</channel>
<channel lang="ms" xmltv_id="KPlus.sg" site_id="266">K+</channel>
<channel lang="ms" xmltv_id="LifetimeAsia.us" site_id="447">Lifetime</channel>
<channel lang="ms" xmltv_id="MoonbugKids.uk" site_id="465">Moonbug Kids</channel>
<channel lang="ms" xmltv_id="MTVAsia.sg" site_id="420">MTV</channel>
<channel lang="ms" xmltv_id="NatGeoPeopleMalaysia.my" site_id="199">Nat Geo People</channel>
<channel lang="ms" xmltv_id="NationalGeographicMalaysia.my" site_id="140">National Geographic</channel>
<channel lang="ms" xmltv_id="NationalGeographicWildMalaysia.my" site_id="322">National Geographic Wild</channel>
<channel lang="ms" xmltv_id="NHKWorldPremium.jp" site_id="428">NHK World Premium</channel>
<channel lang="ms" xmltv_id="NickelodeonAsia.sg" site_id="370">Nickelodeon</channel>
<channel lang="ms" xmltv_id="NickJrAsia.sg" site_id="392">Nick Jr</channel>
<channel lang="ms" xmltv_id="NjoiTV.my" site_id="302">Njoi TV</channel>
<channel lang="ms" xmltv_id="NTV7.my" site_id="93">NTV 7</channel>
<channel lang="ms" xmltv_id="OneTVAsia.sg" site_id="133">One</channel>
<channel lang="ms" xmltv_id="ParamountNetworkMalaysia.my" site_id="448">Paramount Network</channel>
<channel lang="ms" xmltv_id="PhoenixChineseChannel.hk" site_id="382">Phoenix Chinese Channel</channel>
<channel lang="ms" xmltv_id="PhoenixInfoNewsChannel.hk" site_id="43">Phoenix InfoNews Channel</channel>
<channel lang="ms" xmltv_id="PremierSports1Asia.ie" site_id="393">Premier Sports</channel>
<channel lang="ms" xmltv_id="PRIMEtime.my" site_id="453">PRIMEtime</channel>
<channel lang="ms" xmltv_id="TV1.my" site_id="395">RTM TV 1</channel>
<channel lang="ms" xmltv_id="TV2.my" site_id="396">RTM TV2</channel>
<channel lang="ms" xmltv_id="Okey.my" site_id="97">RTM TV Okey</channel>
<channel lang="ms" xmltv_id="ShowcaseMovies.my" site_id="454">Showcase Movies</channel>
<channel lang="ms" xmltv_id="SkyNews.uk" site_id="155">Sky News UK</channel>
<channel lang="ms" xmltv_id="SPOTV.kr" site_id="456">SPOTV</channel>
<channel lang="ms" xmltv_id="StarVijay.in" site_id="357">Star Vijay</channel>
<channel lang="ms" xmltv_id="SunMusic.in" site_id="417">Sun Music</channel>
<channel lang="ms" xmltv_id="SunTVMalaysia.my" site_id="358">Sun TV</channel>
<channel lang="ms" xmltv_id="TADAA.my" site_id="432">Ta-Daa!</channel>
<channel lang="ms" xmltv_id="TLCSoutheastAsia.sg" site_id="338">TLC</channel>
<channel lang="ms" xmltv_id="TV3.my" site_id="106">TV 3</channel>
<channel lang="ms" xmltv_id="TV9.my" site_id="48">TV 9</channel>
<channel lang="ms" xmltv_id="TVAlhijrah.my" site_id="149">TV Alhijrah</channel>
<channel lang="ms" xmltv_id="TVBClassic.hk" site_id="425">TVB Classic</channel>
<channel lang="ms" xmltv_id="EntertainmentNews.hk" site_id="427">TVB Entertainment News</channel>
<channel lang="ms" xmltv_id="Jade.hk" site_id="203">TVB Jade</channel>
<channel lang="ms" xmltv_id="TVBSAsia.tw" site_id="384">TVBS Asia</channel>
<channel lang="ms" xmltv_id="TVBXingHe.hk" site_id="383">TVB Xing He</channel>
<channel lang="ms" xmltv_id="tvNAsia.hk" site_id="190">TVN HD</channel>
<channel lang="ms" xmltv_id="tvNMoviesAsia.hk" site_id="274">TVN Movies</channel>
<channel lang="ms" xmltv_id="TVS.my" site_id="429">TVS</channel>
<channel lang="ms" xmltv_id="WarnerTVAsia.us" site_id="270">Warner TV</channel>
<channel lang="ms" xmltv_id="WWENetwork.us" site_id="194">WWE Network</channel>
<channel lang="ms" xmltv_id="ZeeTamil.in" site_id="297">Zee Tamil</channel>
</channels>
</site>

View File

@@ -0,0 +1,116 @@
const axios = require('axios')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
dayjs.extend(utc)
const API_ENDPOINT = `https://contenthub-api.eco.astro.com.my`
module.exports = {
site: 'astro.com.my',
days: 2,
url: function ({ channel }) {
return `${API_ENDPOINT}/channel/${channel.site_id}.json`
},
async parser({ content, date }) {
const programs = []
const items = parseItems(content, date)
for (let item of items) {
const start = dayjs.utc(item.datetimeInUtc)
const duration = parseDuration(item.duration)
const stop = start.add(duration, 's')
const details = await loadProgramDetails(item)
programs.push({
title: item.title,
sub_title: item.subtitles,
description: details.longSynopsis || details.shortSynopsis,
actors: parseList(details.cast),
directors: parseList(details.director),
icon: details.imageUrl,
rating: parseRating(details),
categories: parseCategories(details),
episode: parseEpisode(item),
start: start,
stop: stop
})
}
return programs
}
}
function parseEpisode(item) {
const [_, number] = item.title.match(/Ep(\d+)$/) || [null, null]
return number ? parseInt(number) : null
}
function parseList(list) {
return typeof list === 'string' ? list.split(',') : []
}
function parseRating(details) {
return details.certification
? {
system: 'LPF',
value: details.certification
}
: null
}
function parseItems(content, date) {
try {
const data = JSON.parse(content)
const schedules = data.response.schedule
return schedules[date.format('YYYY-MM-DD')] || []
} catch (e) {
return []
}
}
function parseDuration(duration) {
const match = duration.match(/(\d{2}):(\d{2}):(\d{2})/)
const hours = parseInt(match[1])
const minutes = parseInt(match[2])
const seconds = parseInt(match[3])
return hours * 3600 + minutes * 60 + seconds
}
function parseCategories(details) {
const genres = {
'filter/2': 'Action',
'filter/4': 'Anime',
'filter/12': 'Cartoons',
'filter/16': 'Comedy',
'filter/19': 'Crime',
'filter/24': 'Drama',
'filter/25': 'Educational',
'filter/36': 'Horror',
'filter/39': 'Live Action',
'filter/55': 'Pre-school',
'filter/56': 'Reality',
'filter/60': 'Romance',
'filter/68': 'Talk Show',
'filter/69': 'Thriller',
'filter/72': 'Variety',
'filter/75': 'Series',
'filter/100': 'Others (Children)'
}
return Array.isArray(details.subFilter)
? details.subFilter.map(g => genres[g.toLowerCase()]).filter(Boolean)
: []
}
async function loadProgramDetails(item) {
const url = `${API_ENDPOINT}/api/v1/linear-detail?siTrafficKey=${item.siTrafficKey}`
const data = await axios
.get(url)
.then(r => r.data)
.catch(err => {})
if (!data) return {}
return data.response || {}
}

View File

@@ -0,0 +1,72 @@
// npx epg-grabber --config=sites/astro.com.my/astro.com.my.config.js --channels=sites/astro.com.my/astro.com.my.channels.xml --output=guide.xml --timeout=30000 --days=2
const { parser, url } = require('./astro.com.my.config.js')
const fs = require('fs')
const path = require('path')
const axios = require('axios')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const customParseFormat = require('dayjs/plugin/customParseFormat')
dayjs.extend(customParseFormat)
dayjs.extend(utc)
jest.mock('axios')
const date = dayjs.utc('2022-10-31', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: '425',
xmltv_id: 'TVBClassic.hk'
}
it('can generate valid url', () => {
expect(url({ channel })).toBe('https://contenthub-api.eco.astro.com.my/channel/425.json')
})
it('can parse response', async () => {
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
axios.get.mockImplementation(url => {
if (
url ===
'https://contenthub-api.eco.astro.com.my/api/v1/linear-detail?siTrafficKey=1:10000526:47979653'
) {
return Promise.resolve({
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/program.json')))
})
} else {
return Promise.resolve({ data: '' })
}
})
let results = await parser({ content, channel, date })
results = results.map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(results.length).toBe(31)
expect(results[0]).toMatchObject({
start: '2022-10-30T16:10:00.000Z',
stop: '2022-10-30T17:02:00.000Z',
title: 'Triumph in the Skies Ep06',
description:
'This classic drama depicts the many aspects of two complicated relationships set against an airline company. Will those involved ever find true love?',
actors: ['Francis Ng Chun Yu', 'Joe Ma Tak Chung', 'Flora Chan Wai San'],
directors: ['Joe Ma Tak Chung'],
icon: 'https://s3-ap-southeast-1.amazonaws.com/ams-astro/production/images/1035X328883.jpg',
rating: {
system: 'LPF',
value: 'U'
},
episode: 6,
categories: ['Drama']
})
})
it('can handle empty guide', async () => {
const content = fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'))
const results = await parser({ date, content })
expect(results).toMatchObject([])
})

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
<script type=text/javascript>var max_sports=-1;var max_entertainment=-1;</script>
<script>currenthour='21'</script><div class='container container-tvguide categoryheadercss'><div class='row no-gutter' style='margin-top:20px'>
<div class='col-xs-12 col-sm-12 col-md-12 col-lg-12'>
<div id='sports' style='width:50%' class=category_item onclick=setparams('2023-01-19','0','00','sports','bein.net')>Sports</div><div id='entertainment' style='width:50%' class=category_item_selected>Entertainment</div></div></div><div class='row no-gutter'>
<div class='col-xs-12 col-sm-12 col-md-12 col-lg-12'>
<table width=100% border=0 class=day_table><tr><td><span id=day1t1 style=width:100% class=day_item><a href=javascript:selectday('day1');setparams('2023-01-18','0','00','entertainment','bein.net')>Wed</a></span><span id=day1t2 style=width:100% class=day_item1><a href=javascript:selectday('day1');setparams('2023-01-18','0','00','entertainment','bein.net')>18</a></div></td><script language=javascript>lastday='day2';</script><td><div id=day2t1 style=width:100% class=day_item_selected><a href=javascript:setparams('2023-01-19','0','00','entertainment','bein.net')>Thu</a></div><div id=day2t2 style=width:100% class=day_item1_selected><a href=javascript:setparams('2023-01-19','0','00','entertainment','bein.net')>19</a></div></td><td><span id=day3t1 style=width:100% class=day_item><a href=javascript:selectday('day3');setparams('2023-01-20','0','00','entertainment','bein.net')>Fri</a></span><span id=day3t2 style=width:100% class=day_item1><a href=javascript:selectday('day3');setparams('2023-01-20','0','00','entertainment','bein.net')>20</a></div></td><td><span id=day4t1 style=width:100% class=day_item><a href=javascript:selectday('day4');setparams('2023-01-21','0','00','entertainment','bein.net')>Sat</a></span><span id=day4t2 style=width:100% class=day_item1><a href=javascript:selectday('day4');setparams('2023-01-21','0','00','entertainment','bein.net')>21</a></div></td></table></div>
</div><div class='row no-gutter'>
<div class='col-xs-12 col-sm-12 col-md-12 col-lg-12'>
<div style='background-color:#d1d0de;margin:0px auto;text-align:center;display:flex;width:100%'><div id=left style=width:25px;background-color:red;height:50px;padding-top:13px;background-color:#d1d0de;><img src=https://www.bein.com/mena/wp-content/uploads/sites/4/2015/06/left.png onclick=ptime()></div><div id='slider_timer' class='slider_time'>
<ul id='timer'></ul></div><div id=left style=width:25px;background-color:red;height:50px;padding-top:13px;background-color:#d1d0de><img src=https://www.bein.com/mena/wp-content/uploads/sites/4/2015/06/right.png onclick=ntime()></div></div>
</div>
</div><div class='row no-gutter' style='height:15px'></div>
</div><div class='container container-tvguide contentheadercss_entertainment'></div>
</div>

View File

@@ -0,0 +1,162 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="bein.com">
<channels>
<!-- If updating, note that the English and Arabic channels are in a different order so have different IDs -->
<channel lang="en" xmltv_id="beINSportsNews.qa" site_id="sports#1">BeIn Sports News</channel>
<channel lang="en" xmltv_id="beINSports.qa" site_id="sports#2">BeIn Sports</channel>
<channel lang="en" xmltv_id="beINSports1.qa" site_id="sports#3">BeIn Sports 1</channel>
<channel lang="en" xmltv_id="beINSports2.qa" site_id="sports#4">BeIn Sports 2</channel>
<channel lang="en" xmltv_id="beINSports3.qa" site_id="sports#5">BeIn Sports 3</channel>
<channel lang="en" xmltv_id="beINSports4.qa" site_id="sports#6">BeIn Sports 4</channel>
<channel lang="en" xmltv_id="beINSports5.qa" site_id="sports#7">BeIn Sports 5</channel>
<channel lang="en" xmltv_id="beINSports6.qa" site_id="sports#8">BeIn Sports 6</channel>
<channel lang="en" xmltv_id="beINSports7.qa" site_id="sports#9">BeIn Sports 7</channel>
<channel lang="en" xmltv_id="beINSportsPremium1.qa" site_id="sports#10">BeIn Sports Premium 1</channel>
<channel lang="en" xmltv_id="beINSportsPremium2.qa" site_id="sports#11">BeIn Sports Premium 2</channel>
<channel lang="en" xmltv_id="beINSportsPremium3.qa" site_id="sports#12">BeIn Sports Premium 3</channel>
<channel lang="en" xmltv_id="beINSportsXtra1.qa" site_id="sports#13">BeIn Sports Xtra 1</channel>
<channel lang="en" xmltv_id="beINSportsXtra2.qa" site_id="sports#14">BeIn Sports Xtra 2</channel>
<channel lang="en" xmltv_id="beIN4K.qa" site_id="sports#15">BeIn 4K</channel>
<channel lang="en" xmltv_id="beINSportsAFC.qa" site_id="sports#16">BeIN Sports AFC</channel>
<channel lang="en" xmltv_id="beINSportsAFC1.qa" site_id="sports#17">BeIN Sports AFC 1</channel>
<channel lang="en" xmltv_id="beINSportsAFC2.qa" site_id="sports#18">BeIN Sports AFC 2</channel>
<channel lang="en" xmltv_id="beINSportsAFC3.qa" site_id="sports#19">BeIN Sports AFC 3</channel>
<channel lang="en" xmltv_id="beINSportsEnglish1.qa" site_id="sports#20">BeIn Sports English 1</channel>
<channel lang="en" xmltv_id="beINSportsEnglish2.qa" site_id="sports#21">BeIn Sports English 2</channel>
<channel lang="en" xmltv_id="beINSportsEnglish3.qa" site_id="sports#22">BeIn Sports English 3</channel>
<channel lang="en" xmltv_id="beINSportsNBA.qa" site_id="sports#23">BeIn NBA</channel>
<channel lang="en" xmltv_id="beINSportsFrench1.qa" site_id="sports#24">BeIn Sports French 1</channel>
<channel lang="en" xmltv_id="beINSportsFrench2.qa" site_id="sports#25">BeIn Sports French 2</channel>
<channel lang="en" xmltv_id="beINSportsFrench3.qa" site_id="sports#26">BeIn Sports French 3</channel>
<channel lang="en" xmltv_id="beINSportsMax1.qa" site_id="sports#27">beIN Sports Max 1</channel>
<channel lang="en" xmltv_id="beINSportsMax2.qa" site_id="sports#28">beIN Sports Max 2</channel>
<channel lang="en" xmltv_id="beINSportsMax3.qa" site_id="sports#29">beIN Sports Max 3</channel>
<channel lang="en" xmltv_id="beINSportsMax4.qa" site_id="sports#30">beIN Sports Max 4</channel>
<channel lang="en" xmltv_id="beINSportsMax5.qa" site_id="sports#31">beIN Sports Max 5</channel>
<channel lang="en" xmltv_id="beINSportsMax6.qa" site_id="sports#32">beIN Sports Max 6</channel>
<channel lang="en" xmltv_id="AlkassOne.qa" site_id="sports#33">Alkass One</channel>
<channel lang="en" xmltv_id="AlkassTwo.qa" site_id="sports#34">Alkass Two</channel>
<channel lang="en" xmltv_id="AlkassThree.qa" site_id="sports#35">Alkass Three</channel>
<channel lang="en" xmltv_id="AlkassFour.qa" site_id="sports#36">Alkass Four</channel>
<channel lang="en" xmltv_id="AlkassFive.qa" site_id="sports#37">Alkass Five</channel>
<channel lang="en" xmltv_id="AlkassSix.qa" site_id="sports#38">Alkass Six</channel>
<channel lang="en" xmltv_id="AlkassSeven.qa" site_id="sports#39">Alkass Seven</channel>
<channel lang="en" xmltv_id="AlkassEight.qa" site_id="sports#40">Alkass Eight</channel>
<channel lang="ar" xmltv_id="beINSportsNews.qa" site_id="sports#1">BeIn Sports News</channel>
<channel lang="ar" xmltv_id="beINSports.qa" site_id="sports#2">BeIn Sports</channel>
<channel lang="ar" xmltv_id="beINSports1.qa" site_id="sports#3">BeIn Sports 1</channel>
<channel lang="ar" xmltv_id="beINSports2.qa" site_id="sports#4">BeIn Sports 2</channel>
<channel lang="ar" xmltv_id="beINSports3.qa" site_id="sports#5">BeIn Sports 3</channel>
<channel lang="ar" xmltv_id="beINSports4.qa" site_id="sports#6">BeIn Sports 4</channel>
<channel lang="ar" xmltv_id="beINSports5.qa" site_id="sports#7">BeIn Sports 5</channel>
<channel lang="ar" xmltv_id="beINSports6.qa" site_id="sports#8">BeIn Sports 6</channel>
<channel lang="ar" xmltv_id="beINSports7.qa" site_id="sports#9">BeIn Sports 7</channel>
<channel lang="ar" xmltv_id="beINSportsPremium1.qa" site_id="sports#10">BeIn Sports Premium 1</channel>
<channel lang="ar" xmltv_id="beINSportsPremium2.qa" site_id="sports#11">BeIn Sports Premium 2</channel>
<channel lang="ar" xmltv_id="beINSportsPremium3.qa" site_id="sports#12">BeIn Sports Premium 3</channel>
<channel lang="ar" xmltv_id="beINSportsXtra1.qa" site_id="sports#13">BeIn Sports Xtra 1</channel>
<channel lang="ar" xmltv_id="beINSportsXtra2.qa" site_id="sports#14">BeIn Sports Xtra 2</channel>
<channel lang="ar" xmltv_id="beIN4K.qa" site_id="sports#15">BeIn 4K</channel>
<channel lang="ar" xmltv_id="beINSportsAFC.qa" site_id="sports#16">BeIN Sports AFC</channel>
<channel lang="ar" xmltv_id="beINSportsAFC1.qa" site_id="sports#17">BeIN Sports AFC 1</channel>
<channel lang="ar" xmltv_id="beINSportsAFC2.qa" site_id="sports#18">BeIN Sports AFC 2</channel>
<channel lang="ar" xmltv_id="beINSportsAFC3.qa" site_id="sports#19">BeIN Sports AFC 3</channel>
<channel lang="ar" xmltv_id="beINSportsEnglish1.qa" site_id="sports#20">BeIn Sports English 1</channel>
<channel lang="ar" xmltv_id="beINSportsEnglish2.qa" site_id="sports#21">BeIn Sports English 2</channel>
<channel lang="ar" xmltv_id="beINSportsEnglish3.qa" site_id="sports#22">BeIn Sports English 3</channel>
<channel lang="ar" xmltv_id="beINSportsNBA.qa" site_id="sports#23">BeIn NBA</channel>
<channel lang="ar" xmltv_id="beINSportsFrench1.qa" site_id="sports#24">BeIn Sports French 1</channel>
<channel lang="ar" xmltv_id="beINSportsFrench2.qa" site_id="sports#25">BeIn Sports French 2</channel>
<channel lang="ar" xmltv_id="beINSportsFrench3.qa" site_id="sports#26">BeIn Sports French 3</channel>
<channel lang="ar" xmltv_id="beINSportsMax1.qa" site_id="sports#27">beIN Sports Max 1</channel>
<channel lang="ar" xmltv_id="beINSportsMax2.qa" site_id="sports#28">beIN Sports Max 2</channel>
<channel lang="ar" xmltv_id="beINSportsMax3.qa" site_id="sports#29">beIN Sports Max 3</channel>
<channel lang="ar" xmltv_id="beINSportsMax4.qa" site_id="sports#30">beIN Sports Max 4</channel>
<channel lang="ar" xmltv_id="beINSportsMax5.qa" site_id="sports#31">beIN Sports Max 5</channel>
<channel lang="ar" xmltv_id="beINSportsMax6.qa" site_id="sports#32">beIN Sports Max 6</channel>
<channel lang="ar" xmltv_id="AlkassThree.qa" site_id="sports#33">Alkass Three</channel>
<channel lang="ar" xmltv_id="AlkassOne.qa" site_id="sports#34">Alkass One</channel>
<channel lang="ar" xmltv_id="AlkassTwo.qa" site_id="sports#35">Alkass Two</channel>
<channel lang="ar" xmltv_id="AlkassFour.qa" site_id="sports#36">Alkass Four</channel>
<channel lang="ar" xmltv_id="AlkassFive.qa" site_id="sports#37">Alkass Five</channel>
<channel lang="ar" xmltv_id="AlkassSix.qa" site_id="sports#38">Alkass Six</channel>
<channel lang="ar" xmltv_id="AlkassSeven.qa" site_id="sports#39">Alkass Seven</channel>
<channel lang="ar" xmltv_id="AlkassEight.qa" site_id="sports#40">Alkass Eight</channel>
<channel lang="en" xmltv_id="beINMovies1Premiere.qa" site_id="entertainment#1">beIN Movies Premiere</channel>
<channel lang="en" xmltv_id="beINMovies2Action.qa" site_id="entertainment#2">beIN Movies Action</channel>
<channel lang="en" xmltv_id="beINMovies3Drama.qa" site_id="entertainment#3">bein Movies Drama</channel>
<channel lang="en" xmltv_id="beINMovies4Family.qa" site_id="entertainment#4">beIN Movies Family</channel>
<channel lang="en" xmltv_id="FoxMoviesMiddleEast.us" site_id="entertainment#5">FOX Movies</channel>
<channel lang="en" xmltv_id="FoxActionMoviesMiddleEast.hk" site_id="entertainment#6">FOX Action Movies</channel>
<channel lang="en" xmltv_id="StarMoviesMiddleEast.ae" site_id="entertainment#7">Star Movies</channel>
<channel lang="en" xmltv_id="beINSeries1.qa" site_id="entertainment#8">beIN Series 1</channel>
<channel lang="en" xmltv_id="beINSeries2.qa" site_id="entertainment#9">beIN Series 2</channel>
<channel lang="en" xmltv_id="beINDrama1.qa" site_id="entertainment#10">beIN Drama 1</channel>
<channel lang="en" xmltv_id="beINGourmet.qa" site_id="entertainment#11">beIN Gourmet</channel>
<channel lang="en" xmltv_id="TravelChannelEMEA.uk" site_id="entertainment#12">Travel Channel</channel>
<channel lang="en" xmltv_id="FoxArabia.ae" site_id="entertainment#13">FOX</channel>
<channel lang="en" xmltv_id="FoodNetworkEMEA.us" site_id="entertainment#14">Food Network</channel>
<channel lang="en" xmltv_id="HGTVArabia.us" site_id="entertainment#15">HGTV</channel>
<channel lang="en" xmltv_id="StarWorldMiddleEast.ae" site_id="entertainment#16">Star World</channel>
<channel lang="en" xmltv_id="Fatafeat.ae" site_id="entertainment#17">Fatafeat</channel>
<channel lang="en" xmltv_id="FoxLifeMiddleEast.ae" site_id="entertainment#18">FOX Life</channel>
<channel lang="en" xmltv_id="MTV80s.uk" site_id="entertainment#19">MTV 80s</channel>
<channel lang="en" xmltv_id="MTV90s.uk" site_id="entertainment#20">MTV 90s</channel>
<channel lang="en" xmltv_id="ClubMTVEurope.uk" site_id="entertainment#21">Club MTV</channel>
<channel lang="en" xmltv_id="BloombergTVMiddleEast.ae" site_id="entertainment#22">Bloomberg TV</channel>
<channel lang="en" xmltv_id="NationalGeographicMiddleEast.uk" site_id="entertainment#23">National Geographic</channel>
<channel lang="en" xmltv_id="NationalGeographicWildMiddleEast.uk" site_id="entertainment#24">National Geographic Wild</channel>
<channel lang="en" xmltv_id="BBCEarthMiddleEast.uk" site_id="entertainment#25">BBC Earth</channel>
<channel lang="en" xmltv_id="CNNArabic.ae" site_id="entertainment#26">CNN</channel>
<channel lang="en" xmltv_id="EuronewsEnglish.fr" site_id="entertainment#27">EuroNews</channel>
<channel lang="en" xmltv_id="DiscoveryChannelMiddleEastAfrica.us" site_id="entertainment#28">Discovery</channel>
<channel lang="en" xmltv_id="BeJunior.qa" site_id="entertainment#29">be Junior</channel>
<channel lang="en" xmltv_id="JeemTV.qa" site_id="entertainment#30">Jeem</channel>
<channel lang="en" xmltv_id="Baraem.qa" site_id="entertainment#31">Baraem</channel>
<channel lang="en" xmltv_id="CartoonNetworkMENA.uk" site_id="entertainment#32">Cartoon Network</channel>
<channel lang="en" xmltv_id="CartoonNetworkArabic.ae" site_id="entertainment#33">Cartoon Network Arabic</channel>
<channel lang="en" xmltv_id="CartoonNetworkHindi.in" site_id="entertainment#34">Cartoon Network Hindi</channel>
<channel lang="en" xmltv_id="BabyTV.uk" site_id="entertainment#35">Baby TV</channel>
<channel lang="en" xmltv_id="CBeebiesMiddleEast.uk" site_id="entertainment#36">CBeebies</channel>
<channel lang="en" xmltv_id="DreamWorksChannelMiddleEast.us" site_id="entertainment#37">DreamWorks</channel>
<channel lang="ar" xmltv_id="beINMovies1Premiere.qa" site_id="entertainment#1">beIN Movies Premiere</channel>
<channel lang="ar" xmltv_id="beINMovies2Action.qa" site_id="entertainment#2">beIN Movies Action</channel>
<channel lang="ar" xmltv_id="beINMovies3Drama.qa" site_id="entertainment#3">bein Movies Drama</channel>
<channel lang="ar" xmltv_id="beINMovies4Family.qa" site_id="entertainment#4">beIN Movies Family</channel>
<channel lang="ar" xmltv_id="FoxMoviesMiddleEast.us" site_id="entertainment#5">FOX Movies</channel>
<channel lang="ar" xmltv_id="FoxActionMoviesMiddleEast.hk" site_id="entertainment#6">FOX Action Movies</channel>
<channel lang="ar" xmltv_id="StarMoviesMiddleEast.ae" site_id="entertainment#7">Star Movies</channel>
<channel lang="ar" xmltv_id="beINSeries1.qa" site_id="entertainment#8">beIN Series 1</channel>
<channel lang="ar" xmltv_id="beINSeries2.qa" site_id="entertainment#9">beIN Series 2</channel>
<channel lang="ar" xmltv_id="beINDrama1.qa" site_id="entertainment#10">beIN Drama 1</channel>
<channel lang="ar" xmltv_id="beINGourmet.qa" site_id="entertainment#11">beIN Gourmet</channel>
<channel lang="ar" xmltv_id="TravelChannelEMEA.uk" site_id="entertainment#12">Travel Channel</channel>
<channel lang="ar" xmltv_id="FoxArabia.ae" site_id="entertainment#13">FOX</channel>
<channel lang="ar" xmltv_id="FoodNetworkEMEA.us" site_id="entertainment#14">Food Network</channel>
<channel lang="ar" xmltv_id="HGTVArabia.us" site_id="entertainment#15">HGTV</channel>
<channel lang="ar" xmltv_id="StarWorldMiddleEast.ae" site_id="entertainment#16">Star World</channel>
<channel lang="ar" xmltv_id="Fatafeat.ae" site_id="entertainment#17">Fatafeat</channel>
<channel lang="ar" xmltv_id="MTV80s.uk" site_id="entertainment#18">MTV 80s</channel>
<channel lang="ar" xmltv_id="MTV90s.uk" site_id="entertainment#19">MTV 90s</channel>
<channel lang="ar" xmltv_id="ClubMTVEurope.uk" site_id="entertainment#20">Club MTV</channel>
<channel lang="ar" xmltv_id="BeJunior.qa" site_id="entertainment#21">be Junior</channel>
<channel lang="ar" xmltv_id="BloombergTVMiddleEast.ae" site_id="entertainment#22">Bloomberg TV</channel>
<channel lang="ar" xmltv_id="NationalGeographicMiddleEast.uk" site_id="entertainment#23">National Geographic</channel>
<channel lang="ar" xmltv_id="NationalGeographicWildMiddleEast.uk" site_id="entertainment#24">National Geographic Wild</channel>
<channel lang="ar" xmltv_id="BBCEarthMiddleEast.uk" site_id="entertainment#25">BBC Earth</channel>
<channel lang="ar" xmltv_id="AlJazeeraDocumentary.qa" site_id="entertainment#26">Al Jazeera Documentary</channel>
<channel lang="ar" xmltv_id="CNNArabic.ae" site_id="entertainment#27">CNN</channel>
<channel lang="ar" xmltv_id="EuronewsEnglish.fr" site_id="entertainment#28">EuroNews</channel>
<channel lang="ar" xmltv_id="JeemTV.qa" site_id="entertainment#29">Jeem</channel>
<channel lang="ar" xmltv_id="Baraem.qa" site_id="entertainment#30">Baraem</channel>
<channel lang="ar" xmltv_id="CBeebiesMiddleEast.uk" site_id="entertainment#31">CBeebies</channel>
<channel lang="ar" xmltv_id="BabyTV.uk" site_id="entertainment#32">Baby TV</channel>
<channel lang="ar" xmltv_id="CartoonNetworkMENA.uk" site_id="entertainment#33">Cartoon Network</channel>
<channel lang="ar" xmltv_id="CartoonNetworkArabic.ae" site_id="entertainment#34">Cartoon Network Arabic</channel>
<channel lang="ar" xmltv_id="CartoonNetworkHindi.in" site_id="entertainment#35">Cartoon Network Hindi</channel>
<channel lang="ar" xmltv_id="DreamWorksChannelMiddleEast.us" site_id="entertainment#36">DreamWorks</channel>
</channels>
</site>

View File

@@ -0,0 +1,84 @@
const cheerio = require('cheerio')
const dayjs = require('dayjs')
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: 'bein.com',
days: 2,
request: {
cache: {
ttl: 60 * 60 * 1000 // 1 hour
}
},
url: function ({ date, channel }) {
const [category] = channel.site_id.split('#')
const postid = (channel.lang === 'ar') ? '25344' : '25356'
return `https://www.bein.com/${channel.lang}/epg-ajax-template/?action=epg_fetch&category=${category}&cdate=${date.format(
'YYYY-MM-DD'
)}&language=${channel.lang.toUpperCase()}&loadindex=0&mins=00&offset=0&postid=${postid}&serviceidentity=bein.net`
},
parser: function ({ content, channel, date }) {
let programs = []
const items = parseItems(content, channel)
date = date.subtract(1, 'd')
items.forEach(item => {
const $item = cheerio.load(item)
const title = parseTitle($item)
if (!title) return
const category = parseCategory($item)
const prev = programs[programs.length - 1]
let start = parseTime($item, date)
if (prev) {
if (start.isBefore(prev.start)) {
start = start.add(1, 'd')
date = date.add(1, 'd')
}
prev.stop = start
}
let stop = parseTime($item, start)
if (stop.isBefore(start)) {
stop = stop.add(1, 'd')
}
programs.push({
title,
category,
start,
stop
})
})
return programs
}
}
function parseTitle($item) {
return $item('.title').text()
}
function parseCategory($item) {
return $item('.format').text()
}
function parseTime($item, date) {
let [_, time] = $item('.time')
.text()
.match(/^(\d{2}:\d{2})/) || [null, null]
if (!time) return null
time = `${date.format('YYYY-MM-DD')} ${time}`
return dayjs.tz(time, 'YYYY-MM-DD HH:mm', 'Asia/Qatar')
}
function parseItems(content, channel) {
const [_, channelId] = channel.site_id.split('#')
const $ = cheerio.load(content)
return $(`#channels_${channelId} .slider > ul:first-child > li`).toArray()
}

View File

@@ -0,0 +1,60 @@
// npx epg-grabber --config=sites/bein.com/bein.com.config.js --channels=sites/bein.com/bein.com.channels.xml --output=guide.xml --timeout=30000 --days=2
const fs = require('fs')
const path = require('path')
const { parser, url } = require('./bein.com.config.js')
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('2023-01-19', 'YYYY-MM-DD').startOf('d')
const channel = { site_id: 'entertainment#1', xmltv_id: 'beINMovies1Premiere.qa', lang: 'en' }
it('can generate valid url', () => {
const result = url({ date, channel })
expect(result).toBe(
'https://www.bein.com/en/epg-ajax-template/?action=epg_fetch&category=entertainment&cdate=2023-01-19&language=EN&loadindex=0&mins=00&offset=0&postid=25356&serviceidentity=bein.net'
)
})
it('can parse response', () => {
const content = fs.readFileSync(path.resolve('sites/bein.com/__data__/content.html'))
const results = parser({ date, channel, content }).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(results[0]).toMatchObject({
start: '2023-01-18T20:15:00.000Z',
stop: '2023-01-18T22:15:00.000Z',
title: 'The Walk',
category: 'Movies'
})
expect(results[1]).toMatchObject({
start: '2023-01-18T22:15:00.000Z',
stop: '2023-01-19T00:00:00.000Z',
title: 'Resident Evil: Welcome To Raccoon City',
category: 'Movies'
})
expect(results[10]).toMatchObject({
start: '2023-01-19T15:30:00.000Z',
stop: '2023-01-19T18:00:00.000Z',
title: 'Spider-Man: No Way Home',
category: 'Movies'
})
})
it('can handle empty guide', () => {
const noContent = fs.readFileSync(path.resolve('sites/bein.com/__data__/no-content.html'))
const result = parser({
date,
channel,
content: noContent
})
expect(result).toMatchObject([])
})

View File

@@ -0,0 +1,297 @@
<script>
currenthour=10;
</script>
<div class=containertop>
<div class='row no-gutter'>
<div class='col-xs-12 col-sm-12 col-md-12 col-lg-12'>
<table width=100% border=0 class=day_table><tr><script language=javascript>lastday='day1';</script><td><div id=day1t1 style=width:100% class=day_item_selected><a href=javascript:loaders('utctime_hk.php?cdate=2022-05-10&offset=0&mins=00&category=sports',2)>Tue</a></div><div id=day1t2 style=width:100% class=day_item1_selected><a href=javascript:loaders('utctime_hk.php?cdate=2022-05-10&offset=0&mins=00&category=sports',2)>10</a></div></td><td><span id=day2t1 style=width:100% class=day_item><a href=javascript:selectday('day2');loaders('utctime_hk.php?cdate=2022-05-11&offset=0&mins=00&category=sports',2)>Wed</a></span><span id=day2t2 style=width:100% class=day_item1><a href=javascript:selectday('day2');loaders('utctime_hk.php?cdate=2022-05-11&offset=0&mins=00&category=sports',2)>11</a></div></td><td><span id=day3t1 style=width:100% class=day_item><a href=javascript:selectday('day3');loaders('utctime_hk.php?cdate=2022-05-12&offset=0&mins=00&category=sports',2)>Thu</a></span><span id=day3t2 style=width:100% class=day_item1><a href=javascript:selectday('day3');loaders('utctime_hk.php?cdate=2022-05-12&offset=0&mins=00&category=sports',2)>12</a></div></td><td><span id=day4t1 style=width:100% class=day_item><a href=javascript:selectday('day4');loaders('utctime_hk.php?cdate=2022-05-13&offset=0&mins=00&category=sports',2)>Fri</a></span><span id=day4t2 style=width:100% class=day_item1><a href=javascript:selectday('day4');loaders('utctime_hk.php?cdate=2022-05-13&offset=0&mins=00&category=sports',2)>13</a></div></td><td><span id=day5t1 style=width:100% class=day_item><a href=javascript:selectday('day5');loaders('utctime_hk.php?cdate=2022-05-14&offset=0&mins=00&category=sports',2)>Sat</a></span><span id=day5t2 style=width:100% class=day_item1><a href=javascript:selectday('day5');loaders('utctime_hk.php?cdate=2022-05-14&offset=0&mins=00&category=sports',2)>14</a></div></td><td><span id=day6t1 style=width:100% class=day_item><a href=javascript:selectday('day6');loaders('utctime_hk.php?cdate=2022-05-15&offset=0&mins=00&category=sports',2)>Sun</a></span><span id=day6t2 style=width:100% class=day_item1><a href=javascript:selectday('day6');loaders('utctime_hk.php?cdate=2022-05-15&offset=0&mins=00&category=sports',2)>15</a></div></td><td><span id=day7t1 style=width:100% class=day_item><a href=javascript:selectday('day7');loaders('utctime_hk.php?cdate=2022-05-16&offset=0&mins=00&category=sports',2)>Mon</a></span><span id=day7t2 style=width:100% class=day_item1><a href=javascript:selectday('day7');loaders('utctime_hk.php?cdate=2022-05-16&offset=0&mins=00&category=sports',2)>16</a></div></td></table></div>
</div><div class='row no-gutter'>
<div class='col-xs-12 col-sm-12 col-md-12 col-lg-12'>
<div style='background-color:#d1d0de;margin:0px auto;text-align:center;display:flex;width:100%'><div id=left style=width:25px;background-color:red;height:50px;padding-top:13px;background-color:#d1d0de;><img src=ico/left.png onclick=ptime()></div><div id='slider_timer' class='slider_time'>
<ul id='timer'></ul></div><div id=left style=width:25px;background-color:red;height:50px;padding-top:13px;background-color:#d1d0de><img src=ico/right.png onclick=ntime()></div></div>
</div>
</div><div class='row no-gutter' style='height:15px'></div>
<div class='row no-gutter'>
<div class='col-xs-12 col-sm-12 col-md-12 col-lg-12'>
<div id='loader_inner' style='display:none;margin:0 auto;width:100%;margin-top:5px;margin-bottom:5px;text-align:center'>
<div style='text-align:center;margin:auto 0'><img align=center src='images/ajax-loader.gif'></div>
</div>
</div>
</div>
</div><div class='container'><div class='row no-gutter' >
<div style='display:none;min-height:1000px' class='col-xs-12 col-sm-12 col-md-12 col-lg-12' id='category_div'>
</div>
</div>
<div id='epg_div'><div class='row no-gutter' id=channels_1>
<div class='col-xs-3 col-sm-2 col-md-2 col-lg-1'>
<div style='width:100%;text-align:center;'>
<div class=channel>
<div class=centered>
<img align=center style='width:60%;height:auto' src='hk_sports/BS1.svg'>
</div>
</div>
</div>
</div>
<div class='col-xs-8 col-sm-9 col-md-9 col-lg-10'>
<div id='slider_1' class=slider><ul id='ul_slider_1'>
<li id='slider_1_item1' data-id='slider_1_item1' data-index='1' data-start='0' data-start-m='0' data-end='00 data-end-m='10' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Serie A 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Lazio vs Sampdoria</p>
<p class=format>Serie A 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>22:20&nbsp;-&nbsp;00:10</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item2' data-id='slider_1_item2' data-index='2' data-start='00' data-start-m='10' data-end='02' data-end-m='00' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Super Lig 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Alanyaspor vs Konyaspor</p>
<p class=format>Super Lig 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>00:10&nbsp;-&nbsp;02:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item3' data-id='slider_1_item3' data-index='3' data-start='02' data-start-m='00' data-end='04' data-end-m='00' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Liverpool TV 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Liverpool vs Tottenham</p>
<p class=format>Liverpool TV 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>02:00&nbsp;-&nbsp;04:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item4' data-id='slider_1_item4' data-index='4' data-start='04' data-start-m='00' data-end='04' data-end-m='30' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='LFC Trending 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Episode Number 41</p>
<p class=format>LFC Trending 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>04:00&nbsp;-&nbsp;04:30</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item5' data-id='slider_1_item5' data-index='5' data-start='04' data-start-m='30' data-end='05' data-end-m='00' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='LFC TV Specials 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Villarreal vs Liverpool</p>
<p class=format>LFC TV Specials 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>04:30&nbsp;-&nbsp;05:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item6' data-id='slider_1_item6' data-index='6' data-start='05' data-start-m='00' data-end='06' data-end-m='50' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Serie A 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Fiorentina vs Roma</p>
<p class=format>Serie A 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>05:00&nbsp;-&nbsp;06:50</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item7' data-id='slider_1_item7' data-index='7' data-start='06' data-start-m='50' data-end='07' data-end-m='20' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='International Tour of Hellas 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>Day 5</p>
<p class=format>International Tour of Hellas 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>06:50&nbsp;-&nbsp;07:20</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item8' data-id='slider_1_item8' data-index='8' data-start='07' data-start-m='20' data-end='08' data-end-m='20' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Ligue 1 Highlights 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>MD 36</p>
<p class=format>Ligue 1 Highlights 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>07:20&nbsp;-&nbsp;08:20</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item9' data-id='slider_1_item9' data-index='9' data-start='08' data-start-m='20' data-end='10' data-end-m='10' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='TotalEnergies CAF Champions League 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Petro de Luanda vs WAC</p>
<p class=format>TotalEnergies CAF Champions League 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>08:20&nbsp;-&nbsp;10:10</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item10' data-id='slider_1_item10' data-index='10' data-start='10' data-start-m='10' data-end='12' data-end-m='00' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Serie A 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Genoa vs Juventus</p>
<p class=format>Serie A 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>10:10&nbsp;-&nbsp;12:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ><p></td></tr><tr><td ><div class='progress' currents=true><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='24' aria-valuemin='0' aria-valuemax='100' style='width:24.545454545455%'></div></div></tr></table> </li>
<li id='slider_1_item11' data-id='slider_1_item11' data-index='11' data-start='12' data-start-m='00' data-end='12' data-end-m='30' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Chelsea TV: Premier League Years 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Premier League Years 92/93 93/94</p>
<p class=format>Chelsea TV: Premier League Years 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>12:00&nbsp;-&nbsp;12:30</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item12' data-id='slider_1_item12' data-index='12' data-start='12' data-start-m='30' data-end='13' data-end-m='00' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Inside Chelsea 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Episode Number 38</p>
<p class=format>Inside Chelsea 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>12:30&nbsp;-&nbsp;13:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item13' data-id='slider_1_item13' data-index='13' data-start='13' data-start-m='00' data-end='15' data-end-m='00' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Chelsea TV 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Chelsea vs Wolves</p>
<p class=format>Chelsea TV 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>13:00&nbsp;-&nbsp;15:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item14' data-id='slider_1_item14' data-index='14' data-start='15' data-start-m='00' data-end='16' data-end-m='50' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Serie A 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Fiorentina vs Roma</p>
<p class=format>Serie A 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>15:00&nbsp;-&nbsp;16:50</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item15' data-id='slider_1_item15' data-index='15' data-start='16' data-start-m='50' data-end='18' data-end-m='45' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Coupe de France 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Nice vs Nantes</p>
<p class=format>Coupe de France 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>16:50&nbsp;-&nbsp;18:45</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item16' data-id='slider_1_item16' data-index='16' data-start='18' data-start-m='45' data-end='20' data-end-m='35' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='TotalEnergies CAF Confederation Cup 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>TP Mazembe vs RS Berkane</p>
<p class=format>TotalEnergies CAF Confederation Cup 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>18:45&nbsp;-&nbsp;20:35</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item17' data-id='slider_1_item17' data-index='17' data-start='20' data-start-m='35' data-end='22' data-end-m='20' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Ligue 1 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Angers vs Bordeaux</p>
<p class=format>Ligue 1 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>20:35&nbsp;-&nbsp;22:20</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item18' data-id='slider_1_item18' data-index='18' data-start='22' data-start-m='20' data-end='00' data-end-m='10' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Serie A 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Genoa vs Juventus</p>
<p class=format>Serie A 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>22:20&nbsp;-&nbsp;00:10</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<div><ul><li class=item_normal></li><li class=item_normal></li></ul> </ul></div>
</div>
<div class='col-xs-1 nextarrow col-sm-1 nextarrow col-md-1 nextarrow col-lg-1 nextarrow'>
<div class='centered'>
<img align=center width=15 height=15 src=images/nextarrow_en.svg style=cursor:pointer onclick=action('slider_1')>
</div>
</div>
</div>
<div class='row no-gutter' style='height:15px' id='ruler_channels_1'></div>
<div class='row no-gutter' id=channels_2>
<div class='col-xs-3 col-sm-2 col-md-2 col-lg-1'>
<div style='width:100%;text-align:center;'>
<div class=channel>
<div class=centered>
<img align=center style='width:60%;height:auto' src='hk_sports/BS2.svg'>
</div>
</div>
</div>
</div>
<div class='col-xs-8 col-sm-9 col-md-9 col-lg-10'>
<div id='slider_2' class=slider><ul id='ul_slider_2'>
<li id='slider_2_item1' data-id='slider_2_item1' data-index='1' data-start='0' data-start-m='0' data-end='00 data-end-m='20' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Ligue 1 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Lorient vs Marseille</p>
<p class=format>Ligue 1 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>22:30&nbsp;-&nbsp;00:20</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item2' data-id='slider_2_item2' data-index='2' data-start='00' data-start-m='20' data-end='02' data-end-m='10' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Major League Soccer 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>LAFC vs Philadelphia</p>
<p class=format>Major League Soccer 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>00:20&nbsp;-&nbsp;02:10</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item3' data-id='slider_2_item3' data-index='3' data-start='02' data-start-m='10' data-end='04' data-end-m='00' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Major League Soccer 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>Dallas vs Seattle</p>
<p class=format>Major League Soccer 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>02:10&nbsp;-&nbsp;04:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item4' data-id='slider_2_item4' data-index='4' data-start='04' data-start-m='00' data-end='05' data-end-m='00' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Supercars Championship Highlights 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>Bunnings Trade Perth Supernight Sat</p>
<p class=format>Supercars Championship Highlights 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>04:00&nbsp;-&nbsp;05:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item5' data-id='slider_2_item5' data-index='5' data-start='05' data-start-m='00' data-end='06' data-end-m='50' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Challenge Cup 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Edinburgh vs Wasps</p>
<p class=format>Challenge Cup 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>05:00&nbsp;-&nbsp;06:50</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item6' data-id='slider_2_item6' data-index='6' data-start='06' data-start-m='50' data-end='08' data-end-m='20' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='DTM Race 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>Portimao Race 1</p>
<p class=format>DTM Race 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>06:50&nbsp;-&nbsp;08:20</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item7' data-id='slider_2_item7' data-index='7' data-start='08' data-start-m='20' data-end='10' data-end-m='10' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Challenge Cup 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Lyon vs Glasgow</p>
<p class=format>Challenge Cup 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>08:20&nbsp;-&nbsp;10:10</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item8' data-id='slider_2_item8' data-index='8' data-start='10' data-start-m='10' data-end='12' data-end-m='00' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Ligue 1 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>PSG vs Troyes</p>
<p class=format>Ligue 1 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>10:10&nbsp;-&nbsp;12:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ><p></td></tr><tr><td ><div class='progress' currents=true><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='24' aria-valuemin='0' aria-valuemax='100' style='width:24.545454545455%'></div></div></tr></table> </li>
<li id='slider_2_item9' data-id='slider_2_item9' data-index='9' data-start='12' data-start-m='00' data-end='12' data-end-m='30' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='This Is Paris 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Episode Number 37</p>
<p class=format>This Is Paris 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>12:00&nbsp;-&nbsp;12:30</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item10' data-id='slider_2_item10' data-index='10' data-start='12' data-start-m='30' data-end='13' data-end-m='00' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='MLS Show 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>RD 10</p>
<p class=format>MLS Show 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>12:30&nbsp;-&nbsp;13:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item11' data-id='slider_2_item11' data-index='11' data-start='13' data-start-m='00' data-end='14' data-end-m='00' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Ferrari Challenge Highlights 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>Portimao</p>
<p class=format>Ferrari Challenge Highlights 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>13:00&nbsp;-&nbsp;14:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item12' data-id='slider_2_item12' data-index='12' data-start='14' data-start-m='00' data-end='14' data-end-m='15' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='SPFL Highlights 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>MD 36</p>
<p class=format>SPFL Highlights 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>14:00&nbsp;-&nbsp;14:15</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item13' data-id='slider_2_item13' data-index='13' data-start='14' data-start-m='15' data-end='16' data-end-m='00' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='SPFL Premiership 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Celtic vs Hearts</p>
<p class=format>SPFL Premiership 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>14:15&nbsp;-&nbsp;16:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item14' data-id='slider_2_item14' data-index='14' data-start='16' data-start-m='00' data-end='17' data-end-m='00' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='British Superbike Championship Highlights 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>Oulton Park</p>
<p class=format>British Superbike Championship Highlights 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>16:00&nbsp;-&nbsp;17:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item15' data-id='slider_2_item15' data-index='15' data-start='17' data-start-m='00' data-end='17' data-end-m='50' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='FIM Speedway GP Highlights 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>Gorican</p>
<p class=format>FIM Speedway GP Highlights 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>17:00&nbsp;-&nbsp;17:50</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item16' data-id='slider_2_item16' data-index='16' data-start='17' data-start-m='50' data-end='18' data-end-m='00' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Ligue 1 Club Classic 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>PSG vs Lyon</p>
<p class=format>Ligue 1 Club Classic 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>17:50&nbsp;-&nbsp;18:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item17' data-id='slider_2_item17' data-index='17' data-start='18' data-start-m='00' data-end='20' data-end-m='10' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='SPFL Premiership 2021/22' live='1'invalid=false>
<div class=onecontent>
<p class=title>Inverness CT vs Arbroath</p>
<p class=format>SPFL Premiership 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>18:00&nbsp;-&nbsp;20:10</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/live.svg' class=image_live_css ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item18' data-id='slider_2_item18' data-index='18' data-start='20' data-start-m='10' data-end='20' data-end-m='40' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='MLS Show 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>RD 10</p>
<p class=format>MLS Show 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>20:10&nbsp;-&nbsp;20:40</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item19' data-id='slider_2_item19' data-index='19' data-start='20' data-start-m='40' data-end='22' data-end-m='30' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Champions Cup 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Racing 92 vs Sale</p>
<p class=format>Champions Cup 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>20:40&nbsp;-&nbsp;22:30</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item20' data-id='slider_2_item20' data-index='20' data-start='22' data-start-m='30' data-end='00' data-end-m='20' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Ligue 1 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Metz vs Lyon</p>
<p class=format>Ligue 1 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>22:30&nbsp;-&nbsp;00:20</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<div><ul><li class=item_normal></li><li class=item_normal></li></ul> </ul></div>
</div>
<div class='col-xs-1 nextarrow col-sm-1 nextarrow col-md-1 nextarrow col-lg-1 nextarrow'>
<div class='centered'>
<img align=center width=15 height=15 src=images/nextarrow_en.svg style=cursor:pointer onclick=action('slider_2')>
</div>
</div>
</div>
<div class='row no-gutter' style='height:15px' id='ruler_channels_2'></div>
</div>
</div></div></div>
<div id="immobile" style="display:'none'"></div><div id="imtablet" style="display:'none'"></div><div id="imdesktop" style="display:'none'"></div>

View File

@@ -0,0 +1,297 @@
<script>
currenthour=10;
</script>
<div class=containertop>
<div class='row no-gutter'>
<div class='col-xs-12 col-sm-12 col-md-12 col-lg-12'>
<table width=100% border=0 class=day_table><tr><td><span id=day1t1 style=width:100% class=day_item><a href=javascript:selectday('day1');loaders('utctime_hk.php?cdate=2022-05-10&offset=0&mins=00&category=sports',2)>Tue</a></span><span id=day1t2 style=width:100% class=day_item1><a href=javascript:selectday('day1');loaders('utctime_hk.php?cdate=2022-05-10&offset=0&mins=00&category=sports',2)>10</a></div></td><script language=javascript>lastday='day2';</script><td><div id=day2t1 style=width:100% class=day_item_selected><a href=javascript:loaders('utctime_hk.php?cdate=2022-05-11&offset=0&mins=00&category=sports',2)>Wed</a></div><div id=day2t2 style=width:100% class=day_item1_selected><a href=javascript:loaders('utctime_hk.php?cdate=2022-05-11&offset=0&mins=00&category=sports',2)>11</a></div></td><td><span id=day3t1 style=width:100% class=day_item><a href=javascript:selectday('day3');loaders('utctime_hk.php?cdate=2022-05-12&offset=0&mins=00&category=sports',2)>Thu</a></span><span id=day3t2 style=width:100% class=day_item1><a href=javascript:selectday('day3');loaders('utctime_hk.php?cdate=2022-05-12&offset=0&mins=00&category=sports',2)>12</a></div></td><td><span id=day4t1 style=width:100% class=day_item><a href=javascript:selectday('day4');loaders('utctime_hk.php?cdate=2022-05-13&offset=0&mins=00&category=sports',2)>Fri</a></span><span id=day4t2 style=width:100% class=day_item1><a href=javascript:selectday('day4');loaders('utctime_hk.php?cdate=2022-05-13&offset=0&mins=00&category=sports',2)>13</a></div></td><td><span id=day5t1 style=width:100% class=day_item><a href=javascript:selectday('day5');loaders('utctime_hk.php?cdate=2022-05-14&offset=0&mins=00&category=sports',2)>Sat</a></span><span id=day5t2 style=width:100% class=day_item1><a href=javascript:selectday('day5');loaders('utctime_hk.php?cdate=2022-05-14&offset=0&mins=00&category=sports',2)>14</a></div></td><td><span id=day6t1 style=width:100% class=day_item><a href=javascript:selectday('day6');loaders('utctime_hk.php?cdate=2022-05-15&offset=0&mins=00&category=sports',2)>Sun</a></span><span id=day6t2 style=width:100% class=day_item1><a href=javascript:selectday('day6');loaders('utctime_hk.php?cdate=2022-05-15&offset=0&mins=00&category=sports',2)>15</a></div></td><td><span id=day7t1 style=width:100% class=day_item><a href=javascript:selectday('day7');loaders('utctime_hk.php?cdate=2022-05-16&offset=0&mins=00&category=sports',2)>Mon</a></span><span id=day7t2 style=width:100% class=day_item1><a href=javascript:selectday('day7');loaders('utctime_hk.php?cdate=2022-05-16&offset=0&mins=00&category=sports',2)>16</a></div></td></table></div>
</div><div class='row no-gutter'>
<div class='col-xs-12 col-sm-12 col-md-12 col-lg-12'>
<div style='background-color:#d1d0de;margin:0px auto;text-align:center;display:flex;width:100%'><div id=left style=width:25px;background-color:red;height:50px;padding-top:13px;background-color:#d1d0de;><img src=ico/left.png onclick=ptime()></div><div id='slider_timer' class='slider_time'>
<ul id='timer'></ul></div><div id=left style=width:25px;background-color:red;height:50px;padding-top:13px;background-color:#d1d0de><img src=ico/right.png onclick=ntime()></div></div>
</div>
</div><div class='row no-gutter' style='height:15px'></div>
<div class='row no-gutter'>
<div class='col-xs-12 col-sm-12 col-md-12 col-lg-12'>
<div id='loader_inner' style='display:none;margin:0 auto;width:100%;margin-top:5px;margin-bottom:5px;text-align:center'>
<div style='text-align:center;margin:auto 0'><img align=center src='images/ajax-loader.gif'></div>
</div>
</div>
</div>
</div><div class='container'><div class='row no-gutter' >
<div style='display:none;min-height:1000px' class='col-xs-12 col-sm-12 col-md-12 col-lg-12' id='category_div'>
</div>
</div>
<div id='epg_div'><div class='row no-gutter' id=channels_1>
<div class='col-xs-3 col-sm-2 col-md-2 col-lg-1'>
<div style='width:100%;text-align:center;'>
<div class=channel>
<div class=centered>
<img align=center style='width:60%;height:auto' src='hk_sports/BS1.svg'>
</div>
</div>
</div>
</div>
<div class='col-xs-8 col-sm-9 col-md-9 col-lg-10'>
<div id='slider_1' class=slider><ul id='ul_slider_1'>
<li id='slider_1_item1' data-id='slider_1_item1' data-index='1' data-start='00' data-start-m='10' data-end='02' data-end-m='00' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Super Lig 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Besiktas vs Fenerbahce</p>
<p class=format>Super Lig 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>00:10&nbsp;-&nbsp;02:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item2' data-id='slider_1_item2' data-index='2' data-start='02' data-start-m='00' data-end='02' data-end-m='30' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Chelsea TV: Premier League Years 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Premier League Years 92/93 93/94</p>
<p class=format>Chelsea TV: Premier League Years 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>02:00&nbsp;-&nbsp;02:30</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item3' data-id='slider_1_item3' data-index='3' data-start='02' data-start-m='30' data-end='03' data-end-m='00' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Inside Chelsea 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Episode Number 38</p>
<p class=format>Inside Chelsea 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>02:30&nbsp;-&nbsp;03:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item4' data-id='slider_1_item4' data-index='4' data-start='03' data-start-m='00' data-end='05' data-end-m='00' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Chelsea TV 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Chelsea vs Wolves</p>
<p class=format>Chelsea TV 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>03:00&nbsp;-&nbsp;05:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item5' data-id='slider_1_item5' data-index='5' data-start='05' data-start-m='00' data-end='06' data-end-m='50' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Serie A 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Sassuolo vs Udinese</p>
<p class=format>Serie A 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>05:00&nbsp;-&nbsp;06:50</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item6' data-id='slider_1_item6' data-index='6' data-start='06' data-start-m='50' data-end='08' data-end-m='40' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='TotalEnergies CAF Champions League 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Al Ahly FC vs ES Setif</p>
<p class=format>TotalEnergies CAF Champions League 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>06:50&nbsp;-&nbsp;08:40</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item7' data-id='slider_1_item7' data-index='7' data-start='08' data-start-m='40' data-end='09' data-end-m='40' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Ligue 1 Highlights 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>MD 36</p>
<p class=format>Ligue 1 Highlights 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>08:40&nbsp;-&nbsp;09:40</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item8' data-id='slider_1_item8' data-index='8' data-start='09' data-start-m='40' data-end='11' data-end-m='30' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Serie A 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Torino vs Napoli</p>
<p class=format>Serie A 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>09:40&nbsp;-&nbsp;11:30</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item9' data-id='slider_1_item9' data-index='9' data-start='11' data-start-m='30' data-end='12' data-end-m='00' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Serie A Full Impact 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>MD 36</p>
<p class=format>Serie A Full Impact 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>11:30&nbsp;-&nbsp;12:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item10' data-id='slider_1_item10' data-index='10' data-start='12' data-start-m='00' data-end='12' data-end-m='30' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Arsenal World 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Episode Number 39</p>
<p class=format>Arsenal World 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>12:00&nbsp;-&nbsp;12:30</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item11' data-id='slider_1_item11' data-index='11' data-start='12' data-start-m='30' data-end='13' data-end-m='00' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Arsenal 360 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Episode Number 39</p>
<p class=format>Arsenal 360 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>12:30&nbsp;-&nbsp;13:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item12' data-id='slider_1_item12' data-index='12' data-start='13' data-start-m='00' data-end='15' data-end-m='00' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Arsenal TV 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Arsenal vs Leeds</p>
<p class=format>Arsenal TV 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>13:00&nbsp;-&nbsp;15:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item13' data-id='slider_1_item13' data-index='13' data-start='15' data-start-m='00' data-end='17' data-end-m='00' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Liverpool TV 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Aston Villa vs Liverpool</p>
<p class=format>Liverpool TV 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>15:00&nbsp;-&nbsp;17:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item14' data-id='slider_1_item14' data-index='14' data-start='17' data-start-m='00' data-end='17' data-end-m='30' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='LFC Trending 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Episode Number 41</p>
<p class=format>LFC Trending 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>17:00&nbsp;-&nbsp;17:30</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item15' data-id='slider_1_item15' data-index='15' data-start='17' data-start-m='30' data-end='18' data-end-m='00' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='LFC TV Specials 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Villarreal vs Liverpool</p>
<p class=format>LFC TV Specials 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>17:30&nbsp;-&nbsp;18:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item16' data-id='slider_1_item16' data-index='16' data-start='18' data-start-m='00' data-end='18' data-end-m='10' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Serie A Highlights 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Genoa vs Napoli</p>
<p class=format>Serie A Highlights 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>18:00&nbsp;-&nbsp;18:10</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item17' data-id='slider_1_item17' data-index='17' data-start='18' data-start-m='10' data-end='18' data-end-m='25' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='SPFL Highlights 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>MD 36</p>
<p class=format>SPFL Highlights 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>18:10&nbsp;-&nbsp;18:25</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item18' data-id='slider_1_item18' data-index='18' data-start='18' data-start-m='25' data-end='20' data-end-m='30' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='SPFL Premiership 2021/22' live='1'invalid=false>
<div class=onecontent>
<p class=title>Dundee Utd vs Celtic</p>
<p class=format>SPFL Premiership 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>18:25&nbsp;-&nbsp;20:30</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/live.svg' class=image_live_css ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item19' data-id='slider_1_item19' data-index='19' data-start='20' data-start-m='30' data-end='22' data-end-m='20' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Ligue 1 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Brest vs Strasbourg</p>
<p class=format>Ligue 1 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>20:30&nbsp;-&nbsp;22:20</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_1_item20' data-id='slider_1_item20' data-index='20' data-start='22' data-start-m='20' data-end='00' data-end-m='10' data-img='hk_sports/BS1.svg' data-desc='' parent='slider_1' category='Serie A 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Fiorentina vs Roma</p>
<p class=format>Serie A 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>22:20&nbsp;-&nbsp;00:10</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<div><ul><li class=item_normal></li><li class=item_normal></li></ul> </ul></div>
</div>
<div class='col-xs-1 nextarrow col-sm-1 nextarrow col-md-1 nextarrow col-lg-1 nextarrow'>
<div class='centered'>
<img align=center width=15 height=15 src=images/nextarrow_en.svg style=cursor:pointer onclick=action('slider_1')>
</div>
</div>
</div>
<div class='row no-gutter' style='height:15px' id='ruler_channels_1'></div>
<div class='row no-gutter' id=channels_2>
<div class='col-xs-3 col-sm-2 col-md-2 col-lg-1'>
<div style='width:100%;text-align:center;'>
<div class=channel>
<div class=centered>
<img align=center style='width:60%;height:auto' src='hk_sports/BS2.svg'>
</div>
</div>
</div>
</div>
<div class='col-xs-8 col-sm-9 col-md-9 col-lg-10'>
<div id='slider_2' class=slider><ul id='ul_slider_2'>
<li id='slider_2_item1' data-id='slider_2_item1' data-index='1' data-start='00' data-start-m='20' data-end='02' data-end-m='10' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='SPFL Premiership 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Celtic vs Hearts</p>
<p class=format>SPFL Premiership 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>00:20&nbsp;-&nbsp;02:10</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item2' data-id='slider_2_item2' data-index='2' data-start='02' data-start-m='10' data-end='04' data-end-m='00' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='SPFL Premiership 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Inverness CT vs Arbroath</p>
<p class=format>SPFL Premiership 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>02:10&nbsp;-&nbsp;04:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item3' data-id='slider_2_item3' data-index='3' data-start='04' data-start-m='00' data-end='05' data-end-m='00' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Supercars Championship Highlights 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>Bunnings Trade Perth Supernight Sun</p>
<p class=format>Supercars Championship Highlights 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>04:00&nbsp;-&nbsp;05:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item4' data-id='slider_2_item4' data-index='4' data-start='05' data-start-m='00' data-end='06' data-end-m='50' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Ligue 1 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Brest vs Strasbourg</p>
<p class=format>Ligue 1 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>05:00&nbsp;-&nbsp;06:50</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item5' data-id='slider_2_item5' data-index='5' data-start='06' data-start-m='50' data-end='08' data-end-m='20' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='DTM Race 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>Portimao Race 2</p>
<p class=format>DTM Race 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>06:50&nbsp;-&nbsp;08:20</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item6' data-id='slider_2_item6' data-index='6' data-start='08' data-start-m='20' data-end='10' data-end-m='10' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Champions Cup 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Leicester vs Leinster</p>
<p class=format>Champions Cup 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>08:20&nbsp;-&nbsp;10:10</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item7' data-id='slider_2_item7' data-index='7' data-start='10' data-start-m='10' data-end='12' data-end-m='00' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Ligue 1 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Lorient vs Marseille</p>
<p class=format>Ligue 1 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>10:10&nbsp;-&nbsp;12:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item8' data-id='slider_2_item8' data-index='8' data-start='12' data-start-m='00' data-end='12' data-end-m='50' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Porsche Carrera Cup Germany 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>Spa Race 1</p>
<p class=format>Porsche Carrera Cup Germany 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>12:00&nbsp;-&nbsp;12:50</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item9' data-id='slider_2_item9' data-index='9' data-start='12' data-start-m='50' data-end='13' data-end-m='40' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Porsche Carrera Cup Germany 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>Spa Race 2</p>
<p class=format>Porsche Carrera Cup Germany 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>12:50&nbsp;-&nbsp;13:40</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item10' data-id='slider_2_item10' data-index='10' data-start='13' data-start-m='40' data-end='14' data-end-m='10' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='UIM X-Cat World Championship 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>Fujairah</p>
<p class=format>UIM X-Cat World Championship 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>13:40&nbsp;-&nbsp;14:10</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item11' data-id='slider_2_item11' data-index='11' data-start='14' data-start-m='10' data-end='15' data-end-m='55' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Ligue 1 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Lille vs Monaco</p>
<p class=format>Ligue 1 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>14:10&nbsp;-&nbsp;15:55</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item12' data-id='slider_2_item12' data-index='12' data-start='15' data-start-m='55' data-end='16' data-end-m='25' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='MLS Show 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>RD 10</p>
<p class=format>MLS Show 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>15:55&nbsp;-&nbsp;16:25</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item13' data-id='slider_2_item13' data-index='13' data-start='16' data-start-m='25' data-end='16' data-end-m='55' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Mini Match - Ligue 1 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>PSG vs Troyes</p>
<p class=format>Mini Match - Ligue 1 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>16:25&nbsp;-&nbsp;16:55</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item14' data-id='slider_2_item14' data-index='14' data-start='16' data-start-m='55' data-end='18' data-end-m='55' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Ligue 1 2021/22' live='1'invalid=false>
<div class=onecontent>
<p class=title>Nice vs St Etienne</p>
<p class=format>Ligue 1 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>16:55&nbsp;-&nbsp;18:55</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/live.svg' class=image_live_css ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item15' data-id='slider_2_item15' data-index='15' data-start='18' data-start-m='55' data-end='21' data-end-m='00' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Ligue 1 2021/22' live='1'invalid=false>
<div class=onecontent>
<p class=title>Nantes vs Rennes</p>
<p class=format>Ligue 1 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>18:55&nbsp;-&nbsp;21:00</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/live.svg' class=image_live_css ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item16' data-id='slider_2_item16' data-index='16' data-start='21' data-start-m='00' data-end='21' data-end-m='30' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Mini Match - Ligue 1 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>Lorient vs Marseille</p>
<p class=format>Mini Match - Ligue 1 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>21:00&nbsp;-&nbsp;21:30</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item17' data-id='slider_2_item17' data-index='17' data-start='21' data-start-m='30' data-end='22' data-end-m='30' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Supercars Championship Highlights 2022' live=''invalid=false>
<div class=onecontent>
<p class=title>Bunnings Trade Perth Supernight Sat</p>
<p class=format>Supercars Championship Highlights 2022</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>21:30&nbsp;-&nbsp;22:30</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<li id='slider_2_item18' data-id='slider_2_item18' data-index='18' data-start='22' data-start-m='30' data-end='00' data-end-m='20' data-img='hk_sports/BS2.svg' data-desc='' parent='slider_2' category='Ligue 1 2021/22' live=''invalid=false>
<div class=onecontent>
<p class=title>PSG vs Troyes</p>
<p class=format>Ligue 1 2021/22</p>
</div>
<div class=timer><table border=0 cellspacing=0 cellpadding=0 width=100%><tr><td style=width:80%><p class=time>22:30&nbsp;-&nbsp;00:20</td><td style=width:20% rowspan=2 valign=top class=showornot><img src='images/transparent.png' width=80 height=27 ></p></td></tr><tr><td><div class='progress'><div class='progress-bar progress-bar-custom' role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100'></div></div></tr></table> </li>
<div><ul><li class=item_normal></li><li class=item_normal></li></ul> </ul></div>
</div>
<div class='col-xs-1 nextarrow col-sm-1 nextarrow col-md-1 nextarrow col-lg-1 nextarrow'>
<div class='centered'>
<img align=center width=15 height=15 src=images/nextarrow_en.svg style=cursor:pointer onclick=action('slider_2')>
</div>
</div>
</div>
<div class='row no-gutter' style='height:15px' id='ruler_channels_2'></div>
</div>
</div></div></div>
<div id="immobile" style="display:'none'"></div><div id="imtablet" style="display:'none'"></div><div id="imdesktop" style="display:'none'"></div>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
<script>
currenthour="13";
</script>
<div class=container>
<div class='row no-gutter'>
<div class='col-xs-12 col-sm-12 col-md-12 col-lg-12'>
</div></div><div class='row no-gutter'>
<div class='col-xs-12 col-sm-12 col-md-12 col-lg-12'>
<table width=100% border=0 class=day_table><tr><td><span id=day1t1 style=width:100% class=day_item><a href=javascript:selectday('day1');loaders('utctime.php?cdate=2022-05-08&offset=0&mins=00&category=sports&serviceidentity=beinsports.com',2)>Sun</a></span><span id=day1t2 style=width:100% class=day_item1><a href=javascript:selectday('day1');loaders('utctime.php?cdate=2022-05-08&offset=0&mins=00&category=sports&serviceidentity=beinsports.com',2)>08</a></div></td><td><span id=day2t1 style=width:100% class=day_item><a href=javascript:selectday('day2');loaders('utctime.php?cdate=2022-05-09&offset=0&mins=00&category=sports&serviceidentity=beinsports.com',2)>Mon</a></span><span id=day2t2 style=width:100% class=day_item1><a href=javascript:selectday('day2');loaders('utctime.php?cdate=2022-05-09&offset=0&mins=00&category=sports&serviceidentity=beinsports.com',2)>09</a></div></td><td><span id=day3t1 style=width:100% class=day_item><a href=javascript:selectday('day3');loaders('utctime.php?cdate=2022-05-10&offset=0&mins=00&category=sports&serviceidentity=beinsports.com',2)>Tue</a></span><span id=day3t2 style=width:100% class=day_item1><a href=javascript:selectday('day3');loaders('utctime.php?cdate=2022-05-10&offset=0&mins=00&category=sports&serviceidentity=beinsports.com',2)>10</a></div></td><td><span id=day4t1 style=width:100% class=day_item><a href=javascript:selectday('day4');loaders('utctime.php?cdate=2022-05-11&offset=0&mins=00&category=sports&serviceidentity=beinsports.com',2)>Wed</a></span><span id=day4t2 style=width:100% class=day_item1><a href=javascript:selectday('day4');loaders('utctime.php?cdate=2022-05-11&offset=0&mins=00&category=sports&serviceidentity=beinsports.com',2)>11</a></div></td><td><span id=day5t1 style=width:100% class=day_item><a href=javascript:selectday('day5');loaders('utctime.php?cdate=2022-05-12&offset=0&mins=00&category=sports&serviceidentity=beinsports.com',2)>Thu</a></span><span id=day5t2 style=width:100% class=day_item1><a href=javascript:selectday('day5');loaders('utctime.php?cdate=2022-05-12&offset=0&mins=00&category=sports&serviceidentity=beinsports.com',2)>12</a></div></td><td><span id=day6t1 style=width:100% class=day_item><a href=javascript:selectday('day6');loaders('utctime.php?cdate=2022-05-13&offset=0&mins=00&category=sports&serviceidentity=beinsports.com',2)>Fri</a></span><span id=day6t2 style=width:100% class=day_item1><a href=javascript:selectday('day6');loaders('utctime.php?cdate=2022-05-13&offset=0&mins=00&category=sports&serviceidentity=beinsports.com',2)>13</a></div></td><td><span id=day7t1 style=width:100% class=day_item><a href=javascript:selectday('day7');loaders('utctime.php?cdate=2022-05-14&offset=0&mins=00&category=sports&serviceidentity=beinsports.com',2)>Sat</a></span><span id=day7t2 style=width:100% class=day_item1><a href=javascript:selectday('day7');loaders('utctime.php?cdate=2022-05-14&offset=0&mins=00&category=sports&serviceidentity=beinsports.com',2)>14</a></div></td></table></div>
</div><div class='row no-gutter'>
<div class='col-xs-12 col-sm-12 col-md-12 col-lg-12'>
<div style='background-color:#d1d0de;margin:0px auto;text-align:center;display:flex;width:100%'><div id=left style=width:25px;background-color:red;height:50px;padding-top:13px;background-color:#d1d0de;><img src=ico/left.png onclick=ptime()></div><div id='slider_timer' class='slider_time'>
<ul id='timer'></ul></div><div id=left style=width:25px;background-color:red;height:50px;padding-top:13px;background-color:#d1d0de><img src=ico/right.png onclick=ntime()></div></div>
</div>
</div><div class='row no-gutter' style='height:10px'></div>
<div class='row no-gutter'>
<div class='col-xs-7 col-xs-offset-5 col-sm-4 col-sm-offset-8 col-md-2 col-md-offset-10 col-lg-2 col-lg-offset-10'>
<div style='position:absolute;font-size:18px;margin-top:5px'>Live Events</div><div class="onoffswitch" style='left:120px'><input onchange=showhides() type="checkbox" name="onoffswitch" class="onoffswitch-checkbox" id="myonoffswitch" tabindex="0"><label class="onoffswitch-label" for="myonoffswitch"><span class="onoffswitch-inner"></span><span class="onoffswitch-switch"></span></label></div></div></div><div class='row no-gutter' style='height:10px'></div>
<div class='row no-gutter'>
<div class='col-xs-12 col-sm-12 col-md-12 col-lg-12'>
<div id='loader_inner' style='display:none;margin:0 auto;width:100%;margin-top:5px;margin-bottom:5px;text-align:center'>
<div style='text-align:center;margin:auto 0;'><img src='images/ajax-loader.gif'></div>
</div>
</div>
</div>
</div><div class='container'><div class='row no-gutter' id='cta_row'><div id='cta' class='col-xs-12 col-sm-12 col-md-12 col-lg-12'><img style=cursor:pointer onclick=gobein('entertainment','e') class='img-responsive' src=images/entertain_cta_en.png></div><div></div>
</div>
<div id="immobile" style="display:'none'"></div><div id="imtablet" style="display:'none'"></div><div id="imdesktop" style="display:'none'"></div>

View File

@@ -0,0 +1,130 @@
const axios = require('axios')
const cheerio = require('cheerio')
const dayjs = require('dayjs')
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: 'beinsports.com',
days: 2,
request: {
cache: {
ttl: 60 * 60 * 1000, // 1h
interpretHeader: false
}
},
url: function ({ date, channel }) {
let [region] = channel.site_id.split('#')
region = region ? `_${region}` : ''
return `https://epg.beinsports.com/utctime${region}.php?mins=00&serviceidentity=beinsports.com&cdate=${date.format(
'YYYY-MM-DD'
)}`
},
parser: function ({ content, channel, date, cached }) {
let programs = []
const items = parseItems(content, channel)
let i = 0
items.forEach(item => {
const $item = cheerio.load(item)
const title = parseTitle($item)
if (!title) return
const category = parseCategory($item)
const prev = programs[programs.length - 1]
let start = parseStart($item, date)
if (i === 0 && start.hour() > 18) {
date = date.subtract(1, 'd')
start = start.subtract(1, 'd')
}
if (prev) {
if (start.isBefore(prev.start)) {
start = start.add(1, 'd')
date = date.add(1, 'd')
}
prev.stop = start
}
let stop = parseStop($item, start)
if (stop.isBefore(start)) {
stop = stop.add(1, 'd')
}
programs.push({ title, category, start, stop })
i++
})
return programs
},
async channels({ region, lang }) {
const suffix = region ? `_${region}` : ''
const content = await axios
.get(
`https://epg.beinsports.com/utctime${suffix}.php?mins=00&serviceidentity=beinsports.com&cdate=2022-05-08`
)
.then(r => r.data)
.catch(console.log)
const $ = cheerio.load(content)
const items = $(`.container > div, #epg_div > div`).toArray()
return items
.map(item => {
const $item = cheerio.load(item)
const id = $item('*').attr('id')
if (!/^channels\_[0-9]+$/.test(id)) return null
const channelId = id.replace('channels_', '')
const imgSrc = $item('img').attr('src')
const [_, __, name] = imgSrc.match(/(\/|)([a-z0-9-_.]+)(.png|.svg)$/i) || [null, null, '']
return {
lang,
site_id: `${region}#${channelId}`,
name
}
})
.filter(i => i)
}
}
function parseTitle($item) {
return $item('.title').text()
}
function parseCategory($item) {
return $item('.format')
.map(function () {
return $item(this).text()
})
.get()
}
function parseStart($item, date) {
let time = $item('.time').text()
if (!time) return null
let [_, start, period] = time.match(/^(\d{2}:\d{2})( AM| PM|)/) || [null, null, null]
if (!start) return null
start = `${date.format('YYYY-MM-DD')} ${start}${period}`
const format = period ? 'YYYY-MM-DD hh:mm A' : 'YYYY-MM-DD HH:mm'
return dayjs.tz(start, format, 'Asia/Qatar')
}
function parseStop($item, date) {
let time = $item('.time').text()
if (!time) return null
let [_, stop, period] = time.match(/(\d{2}:\d{2})( AM| PM|)$/) || [null, null, null]
if (!stop) return null
stop = `${date.format('YYYY-MM-DD')} ${stop}${period}`
const format = period ? 'YYYY-MM-DD hh:mm A' : 'YYYY-MM-DD HH:mm'
return dayjs.tz(stop, format, 'Asia/Qatar')
}
function parseItems(content, channel) {
const [_, channelId] = channel.site_id.split('#')
const $ = cheerio.load(content)
return $(`#channels_${channelId} .slider > ul:first-child > li`).toArray()
}

View File

@@ -0,0 +1,91 @@
// npm run channels:parse -- --config=./sites/beinsports.com/beinsports.com.config.js --output=./sites/beinsports.com/beinsports.com_qa-ar.channels.xml --set=lang:ar --set=region:ar
// npx epg-grabber --config=sites/beinsports.com/beinsports.com.config.js --channels=sites/beinsports.com/beinsports.com_qa-en.channels.xml --output=guide.xml --timeout=30000 --days=2
// npx epg-grabber --config=sites/beinsports.com/beinsports.com.config.js --channels=sites/beinsports.com/beinsports.com_us-en.channels.xml --output=guide.xml --timeout=30000 --days=2
const { parser, url } = require('./beinsports.com.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-05-08', 'YYYY-MM-DD').startOf('d')
const channel = { site_id: '#2', xmltv_id: 'BeINSports.qa' }
it('can generate valid url', () => {
const result = url({ date, channel })
expect(result).toBe(
'https://epg.beinsports.com/utctime.php?mins=00&serviceidentity=beinsports.com&cdate=2022-05-08'
)
})
it('can generate valid url for arabic guide', () => {
const channel = { site_id: 'ar#1', xmltv_id: 'BeINSports.qa' }
const result = url({ date, channel })
expect(result).toBe(
'https://epg.beinsports.com/utctime_ar.php?mins=00&serviceidentity=beinsports.com&cdate=2022-05-08'
)
})
it('can parse response', () => {
const content = fs.readFileSync(path.resolve('sites/beinsports.com/__data__/content.html'))
const results = parser({ date, channel, content }).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(results[0]).toMatchObject({
start: '2022-05-07T19:30:00.000Z',
stop: '2022-05-07T21:20:00.000Z',
title: 'Lorient vs Marseille',
category: ['Ligue 1 2021/22']
})
})
it('can parse response for tomorrow', () => {
const date = dayjs.utc('2022-05-09', 'YYYY-MM-DD').startOf('d')
const content = fs.readFileSync(
path.resolve('sites/beinsports.com/__data__/content_tomorrow.html')
)
const results = parser({ date, channel, content }).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(results[0]).toMatchObject({
start: '2022-05-08T21:20:00.000Z',
stop: '2022-05-08T23:10:00.000Z',
title: 'Celtic vs Hearts',
category: ['SPFL Premiership 2021/22']
})
})
it('can parse US response', () => {
const content = fs.readFileSync(path.resolve('sites/beinsports.com/__data__/content_us.html'))
const results = parser({ date, channel, content }).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(results[0]).toMatchObject({
start: '2022-05-07T20:00:00.000Z',
stop: '2022-05-07T22:00:00.000Z',
title: 'Basaksehir vs. Galatasaray',
category: ['Fútbol Turco Superliga', 'Soccer']
})
})
it('can handle empty guide', () => {
const noContent = fs.readFileSync(path.resolve('sites/beinsports.com/__data__/no-content.html'))
const result = parser({
date,
channel,
content: noContent
})
expect(result).toMatchObject([])
})

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="beinsports.com">
<channels>
<channel lang="en" xmltv_id="beINSports1Australia.au" site_id="au#1">BeIn Sports 1 Australia</channel>
<channel lang="en" xmltv_id="beINSports2Australia.au" site_id="au#2">BeIn Sports 2 Australia</channel>
<channel lang="en" xmltv_id="beINSports3Australia.au" site_id="au#3">BeIn Sports 3 Australia</channel>
</channels>
</site>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="beinsports.com">
<channels>
<channel lang="fr" xmltv_id="beINSports1France.fr" site_id="france#1">BeIN Sports 1 HD France</channel>
<channel lang="fr" xmltv_id="beINSports2France.fr" site_id="france#2">BeIN Sports 2 HD France</channel>
<channel lang="fr" xmltv_id="beINSports3France.fr" site_id="france#3">BeIN Sports 3 France</channel>
<channel lang="fr" xmltv_id="beINSportsMax4France.fr" site_id="france#4">BeIN Sports Max 4 France</channel>
<channel lang="fr" xmltv_id="beINSportsMax5France.fr" site_id="france#5">BeIN Sports Max 5 France</channel>
<channel lang="fr" xmltv_id="beINSportsMax6France.fr" site_id="france#6">BeIN Sports Max 6 France</channel>
<channel lang="fr" xmltv_id="beINSportsMax7France.fr" site_id="france#7">BeIN Sports Max 7 France</channel>
<channel lang="fr" xmltv_id="beINSportsMax8France.fr" site_id="france#8">BeIN Sports Max 8 France</channel>
<channel lang="fr" xmltv_id="beINSportsMax9France.fr" site_id="france#9">BeIN Sports Max 9 France</channel>
<channel lang="fr" xmltv_id="beINSportsMax10France.fr" site_id="france#10">BeIN Sports Max 10 France</channel>
</channels>
</site>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="beinsports.com">
<channels>
<channel lang="en" xmltv_id="beINSports1HongKong.hk" site_id="hk#1">BeIN Sports 1 Hong Kong</channel>
<channel lang="en" xmltv_id="beINSports2HongKong.hk" site_id="hk#2">BeIN Sports 2 Hong Kong</channel>
</channels>
</site>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="beinsports.com">
<channels>
<channel lang="en" xmltv_id="beINSports1Indonesia.id" site_id="id#1">BeIN Sports 1 Indonesia</channel>
<channel lang="en" xmltv_id="beINSports3Indonesia.id" site_id="id#2">BeIN Sports 3 Indonesia</channel>
</channels>
</site>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="beinsports.com">
<channels>
<channel lang="en" xmltv_id="beINSports1MalaysiaSingapore.my" site_id="my#1">BeIN Sports 1 Malaysia &amp; Singapore</channel>
</channels>
</site>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="beinsports.com">
<channels>
<channel lang="en" xmltv_id="beINSports1Philippines.ph" site_id="id#1">BeIN Sports 1 Philippines</channel>
<channel lang="en" xmltv_id="beINSports3Philippines.ph" site_id="id#2">BeIN Sports 3 Philippines</channel>
</channels>
</site>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="beinsports.com">
<channels>
<channel lang="ar" xmltv_id="beINSports.qa" site_id="ar#1">beIN SPORTS FTA</channel>
<channel lang="ar" xmltv_id="beINSportsNews.qa" site_id="ar#2">beIN SPORTS News</channel>
<channel lang="ar" xmltv_id="beINSports2.qa" site_id="ar#3">beIN SPORTS2</channel>
<channel lang="ar" xmltv_id="beINSports3.qa" site_id="ar#4">beIN SPORTS3</channel>
<channel lang="ar" xmltv_id="beINSports4.qa" site_id="ar#5">beIN SPORTS4</channel>
<channel lang="ar" xmltv_id="beINSports5.qa" site_id="ar#6">beIN SPORTS5</channel>
<channel lang="ar" xmltv_id="beINSports6.qa" site_id="ar#7">beIN SPORTS6</channel>
<channel lang="ar" xmltv_id="beINSports7.qa" site_id="ar#8">beIN SPORTS7</channel>
<channel lang="ar" xmltv_id="beINSportsPremium3.qa" site_id="ar#9">beIN SPORTS3 PREMIUM</channel>
<channel lang="ar" xmltv_id="beINSportsXtra1.qa" site_id="ar#10">beIN SPORTS XTRA1</channel>
<channel lang="ar" xmltv_id="beINSportsXtra2.qa" site_id="ar#11">beIN SPORTS XTRA2</channel>
<channel lang="ar" xmltv_id="beIN4K.qa" site_id="ar#12">beIN 4k</channel>
<channel lang="ar" xmltv_id="beINSportsAFC.qa" site_id="ar#13">beIN SPORTS AFC</channel>
<channel lang="ar" xmltv_id="beINSportsAFC1.qa" site_id="ar#14">beIN SPORTS AFC1</channel>
<channel lang="ar" xmltv_id="beINSportsAFC2.qa" site_id="ar#15">beIN SPORTS AFC2</channel>
<channel lang="ar" xmltv_id="beINSportsAFC3.qa" site_id="ar#16">beIN SPORTS AFC3</channel>
<channel lang="ar" xmltv_id="beINSportsNBA.qa" site_id="ar#17">beIN SPORTS NBA</channel>
<channel lang="ar" xmltv_id="beINSportsEnglish1.qa" site_id="ar#18">beIN SPORTS1 ENGLISH</channel>
<channel lang="ar" xmltv_id="beINSportsEnglish2.qa" site_id="ar#19">beIN SPORTS2 ENGLISH</channel>
<channel lang="ar" xmltv_id="beINSportsEnglish3.qa" site_id="ar#20">beIN SPORTS3 ENGLISH</channel>
<channel lang="ar" xmltv_id="beINSportsFrench1.qa" site_id="ar#21">beIN SPORTS1 FRENCH</channel>
<channel lang="ar" xmltv_id="beINSportsFrench2.qa" site_id="ar#22">beIN SPORTS2 FRENCH</channel>
<channel lang="ar" xmltv_id="beINSportsFrench3.qa" site_id="ar#23">beIN SPORTS3 FRENCH</channel>
<channel lang="ar" xmltv_id="beINSportsMax1.qa" site_id="ar#24">beIN SPORTS MAX 1</channel>
<channel lang="ar" xmltv_id="beINSportsMax2.qa" site_id="ar#25">beIN SPORTS MAX 2</channel>
</channels>
</site>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="beinsports.com">
<channels>
<channel lang="en" xmltv_id="beINSports.qa" site_id="#1">BeIn Sports</channel>
<channel lang="en" xmltv_id="beINSportsNews.qa" site_id="#2">BeIn Sports News</channel>
<channel lang="en" xmltv_id="beINSports2.qa" site_id="#3">BeIn Sports 2</channel>
<channel lang="en" xmltv_id="beINSports3.qa" site_id="#4">BeIn Sports 3</channel>
<channel lang="en" xmltv_id="beINSports4.qa" site_id="#5">BeIn Sports 4</channel>
<channel lang="en" xmltv_id="beINSports5.qa" site_id="#6">BeIn Sports 5</channel>
<channel lang="en" xmltv_id="beINSports6.qa" site_id="#7">BeIn Sports 6</channel>
<channel lang="en" xmltv_id="beINSports7.qa" site_id="#8">BeIn Sports 7</channel>
<channel lang="en" xmltv_id="beINSportsPremium3.qa" site_id="#9">BeIn Sports Premium 3</channel>
<channel lang="en" xmltv_id="beINSportsXtra1.qa" site_id="#10">BeIn Sports Xtra 1</channel>
<channel lang="en" xmltv_id="beINSportsXtra2.qa" site_id="#11">BeIn Sports Xtra 2</channel>
<channel lang="en" xmltv_id="beIN4K.qa" site_id="#12">BeIn 4K</channel>
<channel lang="en" xmltv_id="beINSportsNBA.qa" site_id="#13">BeIn NBA</channel>
<channel lang="en" xmltv_id="beINSportsEnglish1.qa" site_id="#14">BeIn Sports English 1</channel>
<channel lang="en" xmltv_id="beINSportsEnglish2.qa" site_id="#15">BeIn Sports English 2</channel>
<channel lang="en" xmltv_id="beINSportsEnglish3.qa" site_id="#16">BeIn Sports English 3</channel>
<channel lang="fr" xmltv_id="beINSportsFrench1.qa" site_id="#17">BeIn Sports French 1</channel>
<channel lang="fr" xmltv_id="beINSportsFrench2.qa" site_id="#18">BeIn Sports French 2</channel>
<channel lang="fr" xmltv_id="beINSportsFrench3.qa" site_id="#19">BeIn Sports French 3</channel>
</channels>
</site>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="beinsports.com">
<channels>
<channel lang="en" xmltv_id="beINSports1Thailand.th" site_id="th#1">BeIN Sports 1 Thailand</channel>
<channel lang="en" xmltv_id="beINSports3Thailand.th" site_id="th#2">BeIN Sports 3 Thailand</channel>
</channels>
</site>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="beinsports.com">
<channels>
<channel lang="en" xmltv_id="beINSportsUSA.us" site_id="us#1">BeIN Sports USA</channel>
<channel lang="en" xmltv_id="beINSportsenEspanol.us" site_id="us#2">BeIN Sports en Español</channel>
<channel lang="en" xmltv_id="beINSPORTSXTRA.us" site_id="us#3">BeIN Sports Xtra USA</channel>
<channel lang="en" xmltv_id="beINSPORTSXTRAenEspanol.us" site_id="us#4">BeIN Sports Xtra en Español</channel>
<channel lang="en" xmltv_id="beINSports3USA.us" site_id="us#5">BeIN Sports 3 USA</channel>
<channel lang="en" xmltv_id="beINSports4USA.us" site_id="us#6">BeIN Sports 4 USA</channel>
<channel lang="en" xmltv_id="beINSports5USA.us" site_id="us#7">BeIN Sports 5 USA</channel>
<channel lang="en" xmltv_id="beINSports6USA.us" site_id="us#8">BeIN Sports 6 USA</channel>
<channel lang="en" xmltv_id="beINSports7USA.us" site_id="us#9">BeIN Sports 7 USA</channel>
<channel lang="en" xmltv_id="beINSports8USA.us" site_id="us#10">BeIN Sports 8 USA</channel>
</channels>
</site>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="beinsports.com">
<channels>
<channel lang="es" xmltv_id="beINSportsUSA.us" site_id="us_es#1">BeIN Sports USA</channel>
<channel lang="es" xmltv_id="beINSportsenEspanol.us" site_id="us_es#2">BeIN Sports en Español</channel>
<channel lang="es" xmltv_id="beINSPORTSXTRA.us" site_id="us_es#3">BeIN Sports Xtra USA</channel>
<channel lang="es" xmltv_id="beINSPORTSXTRAenEspanol.us" site_id="us_es#4">BeIN Sports Xtra en Español</channel>
<channel lang="es" xmltv_id="beINSports3USA.us" site_id="us_es#5">BeIN Sports 3 USA</channel>
<channel lang="es" xmltv_id="beINSports4USA.us" site_id="us_es#6">BeIN Sports 4 USA</channel>
<channel lang="es" xmltv_id="beINSports5USA.us" site_id="us_es#7">BeIN Sports 5 USA</channel>
<channel lang="es" xmltv_id="beINSports6USA.us" site_id="us_es#8">BeIN Sports 6 USA</channel>
<channel lang="es" xmltv_id="beINSports7USA.us" site_id="us_es#9">BeIN Sports 7 USA</channel>
<channel lang="es" xmltv_id="beINSports8USA.us" site_id="us_es#10">BeIN Sports 8 USA</channel>
</channels>
</site>

View File

@@ -0,0 +1,386 @@
<ul class="sc_day">
<li onclick="setWeek('prev');"> < </li>
<li onclick="setDay('2023-01-23');" class="">
<span>01.23</span>
<p></p>
</li>
<li onclick="setDay('2023-01-24');" class=""><!-- 선택된 편성표 요일에 클래스 부여 -->
<span>01.24</span>
<p></p>
</li>
<li onclick="setDay('2023-01-25');" class="">
<span>01.25</span>
<p></p>
</li>
<li onclick="setDay('2023-01-26');" class="on">
<span>01.26</span>
<p></p>
</li>
<li onclick="setDay('2023-01-27');" class="">
<span>01.27</span>
<p></p>
</li>
<li onclick="setDay('2023-01-28');" class="">
<span>01.28</span>
<p></p>
</li>
<li onclick="setDay('2023-01-29');" class="">
<span>01.29</span>
<p></p>
</li>
<li onclick="setWeek('next');"> > </li>
</ul>
<dl class="sc_time">
<dt>
<span>시간</span>
<span>장르</span>
<span>프로그램</span>
<span>회차</span>
<span>세부정보</span>
<span>방송시간</span>
</dt>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>00:00</span>
<span><p >연예/오락</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
더트롯쇼 </span>
<span>36회</span>
<span>
<p class="sc_year3">
15 </p>
<p class="on">HD</p><!-- 화질 -->
<p class="on"></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p >Original</p><!-- 자체 -->
</span>
<span>60분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>01:00</span>
<span><p class="sc_col2">교양</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
특종세상 </span>
<span>21회</span>
<span>
<p class="sc_year3">
15 </p>
<p class="on">HD</p><!-- 화질 -->
<p class="on"></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p >Original</p><!-- 자체 -->
</span>
<span>70분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>02:10</span>
<span><p class="sc_col2">교양</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
특종세상 </span>
<span>22회</span>
<span>
<p class="sc_year3">
15 </p>
<p class="on">HD</p><!-- 화질 -->
<p class="on"></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p >Original</p><!-- 자체 -->
</span>
<span>70분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>03:20</span>
<span><p class="sc_col2">교양</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
나는 자연인이다 </span>
<span>124회</span>
<span>
<p class="sc_year1">
ALL </p>
<p class="on">HD</p><!-- 화질 -->
<p ></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p >Original</p><!-- 자체 -->
</span>
<span>70분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>04:30</span>
<span><p >패션/뷰티</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
탑시크릿란제리HD </span>
<span>1회</span>
<span>
<p class="sc_year4">
19 </p>
<p class="on">HD</p><!-- 화질 -->
<p class="on"></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p class="on">Original</p><!-- 자체 -->
</span>
<span>30분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>05:00</span>
<span><p >연예/오락</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
SALON INTERNATIONAL DE LA LINGERIE </span>
<span>7회</span>
<span>
<p class="sc_year4">
19 </p>
<p class="on">HD</p><!-- 화질 -->
<p class="on"></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p class="on">Original</p><!-- 자체 -->
</span>
<span>30분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>05:30</span>
<span><p >연예/오락</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
노컷 란제리 페스티벌 </span>
<span>14회</span>
<span>
<p class="sc_year4">
19 </p>
<p class="on">HD</p><!-- 화질 -->
<p class="on"></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p >Original</p><!-- 자체 -->
</span>
<span>60분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>06:30</span>
<span><p >연예/오락</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
요가에 빠지다 </span>
<span>7회</span>
<span>
<p class="sc_year3">
15 </p>
<p class="on">HD</p><!-- 화질 -->
<p class="on"></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p class="on">Original</p><!-- 자체 -->
</span>
<span>40분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>07:10</span>
<span><p >연예/오락</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
이제 만나러 갑니다 </span>
<span>20회</span>
<span>
<p class="sc_year2">
12 </p>
<p class="on">HD</p><!-- 화질 -->
<p class="on"></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p >Original</p><!-- 자체 -->
</span>
<span>70분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>08:20</span>
<span><p >연예/오락</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
미스터트롯 영웅들의 탄생 </span>
<span>5회</span>
<span>
<p class="sc_year3">
15 </p>
<p class="on">HD</p><!-- 화질 -->
<p ></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p >Original</p><!-- 자체 -->
</span>
<span>100분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>10:00</span>
<span><p >연예/오락</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
미스터트롯 영웅들의 탄생 </span>
<span>6회</span>
<span>
<p class="sc_year3">
15 </p>
<p class="on">HD</p><!-- 화질 -->
<p ></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p >Original</p><!-- 자체 -->
</span>
<span>100분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>11:40</span>
<span><p >연예/오락</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
불타는 트롯맨 5 </span>
<span>3회</span>
<span>
<p class="sc_year3">
15 </p>
<p class="on">HD</p><!-- 화질 -->
<p ></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p >Original</p><!-- 자체 -->
</span>
<span>80분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>13:00</span>
<span><p >연예/오락</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
화요일은 밤이 좋아 </span>
<span>17회</span>
<span>
<p class="sc_year3">
15 </p>
<p class="on">HD</p><!-- 화질 -->
<p class="on"></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p >Original</p><!-- 자체 -->
</span>
<span>130분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>15:10</span>
<span><p >연예/오락</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
불타는 트롯맨 6 </span>
<span>3회</span>
<span>
<p class="sc_year3">
15 </p>
<p class="on">HD</p><!-- 화질 -->
<p ></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p >Original</p><!-- 자체 -->
</span>
<span>110분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>17:00</span>
<span><p class="sc_col2">교양</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
행복한 힐링 메이트 </span>
<span>41회</span>
<span>
<p class="sc_year3">
15 </p>
<p class="on">HD</p><!-- 화질 -->
<p ></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p >Original</p><!-- 자체 -->
</span>
<span>60분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>18:00</span>
<span><p >연예/오락</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
내일은 미스트롯 2 </span>
<span>7회</span>
<span>
<p class="sc_year3">
15 </p>
<p class="on">HD</p><!-- 화질 -->
<p class="on"></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p >Original</p><!-- 자체 -->
</span>
<span>180분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>21:00</span>
<span><p >연예/오락</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
불타는 트롯맨 3 </span>
<span>2회</span>
<span>
<p class="sc_year3">
15 </p>
<p class="on">HD</p><!-- 화질 -->
<p ></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p >Original</p><!-- 자체 -->
</span>
<span>110분</span>
</dd>
<dd class=""><!-- onair 시 class="on" 추가 -->
<span>22:50</span>
<span><p class="sc_col2">교양</p></span>
<span class="sdfsdf">
<script>
document.writeln($('.sc_time').val("outerWidth : " + $(".sdfsdf").outerWidth()););
</script>
나는 자연인이다 </span>
<span>154회</span>
<span>
<p class="sc_year1">
ALL </p>
<p class="on">HD</p><!-- 화질 -->
<p class="on"></p><!-- 본/재방 -->
<p ></p><!-- 생방송 -->
<p >Original</p><!-- 자체 -->
</span>
<span>70분</span>
</dd>
</dl>

View File

@@ -0,0 +1,44 @@
<ul class="sc_day">
<li onclick="setWeek('prev');"> < </li>
<li onclick="setDay('2023-01-23');" class="">
<span>01.23</span>
<p></p>
</li>
<li onclick="setDay('2023-01-24');" class=""><!-- 선택된 편성표 요일에 클래스 부여 -->
<span>01.24</span>
<p></p>
</li>
<li onclick="setDay('2023-01-25');" class="">
<span>01.25</span>
<p></p>
</li>
<li onclick="setDay('2023-01-26');" class="on">
<span>01.26</span>
<p></p>
</li>
<li onclick="setDay('2023-01-27');" class="">
<span>01.27</span>
<p></p>
</li>
<li onclick="setDay('2023-01-28');" class="">
<span>01.28</span>
<p></p>
</li>
<li onclick="setDay('2023-01-29');" class="">
<span>01.29</span>
<p></p>
</li>
<li onclick="setWeek('next');"> > </li>
</ul>
<dl class="sc_time">
<dt>
<span>시간</span>
<span>장르</span>
<span>프로그램</span>
<span>회차</span>
<span>세부정보</span>
<span>방송시간</span>
</dt>
<div><img src="/img/noschedule.jpg"></div></dl>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="berrymedia.co.kr">
<channels>
<channel lang="ko" xmltv_id="BallTV.kr" site_id="6">BallTV</channel>
<channel lang="ko" xmltv_id="CookTV.kr" site_id="2">CookTV</channel>
<channel lang="ko" xmltv_id="GMTV.kr" site_id="4">GMTV</channel>
<channel lang="ko" xmltv_id="GTV.kr" site_id="">GTV</channel>
<channel lang="ko" xmltv_id="LifeSportsTV.kr" site_id="3">생활체육TV</channel>
<channel lang="ko" xmltv_id="UHDDreamTV.kr" site_id="5">UHDDreamTV</channel>
</channels>
</site>

View File

@@ -0,0 +1,93 @@
const cheerio = require('cheerio')
const dayjs = require('dayjs')
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)
dayjs.Ls.en.weekStart = 1
module.exports = {
site: 'berrymedia.co.kr',
days: 2,
url({ channel }) {
return `http://www.berrymedia.co.kr/schedule_proc${channel.site_id}.php`
},
request: {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-Requested-With': 'XMLHttpRequest'
},
data({ date }) {
let params = new URLSearchParams()
let startOfWeek = date.startOf('week').format('YYYY-MM-DD')
let endOfWeek = date.endOf('week').format('YYYY-MM-DD')
params.append('week', `${startOfWeek}~${endOfWeek}`)
params.append('day', date.format('YYYY-MM-DD'))
return params
}
},
parser({ content, date }) {
const programs = []
const items = parseItems(content)
items.forEach(item => {
const $item = cheerio.load(item)
const prev = programs[programs.length - 1]
let start = parseStart($item, date)
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),
category: parseCategory($item),
rating: parseRating($item),
start,
stop
})
})
return programs
}
}
function parseStart($item, date) {
const time = $item('span:nth-child(1)').text().trim()
return dayjs.tz(`${date.format('YYYY-MM-DD')} ${time}`, 'YYYY-MM-DD HH:mm', 'Asia/Seoul')
}
function parseTitle($item) {
return $item('span.sdfsdf').clone().children().remove().end().text().trim()
}
function parseCategory($item) {
return $item('span:nth-child(2) > p').text().trim()
}
function parseRating($item) {
const rating = $item('span:nth-child(5) > p:nth-child(1)').text().trim()
return rating
? {
system: 'KMRB',
value: rating
}
: null
}
function parseItems(content, channel, date) {
const $ = cheerio.load(content)
return $('.sc_time dd').toArray()
}

View File

@@ -0,0 +1,79 @@
// npx epg-grabber --config=sites/berrymedia.co.kr/berrymedia.co.kr.config.js --channels=sites/berrymedia.co.kr/berrymedia.co.kr.channels.xml --output=guide.xml --days=2
const { parser, url, request } = require('./berrymedia.co.kr.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('2023-01-26', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: '',
xmltv_id: 'GTV.kr'
}
it('can generate valid url', () => {
expect(url({ channel })).toBe('http://www.berrymedia.co.kr/schedule_proc.php')
})
it('can generate request method', () => {
expect(request.method).toBe('POST')
})
it('can generate valid request headers', () => {
expect(request.headers).toMatchObject({
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-Requested-With': 'XMLHttpRequest'
})
})
it('can generate valid request data', () => {
let params = request.data({ date })
expect(params.get('week')).toBe('2023-01-23~2023-01-29')
expect(params.get('day')).toBe('2023-01-26')
})
it('can parse response', () => {
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
let results = parser({ content, date })
results = results.map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(results[0]).toMatchObject({
start: '2023-01-25T15:00:00.000Z',
stop: '2023-01-25T16:00:00.000Z',
title: `더트롯쇼`,
category: '연예/오락',
rating: {
system: 'KMRB',
value: '15'
}
})
expect(results[17]).toMatchObject({
start: '2023-01-26T13:50:00.000Z',
stop: '2023-01-26T14:20:00.000Z',
title: `나는 자연인이다`,
category: '교양',
rating: {
system: 'KMRB',
value: 'ALL'
}
})
})
it('can handle empty guide', () => {
const results = parser({
date,
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
})
expect(results).toMatchObject([])
})

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="bt.com">
<channels>
<channel lang="en" xmltv_id="4seven.uk" site_id="hswj">4seven</channel>
<channel lang="en" xmltv_id="5Action.uk" site_id="hsvx">5 Action</channel>
<channel lang="en" xmltv_id="5Select.uk" site_id="ht94">5 Select</channel>
<channel lang="en" xmltv_id="5Star.uk" site_id="hsvw">5 Star</channel>
<channel lang="en" xmltv_id="5USA.uk" site_id="hsvk">5 USA</channel>
<channel lang="en" xmltv_id="AlJazeeraEnglish.qa" site_id="hsyp">Al Jazeera English</channel>
<channel lang="en" xmltv_id="BBCAlba.uk" site_id="hs6q">BBC Alba</channel>
<channel lang="en" xmltv_id="BBCFour.uk" site_id="hst5">BBC Four</channel>
<channel lang="en" xmltv_id="BBCNews.uk" site_id="hsx4">BBC News</channel>
<channel lang="en" xmltv_id="BBCOneEngland.uk" site_id="hsxv">BBC One HD</channel>
<channel lang="en" xmltv_id="BBCOneCambridgeshire.uk" site_id="hs56">BBC One Cambridgeshire</channel>
<channel lang="en" xmltv_id="BBCOneChannelIslands.uk" site_id="hs5y">BBC One Channel Islands</channel>
<channel lang="en" xmltv_id="BBCOneEastMidlands.uk" site_id="hs6h">BBC One East Midlands</channel>
<channel lang="en" xmltv_id="BBCOneLondon.uk" site_id="hs44">BBC One London</channel>
<channel lang="en" xmltv_id="BBCOneNorthEastCumbria.uk" site_id="hs2t">BBC One North East &amp; Cumbria</channel>
<channel lang="en" xmltv_id="BBCOneNorthWest.uk" site_id="hs5k">BBC One North West</channel>
<channel lang="en" xmltv_id="BBCOneOxfordshire.uk" site_id="hstv">BBC One Oxford</channel>
<channel lang="en" xmltv_id="BBCOneScotland.uk" site_id="hs6n">BBC One Scotland</channel>
<channel lang="en" xmltv_id="BBCOneSouth.uk" site_id="hs5v">BBC One South</channel>
<channel lang="en" xmltv_id="BBCOneSouthEast.uk" site_id="hsz7">BBC One South East</channel>
<channel lang="en" xmltv_id="BBCOneSouthWest.uk" site_id="hs48">BBC One South West</channel>
<channel lang="en" xmltv_id="BBCOneWales.uk" site_id="hs4j">BBC One Wales</channel>
<channel lang="en" xmltv_id="BBCOneWest.uk" site_id="hs7x">BBC One West</channel>
<channel lang="en" xmltv_id="BBCOneWestMidlands.uk" site_id="hs4c">BBC One West Midlands</channel>
<channel lang="en" xmltv_id="BBCOneYorksLincs.uk" site_id="hs24">BBC One Yorks</channel>
<channel lang="en" xmltv_id="BBCParliament.uk" site_id="hsyk">BBC Parliament</channel>
<channel lang="en" xmltv_id="BBCScotland.uk" site_id="hs6s">BBC Scotland</channel>
<channel lang="en" xmltv_id="BBCTwoEngland.uk" site_id="hstw">BBC Two England</channel>
<channel lang="en" xmltv_id="BBCTwoWales.uk" site_id="hs4k">BBC Two Wales</channel>
<channel lang="en" xmltv_id="Blaze.uk" site_id="hswv">Blaze UK</channel>
<channel lang="en" xmltv_id="BoomerangUK.uk" site_id="hstb">Boomerang UK</channel>
<channel lang="en" xmltv_id="BTSport1.uk" site_id="hspc">BT Sport 1</channel>
<channel lang="en" xmltv_id="BTSport10.uk" site_id="hsp6">BT Sport 10</channel>
<channel lang="en" xmltv_id="BTSport2.uk" site_id="hspd">BT Sport 2</channel>
<channel lang="en" xmltv_id="BTSport3.uk" site_id="hspf">BT Sport 3</channel>
<channel lang="en" xmltv_id="BTSport4.uk" site_id="hspg">BT Sport 4</channel>
<channel lang="en" xmltv_id="BTSport5.uk" site_id="hspy">BT Sport 5</channel>
<channel lang="en" xmltv_id="BTSport6.uk" site_id="hspz">BT Sport 6</channel>
<channel lang="en" xmltv_id="BTSport7.uk" site_id="hsp2">BT Sport 7</channel>
<channel lang="en" xmltv_id="BTSport8.uk" site_id="hsp4">BT Sport 8</channel>
<channel lang="en" xmltv_id="BTSport9.uk" site_id="hsp5">BT Sport 9</channel>
<channel lang="en" xmltv_id="BTSportBoxOffice.uk" site_id="hsqs">BT Sport Box Office UK</channel>
<channel lang="en" xmltv_id="BTSportBoxOffice2.uk" site_id="hsqt">BT Sport Box Office 2 UK</channel>
<channel lang="en" xmltv_id="BTSportUltimate.uk" site_id="hspr">BT Sport Ultimate</channel>
<channel lang="en" xmltv_id="CartoonitoUK.uk" site_id="hss8">Cartoonito UK</channel>
<channel lang="en" xmltv_id="CartoonNetworkUK.uk" site_id="hss2">Cartoon Network UK</channel>
<channel lang="en" xmltv_id="CBBC.uk" site_id="hsyd">CBBC</channel>
<channel lang="en" xmltv_id="CBeebies.uk" site_id="hsyf">CBeebies UK</channel>
<channel lang="en" xmltv_id="CBSDramaUK.uk" site_id="hswz">CBS Drama UK</channel>
<channel lang="en" xmltv_id="CBSJusticeUK.uk" site_id="hsv8">CBS Justice UK</channel>
<channel lang="en" xmltv_id="CBSRealityUK.uk" site_id="hswy">CBS Reality UK</channel>
<channel lang="en" xmltv_id="Challenge.uk" site_id="hswh">Challenge UK</channel>
<channel lang="en" xmltv_id="Channel4.uk" site_id="hsxy">Channel 4</channel>
<channel lang="en" xmltv_id="Channel5.uk" site_id="hsxz">Channel 5</channel>
<channel lang="en" xmltv_id="Channel5Plus1.uk" site_id="hswf">Channel 5 +1</channel>
<channel lang="en" xmltv_id="CITV.uk" site_id="hsyc">CITV</channel>
<channel lang="en" xmltv_id="ClublandTV.uk" site_id="hs8s">Clubland TV</channel>
<channel lang="en" xmltv_id="ComedyCentralUK.uk" site_id="hsrs">Comedy Central UK</channel>
<!-- <channel lang="en" xmltv_id="" site_id="hsxg">Craft Store TV</channel> -->
<channel lang="en" xmltv_id="CreateandCraft.uk" site_id="hsxr">Create and Craft</channel>
<channel lang="en" xmltv_id="Davejavu.uk" site_id="hsxb">Dave ja vu</channel>
<channel lang="en" xmltv_id="Dave.uk" site_id="hsvh">Dave UK</channel>
<channel lang="en" xmltv_id="DMAXUK.uk" site_id="hsv6">DMAX UK</channel>
<channel lang="en" xmltv_id="Drama.uk" site_id="hsvj">Drama UK</channel>
<channel lang="en" xmltv_id="E4Extra.uk" site_id="hsvv">E4 Extra</channel>
<channel lang="en" xmltv_id="E4.uk" site_id="hs4s">E4 UK</channel>
<channel lang="en" xmltv_id="E4Plus1.uk" site_id="hsvt">E4+1</channel>
<channel lang="en" xmltv_id="Eurosport1UK.uk" site_id="hspt">Eurosport 1 UK</channel>
<channel lang="en" xmltv_id="Eurosport2UK.uk" site_id="hspv">Eurosport 2 UK</channel>
<channel lang="en" xmltv_id="Film4.uk" site_id="hsvb">Film 4 UK</channel>
<channel lang="en" xmltv_id="Film4Plus1.uk" site_id="hswg">Film 4 UK +1</channel>
<channel lang="en" xmltv_id="FoodNetworkUK.uk" site_id="hswb">Food Network UK</channel>
<channel lang="en" xmltv_id="ViaplayXtra.uk" site_id="hsww">Viaplay Xtra</channel>
<channel lang="en" xmltv_id="GBNews.uk" site_id="ht7w">GB News</channel>
<channel lang="en" xmltv_id="GemsTV.uk" site_id="hswd">Gems TV</channel>
<channel lang="en" xmltv_id="Gold.uk" site_id="hsrr">Gold HD</channel>
<channel lang="en" xmltv_id="GreatMovies.uk" site_id="hsvy">Great! Movies</channel>
<channel lang="en" xmltv_id="GreatMoviesAction.uk" site_id="hsv9">Great! Movies Action</channel>
<channel lang="en" xmltv_id="GreatMoviesActionPlus1.uk" site_id="hswt">Great! Movies Action + 1</channel>
<channel lang="en" xmltv_id="GreatMoviesClassic.uk" site_id="hswn">Great! Movies Classic</channel>
<channel lang="en" xmltv_id="GreatMoviesClassicPlus1.uk" site_id="hs8q">Great! Movies Classic +1</channel>
<channel lang="en" xmltv_id="GreatTV.uk" site_id="hswk">Great! TV</channel>
<channel lang="en" xmltv_id="GreatTVPlus1.uk" site_id="hs8p">Great! TV +1</channel>
<channel lang="en" xmltv_id="HGTVUK.uk" site_id="hswc">HGTV UK</channel>
<channel lang="en" xmltv_id="Legend.uk" site_id="hsw2">Horror Channel UK</channel>
<!-- <channel lang="en" xmltv_id="" site_id="hsxq">Ideal Extra</channel> -->
<channel lang="en" xmltv_id="IdealWorldTV.uk" site_id="hsvm">Ideal World</channel>
<channel lang="en" xmltv_id="ITV1.uk" site_id="hs2m">ITV</channel>
<channel lang="en" xmltv_id="ITV2.uk" site_id="hst2">ITV 2</channel>
<channel lang="en" xmltv_id="ITV2Plus1.uk" site_id="hsvs">ITV 2 +1</channel>
<channel lang="en" xmltv_id="ITV3.uk" site_id="hst6">ITV 3</channel>
<channel lang="en" xmltv_id="ITV3Plus1.uk" site_id="hswr">ITV 3 +1</channel>
<channel lang="en" xmltv_id="ITV4.uk" site_id="hsvp">ITV 4</channel>
<channel lang="en" xmltv_id="ITV4Plus1.uk" site_id="hsws">ITV 4 +1</channel>
<channel lang="en" xmltv_id="ITVBe.uk" site_id="hs52">ITV Be</channel>
<channel lang="en" xmltv_id="JewelleryMaker.uk" site_id="hsw5">Jewellery Maker</channel>
<channel lang="en" xmltv_id="LFCTV.uk" site_id="hs8k">LFC TV</channel>
<channel lang="en" xmltv_id="More4.uk" site_id="hsvg">More 4 UK</channel>
<channel lang="en" xmltv_id="More4Plus1.uk" site_id="hsxh">More4+1</channel>
<channel lang="en" xmltv_id="MTVUK.uk" site_id="hsrh">MTV UK</channel>
<channel lang="en" xmltv_id="NationalGeographicUK.uk" site_id="hsr4">National Geographic UK</channel>
<channel lang="en" xmltv_id="NickelodeonUK.uk" site_id="hstc">Nickelodeon</channel>
<channel lang="en" xmltv_id="NickJrUK.uk" site_id="hstd">Nick Jr UK</channel>
<channel lang="en" xmltv_id="NicktoonsUK.uk" site_id="hss6">NickToons UK</channel>
<channel lang="en" xmltv_id="Now70s.uk" site_id="hs8r">Now 70&apos;s</channel>
<channel lang="en" xmltv_id="Now80s.uk" site_id="hsxf">Now 80&apos;s</channel>
<channel lang="en" xmltv_id="Now90s.uk" site_id="hs8t">Now 90&apos;s</channel>
<channel lang="en" xmltv_id="PBSAmerica.uk" site_id="hsxm">PBS America</channel>
<channel lang="en" xmltv_id="Pick.uk" site_id="hst7">Pick UK</channel>
<channel lang="en" xmltv_id="Pop.uk" site_id="hsyg">Pop</channel>
<channel lang="en" xmltv_id="PopMax.uk" site_id="hs8x">Pop Max</channel>
<channel lang="en" xmltv_id="QuestRedUK.uk" site_id="hsv7">Quest Red UK</channel>
<channel lang="en" xmltv_id="QuestRedUKPlus1.uk" site_id="hsw4">Quest Red UK +1</channel>
<channel lang="en" xmltv_id="QuestUK.uk" site_id="hsx8">Quest</channel>
<channel lang="en" xmltv_id="QuestUKPlus1.uk" site_id="hsw8">Quest UK +1</channel>
<channel lang="en" xmltv_id="QVCBeautyUK.uk" site_id="hsx6">QVC UK Beauty</channel>
<channel lang="en" xmltv_id="QVCStyleUK.uk" site_id="hsv5">QVC Style UK</channel>
<channel lang="en" xmltv_id="QVCUK.uk" site_id="hsx5">QVC UK</channel>
<channel lang="en" xmltv_id="Really.uk" site_id="hsvf">Really UK</channel>
<channel lang="en" xmltv_id="S4C.uk" site_id="hs4n">S4C</channel>
<channel lang="en" xmltv_id="SkyArts.uk" site_id="hsrx">Sky Arts HD</channel>
<channel lang="en" xmltv_id="SkyCinemaAction.uk" site_id="hstp">Sky Cinema Action HD</channel>
<channel lang="en" xmltv_id="SkyCinemaAnimation.uk" site_id="hstf">Sky Cinema Animation HD</channel>
<channel lang="en" xmltv_id="SkyCinemaComedy.uk" site_id="hstq">Sky Cinema Comedy HD</channel>
<channel lang="en" xmltv_id="SkyCinemaDrama.uk" site_id="hsts">Sky Cinema Drama HD</channel>
<channel lang="en" xmltv_id="SkyCinemaFamily.uk" site_id="hstn">Sky Cinema Family HD</channel>
<channel lang="en" xmltv_id="SkyCinemaGreats.uk" site_id="hstk">Sky Cinema Greats HD</channel>
<channel lang="en" xmltv_id="SkyCinemaHits.uk" site_id="hstj">Sky Cinema Hits HD</channel>
<channel lang="en" xmltv_id="SkyCinemaPremiere.uk" site_id="hstg">Sky Cinema Premiere HD</channel>
<channel lang="en" xmltv_id="SkyCinemaSciFiHorror.uk" site_id="hstt">Sky Cinema Sci-Fi Horror HD</channel>
<channel lang="en" xmltv_id="SkyCinemaSelect.uk" site_id="hsth">Sky Cinema Select</channel>
<channel lang="en" xmltv_id="SkyCinemaThriller.uk" site_id="hstr">Sky Cinema Thriller HD</channel>
<channel lang="en" xmltv_id="SkyComedy.uk" site_id="hsq9">Sky Comedy</channel>
<channel lang="en" xmltv_id="SkyCrime.uk" site_id="hsrc">Sky Crime</channel>
<channel lang="en" xmltv_id="SkyDocumentaries.uk" site_id="hsrk">Sky Documentaries</channel>
<channel lang="en" xmltv_id="SkyHistory.uk" site_id="hsr6">Sky History HD</channel>
<channel lang="en" xmltv_id="SkyMax.uk" site_id="hsrn">Sky Max HD</channel>
<channel lang="en" xmltv_id="SkyNature.uk" site_id="hsq2">Sky Nature</channel>
<channel lang="en" xmltv_id="SkyNews.uk" site_id="htdm">Sky News HD</channel>
<channel lang="en" xmltv_id="SkySciFi.uk" site_id="hsrv">Sky Sci-Fi</channel>
<channel lang="en" xmltv_id="SkyShowcase.uk" site_id="hvpg">Sky Showcase HD</channel>
<channel lang="en" xmltv_id="SkySportsAction.uk" site_id="hssw">Sky Sports Action</channel>
<channel lang="en" xmltv_id="SkySportsArena.uk" site_id="hssx">Sky Sports Arena</channel>
<channel lang="en" xmltv_id="SkySportsBoxOffice.uk" site_id="hsqv">Sky Sports Box Office</channel>
<channel lang="en" xmltv_id="SkySportsCricket.uk" site_id="hsss">Sky Sports Cricket</channel>
<channel lang="en" xmltv_id="SkySportsF1.uk" site_id="hssv">Sky Sports F1</channel>
<channel lang="en" xmltv_id="SkySportsFootball.uk" site_id="hssr">Sky Sports Football</channel>
<channel lang="en" xmltv_id="SkySportsGolf.uk" site_id="hsst">Sky Sports Golf</channel>
<channel lang="en" xmltv_id="SkySportsMainEvent.uk" site_id="hssp">Sky Sports Main Event</channel>
<channel lang="en" xmltv_id="SkySportsMix.uk" site_id="hssz">Sky Sports Mix</channel>
<channel lang="en" xmltv_id="SkySportsNews.uk" site_id="hssn">Sky Sports News UK</channel>
<channel lang="en" xmltv_id="SkySportsPremierLeague.uk" site_id="hssq">Sky Sports Premier League</channel>
<channel lang="en" xmltv_id="SkySportsRacing.uk" site_id="hssy">Sky Sports Racing</channel>
<channel lang="en" xmltv_id="SkyWitness.uk" site_id="hsq5">Sky Witness</channel>
<channel lang="en" xmltv_id="SmithsonianChannelUK.uk" site_id="hswq">Smithsonian Channel UK</channel>
<channel lang="en" xmltv_id="STV.uk" site_id="hs6w">STV</channel>
<channel lang="en" xmltv_id="STVPlus1.uk" site_id="hs8h">STV+1</channel>
<channel lang="en" xmltv_id="TalkingPicturesTV.uk" site_id="hsxd">Talking Pictures TV</channel>
<channel lang="en" xmltv_id="TBNUK.uk" site_id="hswx">TBN UK</channel>
<channel lang="en" xmltv_id="TinyPop.uk" site_id="hsyh">Tiny Pop</channel>
<channel lang="en" xmltv_id="TJC.uk" site_id="hswm">TJC</channel>
<channel lang="en" xmltv_id="TogetherTV.uk" site_id="hsxj">Together TV</channel>
<channel lang="en" xmltv_id="XpandedTV.uk" site_id="hsyv">Xpanded TV</channel>
<channel lang="en" xmltv_id="Yesterday.uk" site_id="hsvq">Yesterday</channel>
<channel lang="en" xmltv_id="YesterdayPlus1.uk" site_id="hsw7">Yesterday+1</channel>
</channels>
</site>

View File

@@ -0,0 +1,54 @@
const dayjs = require('dayjs')
module.exports = {
site: 'bt.com',
days: 2,
url: function ({ date, channel }) {
return `https://voila.metabroadcast.com/4/schedules/${
channel.site_id
}.json?key=b4d2edb68da14dfb9e47b5465e99b1b1&from=${date.utc().format()}&to=${date
.add(1, 'd')
.utc()
.format()}&source=api.youview.tv&annotations=content.description`
},
parser: function ({ content }) {
const programs = []
const items = parseItems(content)
items.forEach(item => {
programs.push({
title: item.item.title,
description: item.item.description,
icon: parseIcon(item),
season: parseSeason(item),
episode: parseEpisode(item),
start: parseStart(item),
stop: parseStop(item)
})
})
return programs
}
}
function parseItems(content) {
const data = JSON.parse(content)
return data && data.schedule.entries ? data.schedule.entries : []
}
function parseSeason(item) {
if (item.item.type !== 'episode') return null
return item.item.series_number || null
}
function parseEpisode(item) {
if (item.item.type !== 'episode') return null
return item.item.episode_number || null
}
function parseIcon(item) {
return item.item.image || null
}
function parseStart(item) {
return dayjs(item.broadcast.transmission_time)
}
function parseStop(item) {
return dayjs(item.broadcast.transmission_end_time)
}

View File

@@ -0,0 +1,50 @@
// npx epg-grabber --config=sites/bt.com/bt.com.config.js --channels=sites/bt.com/bt.com.channels.xml --output=guide.xml --days=2
const { parser, url } = require('./bt.com.config.js')
const axios = require('axios')
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-03-20', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: 'hsxv',
xmltv_id: 'BBCOneHD.uk'
}
it('can generate valid url', () => {
expect(url({ date, channel })).toBe(
'https://voila.metabroadcast.com/4/schedules/hsxv.json?key=b4d2edb68da14dfb9e47b5465e99b1b1&from=2022-03-20T00:00:00Z&to=2022-03-21T00:00:00Z&source=api.youview.tv&annotations=content.description'
)
})
it('can parse response', () => {
const content = `{"schedule":{"channel":{"title":"BBC One HD","id":"hsxv","uri":"http://api.youview.tv/channels/dvb://233a..4484","images":[{"uri":"https://images.metabroadcast.com?source=http%3A%2F%2Fimages-live.youview.tv%2Fimages%2Fentity%2F8c4c0357-d7ee-5d8a-8bc4-b177b6875128%2Fident%2F1_1024x532.png%3Fdefaultimg%3D0&ETag=r5vyecG6of%2BhCbHeEClx0Q%3D%3D","mime_type":"image/png","type":null,"color":"monochrome","theme":"light_monochrome","aspect_ratio":null,"availability_start":null,"availability_end":null,"width":1024,"height":532,"hasTitleArt":null,"source":null}],"available_from":[{"key":"api.youview.tv","name":"YouView JSON","country":"GB"}],"source":{"key":"api.youview.tv","name":"YouView JSON","country":"GB"},"same_as":[],"media_type":"video","broadcaster":null,"aliases":[{"namespace":"youview:serviceLocator","value":"dvb://233a..4484"},{"namespace":"youview:channel:id","value":"8c4c0357-d7ee-5d8a-8bc4-b177b6875128"}],"genres":[],"high_definition":true,"timeshifted":null,"regional":null,"related_links":[],"start_date":null,"advertised_from":null,"advertised_to":null,"short_description":null,"medium_description":null,"long_description":null,"region":null,"target_regions":[],"channel_type":"CHANNEL","interactive":false,"transmission_types":["DTT"],"quality":"HD","hdr":false},"source":"api.youview.tv","entries":[{"broadcast":{"aliases":[{"namespace":"api.youview.tv:slot","value":"dvb://233a..4484;76bc"},{"namespace":"dvb:event-locator","value":"dvb://233a..4484;76bc"},{"namespace":"dvb:pcrid","value":"crid://fp.bbc.co.uk/b/3Q30S2"},{"namespace":"youview:schedule_event:id","value":"79d318f3-b41a-582d-b089-7b0172538b42"}],"transmission_time":"2022-03-19T23:30:00.000Z","transmission_end_time":"2022-03-20T01:20:00.000Z","broadcast_duration":6600,"broadcast_on":"hsxv","schedule_date":null,"repeat":null,"subtitled":true,"signed":null,"audio_described":false,"high_definition":null,"widescreen":null,"surround":null,"live":null,"premiere":null,"continuation":null,"new_series":null,"new_episode":null,"new_one_off":null,"revised_repeat":null,"blackout_restriction":{"all":false}},"item":{"id":"n72nsw","type":"item","display_title":{"title":"The Finest Hours (2016)","subtitle":null},"year":null,"media_type":"video","specialization":"tv","source":{"key":"api.youview.tv","name":"YouView JSON","country":"GB"},"title":"The Finest Hours (2016)","description":"Drama based on a true story, recounting one of history's most daring coastguard rescue attempts. Stranded on a sinking oil tanker along with 30 other sailors, engineer Ray Sybert battles to buy his crew more time as Captain Bernie Webber and three of his colleagues tackle gigantic waves and gale-force winds in their astonishing bid to save the seamen.","image":"https://images.metabroadcast.com?source=http%3A%2F%2Fimages-live.youview.tv%2Fimages%2Fentity%2F52172983%2Fprimary%2F1_1024x576.jpg%3Fdefaultimg%3D0&ETag=z7ucT5kdAq7HuNQf%2FGTEJg%3D%3D","thumbnail":null,"duration":null,"container":null}}]},"terms_and_conditions":{"text":"Specific terms and conditions in your agreement with MetaBroadcast, and with any data provider, apply to your use of this data, and associated systems."},"results":1,"request":{"path":"/4/schedules/hsxv.json","parameters":{"annotations":"content.description","from":"2022-03-20T00:00:00Z","to":"2022-03-21T00:00:00Z","source":"api.youview.tv","key":"b4d2edb68da14dfb9e47b5465e99b1b1"}}}`
const result = parser({ content }).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
title: 'The Finest Hours (2016)',
description: `Drama based on a true story, recounting one of history's most daring coastguard rescue attempts. Stranded on a sinking oil tanker along with 30 other sailors, engineer Ray Sybert battles to buy his crew more time as Captain Bernie Webber and three of his colleagues tackle gigantic waves and gale-force winds in their astonishing bid to save the seamen.`,
icon: 'https://images.metabroadcast.com?source=http%3A%2F%2Fimages-live.youview.tv%2Fimages%2Fentity%2F52172983%2Fprimary%2F1_1024x576.jpg%3Fdefaultimg%3D0&ETag=z7ucT5kdAq7HuNQf%2FGTEJg%3D%3D',
season: null,
episode: null,
start: '2022-03-19T23:30:00.000Z',
stop: '2022-03-20T01:20:00.000Z'
}
])
})
it('can handle empty guide', () => {
const result = parser({
content: `{"schedule":{"channel":{"title":"BBC One HD","id":"hsxv","uri":"http://api.youview.tv/channels/dvb://233a..4484","images":[{"uri":"https://images.metabroadcast.com?source=http%3A%2F%2Fimages-live.youview.tv%2Fimages%2Fentity%2F8c4c0357-d7ee-5d8a-8bc4-b177b6875128%2Fident%2F1_1024x532.png%3Fdefaultimg%3D0&ETag=r5vyecG6of%2BhCbHeEClx0Q%3D%3D","mime_type":"image/png","type":null,"color":"monochrome","theme":"light_monochrome","aspect_ratio":null,"availability_start":null,"availability_end":null,"width":1024,"height":532,"hasTitleArt":null,"source":null}],"available_from":[{"key":"api.youview.tv","name":"YouView JSON","country":"GB"}],"source":{"key":"api.youview.tv","name":"YouView JSON","country":"GB"},"same_as":[],"media_type":"video","broadcaster":null,"aliases":[{"namespace":"youview:serviceLocator","value":"dvb://233a..4484"},{"namespace":"youview:channel:id","value":"8c4c0357-d7ee-5d8a-8bc4-b177b6875128"}],"genres":[],"high_definition":true,"timeshifted":null,"regional":null,"related_links":[],"start_date":null,"advertised_from":null,"advertised_to":null,"short_description":null,"medium_description":null,"long_description":null,"region":null,"target_regions":[],"channel_type":"CHANNEL","interactive":false,"transmission_types":["DTT"],"quality":"HD","hdr":false},"source":"api.youview.tv","entries":[]},"terms_and_conditions":{"text":"Specific terms and conditions in your agreement with MetaBroadcast, and with any data provider, apply to your use of this data, and associated systems."},"results":1,"request":{"path":"/4/schedules/hsxv.json","parameters":{"annotations":"content.description","from":"2022-03-20T00:00:00Z","to":"2022-03-21T00:00:00Z","source":"api.youview.tv","key":"b4d2edb68da14dfb9e47b5465e99b1b1"}}}`
})
expect(result).toMatchObject([])
})

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="cablego.com.pe">
<channels>
<channel lang="es" xmltv_id="AmericaTelevision.pe" site_id="0#AMERICATV">AMERICA TV</channel>
<channel lang="es" xmltv_id="ATV.pe" site_id="0#ATVHD">ATV</channel>
<channel lang="es" xmltv_id="ATVPlus.pe" site_id="0#ATVMAS">ATV+</channel>
<channel lang="es" xmltv_id="BHTV.pe" site_id="0#BHTV">BHTV</channel>
<channel lang="es" xmltv_id="Conecta2TV.pe" site_id="0#CONECTA2">CONECTA2 TV</channel>
<channel lang="es" xmltv_id="CongresoTV.pe" site_id="0#CANALCONGRESO">CONGRESO TV</channel>
<channel lang="es" xmltv_id="DePeliculaLatinAmerica.mx" site_id="1#DEPELICULA">DE PELICULA</channel>
<channel lang="es" xmltv_id="DistritoComedia.mx" site_id="3#DISTRITOCOMEDIA">DISTRITO COMEDIA</channel>
<channel lang="es" xmltv_id="EcuadorTV.ec" site_id="4#ECUADORTV">ECUADOR TV</channel>
<channel lang="es" xmltv_id="EuropaEuropa.ar" site_id="1#EUROPAEUROPA">EUROPA EUROPA</channel>
<channel lang="es" xmltv_id="ExitosaTV.pe" site_id="0#EXITOSATV">EXITOSA TV</channel>
<channel lang="es" xmltv_id="GlobalTV.pe" site_id="0#GLOBAL">GLOBAL</channel>
<channel lang="es" xmltv_id="GoldenEdgePanregional.mx" site_id="1#GOLDENEDGE">GOLDEN EDGE</channel>
<channel lang="es" xmltv_id="Karibena.pe" site_id="4#KARIBENA">KARIBEÑA</channel>
<channel lang="es" xmltv_id="Latina.pe" site_id="0#LATINA">LATINA</channel>
<channel lang="es" xmltv_id="Nativa.pe" site_id="0#NATIVA">NATIVA</channel>
<channel lang="es" xmltv_id="OvacionTV.pe" site_id="3#OVACION">OVACION</channel>
<channel lang="es" xmltv_id="PanamericanaTV.pe" site_id="0#PANAMERICANATV">PANAMERICANA TV</channel>
<channel lang="es" xmltv_id="PasionesLatinAmerica.us" site_id="2#PASIONES">PASIONES</channel>
<channel lang="es" xmltv_id="PBO.pe" site_id="0#PBO">PBO</channel>
<channel lang="es" xmltv_id="TVPeru.pe" site_id="0#TVPERU">TV PERU</channel>
<channel lang="es" xmltv_id="USMPTV.pe" site_id="0#USMPTV">USMP TV</channel>
<channel lang="es" xmltv_id="Venus.ar" site_id="4#VENUS">VENUS</channel>
<channel lang="es" xmltv_id="WillaxTV.pe" site_id="0#WILLAX">WILLAX</channel>
<!-- <channel lang="es" xmltv_id="" site_id="0#AMC">AMC</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="0#CloverCH">CLOVER CHANNEL</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="0#FOXCHANNEL">STAR CHANNEL</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="0#FX">FX</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="0#ID">ID</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="0#PARAMOUNTCH">PARAMOUNT CHANNEL</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1#ANIMALPLANET">ANIMAL PLANET</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1#AZCINEMA">CINEMA INOLVIDABLE</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1#AZCORAZON">CORAZON</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1#CHESTRELLAS">CANAL DE LAS ESTRELLAS</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1#CINECANAL">CINECANAL</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1#DISCOVERYCHANNEL">DISCOVERY CHANNEL</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1#DISCOVERYSCIENCE">DISCOVERY SCIENCE</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1#DISCOVERYTHEATER">DISCOVERY THEATER</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1#DISCOVERYTURBO">DISCOVERY TURBO</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1#DISCOVERYWORLD">DISCOVERY WORLD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1#FILMSandARTS">FILMS &amp; ARTS</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1#GOLDENLATINO">GOLDEN LATINO</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1#NATGEO">NATGEO</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1#SONYMOVIES">SONY MOVIES</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1#TELEMUNDO">TELEMUNDO</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1#UNIVISION">UNIVISION</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#AZMUNDO">MUNDO</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#BITME">BITME</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#DISCOVERYKIDS">DISCOVERY KIDS</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#DISNEYCHANNEL">DISNEY CHANNEL</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#DISNEYJUNIOR">DISNEY JUNIOR</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#DREAMWORKS">DREAMWORKS</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#ESPN">ESPN</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#ESPN2">ESPN2</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#FOODNETWORK">FOOD NETWORK</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#GOURMET">GOURMET</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#HGTV">HGTV</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#HOMEANDHEALTH">HOME &amp; HEALTH</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#KANALD">KANAL D</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#MASCHIC">MAS CHIC</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#NICKELODEON">NICKELODEON</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#NICKJR">NICK JR</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#TELENOVELAS">TELENOVELAS</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#TRAVELANDLIVING">TLC</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2#ZOOMOO">ZOOMOO</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#ANTENA3">ANTENA 3</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#BANDAMAX">BANDAMAX</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#CGTN">CGTN</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#ESPN3">ESPN3</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#ESPNMAS">ESPN EXTRA</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#FOXSPORTS">ESPN4</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#FOXSPORTS2">FOX SPORTS 2</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#FOXSPORTS3">FOX SPORTS 3</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#IVCNETWORKS">IVC NETWORKS</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#LANACIONAL">LA NACIONAL</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#MTV">MTV</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#NICKMUSIC">NICKMUSIC</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#NOTICIASCARACOL">NOTICIAS CARACOL</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#SBTBRASIL">SBT Brasil</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#TELEFE">TELEFE</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#TELEHITLATINO">TELEHIT LATINO</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#TELEHITMUSICA">TELEHIT MUSICA</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3#TRECEARGENTINA">TRECE ARGENTINA</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4#AandEMUNDO">A&amp;E</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4#AXN">AXN</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4#DW">DW</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4#ECH">E!</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4#HISTORY2">HISTORY 2</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4#HISTORYCHANNEL">HISTORY CHANNEL</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4#LIFETIME">LIFE TIME</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4#PLAYBOY">PLAYBOY</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4#SONY">SONY</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4#STUDIOUNIVERSAL">STUDIO UNIVERSAL</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4#SYFY">SYFY</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4#UNIVERSAL">UNIVERSAL</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4#WARNERCHANNEL">WARNER CH</channel> -->
</channels>
</site>

View File

@@ -0,0 +1,109 @@
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',
days: 2,
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()
}

View File

@@ -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.channels.xml
// npx epg-grabber --config=sites/cablego.com.pe/cablego.com.pe.config.js --channels=sites/cablego.com.pe/cablego.com.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([])
})

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,163 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="cableplus.com.uy">
<channels>
<channel lang="es" xmltv_id="360TV.ar" site_id="2000">360 TV</channel>
<channel lang="es" xmltv_id="A24.ar" site_id="343">A24</channel>
<channel lang="es" xmltv_id="AmericaSports.ar" site_id="84">AMERICA SPORTS</channel>
<channel lang="es" xmltv_id="APlusV.uy" site_id="2035">A+V</channel>
<channel lang="es" xmltv_id="ArgentinisimaSatelital.ar" site_id="57">ARGENTINISIMA</channel>
<channel lang="es" xmltv_id="BBCWorldNewsLatinAmerica.uk" site_id="80">BBC WORLD</channel>
<channel lang="es" xmltv_id="BYUTVLatinAmerica.us" site_id="574">BYUTV</channel>
<channel lang="es" xmltv_id="Canal10.uy" site_id="1387">SAETA</channel>
<channel lang="es" xmltv_id="Canal26.ar" site_id="3">CANAL 26</channel>
<channel lang="es" xmltv_id="Canal5.uy" site_id="475">TV NACIONAL</channel>
<channel lang="es" xmltv_id="Canal7PuntadelEste.uy" site_id="2858">CANAL 7 PUNTA DEL ESTE</channel>
<channel lang="es" xmltv_id="CanalRural.ar" site_id="11">CANAL RURAL</channel>
<channel lang="es" xmltv_id="CardinalTV.uy" site_id="4866">CARDINAL TV</channel>
<channel lang="es" xmltv_id="CharruaTelevision.uy" site_id="2874">CHARRUA TV</channel>
<channel lang="es" xmltv_id="Clan.es" site_id="4312">CLAN HD</channel>
<channel lang="es" xmltv_id="CNNenEspanol.us" site_id="62">CNN EN ESPAÑOL</channel>
<channel lang="es" xmltv_id="CronicaTV.ar" site_id="192">CRONICA</channel>
<channel lang="es" xmltv_id="DWDeutschPlus.de" site_id="2067">DEUTSCHE WELLE (DEUTSCH+)</channel>
<channel lang="es" xmltv_id="DWEspanol.de" site_id="16">DW ESPAÑOL</channel>
<channel lang="es" xmltv_id="ElCanaldelaRegion.uy" site_id="5020">CANAL DE LA REGIÓN</channel>
<channel lang="es" xmltv_id="ElGarageTV.ar" site_id="358">EL GARAGE</channel>
<channel lang="es" xmltv_id="ETBBasque.es" site_id="273">CANAL VASCO</channel>
<channel lang="es" xmltv_id="France24Espanol.fr" site_id="4124">FRANCE 24 ESPAÑOL</channel>
<channel lang="es" xmltv_id="France24French.fr" site_id="3431">FRANCE 24 FRANCES</channel>
<channel lang="es" xmltv_id="GaliciaTVAmerica.es" site_id="65">GALICIA TV</channel>
<channel lang="es" xmltv_id="GolTVLatinAmerica.us" site_id="1519">GOL TV</channel>
<channel lang="es" xmltv_id="HBOMundiLatinAmerica.us" site_id="12">HBO MUNDI</channel>
<channel lang="es" xmltv_id="HBOPopLatinAmerica.us" site_id="1378">HBO POP</channel>
<channel lang="es" xmltv_id="HBOSignatureLatinAmerica.us" site_id="500">HBO SIGNATURE</channel>
<channel lang="es" xmltv_id="LaNacionPlus.ar" site_id="3644">LA NACION +</channel>
<channel lang="es" xmltv_id="MaronasEntertainment.uy" site_id="2412">MAROÑAS</channel>
<channel lang="es" xmltv_id="PXSports.mx" site_id="2063">PX SPORTS HD</channel>
<channel lang="es" xmltv_id="RaiItaliaAmerica.it" site_id="29">RAI</channel>
<channel lang="es" xmltv_id="RTenEspanol.ru" site_id="1502">RT TV</channel>
<channel lang="es" xmltv_id="Siemprecine.uy" site_id="365">SIEMPRE CINE</channel>
<channel lang="es" xmltv_id="SunChannel.ve" site_id="2257">SUN CHANNEL HD</channel>
<channel lang="es" xmltv_id="Teledoce.uy" site_id="483">TELEDOCE</channel>
<channel lang="es" xmltv_id="Tooncast.us" site_id="880">TOONCAST</channel>
<channel lang="es" xmltv_id="truTVLatinAmerica.us" site_id="912">TRU TV</channel>
<channel lang="es" xmltv_id="TVCiudad.uy" site_id="1290">TEVECIUDAD</channel>
<channel lang="es" xmltv_id="TVN.cl" site_id="39">TVN CHILE</channel>
<channel lang="es" xmltv_id="TVPublica.ar" site_id="135">TV PUBLICA ARG</channel>
<channel lang="es" xmltv_id="UCL.uy" site_id="2541">UCL</channel>
<channel lang="es" xmltv_id="VTV.uy" site_id="373">VTV</channel>
<channel lang="es" xmltv_id="VTVPlus.uy" site_id="2368">VTV +</channel>
<channel lang="es" xmltv_id="WOBI.ar" site_id="723">WOBI TV</channel>
<channel lang="es" xmltv_id="ZooMoo.sg" site_id="3271">ZOOMOO</channel>
<!-- <channel lang="es" xmltv_id="" site_id="100">AXN</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1011">CITYTV</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="111">DISCOVERY ID</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1120">STUDIO UNIVERSAL</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1132">ESPN EXTRA HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1181">DISCOVERY HD THEATER</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="125">EL GOURMET</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="13">CNN</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="136">DISNEY</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1383">MONTECARLO</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1389">DISCOVERY WORLD HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1499">HISTORY HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="15">CINECANAL</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1531">HGTV</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1552">CGTN</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1579">SONY HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1623">ANIMAL PLANET</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1624">DISCOVERY TRAVEL AND LIVING</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1666">TYC SPORTS HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="167">A&amp;E MUNDO</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="17">DISCOVERY</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="174">CARTOONITO</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="178">HISTORY</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="1862">AXN HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2040">FX HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="21">HBO</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2127">HBO 2</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2165">HBO PLUS ESTE</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2218">DISCOVERY HOME AND HEALTH HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="226">CARTOON NETWORK</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2271">TYC SPORTS</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2292">CINEMAX</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="265">TNT</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2670">HOLA TV HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2693">ESPN 4 HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2711">NAT GEO HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2729">FOX SPORTS 2</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2788">LIFETIME</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="28">MUCHMUSIC</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="281">CANAL 24 HS</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2845">CARTOON NETWORK HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="2860">MONTECARLO HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3064">STAR CHANNEL HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3066">DISCOVERY HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3142">CINEMAX HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3154">ALLEGRO HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="32">SONY</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3223">DISCOVERY TURBO HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3244">EL GOURMET HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="33">SPACE</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="334">HBO XTREME ESTE</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="335">HBO FAMILY</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3373">CANAL 6 LOCAL</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3374">EVENTOS CABLEPLUS</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3375">EVENTOS HD CABLEPLUS</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3389">STAR HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="340">DISCOVERY HOME AND HEALTH</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3438">FOOD NETWORK</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3445">CINECANAL HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="348">ESPN 4</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3573">LIFETIME HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3601">FOX SPORTS 2 HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3621">H2 HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3628">ATRES CINE HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="372">BANDEIRANTES</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3787">WARNER HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="38">TV 5</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="388">TELESUR</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3898">FOX SPORTS 3</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3899">FOX SPORTS 3 HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="3988">ATRESERIES HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4054">TNT HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="413">ENLACE TBN</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4226">HTV HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4256">ANTENA3 HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="426">FX</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4301">TELEMUNDO HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4367">DISNEY HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="451">STAR CHANNEL</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4535">SPACE HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="46">WARNER</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4600">AL JAZEERA HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4605">ANIMAL PLANET HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="463">NATIONAL GEOGRAPHIC</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="465">UNIVERSAL TV</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4704">DISCOVERY SCIENCE HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4718">LOVE NATURE</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4867">LA REPUBLICA TV</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="4902">DISCOVERY ID HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="492">DISCOVERY TURBO</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="493">DISCOVERY SCIENCE</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="50">ENTERTAINMENT</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="5249">ESPN 3</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="5252">ESPN 3 HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="5253">ESPN</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="5254">ESPN HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="59">TVE</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="61">ANTENA3</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="6198">ESPN 2</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="6199">ESPN 2 HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="64">EWTN</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="685">RECORD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="695">BABY TV</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="743">NHK WORLD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="756">DISNEY JR</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="76">DISCOVERY KIDS</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="760">SY FY</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="82">TV GLOBO</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="875">HBO HD</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="943">AMERICA 2</channel> -->
<!-- <channel lang="es" xmltv_id="" site_id="958">TELEMUNDO</channel> -->
</channels>
</site>

View File

@@ -0,0 +1,133 @@
const cheerio = require('cheerio')
const axios = require('axios')
const dayjs = require('dayjs')
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)
const API_ENDPOINT = 'https://www.reportv.com.ar/finder'
module.exports = {
site: 'cableplus.com.uy',
days: 2,
url: `${API_ENDPOINT}/channel`,
request: {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
data({ date, channel }) {
const params = new URLSearchParams()
params.append('idAlineacion', '3017')
params.append('idSenial', channel.site_id)
params.append('fecha', date.format('YYYY-MM-DD'))
params.append('hora', '00:00')
return params
}
},
parser({ content, date }) {
const programs = []
const items = parseItems(content, date)
items.forEach(item => {
const $item = cheerio.load(item)
const prev = programs[programs.length - 1]
let start = parseStart($item, date)
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),
categories: parseCategories($item),
icon: parseIcon($item),
start,
stop
})
})
return programs
},
async channels() {
const params = new URLSearchParams({ idAlineacion: '3017' })
const data = await axios
.post(`${API_ENDPOINT}/channelGrid`, params, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }
})
.then(r => r.data)
.catch(console.error)
const $ = cheerio.load(data)
return $('.senial')
.map(function () {
return {
lang: 'es',
site_id: $(this).attr('id'),
name: $(this).find('img').attr('alt')
}
})
.get()
}
}
function parseTitle($item) {
return $item('p.evento_titulo.texto_a_continuacion.dotdotdot,.programa-titulo > span:first-child')
.text()
.trim()
}
function parseIcon($item) {
return $item('img').data('src') || $item('img').attr('src') || null
}
function parseCategories($item) {
return $item('p.evento_genero')
.map(function () {
return $item(this).text().trim()
})
.toArray()
}
function parseStart($item, date) {
let time = $item('.grid_fecha_hora').text().trim()
if (time) {
return dayjs.tz(`${date.format('YYYY')} ${time}`, 'YYYY DD-MM HH:mm[hs.]', 'America/Montevideo')
}
time = $item('.fechaHora').text().trim()
return time
? dayjs.tz(`${date.format('YYYY')} ${time}`, 'YYYY DD/MM HH:mm[hs.]', 'America/Montevideo')
: null
}
function parseItems(content, date) {
const $ = cheerio.load(content)
let featuredItems = $('.vista-pc > .programacion-fila > .channel-programa')
.filter(function () {
return $(this).find(`.grid_fecha_hora`).text().indexOf(date.format('DD-MM')) > -1
})
.toArray()
let otherItems = $(`#owl-pc > .item-program`)
.filter(function () {
return (
$(this)
.find(`.evento_titulo > .horario > p.fechaHora`)
.text()
.indexOf(date.format('DD/MM')) > -1
)
})
.toArray()
return featuredItems.concat(otherItems)
}

View File

@@ -0,0 +1,76 @@
// npm run channels:parse -- --config=./sites/cableplus.com.uy/cableplus.com.uy.config.js --output=./sites/cableplus.com.uy/cableplus.com.uy.channels.xml
// npx epg-grabber --config=sites/cableplus.com.uy/cableplus.com.uy.config.js --channels=sites/cableplus.com.uy/cableplus.com.uy.channels.xml --output=guide.xml --days=2
const { parser, url, request } = require('./cableplus.com.uy.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('2023-02-12', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: '2035',
xmltv_id: 'APlusV.uy'
}
it('can generate valid url', () => {
expect(url).toBe('https://www.reportv.com.ar/finder/channel')
})
it('can generate valid request method', () => {
expect(request.method).toBe('POST')
})
it('can generate valid request headers', () => {
expect(request.headers).toMatchObject({
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
})
})
it('can generate valid request data', () => {
const params = request.data({ date, channel })
expect(params.get('idAlineacion')).toBe('3017')
expect(params.get('idSenial')).toBe('2035')
expect(params.get('fecha')).toBe('2023-02-12')
expect(params.get('hora')).toBe('00:00')
})
it('can parse response', () => {
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
let results = parser({ content, date })
results = results.map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(results.length).toBe(21)
expect(results[0]).toMatchObject({
start: '2023-02-12T09:30:00.000Z',
stop: '2023-02-12T10:30:00.000Z',
title: `Revista agropecuaria`,
icon: 'https://www.reportv.com.ar/buscador/img/Programas/2797844.jpg',
categories: []
})
expect(results[4]).toMatchObject({
start: '2023-02-12T12:30:00.000Z',
stop: '2023-02-12T13:30:00.000Z',
title: `De pago en pago`,
icon: 'https://www.reportv.com.ar/buscador/img/Programas/3772835.jpg',
categories: ['Cultural']
})
})
it('can handle empty guide', () => {
const result = parser({
date,
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
})
expect(result).toMatchObject([])
})

View File

@@ -0,0 +1,247 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="canalplus-afrique.com">
<channels>
<channel lang="fr" xmltv_id="2STV.sn" site_id="80122">2S TV</channel>
<channel lang="fr" xmltv_id="3TV.bf" site_id="80623">3 TV</channel>
<channel lang="fr" xmltv_id="7Info.ci" site_id="80829">7 Info</channel>
<channel lang="fr" xmltv_id="10emeRueTV.cd" site_id="80180">10&apos;ème Rue TV</channel>
<channel lang="fr" xmltv_id="13emeRue.fr" site_id="80001">13ème Rue</channel>
<channel lang="fr" xmltv_id="AB1.fr" site_id="80003">AB 1</channel>
<channel lang="fr" xmltv_id="Action.fr" site_id="80004">Action</channel>
<channel lang="fr" xmltv_id="Africa24.fr" site_id="80168">Africa 24</channel>
<channel lang="fr" xmltv_id="AfricableTV.ml" site_id="80166">Africable TV</channel>
<channel lang="fr" xmltv_id="Africanews.cg" site_id="80420">Africanews</channel>
<channel lang="fr" xmltv_id="AlafiaTV.ml" site_id="80922">Alafia TV</channel>
<channel lang="fr" xmltv_id="AlJazeeraChannel.qa" site_id="80277">Aljazeera Channel</channel>
<channel lang="fr" xmltv_id="Animaux.fr" site_id="80759">Animaux</channel>
<channel lang="fr" xmltv_id="AntenneA.cd" site_id="80322">Antenne A</channel>
<channel lang="fr" xmltv_id="APlus.fr" site_id="80335">A+</channel>
<channel lang="fr" xmltv_id="APlusIvoire.ci" site_id="80681">A+ Ivoire</channel>
<channel lang="fr" xmltv_id="APlusKidsTV.uk" site_id="80758">A+ Kids TV</channel>
<channel lang="fr" xmltv_id="Arewa24.ng" site_id="80686">Arewa 24</channel>
<channel lang="fr" xmltv_id="ARTEFrance.fr" site_id="80007">ARTE Français</channel>
<channel lang="fr" xmltv_id="AsfiyahiTV.sn" site_id="80612">Asfiyahi TV</channel>
<channel lang="fr" xmltv_id="AsongaTV.gq" site_id="80378">Asonga TV</channel>
<channel lang="fr" xmltv_id="AuthenticTV.rw" site_id="80749">Authentic TV</channel>
<channel lang="fr" xmltv_id="Automotolachaine.fr" site_id="80565">Automoto la chaîne</channel>
<channel lang="fr" xmltv_id="BantambaTV.sn" site_id="80569">Bantamba TV</channel>
<channel lang="fr" xmltv_id="BBCWorldNewsAfrica.uk" site_id="80008">BBC World News Africa</channel>
<channel lang="fr" xmltv_id="BF1.bf" site_id="80337">BF1</channel>
<channel lang="fr" xmltv_id="BloombergTVAfrica.us" site_id="80840">Bloomberg TV Africa</channel>
<channel lang="fr" xmltv_id="BOneTV.cd" site_id="80273">B-One TV</channel>
<channel lang="fr" xmltv_id="Bonferey.ne" site_id="80925">Bonferey</channel>
<channel lang="fr" xmltv_id="BTNTV.rw" site_id="80753">BTN TV</channel>
<channel lang="fr" xmltv_id="BurkinaInfoTV.bf" site_id="80556">Burkina Info TV</channel>
<channel lang="fr" xmltv_id="Business24Africa.ci" site_id="80390">Business 24 Africa</channel>
<channel lang="fr" xmltv_id="C8.fr" site_id="80120">C8</channel>
<channel lang="fr" xmltv_id="Canal2International.cm" site_id="80172">Canal 2 International</channel>
<channel lang="fr" xmltv_id="Canal2Movies.cm" site_id="80671">Canal 2 Movies</channel>
<channel lang="fr" xmltv_id="Canal3.bf" site_id="80795">Canal 3</channel>
<channel lang="fr" xmltv_id="Canal3Benin.bj" site_id="80546">Canal 3 Benin</channel>
<channel lang="fr" xmltv_id="CanalPlusActionCentre.fr" site_id="80626">Canal + Action Centre</channel>
<channel lang="fr" xmltv_id="CanalPlusActionOuest.fr" site_id="80645">Canal + Action Ouest</channel>
<channel lang="fr" xmltv_id="CanalPlusCinemaCentre.fr" site_id="80125">Canal + Cinéma Centre</channel>
<channel lang="fr" xmltv_id="CanalPlusCinemaOuest.fr" site_id="80016">Canal + Cinéma Ouest</channel>
<channel lang="fr" xmltv_id="CanalPlusEllesCentre.fr" site_id="80302">Canal + Elles Centre</channel>
<channel lang="fr" xmltv_id="CanalPlusEllesOuest.fr" site_id="80402">Canal + Elles Ouest</channel>
<channel lang="fr" xmltv_id="CanalPlusFamilyCentre.fr" site_id="80144">Canal + Family Centre</channel>
<channel lang="fr" xmltv_id="CanalPlusFamilyOuest.fr" site_id="80403">Canal + Family Ouest</channel>
<channel lang="fr" xmltv_id="CanalPlusPopCentre.fr" site_id="80628">Canal + Pop Centre</channel>
<channel lang="fr" xmltv_id="CanalPlusPopOuest.fr" site_id="80646">Canal + Pop Ouest</channel>
<channel lang="fr" xmltv_id="CanalPlusPremiereCentre.fr" site_id="80129">Canal + Première Centre</channel>
<channel lang="fr" xmltv_id="CanalPlusPremiereOuest.fr" site_id="80018">Canal + Première Ouest</channel>
<channel lang="fr" xmltv_id="CanalPlusSport1.fr" site_id="80625">Canal + Sport 1</channel>
<channel lang="fr" xmltv_id="CanalPlusSport2.fr" site_id="80124">Canal + Sport 2</channel>
<channel lang="fr" xmltv_id="CanalPlusSport3.fr" site_id="80149">Canal + Sport 3</channel>
<channel lang="fr" xmltv_id="CanalPlusSport4.fr" site_id="80393">Canal + Sport 4</channel>
<channel lang="fr" xmltv_id="CanalPlusSport5.fr" site_id="80394">Canal + Sport 5</channel>
<channel lang="fr" xmltv_id="CapitalSanteTV.cm" site_id="80928">Capital Santé TV</channel>
<channel lang="fr" xmltv_id="CartoonNetworkFrance.fr" site_id="80756">Cartoon Network France</channel>
<channel lang="fr" xmltv_id="CDirect.fr" site_id="80765">CDirect</channel>
<channel lang="fr" xmltv_id="CGTNFrench.cn" site_id="80309">CGTN Français</channel>
<channel lang="fr" xmltv_id="CheriflaTV.ml" site_id="80669">Cherifla TV</channel>
<channel lang="fr" xmltv_id="CISTV.gn" site_id="80602">CIS TV</channel>
<channel lang="fr" xmltv_id="CliqueTV.fr" site_id="80615">Clique TV</channel>
<channel lang="fr" xmltv_id="CNBCAfrica.za" site_id="80571">CNBC Africa</channel>
<channel lang="fr" xmltv_id="CNews.fr" site_id="80048">C News</channel>
<channel lang="fr" xmltv_id="CrimeDistrict.fr" site_id="80760">Crime District</channel>
<channel lang="fr" xmltv_id="CRTV.cm" site_id="80010">CRTV</channel>
<channel lang="fr" xmltv_id="CRTVNews.cm" site_id="80668">CRTV News</channel>
<channel lang="fr" xmltv_id="CRTVSportsandEntertainment.cm" site_id="80717">CRTV Sports and Entertainment</channel>
<channel lang="fr" xmltv_id="CStar.fr" site_id="80217">C Star</channel>
<channel lang="fr" xmltv_id="Cuisines.fr" site_id="80711">Cuisines</channel>
<channel lang="fr" xmltv_id="CVK.bf" site_id="80764">CVK</channel>
<channel lang="fr" xmltv_id="DigitalCongoTV.cd" site_id="80380">Digital Congo TV</channel>
<channel lang="fr" xmltv_id="DiscoveryChannelFrance.fr" site_id="80248">Discovery Channel France</channel>
<channel lang="fr" xmltv_id="DiscoveryScienceFrance.fr" site_id="80249">Discovery Science France</channel>
<channel lang="fr" xmltv_id="DisneyChannelFrance.fr" site_id="80035">Disney Channel France</channel>
<channel lang="fr" xmltv_id="DisneyJuniorFrance.fr" site_id="80075">Disney Junior France</channel>
<channel lang="fr" xmltv_id="DjomaTV.gn" site_id="80930">Djoma TV</channel>
<channel lang="fr" xmltv_id="DorcelTV.nl" site_id="80638">Dorcel TV</channel>
<channel lang="fr" xmltv_id="DorcelTVAfrica.nl" site_id="80702">Dorcel TV Africa</channel>
<channel lang="fr" xmltv_id="DouniaTV.ne" site_id="80924">Dounia TV</channel>
<channel lang="fr" xmltv_id="DRTVInternational.cg" site_id="80383">DRTV International</channel>
<channel lang="fr" xmltv_id="EAfrica.us" site_id="80036">E! Africa</channel>
<channel lang="fr" xmltv_id="EcclesiaTV.ci" site_id="80974">Ecclesia TV</channel>
<channel lang="fr" xmltv_id="EDAN.fr" site_id="80369">EDAN</channel>
<channel lang="fr" xmltv_id="ElectronTV.td" site_id="80387">Electron TV</channel>
<channel lang="fr" xmltv_id="Elmouritania.mr" site_id="80384">Elmouritania</channel>
<channel lang="fr" xmltv_id="EMCITVAfrique.cd" site_id="80673">EMCI TV Afrique</channel>
<channel lang="fr" xmltv_id="EquinoxeTV.cm" site_id="80170">Equinoxe TV</channel>
<channel lang="fr" xmltv_id="MGGTV.fr" site_id="80667">ES1</channel>
<channel lang="fr" xmltv_id="EspaceTV.gn" site_id="80425">Espace TV</channel>
<channel lang="fr" xmltv_id="Etele.bj" site_id="80421">E-Télé Benin</channel>
<channel lang="fr" xmltv_id="EuronewsFrench.fr" site_id="80040">EuroNews Français</channel>
<channel lang="fr" xmltv_id="Eurosport1.fr" site_id="80041">Eurosport 1 France</channel>
<channel lang="fr" xmltv_id="Eurosport2.fr" site_id="80042">Eurosport 2 France</channel>
<channel lang="fr" xmltv_id="EvasionTV.gn" site_id="80398">Evasión Guinée</channel>
<channel lang="fr" xmltv_id="FarinWata.ng" site_id="80740">Farin Wata</channel>
<channel lang="fr" xmltv_id="FashionAfricaTV.sn" site_id="80376">Fashion Africa TV</channel>
<channel lang="fr" xmltv_id="FlashTV.rw" site_id="80750">Flash TV</channel>
<channel lang="fr" xmltv_id="France2.fr" site_id="80044">France 2</channel>
<channel lang="fr" xmltv_id="France3.fr" site_id="80045">France 3</channel>
<channel lang="fr" xmltv_id="France5.fr" site_id="80046">France 5</channel>
<channel lang="fr" xmltv_id="France24French.fr" site_id="80114">France 24 Français</channel>
<channel lang="fr" xmltv_id="Gabon1ere.ga" site_id="80187">Gabon 1ère</channel>
<channel lang="fr" xmltv_id="Gabon24.ga" site_id="80427">Gabon 24</channel>
<channel lang="fr" xmltv_id="GabonCulture.ga" site_id="80830">Gabon Culture</channel>
<channel lang="fr" xmltv_id="GameOne.fr" site_id="80136">Game One</channel>
<channel lang="fr" xmltv_id="GenesisTV.rw" site_id="80752">Genesis TV</channel>
<channel lang="fr" xmltv_id="GolfeTVAfrica.bj" site_id="80379">Golfe TV Africa</channel>
<channel lang="fr" xmltv_id="GulliAfrica.fr" site_id="80367">Gulli Africa</channel>
<channel lang="fr" xmltv_id="HistoireTV.fr" site_id="80158">Histoire TV</channel>
<channel lang="fr" xmltv_id="I24NewsFrench.il" site_id="80308">I24 News Français</channel>
<channel lang="fr" xmltv_id="ImpactTV.bf" site_id="80386">ImpacTV</channel>
<channel lang="fr" xmltv_id="InfosportPlus.fr" site_id="80050">InfoSport +</channel>
<channel lang="fr" xmltv_id="InfoTV.cm" site_id="80389">InfoTV</channel>
<channel lang="fr" xmltv_id="IqraaAfricaEurope.sa" site_id="80279">Iqraa Africa &amp; Europe</channel>
<channel lang="fr" xmltv_id="IsangoTV.rw" site_id="80751">Isango TV</channel>
<channel lang="fr" xmltv_id="ITV.sn" site_id="80722">ITV</channel>
<channel lang="fr" xmltv_id="IvoireTVMusic.fr" site_id="80580">Ivoire TV Music</channel>
<channel lang="fr" xmltv_id="JolibaTVNews.ml" site_id="80527">Joliba TV News</channel>
<channel lang="fr" xmltv_id="JOne.fr" site_id="80568">J-One</channel>
<channel lang="fr" xmltv_id="KalacTV.gn" site_id="80640">Kalac TV</channel>
<channel lang="fr" xmltv_id="KC2.rw" site_id="80747">KC2</channel>
<channel lang="fr" xmltv_id="KTO.fr" site_id="80278">KTO</channel>
<channel lang="fr" xmltv_id="LabelTV.ga" site_id="80622">Label TV</channel>
<channel lang="fr" xmltv_id="LampFallTV.sn" site_id="80921">Lamp Fall TV</channel>
<channel lang="fr" xmltv_id="LaNouvelleChaineIvorienne.ci" site_id="80715">La Nouvelle Chaîne Ivorienne</channel>
<channel lang="fr" xmltv_id="LCA.bf" site_id="80777">LCA</channel>
<channel lang="fr" xmltv_id="LCI.fr" site_id="80054">LCI</channel>
<channel lang="fr" xmltv_id="LifeTV.ci" site_id="80762">Life TV</channel>
<channel lang="fr" xmltv_id="LMTVFrench.ci" site_id="80323">LM TV Français</channel>
<channel lang="fr" xmltv_id="LoveNature.ca" site_id="80755">Love Nature</channel>
<channel lang="fr" xmltv_id="LTMTV.cm" site_id="80573">LTM TV</channel>
<channel lang="fr" xmltv_id="Ludikids.fr" site_id="80931">Ludikids</channel>
<channel lang="fr" xmltv_id="LuxTV.cg" site_id="80639">Lux TV</channel>
<channel lang="fr" xmltv_id="M6.fr" site_id="80712">M6</channel>
<channel lang="fr" xmltv_id="MabokeTV.cg" site_id="80973">Maboke TV</channel>
<channel lang="fr" xmltv_id="MadiTV.cd" site_id="80972">Madi TV</channel>
<channel lang="fr" xmltv_id="MandeTV.ml" site_id="80585">Mandé TV</channel>
<channel lang="fr" xmltv_id="Mangas.fr" site_id="80059">Mangas</channel>
<channel lang="fr" xmltv_id="MCRTVNF.cg" site_id="80412">MCR TV NF</channel>
<channel lang="fr" xmltv_id="Medi1TVArabic.ma" site_id="80574">Medi 1 TV Arabic</channel>
<channel lang="fr" xmltv_id="Melody.fr" site_id="80693">Melody</channel>
<channel lang="fr" xmltv_id="MikubaTV.cd" site_id="80929">Mikuba TV</channel>
<channel lang="fr" xmltv_id="MishapiVoiceTV.cd" site_id="80627">Mishapi Voice TV</channel>
<channel lang="fr" xmltv_id="MoliereTV.cd" site_id="80665">Moliere TV</channel>
<channel lang="fr" xmltv_id="MTVFrance.fr" site_id="80065">MTV France</channel>
<channel lang="fr" xmltv_id="MTVHitsFrance.fr" site_id="80147">MTV Hits France</channel>
<channel lang="fr" xmltv_id="MuseumTV.fr" site_id="80670">Museum International</channel>
<channel lang="fr" xmltv_id="MyMediaPrime.cm" site_id="80372">My Media Prime</channel>
<channel lang="fr" xmltv_id="NathanTV.fr" site_id="80959">Nathan TV</channel>
<channel lang="fr" xmltv_id="NationalGeographicFrance.fr" site_id="80145">National Geographic France</channel>
<channel lang="fr" xmltv_id="NationalGeographicWildFrance.fr" site_id="80223">National Geographic Wild France</channel>
<channel lang="fr" xmltv_id="NBATV.us" site_id="80555">NBA TV</channel>
<channel lang="fr" xmltv_id="NHKWorldJapan.jp" site_id="80307">NHK World Japan</channel>
<channel lang="fr" xmltv_id="NickelodeonFrance.fr" site_id="80224">Nickelodeon France</channel>
<channel lang="fr" xmltv_id="NickelodeonJunior.fr" site_id="80941">Nickelodeon Junior France</channel>
<channel lang="fr" xmltv_id="NollywoodTV.fr" site_id="80270">Nollywood TV</channel>
<channel lang="fr" xmltv_id="NollywoodTVEpic.fr" site_id="80600">Nollywood TV Épic</channel>
<channel lang="fr" xmltv_id="NovelasTV.fr" site_id="80971">Novelas TV</channel>
<channel lang="fr" xmltv_id="NyotaTV.cd" site_id="80428">Nyota TV</channel>
<channel lang="fr" xmltv_id="OmegaTV.bf" site_id="80415">Omega TV</channel>
<channel lang="fr" xmltv_id="ORTBTV.bj" site_id="80207">ORTB TV</channel>
<channel lang="fr" xmltv_id="ORTM1.ml" site_id="80069">ORTM 1</channel>
<channel lang="fr" xmltv_id="ORTM2.ml" site_id="80397">ORTM 2</channel>
<channel lang="fr" xmltv_id="PacisTV.rw" site_id="80371">Pacis TV</channel>
<channel lang="fr" xmltv_id="ParamountChannelFrance.fr" site_id="80303">Paramount Channel France</channel>
<channel lang="fr" xmltv_id="PenthouseBlack.us" site_id="80652">Penthouse Black</channel>
<channel lang="fr" xmltv_id="PiwiPlus.fr" site_id="80128">Piwi +</channel>
<channel lang="fr" xmltv_id="PlanetePlus.fr" site_id="80072">Planète +</channel>
<channel lang="fr" xmltv_id="PlanetePlusAE.fr" site_id="80073">Planète + A&amp;E</channel>
<channel lang="fr" xmltv_id="PlanetePlusCI.fr" site_id="80142">Planète + CI</channel>
<channel lang="fr" xmltv_id="PSTVHD.cd" site_id="80728">PSTV HD</channel>
<channel lang="fr" xmltv_id="RaiItaliaAfrica.it" site_id="80947">Rai Italia Africa</channel>
<channel lang="fr" xmltv_id="RebaTV1.rw" site_id="80748">Reba TV 1</channel>
<channel lang="fr" xmltv_id="RenouveauTV.ml" site_id="80778">Renouveau TV</channel>
<channel lang="fr" xmltv_id="RTB.bf" site_id="80121">RTB TV</channel>
<channel lang="fr" xmltv_id="RTDSDeltaTV.tg" site_id="80779">RTDS Delta TV</channel>
<channel lang="fr" xmltv_id="RTG1.gn" site_id="80202">RTG</channel>
<channel lang="fr" xmltv_id="RTI1.ci" site_id="80171">RTI 1</channel>
<channel lang="fr" xmltv_id="RTI2.ci" site_id="80271">RTI 2</channel>
<channel lang="fr" xmltv_id="RTILa3.ci" site_id="80761">RTI La 3</channel>
<channel lang="fr" xmltv_id="RTL9.lu" site_id="80077">RTL 9</channel>
<channel lang="fr" xmltv_id="RTNBTV.bi" site_id="80716">RTNB TV</channel>
<channel lang="fr" xmltv_id="RTNC.cd" site_id="80208">RTNC</channel>
<channel lang="fr" xmltv_id="RTS1.sn" site_id="80076">RTS 1</channel>
<channel lang="fr" xmltv_id="RTS2.sn" site_id="80666">RTS 2</channel>
<channel lang="fr" xmltv_id="RwandaTV.rw" site_id="80251">Rwanda TV</channel>
<channel lang="fr" xmltv_id="SaharaTV.td" site_id="80700">Sahara TV</channel>
<channel lang="fr" xmltv_id="SavaneTV.bf" site_id="80664">Savane TV</channel>
<channel lang="fr" xmltv_id="ScienceVieTV.fr" site_id="80373">Science &amp; Vie TV</channel>
<channel lang="fr" xmltv_id="SenTV.sn" site_id="80377">Sen TV</channel>
<channel lang="fr" xmltv_id="SerieClub.fr" site_id="80080">Série Club</channel>
<channel lang="fr" xmltv_id="SSMTV.sn" site_id="80411">SSM TV</channel>
<channel lang="fr" xmltv_id="STV.cm" site_id="80192">STV</channel>
<channel lang="fr" xmltv_id="Sud1ere.fr" site_id="80828">Sud1ère</channel>
<channel lang="fr" xmltv_id="SunnaTV.ng" site_id="80926">Sunna TV</channel>
<channel lang="fr" xmltv_id="SunuYeuf.sn" site_id="80710">Sunu Yeuf</channel>
<channel lang="fr" xmltv_id="SyfyFrance.fr" site_id="80078">Syfy France</channel>
<channel lang="fr" xmltv_id="Tele50.cd" site_id="80381">Télé 50</channel>
<channel lang="fr" xmltv_id="TeleAfrica.ga" site_id="80235">Télé Africa</channel>
<channel lang="fr" xmltv_id="TeleCongo.cg" site_id="80204">Tele Congo</channel>
<channel lang="fr" xmltv_id="TeleSahel.ne" site_id="80274">Télé Sahel</channel>
<channel lang="fr" xmltv_id="Telesud.fr" site_id="80002">Telesud</channel>
<channel lang="fr" xmltv_id="TeleTchad.td" site_id="80275">Télé Tchad</channel>
<channel lang="fr" xmltv_id="TeleToonAfrica.fr" site_id="80148">TéléToon Africa</channel>
<channel lang="fr" xmltv_id="TF1.fr" site_id="80095">TF 1</channel>
<channel lang="fr" xmltv_id="TF1SeriesFilms.fr" site_id="80613">TF 1 Séries Films</channel>
<channel lang="fr" xmltv_id="TFM.sn" site_id="80234">TFM</channel>
<channel lang="fr" xmltv_id="TFX.fr" site_id="80067">TFX</channel>
<channel lang="fr" xmltv_id="TGB.gw" site_id="80499">TGB</channel>
<channel lang="fr" xmltv_id="TiJi.fr" site_id="80097">Tiji</channel>
<channel lang="fr" xmltv_id="TiVi5Monde.fr" site_id="80545">Tivi 5 Monde</channel>
<channel lang="fr" xmltv_id="TLSAfrica.tg" site_id="80404">TLS Africa</channel>
<channel lang="fr" xmltv_id="TM1TV.ml" site_id="80723">TM1 TV</channel>
<channel lang="fr" xmltv_id="TMC.fr" site_id="80098">TMC</channel>
<channel lang="fr" xmltv_id="TNTAfrica.us" site_id="80757">TNT Africa</channel>
<channel lang="fr" xmltv_id="ToutelHistoire.fr" site_id="80727">Toute l&apos;Histoire</channel>
<channel lang="fr" xmltv_id="TraceAfrica.fr" site_id="80214">Trace Africa Français</channel>
<channel lang="fr" xmltv_id="TraceAfrikora.fr" site_id="80714">Trace Afrikora</channel>
<channel lang="fr" xmltv_id="TraceGospel.fr" site_id="80620">Trace Gospel</channel>
<channel lang="fr" xmltv_id="TraceKitoko.fr" site_id="80621">Trace Kitoko</channel>
<channel lang="fr" xmltv_id="TraceMboa.fr" site_id="80266">Trace MBOA</channel>
<channel lang="fr" xmltv_id="TraceMziki.fr" site_id="80570">Trace Mziki</channel>
<channel lang="fr" xmltv_id="TraceUrban.fr" site_id="80186">Trace Urban Afrique</channel>
<channel lang="fr" xmltv_id="Trek.fr" site_id="80566">Trek</channel>
<channel lang="fr" xmltv_id="TV5MondeAfrica.fr" site_id="80105">TV5Monde Afrique</channel>
<channel lang="fr" xmltv_id="TV7.tg" site_id="80763">TV 7</channel>
<channel lang="fr" xmltv_id="TV10.rw" site_id="80326">TV 10</channel>
<channel lang="fr" xmltv_id="TVAlBayane.ci" site_id="80776">TV Al Bayane</channel>
<channel lang="fr" xmltv_id="TVCBenin.bj" site_id="80923">TVC Benin</channel>
<channel lang="fr" xmltv_id="TVGE.gq" site_id="80927">TVGE</channel>
<channel lang="fr" xmltv_id="TVT.tg" site_id="80272">TVT</channel>
<channel lang="fr" xmltv_id="UshuaiaTV.fr" site_id="80138">Ushuaïa TV</channel>
<channel lang="fr" xmltv_id="Vision4.cm" site_id="80388">Vision 4</channel>
<channel lang="fr" xmltv_id="Vision4RCA.cm" site_id="80682">Vision 4 RCA</channel>
<channel lang="fr" xmltv_id="VixenTV.ca" site_id="80934">Vixen</channel>
<channel lang="fr" xmltv_id="VoirPlus.fr" site_id="80215">Voir +</channel>
<channel lang="fr" xmltv_id="VoxAfrica.uk" site_id="80193">Voxafrica Afrique</channel>
<channel lang="fr" xmltv_id="VoxTV.cg" site_id="80561">Vox TV</channel>
<channel lang="fr" xmltv_id="WalfTV.sn" site_id="80572">Walf TV</channel>
<channel lang="fr" xmltv_id="WataaaTV.fr" site_id="80614">Wataaa TV</channel>
<channel lang="fr" xmltv_id="XXL.fr" site_id="80110">XXL</channel>
<channel lang="fr" xmltv_id="ZeeMagic.fr" site_id="80396">Zee Magic</channel>
</channels>
</site>

View File

@@ -0,0 +1,94 @@
const axios = require('axios')
const cheerio = require('cheerio')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
dayjs.extend(utc)
module.exports = {
site: 'canalplus-afrique.com',
days: 2,
url: function ({ channel, date }) {
const diff = date.diff(dayjs.utc().startOf('d'), 'd')
return `https://service.canal-overseas.com/ott-frontend/vector/83001/channel/${channel.site_id}/events?filter.day=${diff}`
},
async parser({ content }) {
let programs = []
const items = parseItems(content)
for (let item of items) {
if (item.title === 'Fin des programmes') return
const detail = await loadProgramDetails(item)
programs.push({
title: item.title,
description: parseDescription(detail),
category: parseCategory(detail),
icon: parseIcon(item),
start: parseStart(item),
stop: parseStop(item)
})
}
return programs
},
async channels() {
const html = await axios
.get(`https://www.canalplus-afrique.com/bf/guide-tv-maintenant`)
.then(r => r.data)
.catch(console.log)
const $ = cheerio.load(html)
const script = $('body > script:nth-child(2)').html()
const [_, json] = script.match(/window.APP_STATE=(.*);/) || [null, null]
const data = JSON.parse(json)
const items = data.tvGuide.channels.byZapNumber
return Object.values(items).map(item => {
return {
lang: 'fr',
site_id: item.epgID,
name: item.name
}
})
}
}
async function loadProgramDetails(item) {
if (!item.onClick.URLPage) return {}
const url = item.onClick.URLPage
const data = await axios
.get(url)
.then(r => r.data)
.catch(console.log)
return data || {}
}
function parseDescription(detail) {
return detail.detail.informations.summary || null
}
function parseCategory(detail) {
return detail.detail.informations.subGenre || null
}
function parseIcon(item) {
return item.URLImage || item.URLImageDefault
}
function parseStart(item) {
return dayjs.unix(item.startTime)
}
function parseStop(item) {
return dayjs.unix(item.endTime)
}
function parseItems(content) {
const data = JSON.parse(content)
if (!data || !data.timeSlices) return []
const items = data.timeSlices.reduce((acc, curr) => {
acc = acc.concat(curr.contents)
return acc
}, [])
return items
}

View File

@@ -0,0 +1,151 @@
// [Geo-blocked] node ./scripts/commands/parse-channels.js --config=./sites/canalplus-afrique.com/canalplus-afrique.com.config.js --output=./sites/canalplus-afrique.com/canalplus-afrique.com.channels.xml
// npx epg-grabber --config=sites/canalplus-afrique.com/canalplus-afrique.com.config.js --channels=sites/canalplus-afrique.com/canalplus-afrique.com.channels.xml --output=guide.xml --days=2
const { parser, url } = require('./canalplus-afrique.com.config.js')
const axios = require('axios')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const customParseFormat = require('dayjs/plugin/customParseFormat')
dayjs.extend(customParseFormat)
dayjs.extend(utc)
jest.mock('axios')
const channel = {
site_id: '80759',
xmltv_id: 'Animaux.fr'
}
it('can generate valid url for today', () => {
const date = dayjs.utc().startOf('d')
expect(url({ channel, date })).toBe(
'https://service.canal-overseas.com/ott-frontend/vector/83001/channel/80759/events?filter.day=0'
)
})
it('can generate valid url for tomorrow', () => {
const date = dayjs.utc().startOf('d').add(1, 'd')
expect(url({ channel, date })).toBe(
'https://service.canal-overseas.com/ott-frontend/vector/83001/channel/80759/events?filter.day=1'
)
})
it('can parse response', done => {
const content = `{"timeSlices":[{"contents":[{"title":"A petit pas","subtitle":"Episode 1 - La naissance","thirdTitle":"ANIMAUX","startTime":1660794900,"endTime":1660797900,"onClick":{"displayTemplate":"miniDetail","displayName":"A petit pas","URLPage":"https://service.canal-overseas.com/ott-frontend/vector/83001/event/140280189","URLVitrine":"https://service.canal-overseas.com/ott-frontend/vector/83001/program/104991257/recommendations"},"programID":104991257,"diffusionID":"140280189","URLImageDefault":"https://service.canal-overseas.com/image-api/v1/image/generic","URLImage":"https://service.canal-overseas.com/image-api/v1/image/7dedf4a579b66153a1988637e9e023f5"}],"timeSlice":"1"}]}`
axios.get.mockImplementation(url => {
if (url === 'https://service.canal-overseas.com/ott-frontend/vector/83001/event/140280189') {
return Promise.resolve({
data: JSON.parse(`{
"currentPage": {
"displayName": "A petit pas",
"displayTemplate": "detailPage",
"URLVitrine": "https://service.canal-overseas.com/ott-frontend/vector/83001/program/104991257/recommendations"
},
"detail": {
"informations": {
"programmeType": "EPG",
"isInOffer": false,
"isInOfferOnDevice": false,
"isInOfferForD2G": false,
"availableInVoDOnDevice": false,
"availableInVoDOnG5": false,
"availableInD2GOnDevice": false,
"availableInLiveOnDevice": false,
"rediffusions": true,
"canBeRecorded": false,
"channelName": "ANIMAUX",
"startTime": 1660794900,
"endTime": 1660797900,
"title": "A petit pas",
"subtitle": "Episode 1 - La naissance",
"thirdTitle": "ANIMAUX",
"genre": "Découverte",
"subGenre": "Doc. Animalier",
"editorialTitle": "Découverte, France, 2013, 0h50",
"audioLanguage": "VF",
"personnalities": [
{
"prefix": "De :",
"content": "Emilie Fertil"
}
],
"summary": "Suivi pendant une année entière de trois bébés animaux, un border collie, un poulain et un lémurien, prédestinés par leur maître à devenir de véritables champions.",
"summaryMedium": "Suivi pendant une année entière de trois bébés animaux, un border collie, un poulain et un lémurien, prédestinés par leur maître à devenir de véritables champions.",
"programID": 104991257,
"sharingURL": "https://www.canalplus-afrique.com/grille-tv/event/140280189-a-petit-pas.html",
"EpgId": 80759,
"CSA": 1,
"HD": false,
"3D": false,
"diffusionID": "140280189",
"duration": "3000",
"URLImageDefault": "https://service.canal-overseas.com/image-api/v1/image/generic",
"URLImage": "https://service.canal-overseas.com/image-api/v1/image/7dedf4a579b66153a1988637e9e023f5",
"URLLogo": "https://service.canal-overseas.com/image-api/v1/image/9d91bf8d25632e77d004cf5b84f296b1",
"URLLogoBlack": "https://service.canal-overseas.com/image-api/v1/image/9d91bf8d25632e77d004cf5b84f296b1",
"URLVitrine": "https://service.canal-overseas.com/ott-frontend/vector/83001/program/104991257/recommendations"
},
"diffusions": [
{
"diffusionDateUTC": 1660794900,
"sharingUrl": "https://www.canalplus-afrique.com/grille-tv/event/140280189-a-petit-pas.html",
"broadcastId": "140280189",
"name": "ANIMAUX",
"epgID": "80759",
"ZapNumber": "161",
"URLLogo": "https://service.canal-overseas.com/image-api/v1/image/9d91bf8d25632e77d004cf5b84f296b1",
"URLLogoBlack": "https://service.canal-overseas.com/image-api/v1/image/9d91bf8d25632e77d004cf5b84f296b1"
},
{
"diffusionDateUTC": 1661475600,
"sharingUrl": "https://www.canalplus-afrique.com/grille-tv/event/141170299-a-petit-pas.html",
"broadcastId": "141170299",
"name": "ANIMAUX",
"epgID": "80759",
"ZapNumber": "161",
"URLLogo": "https://service.canal-overseas.com/image-api/v1/image/9d91bf8d25632e77d004cf5b84f296b1",
"URLLogoBlack": "https://service.canal-overseas.com/image-api/v1/image/9d91bf8d25632e77d004cf5b84f296b1"
}
]
}
}`)
})
} else {
return Promise.resolve({ data: '' })
}
})
parser({ content })
.then(result => {
result = result.map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2022-08-18T03:55:00.000Z',
stop: '2022-08-18T04:45:00.000Z',
title: 'A petit pas',
icon: 'https://service.canal-overseas.com/image-api/v1/image/7dedf4a579b66153a1988637e9e023f5',
category: 'Doc. Animalier',
description:
'Suivi pendant une année entière de trois bébés animaux, un border collie, un poulain et un lémurien, prédestinés par leur maître à devenir de véritables champions.'
}
])
done()
})
.catch(done)
})
it('can handle empty guide', done => {
parser({
content: `{"currentPage":{"displayTemplate":"error","BOName":"Page introuvable"},"title":"Page introuvable","text":"La page que vous demandez est introuvable. Si le problème persiste, vous pouvez contacter l'assistance de CANAL+/CANALSAT.","code":404}`
})
.then(result => {
expect(result).toMatchObject([])
done()
})
.catch(done)
})

View File

@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="canalplus-caraibes.com">
<channels>
<channel lang="fr" xmltv_id="6ter.fr" site_id="50624">6ter</channel>
<channel lang="fr" xmltv_id="13emeRue.fr" site_id="50001">13ème Rue</channel>
<channel lang="fr" xmltv_id="Action.fr" site_id="50004">Action</channel>
<channel lang="fr" xmltv_id="Alizes.gp" site_id="50365">Alizés</channel>
<channel lang="fr" xmltv_id="APlus.fr" site_id="50416">A+</channel>
<channel lang="fr" xmltv_id="ARTEFrance.fr" site_id="50007">ARTE Français</channel>
<channel lang="fr" xmltv_id="Automotolachaine.fr" site_id="50565">Automoto la chaîne</channel>
<channel lang="fr" xmltv_id="BBCWorldNewsNorthAmerica.uk" site_id="50008">BBC World News Americas</channel>
<channel lang="fr" xmltv_id="BblackCaribbean.fr" site_id="50557">Bblack! Caribbean</channel>
<channel lang="fr" xmltv_id="beINSports1France.fr" site_id="50115">BeIn Sports 1 France</channel>
<channel lang="fr" xmltv_id="beINSports2France.fr" site_id="50243">BeIn Sports 2 France</channel>
<channel lang="fr" xmltv_id="beINSports3France.fr" site_id="50347">BeIn Sports 3 France</channel>
<channel lang="fr" xmltv_id="beINSportsMax4France.fr" site_id="50558">BeIn Sports Max 4 France</channel>
<channel lang="fr" xmltv_id="beINSportsMax5France.fr" site_id="50559">BeIn Sports Max 5 France</channel>
<channel lang="fr" xmltv_id="C8.fr" site_id="50120">C8</channel>
<channel lang="fr" xmltv_id="Canal10.gp" site_id="50176">Canal 10</channel>
<channel lang="fr" xmltv_id="CanalJ.fr" site_id="50011">Canal J</channel>
<channel lang="fr" xmltv_id="CanalPlusCaraibes.fr" site_id="50012">Canal + Caraïbes</channel>
<channel lang="fr" xmltv_id="CanalPlusCinemaFrance.fr" site_id="50014">Canal + Cinéma France</channel>
<channel lang="fr" xmltv_id="CanalPlusKids.fr" site_id="50401">Canal + Kids</channel>
<channel lang="fr" xmltv_id="CanalPlusSeriesFrance.fr" site_id="50312">Canal + Séries France</channel>
<channel lang="fr" xmltv_id="CanalPlusSportFrance.fr" site_id="50022">Canal + Sport France</channel>
<channel lang="fr" xmltv_id="CinePlusClassic.fr" site_id="50328">Cine + Classic</channel>
<channel lang="fr" xmltv_id="CinePlusClub.fr" site_id="50024">Cine + Club</channel>
<channel lang="fr" xmltv_id="CinePlusEmotion.fr" site_id="50025">Cine + Émotion</channel>
<channel lang="fr" xmltv_id="CinePlusFamiz.fr" site_id="50026">Cine + Famiz</channel>
<channel lang="fr" xmltv_id="CinePlusFrisson.fr" site_id="50027">Cine + Frisson</channel>
<channel lang="fr" xmltv_id="CinePlusPremier.fr" site_id="50028">Cine + Premier</channel>
<channel lang="fr" xmltv_id="CNews.fr" site_id="50048">C News</channel>
<channel lang="fr" xmltv_id="CNNInternationalLatinAmerica.us" site_id="50032">CNN International Latin America</channel>
<channel lang="fr" xmltv_id="ComediePlus.fr" site_id="50033">Comédie +</channel>
<channel lang="fr" xmltv_id="CStar.fr" site_id="50217">C Star</channel>
<channel lang="fr" xmltv_id="DiscoveryChannelFrance.fr" site_id="50248">Discovery Channel France</channel>
<channel lang="fr" xmltv_id="DiscoveryScienceFrance.fr" site_id="50249">Discovery Science France</channel>
<channel lang="fr" xmltv_id="DisneyChannelFrance.fr" site_id="50035">Disney Channel France</channel>
<channel lang="fr" xmltv_id="DisneyJuniorFrance.fr" site_id="50075">Disney Junior France</channel>
<channel lang="fr" xmltv_id="DorcelTV.nl" site_id="50154">Dorcel TV</channel>
<channel lang="fr" xmltv_id="EFrance.fr" site_id="50036">E! France</channel>
<channel lang="fr" xmltv_id="EnglishClubTV.uk" site_id="50374">English Club TV</channel>
<channel lang="fr" xmltv_id="Equidia.fr" site_id="50037">Equidia</channel>
<channel lang="fr" xmltv_id="MGGTV.fr" site_id="50667">ES1</channel>
<channel lang="fr" xmltv_id="ESPN2Caribbean.us" site_id="50290">ESPN 2 Caribbean</channel>
<channel lang="fr" xmltv_id="ESPNCaribbean.us" site_id="50038">ESPN Caribbean</channel>
<channel lang="fr" xmltv_id="ETV.gp" site_id="50286">ETV</channel>
<channel lang="fr" xmltv_id="Eurosport1.fr" site_id="50041">Eurosport 1</channel>
<channel lang="fr" xmltv_id="Eurosport2.fr" site_id="50042">Eurosport 2</channel>
<channel lang="fr" xmltv_id="France2.fr" site_id="50188">France 2</channel>
<channel lang="fr" xmltv_id="France3.fr" site_id="50045">France 3</channel>
<channel lang="fr" xmltv_id="France4.fr" site_id="50196">France 4</channel>
<channel lang="fr" xmltv_id="France5.fr" site_id="50046">France 5</channel>
<channel lang="fr" xmltv_id="France24French.fr" site_id="50114">France 24 Français</channel>
<channel lang="fr" xmltv_id="Franceinfo.fr" site_id="50704">Franceinfo:</channel>
<channel lang="fr" xmltv_id="GameOne.fr" site_id="50136">Game One</channel>
<channel lang="fr" xmltv_id="GloboNews.br" site_id="50230">Globo News</channel>
<channel lang="fr" xmltv_id="GolfPlus.fr" site_id="50414">Golf +</channel>
<channel lang="fr" xmltv_id="GrapheTV.mq" site_id="50937">Graphé TV</channel>
<channel lang="fr" xmltv_id="Guadeloupe1ere.gp" site_id="50083">Guadeloupe 1ère</channel>
<channel lang="fr" xmltv_id="Gulli.fr" site_id="50146">Gulli</channel>
<channel lang="fr" xmltv_id="Guyane1ere.gf" site_id="50084">Guyane 1ère</channel>
<channel lang="fr" xmltv_id="HBOXtremeLatinAmerica.us" site_id="50363">HBO Xtreme Latinoamérica</channel>
<channel lang="fr" xmltv_id="InfosportPlus.fr" site_id="50050">InfoSport +</channel>
<channel lang="fr" xmltv_id="IOTV.sx" site_id="50611">IOTV</channel>
<channel lang="fr" xmltv_id="KMT.mq" site_id="50210">KMT</channel>
<channel lang="fr" xmltv_id="KTO.fr" site_id="50278">KTO</channel>
<channel lang="fr" xmltv_id="KTVGuyane.gf" site_id="50288">KTV Guyane</channel>
<channel lang="fr" xmltv_id="LCI.fr" site_id="50054">LCI</channel>
<channel lang="fr" xmltv_id="PublicSenat.fr" site_id="50055">LCP Public Sénat</channel>
<channel lang="fr" xmltv_id="LEquipe.fr" site_id="50056">L&apos;Équipe</channel>
<channel lang="fr" xmltv_id="Ludikids.fr" site_id="50931">Ludikids</channel>
<channel lang="fr" xmltv_id="M6.fr" site_id="50057">M6</channel>
<channel lang="fr" xmltv_id="Martinique1ere.mq" site_id="50085">Martinique 1ère</channel>
<channel lang="fr" xmltv_id="MCM.fr" site_id="50060">MCM France</channel>
<channel lang="fr" xmltv_id="Metropole.ht" site_id="50306">Metropole</channel>
<channel lang="fr" xmltv_id="MTVFrance.fr" site_id="50065">MTV France</channel>
<channel lang="fr" xmltv_id="MTVHitsFrance.fr" site_id="50147">MTV Hits France</channel>
<channel lang="fr" xmltv_id="NationalGeographicFrance.fr" site_id="50145">National Geographic France</channel>
<channel lang="fr" xmltv_id="NationalGeographicWildFrance.fr" site_id="50223">National Geographic Wild France</channel>
<channel lang="fr" xmltv_id="NickelodeonFrance.fr" site_id="50224">Nickelodeon France</channel>
<channel lang="fr" xmltv_id="NickJrAfrica.za" site_id="50941">Nick Jr Africa</channel>
<channel lang="fr" xmltv_id="NollywoodTV.fr" site_id="50418">Nollywood TV</channel>
<channel lang="fr" xmltv_id="NovelasTV.fr" site_id="50548">Novelas TV</channel>
<channel lang="fr" xmltv_id="NRJ12.fr" site_id="50216">NRJ 12</channel>
<channel lang="fr" xmltv_id="OCSChoc.fr" site_id="50318">OCS choc</channel>
<channel lang="fr" xmltv_id="OCSCity.fr" site_id="50317">OCS City</channel>
<channel lang="fr" xmltv_id="OCSGeants.fr" site_id="50319">OCS geants</channel>
<channel lang="fr" xmltv_id="OCSMax.fr" site_id="50316">OCS max</channel>
<channel lang="fr" xmltv_id="ParamountChannelFrance.fr" site_id="50303">Paramount Channel France</channel>
<channel lang="fr" xmltv_id="ParisPremiere.fr" site_id="50070">Paris Première</channel>
<channel lang="fr" xmltv_id="PenthouseBlack.us" site_id="50280">Penthouse Black</channel>
<channel lang="fr" xmltv_id="PinkTV.fr" site_id="50071">Pink TV</channel>
<channel lang="fr" xmltv_id="PiwiPlus.fr" site_id="50128">Piwi +</channel>
<channel lang="fr" xmltv_id="PlanetePlus.fr" site_id="50072">Planète +</channel>
<channel lang="fr" xmltv_id="PlanetePlusAE.fr" site_id="50073">Planète + A&amp;E</channel>
<channel lang="fr" xmltv_id="PlanetePlusCI.fr" site_id="50142">Planète + CI</channel>
<channel lang="fr" xmltv_id="RTL9.lu" site_id="50077">RTL 9</channel>
<channel lang="fr" xmltv_id="Seasons.fr" site_id="50079">Seasons</channel>
<!-- <channel lang="fr" xmltv_id="" site_id="50422">Sony Channel Centro</channel> -->
<channel lang="fr" xmltv_id="STVS81.sr" site_id="50616">STVS 8.1</channel>
<channel lang="fr" xmltv_id="SyfyFrance.fr" site_id="50078">Syfy France</channel>
<channel lang="fr" xmltv_id="Tele20.ht" site_id="50618">Télé 20</channel>
<channel lang="fr" xmltv_id="TelemicroInternacional.do" site_id="50292">Telemicro Internacional</channel>
<channel lang="fr" xmltv_id="TelemundoCentralAmerica.us" site_id="50725">Telemundo</channel>
<channel lang="fr" xmltv_id="TelePacific.ht" site_id="50617">Tele Pacific</channel>
<channel lang="fr" xmltv_id="TeleSoleil.ht" site_id="50936">Tele Soleil</channel>
<channel lang="fr" xmltv_id="TeletoonPlus.fr" site_id="50148">TéléToon +</channel>
<channel lang="fr" xmltv_id="Teva.fr" site_id="50094">Téva</channel>
<channel lang="fr" xmltv_id="TF1.fr" site_id="50095">TF 1</channel>
<channel lang="fr" xmltv_id="TF1SeriesFilms.fr" site_id="50613">TF 1 Séries Films</channel>
<channel lang="fr" xmltv_id="TFX.fr" site_id="50067">TFX</channel>
<channel lang="fr" xmltv_id="TMC.fr" site_id="50098">TMC</channel>
<channel lang="fr" xmltv_id="TNH.ht" site_id="50291">TNH</channel>
<channel lang="fr" xmltv_id="ToutelHistoire.fr" site_id="50727">Toute l&apos;Histoire</channel>
<channel lang="fr" xmltv_id="TraceAyiti.fr" site_id="50654">Trace Ayiti</channel>
<channel lang="fr" xmltv_id="TraceCaribbean.fr" site_id="50155">Trace Caribbean</channel>
<channel lang="fr" xmltv_id="TraceGospel.fr" site_id="50620">Trace Gospel</channel>
<channel lang="fr" xmltv_id="TraceLatina.fr" site_id="50653">Trace Latina</channel>
<channel lang="fr" xmltv_id="TraceUrban.fr" site_id="50102">Trace Urban</channel>
<channel lang="fr" xmltv_id="TV5MondeLatinAmerica.fr" site_id="50106">TV5Monde Amérique Latine</channel>
<channel lang="fr" xmltv_id="TVBreizh.fr" site_id="50104">TV Breizh</channel>
<channel lang="fr" xmltv_id="UshuaiaTV.fr" site_id="50138">Ushuaïa TV</channel>
<channel lang="fr" xmltv_id="ViaATV.mq" site_id="50006">ViàATV</channel>
<channel lang="fr" xmltv_id="VixenTV.ca" site_id="50934">Vixen</channel>
<channel lang="fr" xmltv_id="W9.fr" site_id="50140">W9</channel>
<channel lang="fr" xmltv_id="WataaaTV.fr" site_id="50614">Wataaa TV</channel>
<channel lang="fr" xmltv_id="XXL.fr" site_id="50110">XXL</channel>
<channel lang="fr" xmltv_id="ZitataTV.mq" site_id="50801">Zitata TV</channel>
<channel lang="fr" xmltv_id="ZoukTV.mq" site_id="50285">Zouk TV</channel>
</channels>
</site>

View File

@@ -0,0 +1,93 @@
const axios = require('axios')
const cheerio = require('cheerio')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
dayjs.extend(utc)
module.exports = {
site: 'canalplus-caraibes.com',
days: 2,
url: function ({ channel, date }) {
const diff = date.diff(dayjs.utc().startOf('d'), 'd')
return `https://service.canal-overseas.com/ott-frontend/vector/53001/channel/${channel.site_id}/events?filter.day=${diff}`
},
async parser({ content }) {
let programs = []
const items = parseItems(content)
for (let item of items) {
if (item.title === 'Fin des programmes') return
const detail = await loadProgramDetails(item)
programs.push({
title: item.title,
description: parseDescription(detail),
category: parseCategory(detail),
icon: parseIcon(item),
start: parseStart(item),
stop: parseStop(item)
})
}
return programs
},
async channels() {
const html = await axios
.get(`https://www.canalplus-caraibes.com/bl/guide-tv-ce-soir`)
.then(r => r.data)
.catch(console.log)
const $ = cheerio.load(html)
const script = $('body > script:nth-child(2)').html()
const [_, json] = script.match(/window.APP_STATE=(.*);/) || [null, null]
const data = JSON.parse(json)
const items = data.tvGuide.channels.byZapNumber
return Object.values(items).map(item => {
return {
lang: 'fr',
site_id: item.epgID,
name: item.name
}
})
}
}
async function loadProgramDetails(item) {
if (!item.onClick.URLPage) return {}
const url = item.onClick.URLPage
const data = await axios
.get(url)
.then(r => r.data)
.catch(console.log)
return data || {}
}
function parseDescription(detail) {
return detail.detail.informations.summary || null
}
function parseCategory(detail) {
return detail.detail.informations.subGenre || null
}
function parseIcon(item) {
return item.URLImage || item.URLImageDefault
}
function parseStart(item) {
return dayjs.unix(item.startTime)
}
function parseStop(item) {
return dayjs.unix(item.endTime)
}
function parseItems(content) {
const data = JSON.parse(content)
if (!data || !data.timeSlices) return []
const items = data.timeSlices.reduce((acc, curr) => {
acc = acc.concat(curr.contents)
return acc
}, [])
return items
}

View File

@@ -0,0 +1,135 @@
// [Geo-blocked] node ./scripts/channels.js --config=./sites/canalplus-caraibes.com/canalplus-caraibes.com.config.js --output=./sites/canalplus-caraibes.com/canalplus-caraibes.com.channels.xml
// npx epg-grabber --config=sites/canalplus-caraibes.com/canalplus-caraibes.com.config.js --channels=sites/canalplus-caraibes.com/canalplus-caraibes.com.channels.xml --output=guide.xml --days=2
const { parser, url } = require('./canalplus-caraibes.com.config.js')
const axios = require('axios')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const customParseFormat = require('dayjs/plugin/customParseFormat')
dayjs.extend(customParseFormat)
dayjs.extend(utc)
jest.mock('axios')
const channel = {
site_id: '50115',
xmltv_id: 'beINSports1France.fr'
}
it('can generate valid url for today', () => {
const date = dayjs.utc().startOf('d')
expect(url({ channel, date })).toBe(
'https://service.canal-overseas.com/ott-frontend/vector/53001/channel/50115/events?filter.day=0'
)
})
it('can generate valid url for tomorrow', () => {
const date = dayjs.utc().startOf('d').add(1, 'd')
expect(url({ channel, date })).toBe(
'https://service.canal-overseas.com/ott-frontend/vector/53001/channel/50115/events?filter.day=1'
)
})
it('can parse response', done => {
const content = `{"timeSlices":[{"contents":[{"title":"Rugby - Leinster / La Rochelle","subtitle":"Rugby","thirdTitle":"BEIN SPORTS 1 HD","startTime":1660815000,"endTime":1660816800,"onClick":{"displayTemplate":"miniDetail","displayName":"Rugby - Leinster / La Rochelle","URLPage":"https://service.canal-overseas.com/ott-frontend/vector/53001/event/140377765","URLVitrine":"https://service.canal-overseas.com/ott-frontend/vector/53001/program/224515801/recommendations"},"programID":224515801,"diffusionID":"140377765","URLImageDefault":"https://service.canal-overseas.com/image-api/v1/image/75fca4586fdc3458930dd1ab6fc2e643","URLImage":"https://service.canal-overseas.com/image-api/v1/image/7854e20fb6efecd398598653c57cc771"}],"timeSlice":"4"}]}`
axios.get.mockImplementation(url => {
if (url === 'https://service.canal-overseas.com/ott-frontend/vector/53001/event/140377765') {
return Promise.resolve({
data: JSON.parse(`{
"currentPage": {
"displayName": "Rugby - Leinster / La Rochelle",
"displayTemplate": "detailPage",
"URLVitrine": "https://service.canal-overseas.com/ott-frontend/vector/53001/program/224515801/recommendations"
},
"detail": {
"informations": {
"programmeType": "EPG",
"isInOffer": false,
"isInOfferOnDevice": false,
"isInOfferForD2G": false,
"availableInVoDOnDevice": false,
"availableInVoDOnG5": false,
"availableInD2GOnDevice": false,
"availableInLiveOnDevice": false,
"rediffusions": true,
"canBeRecorded": false,
"channelName": "BEIN SPORTS 1 HD",
"startTime": 1660815000,
"endTime": 1660816800,
"title": "Rugby - Leinster / La Rochelle",
"subtitle": "Rugby",
"thirdTitle": "BEIN SPORTS 1 HD",
"genre": "Sport",
"subGenre": "Rugby",
"editorialTitle": "Sport, France, 0h30",
"audioLanguage": "VF",
"summary": "Retransmission d'un match de Champions Cup de rugby à XV. L'European Rugby Champions Cup est une compétition annuelle interclubs de rugby à XV disputée par les meilleures équipes en Europe. Jusqu'en 2014, cette compétition s'appelait Heineken Cup, ou H Cup, et était sous l'égide de l'ERC, et depuis cette date l'EPRC lui a succédé. La première édition s'est déroulée en 1995.",
"summaryMedium": "Retransmission d'un match de Champions Cup de rugby à XV. L'European Rugby Champions Cup est une compétition annuelle interclubs de rugby à XV disputée par les meilleures équipes en Europe. Jusqu'en 2014, cette compétition s'appelait Heineken Cup, ou H Cup, et était sous l'égide de l'ERC, et depuis cette date l'EPRC lui a succédé. La première édition s'est déroulée en 1995.",
"programID": 224515801,
"sharingURL": "https://www.canalplus-caraibes.com/grille-tv/event/140377765-rugby-leinster-la-rochelle.html",
"EpgId": 50115,
"CSA": 1,
"HD": false,
"3D": false,
"diffusionID": "140377765",
"duration": "1800",
"URLImageDefault": "https://service.canal-overseas.com/image-api/v1/image/75fca4586fdc3458930dd1ab6fc2e643",
"URLImage": "https://service.canal-overseas.com/image-api/v1/image/7854e20fb6efecd398598653c57cc771",
"URLLogo": "https://service.canal-overseas.com/image-api/v1/image/4e121baf92f46b2df622c6d4f9cebf8e",
"URLLogoBlack": "https://service.canal-overseas.com/image-api/v1/image/4e121baf92f46b2df622c6d4f9cebf8e",
"URLVitrine": "https://service.canal-overseas.com/ott-frontend/vector/53001/program/224515801/recommendations"
},
"diffusions": [
{
"diffusionDateUTC": 1660815000,
"sharingUrl": "https://www.canalplus-caraibes.com/grille-tv/event/140377765-rugby-leinster-la-rochelle.html",
"broadcastId": "140377765",
"name": "BEIN SPORTS 1 HD",
"epgID": "50115",
"ZapNumber": "191",
"URLLogo": "https://service.canal-overseas.com/image-api/v1/image/4e121baf92f46b2df622c6d4f9cebf8e",
"URLLogoBlack": "https://service.canal-overseas.com/image-api/v1/image/4e121baf92f46b2df622c6d4f9cebf8e"
}
]
}
}`)
})
} else {
return Promise.resolve({ data: '' })
}
})
parser({ content })
.then(result => {
result = result.map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2022-08-18T09:30:00.000Z',
stop: '2022-08-18T10:00:00.000Z',
title: 'Rugby - Leinster / La Rochelle',
icon: 'https://service.canal-overseas.com/image-api/v1/image/7854e20fb6efecd398598653c57cc771',
category: 'Rugby',
description:
"Retransmission d'un match de Champions Cup de rugby à XV. L'European Rugby Champions Cup est une compétition annuelle interclubs de rugby à XV disputée par les meilleures équipes en Europe. Jusqu'en 2014, cette compétition s'appelait Heineken Cup, ou H Cup, et était sous l'égide de l'ERC, et depuis cette date l'EPRC lui a succédé. La première édition s'est déroulée en 1995."
}
])
done()
})
.catch(done)
})
it('can handle empty guide', done => {
parser({
content: `{"currentPage":{"displayTemplate":"error","BOName":"Page introuvable"},"title":"Page introuvable","text":"La page que vous demandez est introuvable. Si le problème persiste, vous pouvez contacter l'assistance de CANAL+/CANALSAT.","code":404}`
})
.then(result => {
expect(result).toMatchObject([])
done()
})
.catch(done)
})

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="canalplus-haiti.com">
<channels>
<channel lang="fr" xmltv_id="6ter.fr" site_id="51624">6ter</channel>
<channel lang="fr" xmltv_id="13emeRue.fr" site_id="51001">13ème Rue</channel>
<channel lang="fr" xmltv_id="Action.fr" site_id="51004">Action</channel>
<channel lang="fr" xmltv_id="Alizes.gp" site_id="51365">Alizés</channel>
<channel lang="fr" xmltv_id="APlus.fr" site_id="51416">A+</channel>
<channel lang="fr" xmltv_id="Automotolachaine.fr" site_id="51565">Automoto la chaîne</channel>
<channel lang="fr" xmltv_id="BBCWorldNewsNorthAmerica.uk" site_id="51008">BBC World News Americas</channel>
<channel lang="fr" xmltv_id="BblackCaribbean.fr" site_id="51557">Bblack! Caribbean</channel>
<channel lang="fr" xmltv_id="C8.fr" site_id="51120">C8</channel>
<channel lang="fr" xmltv_id="Canal10.gp" site_id="51176">Canal 10</channel>
<channel lang="fr" xmltv_id="CanalPlusCinemaFrance.fr" site_id="51014">Canal + Cinéma France</channel>
<channel lang="fr" xmltv_id="CanalPlusHaiti.fr" site_id="51966">Canal + Haïti</channel>
<channel lang="fr" xmltv_id="CanalPlusKids.fr" site_id="51401">Canal + Kids</channel>
<channel lang="fr" xmltv_id="CanalPlusSportFrance.fr" site_id="51022">Canal + Sport France</channel>
<channel lang="fr" xmltv_id="CinePlusClassic.fr" site_id="51328">Cine + Classic</channel>
<channel lang="fr" xmltv_id="CinePlusClub.fr" site_id="51024">Cine + Club</channel>
<channel lang="fr" xmltv_id="CinePlusEmotion.fr" site_id="51025">Cine + Émotion</channel>
<channel lang="fr" xmltv_id="CinePlusFamiz.fr" site_id="51026">Cine + Famiz</channel>
<channel lang="fr" xmltv_id="CinePlusFrisson.fr" site_id="51027">Cine + Frisson</channel>
<channel lang="fr" xmltv_id="CinePlusPremier.fr" site_id="51028">Cine + Premier</channel>
<channel lang="fr" xmltv_id="CNews.fr" site_id="51048">C News</channel>
<channel lang="fr" xmltv_id="CNNInternationalLatinAmerica.us" site_id="51032">CNN International Latin America</channel>
<channel lang="fr" xmltv_id="ComediePlus.fr" site_id="51033">Comédie +</channel>
<channel lang="fr" xmltv_id="CStar.fr" site_id="51217">C Star</channel>
<channel lang="fr" xmltv_id="Cuisines.fr" site_id="51711">Cuisines</channel>
<channel lang="fr" xmltv_id="DiscoveryChannelFrance.fr" site_id="51248">Discovery Channel France</channel>
<channel lang="fr" xmltv_id="DiscoveryScienceFrance.fr" site_id="51249">Discovery Science France</channel>
<channel lang="fr" xmltv_id="DisneyChannelFrance.fr" site_id="51035">Disney Channel France</channel>
<channel lang="fr" xmltv_id="DisneyJuniorFrance.fr" site_id="51075">Disney Junior France</channel>
<channel lang="fr" xmltv_id="DorcelTVAfrica.nl" site_id="51702">Dorcel TV Africa</channel>
<channel lang="fr" xmltv_id="EFrance.fr" site_id="51036">E! France</channel>
<channel lang="fr" xmltv_id="EnglishClubTV.uk" site_id="51374">English Club TV</channel>
<channel lang="fr" xmltv_id="MGGTV.fr" site_id="51667">ES1</channel>
<channel lang="fr" xmltv_id="ESPN2Caribbean.us" site_id="51290">ESPN 2 Caribbean</channel>
<channel lang="fr" xmltv_id="ESPNCaribbean.us" site_id="51038">ESPN Caribbean</channel>
<channel lang="fr" xmltv_id="ETV.gp" site_id="51286">ETV</channel>
<channel lang="fr" xmltv_id="Eurosport1.fr" site_id="51041">Eurosport 1</channel>
<channel lang="fr" xmltv_id="Eurosport2.fr" site_id="51042">Eurosport 2</channel>
<channel lang="fr" xmltv_id="France2.fr" site_id="51188">France 2</channel>
<channel lang="fr" xmltv_id="France3.fr" site_id="51045">France 3</channel>
<channel lang="fr" xmltv_id="France5.fr" site_id="51046">France 5</channel>
<channel lang="fr" xmltv_id="France24French.fr" site_id="51114">France 24 Français</channel>
<channel lang="fr" xmltv_id="Franceinfo.fr" site_id="51704">Franceinfo:</channel>
<channel lang="fr" xmltv_id="GameOne.fr" site_id="51136">Game One</channel>
<channel lang="fr" xmltv_id="GloboNews.br" site_id="51230">Globo News</channel>
<channel lang="fr" xmltv_id="GrapheTV.mq" site_id="51937">Graphé TV</channel>
<channel lang="fr" xmltv_id="Guadeloupe1ere.gp" site_id="51083">Guadeloupe 1ère</channel>
<channel lang="fr" xmltv_id="Guyane1ere.gf" site_id="51084">Guyane 1ère</channel>
<channel lang="fr" xmltv_id="HaitiSportsTV1.ht" site_id="51358">Haiti Sports TV 1</channel>
<channel lang="fr" xmltv_id="HaitiSportsTV2.ht" site_id="51359">Haiti Sports TV 2</channel>
<channel lang="fr" xmltv_id="HBOXtremeLatinAmerica.us" site_id="51363">HBO Xtreme Latinoamérica</channel>
<channel lang="fr" xmltv_id="InfosportPlus.fr" site_id="51050">InfoSport +</channel>
<channel lang="fr" xmltv_id="IOTV.sx" site_id="51611">IOTV</channel>
<channel lang="fr" xmltv_id="KMT.mq" site_id="51210">KMT</channel>
<channel lang="fr" xmltv_id="KTO.fr" site_id="51278">KTO</channel>
<channel lang="fr" xmltv_id="KTVGuyane.gf" site_id="51288">KTV Guyane</channel>
<channel lang="fr" xmltv_id="LCI.fr" site_id="51054">LCI</channel>
<channel lang="fr" xmltv_id="PublicSenat.fr" site_id="51055">LCP Public Sénat</channel>
<channel lang="fr" xmltv_id="LEquipe.fr" site_id="51056">L&apos;Équipe</channel>
<channel lang="fr" xmltv_id="Ludikids.fr" site_id="51931">Ludikids</channel>
<channel lang="fr" xmltv_id="M6.fr" site_id="51057">M6</channel>
<channel lang="fr" xmltv_id="Martinique1ere.mq" site_id="51085">Martinique 1ère</channel>
<channel lang="fr" xmltv_id="MCM.fr" site_id="51060">MCM France</channel>
<channel lang="fr" xmltv_id="Metropole.ht" site_id="51306">Metropole</channel>
<channel lang="fr" xmltv_id="MTVFrance.fr" site_id="51065">MTV France</channel>
<channel lang="fr" xmltv_id="MTVHitsFrance.fr" site_id="51147">MTV Hits France</channel>
<channel lang="fr" xmltv_id="NathanTV.fr" site_id="51959">Nathan TV</channel>
<channel lang="fr" xmltv_id="NationalGeographicFrance.fr" site_id="51145">National Geographic France</channel>
<channel lang="fr" xmltv_id="NationalGeographicWildFrance.fr" site_id="51223">National Geographic Wild France</channel>
<channel lang="fr" xmltv_id="NickelodeonFrance.fr" site_id="51224">Nickelodeon France</channel>
<channel lang="fr" xmltv_id="NickJrAfrica.za" site_id="51941">Nick Jr Africa</channel>
<channel lang="fr" xmltv_id="NollywoodTV.fr" site_id="51418">Nollywood TV</channel>
<channel lang="fr" xmltv_id="NovelasTV.fr" site_id="51548">Novelas TV</channel>
<channel lang="fr" xmltv_id="NRJ12.fr" site_id="51216">NRJ 12</channel>
<channel lang="fr" xmltv_id="ParamountChannelFrance.fr" site_id="51303">Paramount Channel France</channel>
<channel lang="fr" xmltv_id="ParisPremiere.fr" site_id="51070">Paris Première</channel>
<channel lang="fr" xmltv_id="PenthouseBlack.us" site_id="51280">Penthouse Black</channel>
<channel lang="fr" xmltv_id="PiwiPlus.fr" site_id="51128">Piwi +</channel>
<channel lang="fr" xmltv_id="PlanetePlus.fr" site_id="51072">Planète +</channel>
<channel lang="fr" xmltv_id="PlanetePlusAE.fr" site_id="51073">Planète + A&amp;E</channel>
<channel lang="fr" xmltv_id="PlanetePlusCI.fr" site_id="51142">Planète + CI</channel>
<channel lang="fr" xmltv_id="RTL9.lu" site_id="51077">RTL 9</channel>
<channel lang="fr" xmltv_id="Seasons.fr" site_id="51079">Seasons</channel>
<!-- <channel lang="fr" xmltv_id="" site_id="51422">Sony Channel Centro</channel> -->
<channel lang="fr" xmltv_id="Studiocanal.fr" site_id="51942">Studiocanal</channel>
<channel lang="fr" xmltv_id="STVS81.sr" site_id="51616">STVS 8.1</channel>
<channel lang="fr" xmltv_id="SyfyFrance.fr" site_id="51078">Syfy France</channel>
<channel lang="fr" xmltv_id="Tele20.ht" site_id="51618">Télé 20</channel>
<channel lang="fr" xmltv_id="TelemicroInternacional.do" site_id="51292">Telemicro Internacional</channel>
<channel lang="fr" xmltv_id="TelemundoCentralAmerica.us" site_id="51725">Telemundo</channel>
<channel lang="fr" xmltv_id="TelePacific.ht" site_id="51617">Tele Pacific</channel>
<channel lang="fr" xmltv_id="TeleSoleil.ht" site_id="51936">Tele Soleil</channel>
<channel lang="fr" xmltv_id="TeletoonPlus.fr" site_id="51148">TéléToon +</channel>
<channel lang="fr" xmltv_id="TF1.fr" site_id="51095">TF 1</channel>
<channel lang="fr" xmltv_id="TF1SeriesFilms.fr" site_id="51613">TF 1 Séries Films</channel>
<channel lang="fr" xmltv_id="TFX.fr" site_id="51067">TFX</channel>
<channel lang="fr" xmltv_id="TNH.ht" site_id="51291">TNH</channel>
<channel lang="fr" xmltv_id="ToutelHistoire.fr" site_id="51727">Toute l&apos;Histoire</channel>
<channel lang="fr" xmltv_id="TraceAyiti.fr" site_id="51654">Trace Ayiti</channel>
<channel lang="fr" xmltv_id="TraceCaribbean.fr" site_id="51155">Trace Caribbean</channel>
<channel lang="fr" xmltv_id="TraceGospel.fr" site_id="51620">Trace Gospel</channel>
<channel lang="fr" xmltv_id="TraceLatina.fr" site_id="51653">Trace Latina</channel>
<channel lang="fr" xmltv_id="TraceUrban.fr" site_id="51102">Trace Urban</channel>
<channel lang="fr" xmltv_id="TV5MondeLatinAmerica.fr" site_id="51106">TV5Monde Amérique Latine</channel>
<channel lang="fr" xmltv_id="TVCaraibes.ht" site_id="51423">TV Caraïbes</channel>
<channel lang="fr" xmltv_id="UshuaiaTV.fr" site_id="51138">Ushuaïa TV</channel>
<channel lang="fr" xmltv_id="ViaATV.mq" site_id="51006">ViàATV</channel>
<channel lang="fr" xmltv_id="VixenTV.ca" site_id="51934">Vixen</channel>
<channel lang="fr" xmltv_id="WataaaTV.fr" site_id="51614">Wataaa TV</channel>
<channel lang="fr" xmltv_id="XXL.fr" site_id="51110">XXL</channel>
<channel lang="fr" xmltv_id="ZitataTV.mq" site_id="51801">Zitata TV</channel>
<channel lang="fr" xmltv_id="ZoukTV.mq" site_id="51285">Zouk TV</channel>
</channels>
</site>

View File

@@ -0,0 +1,94 @@
const axios = require('axios')
const cheerio = require('cheerio')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
dayjs.extend(utc)
module.exports = {
site: 'canalplus-haiti.com',
days: 2,
url: function ({ channel, date }) {
const diff = date.diff(dayjs.utc().startOf('d'), 'd')
return `https://service.canal-overseas.com/ott-frontend/vector/53101/channel/${channel.site_id}/events?filter.day=${diff}`
},
async parser({ content }) {
let programs = []
const items = parseItems(content)
for (let item of items) {
if (item.title === 'Fin des programmes') return
const detail = await loadProgramDetails(item)
programs.push({
title: item.title,
description: parseDescription(detail),
category: parseCategory(detail),
icon: parseIcon(item),
start: parseStart(item),
stop: parseStop(item)
})
}
return programs
},
async channels() {
const html = await axios
.get(`https://www.canalplus-haiti.com/guide-tv-ce-soir`)
.then(r => r.data)
.catch(console.log)
const $ = cheerio.load(html)
const script = $('body > script:nth-child(2)').html()
const [_, json] = script.match(/window.APP_STATE=(.*);/) || [null, null]
const data = JSON.parse(json)
const items = data.tvGuide.channels.byZapNumber
return Object.values(items).map(item => {
return {
lang: 'fr',
site_id: item.epgID,
name: item.name
}
})
}
}
async function loadProgramDetails(item) {
if (!item.onClick.URLPage) return {}
const url = item.onClick.URLPage
const data = await axios
.get(url)
.then(r => r.data)
.catch(console.log)
return data || {}
}
function parseDescription(detail) {
return detail.detail.informations.summary || null
}
function parseCategory(detail) {
return detail.detail.informations.subGenre || null
}
function parseIcon(item) {
return item.URLImage || item.URLImageDefault
}
function parseStart(item) {
return dayjs.unix(item.startTime)
}
function parseStop(item) {
return dayjs.unix(item.endTime)
}
function parseItems(content) {
const data = JSON.parse(content)
if (!data || !data.timeSlices) return []
const items = data.timeSlices.reduce((acc, curr) => {
acc = acc.concat(curr.contents)
return acc
}, [])
return items
}

View File

@@ -0,0 +1,175 @@
// [Geo-blocked] npm run channels:parse --config=./sites/canalplus-haiti.com/canalplus-haiti.com.config.js --output=./sites/canalplus-haiti.com/canalplus-haiti.com.channels.xml
// npx epg-grabber --config=sites/canalplus-haiti.com/canalplus-haiti.com.config.js --channels=sites/canalplus-haiti.com/canalplus-haiti.com.channels.xml --output=guide.xml --days=2
const { parser, url } = require('./canalplus-haiti.com.config.js')
const axios = require('axios')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const customParseFormat = require('dayjs/plugin/customParseFormat')
dayjs.extend(customParseFormat)
dayjs.extend(utc)
jest.mock('axios')
const channel = {
site_id: '51006',
xmltv_id: 'ViaATV.mq'
}
it('can generate valid url for today', () => {
const date = dayjs.utc().startOf('d')
expect(url({ channel, date })).toBe(
'https://service.canal-overseas.com/ott-frontend/vector/53101/channel/51006/events?filter.day=0'
)
})
it('can generate valid url for tomorrow', () => {
const date = dayjs.utc().startOf('d').add(1, 'd')
expect(url({ channel, date })).toBe(
'https://service.canal-overseas.com/ott-frontend/vector/53101/channel/51006/events?filter.day=1'
)
})
it('can parse response', done => {
const content = `{
"timeSlices": [
{
"contents": [
{
"title": "New Amsterdam - S3 - Ep7",
"subtitle": "Episode 7 - Le mur de la honte",
"thirdTitle": "viaATV",
"startTime": 1660780500,
"endTime": 1660783200,
"onClick": {
"displayTemplate": "miniDetail",
"displayName": "New Amsterdam - S3 - Ep7",
"URLPage": "https://service.canal-overseas.com/ott-frontend/vector/53101/event/140952809",
"URLVitrine": "https://service.canal-overseas.com/ott-frontend/vector/53101/program/187882282/recommendations"
},
"programID": 187882282,
"diffusionID": "140952809",
"URLImageDefault": "https://service.canal-overseas.com/image-api/v1/image/generic",
"URLImage": "https://service.canal-overseas.com/image-api/v1/image/52a18a209e28380b199201961c27097e"
}
],
"timeSlice": "2"
}
]
}`
axios.get.mockImplementation(url => {
if (url === 'https://service.canal-overseas.com/ott-frontend/vector/53101/event/140952809') {
return Promise.resolve({
data: JSON.parse(`{
"currentPage": {
"displayName": "New Amsterdam - S3 - Ep7",
"displayTemplate": "detailPage",
"URLVitrine": "https://service.canal-overseas.com/ott-frontend/vector/53101/program/187882282/recommendations"
},
"detail": {
"informations": {
"programmeType": "EPG",
"isInOffer": false,
"isInOfferOnDevice": false,
"isInOfferForD2G": false,
"availableInVoDOnDevice": false,
"availableInVoDOnG5": false,
"availableInD2GOnDevice": false,
"availableInLiveOnDevice": false,
"rediffusions": true,
"canBeRecorded": false,
"channelName": "viaATV",
"startTime": 1660780500,
"endTime": 1660783200,
"title": "New Amsterdam - S3 - Ep7",
"subtitle": "Episode 7 - Le mur de la honte",
"thirdTitle": "viaATV",
"genre": "Séries",
"subGenre": "Série Hôpital",
"editorialTitle": "Séries, Etats-Unis, 2020, 0h45",
"audioLanguage": "VF",
"personnalities": [
{
"prefix": "De :",
"content": "Darnell Martin"
},
{
"prefix": "Avec :",
"content": "André De Shields, Anna Suzuki, Anupam Kher, Baylen Thomas, Christine Chang, Craig Wedren, Daniel Dae Kim, Dierdre Friel, Em Grosland, Emma Ramos, Freema Agyeman, Gina Gershon, Graham Norris, Jamie Ann Romero, Janet Montgomery, Jefferson Friedman, Joshua Gitta, Kerry Flanagan, Larry Bryggman, Mike Doyle, Nora Clow, Opal Clow, Ryan Eggold, Simone Policano, Stephen Spinella, Tyler Labine"
}
],
"summary": "C'est la journée nationale de dépistage du VIH et Max offre des soins gratuits à tous les malades séropositifs qui se présentent à New Amsterdam.",
"summaryMedium": "C'est la journée nationale de dépistage du VIH et Max offre des soins gratuits à tous les malades séropositifs qui se présentent à New Amsterdam.",
"programID": 187882282,
"sharingURL": "https://www.canalplus-haiti.com/grille-tv/event/140952809-new-amsterdam-s3-ep7.html",
"labels": {
"allocine": false,
"telerama": false,
"sensCritique": false
},
"EpgId": 51006,
"CSA": 1,
"HD": false,
"3D": false,
"diffusionID": "140952809",
"duration": "2700",
"URLImageDefault": "https://service.canal-overseas.com/image-api/v1/image/generic",
"URLImage": "https://service.canal-overseas.com/image-api/v1/image/52a18a209e28380b199201961c27097e",
"URLLogo": "https://service.canal-overseas.com/image-api/v1/image/0f67b2e85f74101c4c776cf423240fce",
"URLLogoBlack": "https://service.canal-overseas.com/image-api/v1/image/0f67b2e85f74101c4c776cf423240fce",
"URLVitrine": "https://service.canal-overseas.com/ott-frontend/vector/53101/program/187882282/recommendations"
},
"diffusions": [
{
"diffusionDateUTC": 1660780500,
"sharingUrl": "https://www.canalplus-haiti.com/grille-tv/event/140952809-new-amsterdam.html",
"broadcastId": "140952809",
"name": "viaATV",
"epgID": "51006",
"ZapNumber": "28",
"URLLogo": "https://service.canal-overseas.com/image-api/v1/image/0f67b2e85f74101c4c776cf423240fce",
"URLLogoBlack": "https://service.canal-overseas.com/image-api/v1/image/0f67b2e85f74101c4c776cf423240fce"
}
]
}
}`)
})
} else {
return Promise.resolve({ data: '' })
}
})
parser({ content })
.then(result => {
result = result.map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2022-08-17T23:55:00.000Z',
stop: '2022-08-18T00:40:00.000Z',
title: 'New Amsterdam - S3 - Ep7',
icon: 'https://service.canal-overseas.com/image-api/v1/image/52a18a209e28380b199201961c27097e',
category: 'Série Hôpital',
description:
"C'est la journée nationale de dépistage du VIH et Max offre des soins gratuits à tous les malades séropositifs qui se présentent à New Amsterdam."
}
])
done()
})
.catch(done)
})
it('can handle empty guide', done => {
parser({
content: `{"currentPage":{"displayTemplate":"error","BOName":"Page introuvable"},"title":"Page introuvable","text":"La page que vous demandez est introuvable. Si le problème persiste, vous pouvez contacter l'assistance de CANAL+/CANALSAT.","code":404}`
})
.then(result => {
expect(result).toMatchObject([])
done()
})
.catch(done)
})

View File

@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="canalplus-reunion.com">
<channels>
<channel lang="fr" xmltv_id="6ter.fr" site_id="60624">6ter</channel>
<channel lang="fr" xmltv_id="13emeRue.fr" site_id="60001">13ème Rue</channel>
<channel lang="fr" xmltv_id="Action.fr" site_id="60004">Action</channel>
<channel lang="fr" xmltv_id="AntenneReunion.fr" site_id="60005">Antenne Réunion TV</channel>
<channel lang="fr" xmltv_id="APlus.fr" site_id="60416">A+</channel>
<channel lang="fr" xmltv_id="ARTEFrance.fr" site_id="60007">ARTE Français</channel>
<channel lang="fr" xmltv_id="Automotolachaine.fr" site_id="60565">Automoto la chaîne</channel>
<channel lang="fr" xmltv_id="BBCWorldNewsAfrica.uk" site_id="60008">BBC World News Africa</channel>
<channel lang="fr" xmltv_id="beINSports1France.fr" site_id="60115">BeIn Sports 1 France</channel>
<channel lang="fr" xmltv_id="beINSports2France.fr" site_id="60243">BeIn Sports 2 France</channel>
<channel lang="fr" xmltv_id="beINSports3France.fr" site_id="60347">BeIn Sports 3 France</channel>
<channel lang="fr" xmltv_id="C8.fr" site_id="60120">C8</channel>
<channel lang="fr" xmltv_id="CanalPlusCinemaReunion.fr" site_id="60014">Canal + Cinéma Réunion</channel>
<channel lang="fr" xmltv_id="CanalPlusDecale.fr" site_id="60709">Canal + Décalé</channel>
<channel lang="fr" xmltv_id="CanalPlusKids.fr" site_id="60401">Canal + Kids</channel>
<channel lang="fr" xmltv_id="CanalPlusReunion.fr" site_id="60020">Canal + Réunion</channel>
<channel lang="fr" xmltv_id="CanalPlusSeriesReunion.fr" site_id="60312">Canal + Séries Réunion</channel>
<channel lang="fr" xmltv_id="CanalPlusSportReunion.fr" site_id="60022">Canal + Sport Réunion</channel>
<channel lang="fr" xmltv_id="CGTNFrench.cn" site_id="60309">CGTN Français</channel>
<channel lang="fr" xmltv_id="CinePlusClassic.fr" site_id="60328">Cine + Classic</channel>
<channel lang="fr" xmltv_id="CinePlusClub.fr" site_id="60024">Cine + Club</channel>
<channel lang="fr" xmltv_id="CinePlusEmotion.fr" site_id="60025">Cine + Émotion</channel>
<channel lang="fr" xmltv_id="CinePlusFamiz.fr" site_id="60026">Cine + Famiz</channel>
<channel lang="fr" xmltv_id="CinePlusFrisson.fr" site_id="60027">Cine + Frisson</channel>
<channel lang="fr" xmltv_id="CinePlusPremier.fr" site_id="60028">Cine + Premier</channel>
<channel lang="fr" xmltv_id="CNews.fr" site_id="60048">C News</channel>
<channel lang="fr" xmltv_id="ColmaxTV.fr" site_id="60564">Colmax TV</channel>
<channel lang="fr" xmltv_id="Colors.in" site_id="60218">Colors</channel>
<channel lang="fr" xmltv_id="ComediePlus.fr" site_id="60033">Comédie +</channel>
<channel lang="fr" xmltv_id="CStar.fr" site_id="60217">C Star</channel>
<channel lang="fr" xmltv_id="DiscoveryChannelFrance.fr" site_id="60248">Discovery Channel France</channel>
<channel lang="fr" xmltv_id="DiscoveryScienceFrance.fr" site_id="60249">Discovery Science France</channel>
<channel lang="fr" xmltv_id="DisneyChannelFrance.fr" site_id="60035">Disney Channel France</channel>
<channel lang="fr" xmltv_id="DisneyJuniorFrance.fr" site_id="60075">Disney Junior France</channel>
<channel lang="fr" xmltv_id="DorcelTVAfrica.nl" site_id="60154">Dorcel TV Africa</channel>
<channel lang="fr" xmltv_id="EFrance.fr" site_id="60036">E! France</channel>
<channel lang="fr" xmltv_id="EnglishClubTV.uk" site_id="60374">English Club TV</channel>
<channel lang="fr" xmltv_id="Equidia.fr" site_id="60037">Equidia</channel>
<channel lang="fr" xmltv_id="Eurosport1.fr" site_id="60041">Eurosport 1 France</channel>
<channel lang="fr" xmltv_id="Eurosport2.fr" site_id="60042">Eurosport 2 France</channel>
<channel lang="fr" xmltv_id="France2.fr" site_id="60188">France 2</channel>
<channel lang="fr" xmltv_id="France3.fr" site_id="60045">France 3</channel>
<channel lang="fr" xmltv_id="France4.fr" site_id="60196">France 4</channel>
<channel lang="fr" xmltv_id="France5.fr" site_id="60046">France 5</channel>
<channel lang="fr" xmltv_id="France24French.fr" site_id="60114">France 24 Français</channel>
<channel lang="fr" xmltv_id="Franceinfo.fr" site_id="60704">Franceinfo:</channel>
<channel lang="fr" xmltv_id="GameOne.fr" site_id="60136">Game One</channel>
<channel lang="fr" xmltv_id="GolfPlus.fr" site_id="60414">Golf +</channel>
<channel lang="fr" xmltv_id="Gulli.fr" site_id="60146">Gulli</channel>
<channel lang="fr" xmltv_id="HistoireTV.fr" site_id="60158">Histoire TV</channel>
<channel lang="fr" xmltv_id="InfosportPlus.fr" site_id="60050">InfoSport +</channel>
<channel lang="fr" xmltv_id="IqraaAfricaEurope.sa" site_id="60279">Iqraa Africa &amp; Europe</channel>
<channel lang="fr" xmltv_id="KanalAustralTV.re" site_id="60153">Kanal Austral TV</channel>
<channel lang="fr" xmltv_id="KoloTV.mg" site_id="60331">Kolo TV</channel>
<channel lang="fr" xmltv_id="KTO.fr" site_id="60278">KTO</channel>
<channel lang="fr" xmltv_id="KweziTV.yt" site_id="60968">Kwezi TV</channel>
<channel lang="fr" xmltv_id="LCI.fr" site_id="60054">LCI</channel>
<channel lang="fr" xmltv_id="LCP.fr" site_id="60055">LCP Assemblée Nationale</channel>
<channel lang="fr" xmltv_id="LEquipe.fr" site_id="60056">L&apos;Équipe</channel>
<channel lang="fr" xmltv_id="Ludikids.fr" site_id="60931">Ludikids</channel>
<channel lang="fr" xmltv_id="M6.fr" site_id="60057">M6</channel>
<channel lang="fr" xmltv_id="Mayotte1ere.yt" site_id="60206">Mayotte 1ère</channel>
<channel lang="fr" xmltv_id="MBS.mg" site_id="60683">MBS</channel>
<channel lang="fr" xmltv_id="Mezzo.fr" site_id="60063">Mezzo</channel>
<channel lang="fr" xmltv_id="MTVFrance.fr" site_id="60065">MTV France</channel>
<channel lang="fr" xmltv_id="MTVHitsFrance.fr" site_id="60147">MTV Hits France</channel>
<channel lang="fr" xmltv_id="MTVIndia.in" site_id="60342">MTV India</channel>
<channel lang="fr" xmltv_id="NationalGeographicFrance.fr" site_id="60145">National Geographic France</channel>
<channel lang="fr" xmltv_id="NationalGeographicWildFrance.fr" site_id="60223">National Geographic Wild France</channel>
<channel lang="fr" xmltv_id="NickelodeonFrance.fr" site_id="60224">Nickelodeon France</channel>
<channel lang="fr" xmltv_id="NickelodeonJunior.fr" site_id="60941">Nickelodeon Junior France</channel>
<channel lang="fr" xmltv_id="NollywoodTV.fr" site_id="60418">Nollywood TV</channel>
<channel lang="fr" xmltv_id="Novegasy.mg" site_id="60799">Novegasy</channel>
<channel lang="fr" xmltv_id="NovelasTV.fr" site_id="60547">Novelas TV</channel>
<channel lang="fr" xmltv_id="NRJ12.fr" site_id="60216">NRJ 12</channel>
<channel lang="fr" xmltv_id="OCSChoc.fr" site_id="60318">OCS choc</channel>
<channel lang="fr" xmltv_id="OCSCity.fr" site_id="60317">OCS City</channel>
<channel lang="fr" xmltv_id="OCSGeants.fr" site_id="60319">OCS geants</channel>
<channel lang="fr" xmltv_id="OCSMax.fr" site_id="60316">OCS max</channel>
<channel lang="fr" xmltv_id="ORTCTV.km" site_id="60195">ORTC TV</channel>
<channel lang="fr" xmltv_id="ParamountChannelFrance.fr" site_id="60303">Paramount Channel France</channel>
<channel lang="fr" xmltv_id="ParisPremiere.fr" site_id="60070">Paris Première</channel>
<channel lang="fr" xmltv_id="PenthouseBlack.us" site_id="60280">Penthouse Black</channel>
<channel lang="fr" xmltv_id="PiwiPlus.fr" site_id="60128">Piwi +</channel>
<channel lang="fr" xmltv_id="PlanetePlus.fr" site_id="60072">Planète +</channel>
<channel lang="fr" xmltv_id="PlanetePlusAE.fr" site_id="60073">Planète + A&amp;E</channel>
<channel lang="fr" xmltv_id="PlanetePlusCI.fr" site_id="60142">Planète + CI</channel>
<channel lang="fr" xmltv_id="Reunion1ere.fr" site_id="60088">Réunion 1ère</channel>
<channel lang="fr" xmltv_id="RFMTV.fr" site_id="60061">RFM TV</channel>
<channel lang="fr" xmltv_id="RTA.mg" site_id="60726">RTA</channel>
<channel lang="fr" xmltv_id="RTL9.lu" site_id="60077">RTL 9</channel>
<channel lang="fr" xmltv_id="Seasons.fr" site_id="60079">Seasons</channel>
<channel lang="fr" xmltv_id="SerieClub.fr" site_id="60080">Série Club</channel>
<channel lang="fr" xmltv_id="SyfyFrance.fr" site_id="60078">Syfy France</channel>
<channel lang="fr" xmltv_id="TeleKreol.re" site_id="60203">Télé Kréol</channel>
<channel lang="fr" xmltv_id="TeletoonPlus.fr" site_id="60148">TéléToon +</channel>
<channel lang="fr" xmltv_id="Teva.fr" site_id="60094">Téva</channel>
<channel lang="fr" xmltv_id="TF1.fr" site_id="60095">TF 1</channel>
<channel lang="fr" xmltv_id="TF1SeriesFilms.fr" site_id="60613">TF 1 Séries Films</channel>
<channel lang="fr" xmltv_id="TFX.fr" site_id="60067">TFX</channel>
<channel lang="fr" xmltv_id="TMC.fr" site_id="60098">TMC</channel>
<channel lang="fr" xmltv_id="TraceCaribbean.fr" site_id="60155">Trace Caribbean</channel>
<channel lang="fr" xmltv_id="TraceUrban.fr" site_id="60102">Trace Urban Afrique</channel>
<channel lang="fr" xmltv_id="TraceVanillaIslands.fr" site_id="60800">Trace Vanilla Islands</channel>
<channel lang="fr" xmltv_id="Trek.fr" site_id="60566">Trek</channel>
<channel lang="fr" xmltv_id="TV5MondeAfrica.fr" site_id="60105">TV5Monde Afrique</channel>
<channel lang="fr" xmltv_id="TVBreizh.fr" site_id="60104">TV Breizh</channel>
<channel lang="fr" xmltv_id="TVMalagasy.mg" site_id="60194">TV Malagasy</channel>
<channel lang="fr" xmltv_id="TVPlusMadagascar.mg" site_id="60330">TV Plus Madagascar</channel>
<channel lang="fr" xmltv_id="TVRecordMadagascar.mg" site_id="60413">TV Record Madagascar</channel>
<channel lang="fr" xmltv_id="UshuaiaTV.fr" site_id="60138">Ushuaïa TV</channel>
<channel lang="fr" xmltv_id="VixenTV.ca" site_id="60934">Vixen</channel>
<channel lang="fr" xmltv_id="W9.fr" site_id="60140">W9</channel>
<channel lang="fr" xmltv_id="WataaaTV.fr" site_id="60614">Wataaa TV</channel>
<channel lang="fr" xmltv_id="XXL.fr" site_id="60110">XXL</channel>
<channel lang="fr" xmltv_id="ZeeCinemaAfrica.in" site_id="60117">Zee Cinema Africa</channel>
<channel lang="fr" xmltv_id="ZeeTVAfrica.za" site_id="60119">Zee TV Africa</channel>
<channel lang="fr" xmltv_id="ZingUK.uk" site_id="60118">Zing UK</channel>
</channels>
</site>

View File

@@ -0,0 +1,72 @@
const axios = require('axios')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
dayjs.extend(utc)
module.exports = {
site: 'canalplus-reunion.com',
days: 2,
url: function ({ channel, date }) {
const diff = date.diff(dayjs.utc().startOf('d'), 'd')
return `https://service.canal-overseas.com/ott-frontend/vector/63001/channel/${channel.site_id}/events?filter.day=${diff}`
},
async parser({ content }) {
let programs = []
const items = parseItems(content)
for (let item of items) {
if (item.title === 'Fin des programmes') return
const detail = await loadProgramDetails(item)
programs.push({
title: item.title,
description: parseDescription(detail),
category: parseCategory(detail),
icon: parseIcon(item),
start: parseStart(item),
stop: parseStop(item)
})
}
return programs
}
}
async function loadProgramDetails(item) {
if (!item.onClick.URLPage) return {}
const url = item.onClick.URLPage
const data = await axios
.get(url)
.then(r => r.data)
.catch(console.log)
return data || {}
}
function parseDescription(detail) {
return detail.detail.informations.summary || null
}
function parseCategory(detail) {
return detail.detail.informations.subGenre || null
}
function parseIcon(item) {
return item.URLImage || item.URLImageDefault
}
function parseStart(item) {
return dayjs.unix(item.startTime)
}
function parseStop(item) {
return dayjs.unix(item.endTime)
}
function parseItems(content) {
const data = JSON.parse(content)
if (!data || !data.timeSlices) return []
const items = data.timeSlices.reduce((acc, curr) => {
acc = acc.concat(curr.contents)
return acc
}, [])
return items
}

View File

@@ -0,0 +1,159 @@
// npx epg-grabber --config=sites/canalplus-reunion.com/canalplus-reunion.com.config.js --channels=sites/canalplus-reunion.com/canalplus-reunion.com.channels.xml --output=guide.xml --days=2
const { parser, url } = require('./canalplus-reunion.com.config.js')
const axios = require('axios')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const customParseFormat = require('dayjs/plugin/customParseFormat')
dayjs.extend(customParseFormat)
dayjs.extend(utc)
jest.mock('axios')
const channel = {
site_id: '60243',
xmltv_id: 'beINSports2France.fr'
}
it('can generate valid url for today', () => {
const date = dayjs.utc().startOf('d')
expect(url({ channel, date })).toBe(
'https://service.canal-overseas.com/ott-frontend/vector/63001/channel/60243/events?filter.day=0'
)
})
it('can generate valid url for tomorrow', () => {
const date = dayjs.utc().startOf('d').add(1, 'd')
expect(url({ channel, date })).toBe(
'https://service.canal-overseas.com/ott-frontend/vector/63001/channel/60243/events?filter.day=1'
)
})
it('can parse response', done => {
const content = `{
"timeSlices": [
{
"contents": [
{
"title": "Almeria / Real Madrid",
"subtitle": "Football",
"thirdTitle": "BEIN SPORTS 2 HD",
"startTime": 1660780800,
"endTime": 1660788000,
"onClick": {
"displayTemplate": "miniDetail",
"displayName": "Almeria / Real Madrid",
"URLPage": "https://service.canal-overseas.com/ott-frontend/vector/63001/event/140382363",
"URLVitrine": "https://service.canal-overseas.com/ott-frontend/vector/63001/program/224523053/recommendations"
},
"programID": 224523053,
"diffusionID": "140382363",
"URLImageDefault": "https://service.canal-overseas.com/image-api/v1/image/a6b640e16608ffa3d862e2bd8a4b3e4c",
"URLImage": "https://service.canal-overseas.com/image-api/v1/image/47000149dabce60d1769589c766aad20"
}
],
"timeSlice": "4"
}
]
}`
axios.get.mockImplementation(url => {
if (url === 'https://service.canal-overseas.com/ott-frontend/vector/63001/event/140382363') {
return Promise.resolve({
data: JSON.parse(`{
"currentPage": {
"displayName": "Almeria / Real Madrid",
"displayTemplate": "detailPage",
"URLVitrine": "https://service.canal-overseas.com/ott-frontend/vector/63001/program/224523053/recommendations"
},
"detail": {
"informations": {
"programmeType": "EPG",
"isInOffer": false,
"isInOfferOnDevice": false,
"isInOfferForD2G": false,
"availableInVoDOnDevice": false,
"availableInVoDOnG5": false,
"availableInD2GOnDevice": false,
"availableInLiveOnDevice": false,
"rediffusions": true,
"canBeRecorded": false,
"channelName": "BEIN SPORTS 2 HD",
"startTime": 1660780800,
"endTime": 1660788000,
"title": "Almeria / Real Madrid",
"subtitle": "Football",
"thirdTitle": "BEIN SPORTS 2 HD",
"genre": "Sport",
"subGenre": "Football",
"editorialTitle": "Sport, Espagne, 2h00",
"audioLanguage": "VF",
"summary": "Diffusion d'un match de LaLiga Santander, championnat d'Espagne de football, la plus haute compétition de football d'Espagne. Cette compétition professionnelle, placée sous la supervision de la Fédération espagnole de football, a été fondée en 1928 et s'appelle Primera Division jusqu'en 2008. Elle se nomme ensuite Liga BBVA jusqu'en 2016 puis LaLiga Santander depuis cette date.",
"summaryMedium": "Diffusion d'un match de LaLiga Santander, championnat d'Espagne de football, la plus haute compétition de football d'Espagne. Cette compétition professionnelle, placée sous la supervision de la Fédération espagnole de football, a été fondée en 1928 et s'appelle Primera Division jusqu'en 2008. Elle se nomme ensuite Liga BBVA jusqu'en 2016 puis LaLiga Santander depuis cette date.",
"programID": 224523053,
"sharingURL": "https://www.canalplus-reunion.com/grille-tv/event/140382363-almeria-real-madrid.html",
"EpgId": 60243,
"CSA": 1,
"HD": false,
"3D": false,
"diffusionID": "140382363",
"duration": "7200",
"URLImageDefault": "https://service.canal-overseas.com/image-api/v1/image/a6b640e16608ffa3d862e2bd8a4b3e4c",
"URLImage": "https://service.canal-overseas.com/image-api/v1/image/47000149dabce60d1769589c766aad20",
"URLLogo": "https://service.canal-overseas.com/image-api/v1/image/6e2124827406ed41236a8430352d4ed9",
"URLLogoBlack": "https://service.canal-overseas.com/image-api/v1/image/6e2124827406ed41236a8430352d4ed9",
"URLVitrine": "https://service.canal-overseas.com/ott-frontend/vector/63001/program/224523053/recommendations"
},
"diffusions": [
{
"diffusionDateUTC": 1660780800,
"sharingUrl": "https://www.canalplus-reunion.com/grille-tv/event/140382363-almeria-real-madrid.html",
"broadcastId": "140382363",
"name": "BEIN SPORTS 2 HD",
"epgID": "60243",
"ZapNumber": "96",
"URLLogo": "https://service.canal-overseas.com/image-api/v1/image/6e2124827406ed41236a8430352d4ed9",
"URLLogoBlack": "https://service.canal-overseas.com/image-api/v1/image/6e2124827406ed41236a8430352d4ed9"
}
]
}
}`)
})
} else {
return Promise.resolve({ data: '' })
}
})
parser({ content })
.then(result => {
result = result.map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2022-08-18T00:00:00.000Z',
stop: '2022-08-18T02:00:00.000Z',
title: 'Almeria / Real Madrid',
icon: 'https://service.canal-overseas.com/image-api/v1/image/47000149dabce60d1769589c766aad20',
category: 'Football',
description:
"Diffusion d'un match de LaLiga Santander, championnat d'Espagne de football, la plus haute compétition de football d'Espagne. Cette compétition professionnelle, placée sous la supervision de la Fédération espagnole de football, a été fondée en 1928 et s'appelle Primera Division jusqu'en 2008. Elle se nomme ensuite Liga BBVA jusqu'en 2016 puis LaLiga Santander depuis cette date."
}
])
done()
})
.catch(done)
})
it('can handle empty guide', done => {
parser({
content: `{"currentPage":{"displayTemplate":"error","BOName":"Page introuvable"},"title":"Page introuvable","text":"La page que vous demandez est introuvable. Si le problème persiste, vous pouvez contacter l'assistance de CANAL+/CANALSAT.","code":404}`
})
.then(result => {
expect(result).toMatchObject([])
done()
})
.catch(done)
})

View File

@@ -0,0 +1 @@
{"timeSlices":[{"timeSlice":"0","contents":[{"contentID":"20482220_50001","title":"Le cercle","subtitle":"Emission du 06 janv. 2023","startTime":1673504880000,"onClick":{"displayTemplate":"detailSeason","displayName":"Le cercle","path":"/cinema/le-cercle/h/4501558_50001","URLPage":"https://hodor.canalplus.pro/api/v2/mycanal/detail/da2291af3b10e9900d1c55e1a65d3388/okapi/6564630_50001.json?detailType=detailSeason&objectType=season&broadcastID=PLM_1196447642&episodeId=20482220_50001&brandID=4501558_50001&fromDiff=true","parameters":[{"in":"parameters","id":"featureToggles","enum":["detailV5"]}]}}],"context":{"context_type":"epg","context_page_title":"Guide - Grille TV - CANAL+ CINEMA","context_list_title":"CANAL+ CINEMA - J - Maintenant - Matin","context_list_id":"198","context_list_type":"epgGrid","context_list_position":1}},{"timeSlice":"1","contents":[{"contentID":"17230453_50001","title":"Illusions perdues","subtitle":"Film Drame","startTime":1673525160000,"onClick":{"displayTemplate":"detailPage","displayName":"Illusions perdues","path":"/cinema/illusions-perdues-film-drame/h/17230453_50001","URLPage":"https://hodor.canalplus.pro/api/v2/mycanal/detail/da2291af3b10e9900d1c55e1a65d3388/okapi/17230453_50001.json?detailType=detailPage&objectType=unit&broadcastID=PLM_1196447637&fromDiff=true","parameters":[{"in":"parameters","id":"featureToggles","enum":["detailV5"]}]}}],"context":{"context_type":"epg","context_page_title":"Guide - Grille TV - CANAL+ CINEMA","context_list_title":"CANAL+ CINEMA - J - Maintenant - Apres-midi","context_list_id":"198","context_list_type":"epgGrid","context_list_position":2}},{"timeSlice":"2","contents":[],"context":{"context_type":"epg","context_page_title":"Guide - Grille TV - CANAL+ CINEMA","context_list_title":"CANAL+ CINEMA - J - Maintenant - Debut de soiree","context_list_id":"198","context_list_type":"epgGrid","context_list_position":3}},{"timeSlice":"3","contents":[],"context":{"context_type":"epg","context_page_title":"Guide - Grille TV - CANAL+ CINEMA","context_list_title":"CANAL+ CINEMA - J - Maintenant - Soiree","context_list_id":"198","context_list_type":"epgGrid","context_list_position":4}},{"timeSlice":"4","contents":[],"context":{"context_type":"epg","context_page_title":"Guide - Grille TV - CANAL+ CINEMA","context_list_title":"CANAL+ CINEMA - J - Maintenant - Nuit","context_list_id":"198","context_list_type":"epgGrid","context_list_position":5}}]}

View File

@@ -0,0 +1 @@
{"currentPage":{"displayTemplate":"error","displayName":"Page indisponible","path":"/erreur","BOName":"Page indisponible","BOLayoutName":"Erreur 400"},"title":"Page indisponible","text":"La page que vous demandez est indisponible. Si le problème persiste, vous pouvez contacter l'assistance de CANAL+.","code":400,"tracking":{"omniture":{"channel":"error","prop4":"error","prop5":"error - Page indisponible - channels_broadcast","prop10":"Contenu","prop11":"Autres","prop12":"Consumer","pageType":"errorPage","eVar14":"La page que vous demandez est indisponible. Si le problème persiste, vous pouvez contacter l'assistance de CANAL+.","pageName":"error - Page indisponible - channels_broadcast","error_message":"La page que vous demandez est indisponible. Si le problème persiste, vous pouvez contacter l'assistance de CANAL+.","page_level_1":"error","page_level_2":"Page indisponible - channels_broadcast","page_name":"error - Page indisponible - channels_broadcast","page_title":"Page indisponible","page_display_title":"Page indisponible","page_type":"errorPage","user_profile":"Consumer"},"dataLayer":{"error_message":"La page que vous demandez est indisponible. Si le problème persiste, vous pouvez contacter l'assistance de CANAL+.","page_level_1":"error","page_level_2":"Page indisponible - channels_broadcast","page_name":"error - Page indisponible - channels_broadcast","page_title":"Page indisponible","page_display_title":"Page indisponible","page_type":"errorPage","user_profile":"Consumer"}},"errorDetails":[{"message":"\"epgId\" must be a number","path":["epgId"],"type":"number.base"}]}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,452 @@
{
"currentPage": {
"displayTemplate": "detailPage",
"displayName": "Illusions perdues",
"path": "/cinema/illusions-perdues/h/17230453_50001"
},
"meta": {
"title": "Illusions perdues",
"description": "Pendant la Restauration, Lucien de Rubempré, jeune provincial d'Angoulême, se rêve poète. Il débarque à Paris en quête de gloire. Il a le soutien de Louise de Bargeton, une aristocrate qui croit en son talent. Pour gagner sa vie, Lucien trouve un emploi dans le journal dirigé par le peu scrupuleux Etienne Lousteau..."
},
"tracking": {
"omniture": {
"channel": "myCANAL",
"prop4": "myCANAL - Prog",
"prop5": "myCANAL - Prog - Fiche",
"prop6": "myCANAL - Prog - Fiche - Cinema",
"prop7": "myCANAL - Prog - Fiche - Cinema - Illusions perdues",
"pageName": "myCANAL - Prog - Fiche - Cinema - Illusions perdues",
"prop10": "Contenu",
"prop11": "DRM",
"content_protection": "DRM",
"prop12": "Consumer",
"eVar39": "17230453_50001",
"prop19": "CANAL+",
"prop32": "notInOffer",
"prop36": "Cinema",
"prop35": "Film Drame",
"content_title": "Illusions perdues",
"page_level_1": "Prog",
"page_level_2": "Fiche",
"page_level_3": "Cinema",
"page_level_4": "Illusions perdues",
"page_name": "myCANAL - Prog - Fiche - Cinema - Illusions perdues",
"page_title": "Illusions perdues",
"page_display_title": "Illusions perdues",
"user_profile": "Consumer",
"content_id": "17230453_50001",
"content_in_offer": "notInOffer",
"genre": "Cinema",
"subgenre": "Film Drame",
"channel_name": "CANAL+"
},
"dataLayer": {
"page_level_1": "Prog",
"page_level_2": "Fiche",
"page_level_3": "Cinema",
"page_level_4": "Illusions perdues",
"page_name": "myCANAL - Prog - Fiche - Cinema - Illusions perdues",
"page_title": "Illusions perdues",
"page_display_title": "Illusions perdues",
"user_profile": "Consumer",
"content_id": "17230453_50001",
"content_in_offer": "notInOffer",
"genre": "Cinema",
"subgenre": "Film Drame",
"channel_name": "CANAL+",
"content_title": "Illusions perdues",
"content_protection": "DRM"
}
},
"detail": {
"informations": {
"type": "VoD",
"contentID": "17230453_50001",
"idRevision": "17230453_50001",
"title": "Illusions perdues",
"URLImage": "https://thumb.canalplus.pro/http/unsafe/{resolutionXY}/filters:quality({imageQualityPercentage})/img-hapi.canalplus.pro:80/ServiceImage/ImageID/107356485",
"URLLogoChannel": "https://thumb.canalplus.pro/http/unsafe/{resolutionXY}/filters:quality({imageQualityPercentage})/img-hapi.canalplus.pro:80/ServiceImage/ImageID/68603655",
"altLogoChannel": "CANAL+",
"summary": "Pendant la Restauration, Lucien de Rubempré, jeune provincial d'Angoulême, se rêve poète. Il débarque à Paris en quête de gloire. Il a le soutien de Louise de Bargeton, une aristocrate qui croit en son talent. Pour gagner sa vie, Lucien trouve un emploi dans le journal dirigé par le peu scrupuleux Etienne Lousteau...",
"isTVoD": false,
"audioLanguage": "VF",
"subtitle": "Film Drame",
"uploadDate": 1671673200000,
"noPub": true,
"editorialTitle": "Film Drame, France, 2021, 2h24",
"sharingURL": "https://mycan.al/cinema/illusions-perdues/h/17230453_50001",
"formats": {
"video": [
"UHD",
"HD"
],
"audio": [
"DOLBY 5.1",
"STEREO"
]
},
"URLVitrine": "https://hodor.canalplus.pro/api/v2/mycanal/highlight/da2291af3b10e9900d1c55e1a65d3388/objectType/unit/17230453_50001.json?previousPageName=myCANAL%20-%20Prog%20-%20Fiche%20-%20Cinema&adult=false&context_page_title=Content%20-%20See%20also%20-%20Illusions%20perdues&omitTracking=true",
"closedCaptioning": true,
"consumptionPlatform": "HAPI",
"trailer": false,
"teasers": [
{
"URLMedias": "https://static.canal-plus.net/ba/17230453_50001.mp4",
"default": true
}
],
"personnalities": [
{
"prefix": "De :",
"personnalitiesList": [
{
"title": "Xavier Giannoli",
"onClick": {
"displayName": "Xavier Giannoli",
"displayTemplate": "contentGrid",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/contentGrid/da2291af3b10e9900d1c55e1a65d3388/12307.json?objectType=person&dsp=detailPage",
"path": "/personne/xavier-giannoli/12307"
}
}
]
},
{
"prefix": "Avec :",
"personnalitiesList": [
{
"title": "Benjamin Voisin",
"onClick": {
"displayName": "Benjamin Voisin",
"displayTemplate": "contentGrid",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/contentGrid/da2291af3b10e9900d1c55e1a65d3388/339366.json?objectType=person&dsp=detailPage",
"path": "/personne/benjamin-voisin/339366"
}
},
{
"title": "Cécile de France",
"onClick": {
"displayName": "Cécile de France",
"displayTemplate": "contentGrid",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/contentGrid/da2291af3b10e9900d1c55e1a65d3388/31634.json?objectType=person&dsp=detailPage",
"path": "/personne/cecile-de-france/31634"
}
},
{
"title": "Vincent Lacoste",
"onClick": {
"displayName": "Vincent Lacoste",
"displayTemplate": "contentGrid",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/contentGrid/da2291af3b10e9900d1c55e1a65d3388/3554.json?objectType=person&dsp=detailPage",
"path": "/personne/vincent-lacoste/3554"
}
},
{
"title": "Xavier Dolan",
"onClick": {
"displayName": "Xavier Dolan",
"displayTemplate": "contentGrid",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/contentGrid/da2291af3b10e9900d1c55e1a65d3388/29821.json?objectType=person&dsp=detailPage",
"path": "/personne/xavier-dolan/29821"
}
},
{
"title": "Gérard Depardieu",
"onClick": {
"displayName": "Gérard Depardieu",
"displayTemplate": "contentGrid",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/contentGrid/da2291af3b10e9900d1c55e1a65d3388/2033.json?objectType=person&dsp=detailPage",
"path": "/personne/gerard-depardieu/2033"
}
},
{
"title": "Salomé Dewaels",
"onClick": {
"displayName": "Salomé Dewaels",
"displayTemplate": "contentGrid",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/contentGrid/da2291af3b10e9900d1c55e1a65d3388/306041.json?objectType=person&dsp=detailPage",
"path": "/personne/salome-dewaels/306041"
}
},
{
"title": "Jeanne Balibar",
"onClick": {
"displayName": "Jeanne Balibar",
"displayTemplate": "contentGrid",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/contentGrid/da2291af3b10e9900d1c55e1a65d3388/2349.json?objectType=person&dsp=detailPage",
"path": "/personne/jeanne-balibar/2349"
}
},
{
"title": "Louis-Do de Lencquesaing",
"onClick": {
"displayName": "Louis-Do de Lencquesaing",
"displayTemplate": "contentGrid",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/contentGrid/da2291af3b10e9900d1c55e1a65d3388/134975.json?objectType=person&dsp=detailPage",
"path": "/personne/louis-do-de-lencquesaing/134975"
}
},
{
"title": "Alexis Barbosa",
"onClick": {
"displayName": "Alexis Barbosa",
"displayTemplate": "contentGrid",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/contentGrid/da2291af3b10e9900d1c55e1a65d3388/553741.json?objectType=person&dsp=detailPage",
"path": "/personne/alexis-barbosa/553741"
}
},
{
"title": "Jean-François Stévenin",
"onClick": {
"displayName": "Jean-François Stévenin",
"displayTemplate": "contentGrid",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/contentGrid/da2291af3b10e9900d1c55e1a65d3388/578.json?objectType=person&dsp=detailPage",
"path": "/personne/jean-francois-stevenin/578"
}
},
{
"title": "André Marcon",
"onClick": {
"displayName": "André Marcon",
"displayTemplate": "contentGrid",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/contentGrid/da2291af3b10e9900d1c55e1a65d3388/3647.json?objectType=person&dsp=detailPage",
"path": "/personne/andre-marcon/3647"
}
},
{
"title": "Marie Cornillon",
"onClick": {
"displayName": "Marie Cornillon",
"displayTemplate": "contentGrid",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/contentGrid/da2291af3b10e9900d1c55e1a65d3388/553722.json?objectType=person&dsp=detailPage",
"path": "/personne/marie-cornillon/553722"
}
}
]
},
{
"prefix": "Scénario :",
"personnalitiesList": [
{
"title": "Xavier Giannoli",
"onClick": {
"displayName": "Xavier Giannoli",
"displayTemplate": "contentGrid",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/contentGrid/da2291af3b10e9900d1c55e1a65d3388/12307.json?objectType=person&dsp=detailPage",
"path": "/personne/xavier-giannoli/12307"
}
}
]
}
],
"reviews": [
{
"name": "Allociné Presse",
"displayRating": true,
"stars": {
"type": "allocine",
"value": 4
}
},
{
"name": "Allociné Spectateur",
"displayRating": true,
"stars": {
"type": "allocine",
"value": 4.5
}
},
{
"name": "Télérama",
"displayRating": true,
"review": "Lascension et la chute du célèbre Lucien de Rubempré, petit poète venu tenter sa chance à Paris. Avec cette adaptation de lœuvre phare de Balzac, Xavier Giannoli signe une fresque flamboyante et cruelle, qui tend un miroir grimaçant à notre époque.",
"stars": {
"type": "telerama",
"value": 3
}
},
{
"name": "Télécâble Sat",
"displayRating": true,
"review": "Récompensée par sept césars, une adaptation aussi somptueuse que moderne du roman de Balzac. L'écriture est ciselée, l'interprétation parfaite, la réalisation affûtée.",
"stars": {
"type": "telecable",
"value": 4
}
}
],
"recommendationTags": [
{
"label": "Adaptations de textes classiques",
"onClick": {
"displayTemplate": "contentGrid",
"displayName": "Adaptations de textes classiques",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/tag/da2291af3b10e9900d1c55e1a65d3388/id/100000014?dsp=detailPage",
"path": "/tag/100000014/adaptations-de-textes-classiques"
}
},
{
"label": "Journalisme",
"onClick": {
"displayTemplate": "contentGrid",
"displayName": "Journalisme",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/tag/da2291af3b10e9900d1c55e1a65d3388/id/100000455?dsp=detailPage",
"path": "/tag/100000455/journalisme"
}
},
{
"label": "Luxe",
"onClick": {
"displayTemplate": "contentGrid",
"displayName": "Luxe",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/tag/da2291af3b10e9900d1c55e1a65d3388/id/100000484?dsp=detailPage",
"path": "/tag/100000484/luxe"
}
},
{
"label": "Réputation",
"onClick": {
"displayTemplate": "contentGrid",
"displayName": "Réputation",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/tag/da2291af3b10e9900d1c55e1a65d3388/id/100000661?dsp=detailPage",
"path": "/tag/100000661/reputation"
}
},
{
"label": "Écrivains",
"onClick": {
"displayTemplate": "contentGrid",
"displayName": "Écrivains",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/tag/da2291af3b10e9900d1c55e1a65d3388/id/100000252?dsp=detailPage",
"path": "/tag/100000252/ecrivains"
}
},
{
"label": "Déceptions amoureuses",
"onClick": {
"displayTemplate": "contentGrid",
"displayName": "Déceptions amoureuses",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/tag/da2291af3b10e9900d1c55e1a65d3388/id/100000211?dsp=detailPage",
"path": "/tag/100000211/deceptions-amoureuses"
}
},
{
"label": "Attirance ou sentiments",
"onClick": {
"displayTemplate": "contentGrid",
"displayName": "Attirance ou sentiments",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/tag/da2291af3b10e9900d1c55e1a65d3388/id/100000077?dsp=detailPage",
"path": "/tag/100000077/attirance-ou-sentiments"
}
},
{
"label": "Subtil",
"onClick": {
"displayTemplate": "contentGrid",
"displayName": "Subtil",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/tag/da2291af3b10e9900d1c55e1a65d3388/id/100000762?dsp=detailPage",
"path": "/tag/100000762/subtil"
}
},
{
"label": "Glamour",
"onClick": {
"displayTemplate": "contentGrid",
"displayName": "Glamour",
"URLPage": "https://hodor.canalplus.pro/api/v2/mycanal/tag/da2291af3b10e9900d1c55e1a65d3388/id/100000364?dsp=detailPage",
"path": "/tag/100000364/glamour"
}
}
],
"parentalRatings": [
{
"value": "2",
"authority": "CSA"
}
],
"duration": "8640000",
"productionYear": "2021",
"contentAvailability": {
"isInCatalog": true,
"isInOffer": false,
"availabilities": {
"download": {
"consumptionPlatform": "HAPI",
"isAvailable": true,
"isInOffer": false,
"URLMedias": "https://hodor.canalplus.pro/api/v2/mycanal/me/getMediaUrl/{tokenCMS}/okapi/17230453_50001.json",
"availabilityEndDate": 1677797940000
},
"stream": {
"consumptionPlatform": "HAPI",
"isAvailable": true,
"isInOffer": false,
"label": "Dispo. jusqu'au 02/03/2023",
"URLMedias": "https://hodor.canalplus.pro/api/v2/mycanal/me/getMediaUrl/{tokenCMS}/okapi/17230453_50001.json"
},
"live": {
"isInOffer": false,
"isAvailable": true
}
}
}
}
},
"perso": [
{
"platform": "HAPI"
}
],
"associatedContents": [
{
"title": "En plus",
"context": {
"contextType": "associatedContent",
"contextDetail": "mycanal-prog-fiche-cinema-illusions_perdues-creplay_chaine_cplus_illusions_perdues-en_plus",
"context_type": "associatedContent",
"context_page_title": "Prog - Fiche - Cinema - Illusions perdues",
"context_list_id": "creplay_chaine_cplus_illusions_perdues",
"context_list_title": "En plus",
"context_list_type": "contentRow",
"context_list_position": 1
},
"contentID": "creplay_chaine_cplus_illusions_perdues",
"contents": [
{
"contentID": "19644697_50001",
"URLImage": "https://thumb.canalplus.pro/http/unsafe/{resolutionXY}/filters:quality({imageQualityPercentage})/img-hapi.canalplus.pro:80/ServiceImage/ImageID/107282238",
"parentalRatings": [
{
"value": "1",
"authority": "CSA"
}
],
"title": "Intro : Illusions perdues",
"subtitle": "Illusions perdues",
"contentAvailability": {
"isInCatalog": true,
"isInOffer": true,
"availabilities": {
"download": {
"consumptionPlatform": "HAPI",
"isAvailable": true,
"isInOffer": false,
"URLMedias": "https://hodor.canalplus.pro/api/v2/mycanal/me/getMediaUrl/{tokenCMS}/okapi/19644697_50001.json",
"availabilityEndDate": 1679785140000
},
"stream": {
"consumptionPlatform": "HAPI",
"isAvailable": true,
"isInOffer": true,
"URLMedias": "https://hodor.canalplus.pro/api/v2/mycanal/me/getMediaUrl/{tokenCMS}/okapi/19644697_50001.json"
},
"live": {
"isInOffer": false,
"isAvailable": false
}
}
}
}
]
}
]
}

View File

@@ -0,0 +1,231 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="canalplus.com">
<channels>
<channel lang="fr" xmltv_id="6ter.fr" site_id="521">6TER</channel>
<channel lang="fr" xmltv_id="AB1.fr" site_id="611">AB1</channel>
<channel lang="fr" xmltv_id="Action.fr" site_id="504">ACTION</channel>
<channel lang="en" xmltv_id="AlJazeeraEnglish.qa" site_id="675">AL JAZEERA ENG</channel>
<channel lang="fr" xmltv_id="AlticeStudio.fr" site_id="820">ALTICE STUDIO</channel>
<channel lang="fr" xmltv_id="Animaux.fr" site_id="503">ANIMAUX</channel>
<channel lang="fr" xmltv_id="ArirangWorld.kr" site_id="252">ARIRANG TV</channel>
<channel lang="fr" xmltv_id="ARTEFrance.fr" site_id="154">ARTE</channel>
<channel lang="fr" xmltv_id="AstrocenterTV.fr" site_id="632">ASTROCENTER TV</channel>
<channel lang="fr" xmltv_id="Automotolachaine.fr" site_id="612">AUTOMOTO LA CHAINE</channel>
<channel lang="en" xmltv_id="BBCWorldNewsEurope.uk" site_id="589">BBC WORLD NEWS</channel>
<channel lang="fr" xmltv_id="beINSports1France.fr" site_id="381">BEIN SPORTS 1</channel>
<channel lang="fr" xmltv_id="beINSports2France.fr" site_id="384">BEIN SPORTS 2</channel>
<channel lang="fr" xmltv_id="beINSports3France.fr" site_id="516">BEIN SPORTS 3</channel>
<channel lang="fr" xmltv_id="beINSportsMax10France.fr" site_id="605">BEIN SPORTS MAX 10</channel>
<channel lang="fr" xmltv_id="beINSportsMax4France.fr" site_id="596">BEIN SPORTS MAX 4</channel>
<channel lang="fr" xmltv_id="beINSportsMax5France.fr" site_id="597">BEIN SPORTS MAX 5</channel>
<channel lang="fr" xmltv_id="beINSportsMax6France.fr" site_id="598">BEIN SPORTS MAX 6</channel>
<channel lang="fr" xmltv_id="beINSportsMax7France.fr" site_id="599">BEIN SPORTS MAX 7</channel>
<channel lang="fr" xmltv_id="beINSportsMax8France.fr" site_id="603">BEIN SPORTS MAX 8</channel>
<channel lang="fr" xmltv_id="beINSportsMax9France.fr" site_id="604">BEIN SPORTS MAX 9</channel>
<channel lang="fr" xmltv_id="BETFrance.fr" site_id="628">BET</channel>
<channel lang="fr" xmltv_id="BFMBusiness.fr" site_id="645">BFM BUSINESS</channel>
<channel lang="fr" xmltv_id="BFMTV.fr" site_id="633">BFM TV</channel>
<channel lang="fr" xmltv_id="BloombergTVEurope.uk" site_id="47">BLOOMBERG TV</channel>
<channel lang="fr" xmltv_id="BlueZoomD.ch" site_id="893">BLUE ZOOM</channel>
<channel lang="fr" xmltv_id="BoingFrance.fr" site_id="529">BOING</channel>
<channel lang="fr" xmltv_id="BoomerangFrance.fr" site_id="530">BOOMERANG</channel>
<channel lang="fr" xmltv_id="BSmartTV.fr" site_id="849">BSMART TV</channel>
<channel lang="fr" xmltv_id="C8.fr" site_id="450">C8</channel>
<channel lang="fr" xmltv_id="CanalAlphaNE.ch" site_id="772">CANAL ALPHA NE</channel>
<channel lang="fr" xmltv_id="CanalJ.fr" site_id="525">CANAL J</channel>
<channel lang="fr" xmltv_id="CanalPlusCinemaFrance.fr" site_id="198">CANAL+CINEMA</channel>
<channel lang="fr" xmltv_id="CanalPlusDocs.fr" site_id="899">CANAL+DOCS</channel>
<channel lang="fr" xmltv_id="CanalPlusFoot.fr" site_id="19">CANAL+FOOT</channel>
<channel lang="fr" xmltv_id="CanalPlusFormula1.fr" site_id="824">CANAL+FORMULA1</channel>
<channel lang="fr" xmltv_id="CanalPlusFrance.fr" site_id="301">CANAL+</channel>
<channel lang="fr" xmltv_id="CanalPlusGrandEcran.fr" site_id="900">CANAL+GRAND ECRAN</channel>
<channel lang="fr" xmltv_id="CanalPlusKids.fr" site_id="259">CANAL+KIDS</channel>
<channel lang="fr" xmltv_id="CanalPlusMotoGP.fr" site_id="823">CANAL+MOTOGP</channel>
<channel lang="fr" xmltv_id="CanalPlusPremierLeague.fr" site_id="815">CANAL+PREMIER LEAGUE</channel>
<channel lang="fr" xmltv_id="CanalPlusSeriesFrance.fr" site_id="481">CANAL+SERIES</channel>
<channel lang="fr" xmltv_id="CanalPlusSport2.fr" site_id="861">CANAL+ SPORT 2 (CH)</channel>
<channel lang="fr" xmltv_id="CanalPlusSport360.fr" site_id="83">CANAL+SPORT360</channel>
<channel lang="fr" xmltv_id="CanalPlusSportFrance.fr" site_id="177">CANAL+SPORT</channel>
<channel lang="fr" xmltv_id="CanalPlusTop14.fr" site_id="816">CANAL+TOP14</channel>
<channel lang="fr" xmltv_id="CartoonNetworkFrance.fr" site_id="502">CARTOON NETWORK</channel>
<channel lang="fr" xmltv_id="ChassePeche.fr" site_id="681">CHASSE ET PECHE</channel>
<channel lang="fr" xmltv_id="Cherie25.fr" site_id="440">CHERIE 25</channel>
<channel lang="fr" xmltv_id="CinePlusClassic.fr" site_id="531">CINE+ CLASSIC</channel>
<channel lang="fr" xmltv_id="CinePlusClub.fr" site_id="532">CINE+ CLUB</channel>
<channel lang="fr" xmltv_id="CinePlusEmotion.fr" site_id="396">CINE+ EMOTION</channel>
<channel lang="fr" xmltv_id="CinePlusFamiz.fr" site_id="533">CINE+ FAMIZ</channel>
<channel lang="fr" xmltv_id="CinePlusFrisson.fr" site_id="398">CINE+ FRISSON</channel>
<channel lang="fr" xmltv_id="CinePlusPremier.fr" site_id="322">CINE+ PREMIER</channel>
<channel lang="fr" xmltv_id="CliqueTV.fr" site_id="665">CLIQUE TV</channel>
<channel lang="fr" xmltv_id="CNBCEurope.uk" site_id="64">CNBC</channel>
<channel lang="fr" xmltv_id="CNews.fr" site_id="480">CNEWS</channel>
<channel lang="en" xmltv_id="CNNInternationalEurope.us" site_id="30">CNN INT.</channel>
<channel lang="fr" xmltv_id="ColmaxTV.fr" site_id="643">COLMAX TV</channel>
<channel lang="fr" xmltv_id="ComediePlus.fr" site_id="534">COMEDIE+</channel>
<channel lang="fr" xmltv_id="ComedyCentralFrance.fr" site_id="806">COMEDY CENTRAL</channel>
<channel lang="fr" xmltv_id="CStar.fr" site_id="513">CSTAR</channel>
<channel lang="fr" xmltv_id="CStarHitsFrance.fr" site_id="723">CSTAR HITS FRANCE</channel>
<channel lang="fr" xmltv_id="DasErste.de" site_id="781">ARD DAS ERSTE</channel>
<channel lang="fr" xmltv_id="DisneyChannelFrance.fr" site_id="282">DISNEY CHANNEL</channel>
<channel lang="fr" xmltv_id="DisneyChannelFrancePlus1.fr" site_id="535">DISNEY CHANNEL+1</channel>
<channel lang="fr" xmltv_id="DisneyJuniorFrance.fr" site_id="274">DISNEY JUNIOR</channel>
<channel lang="fr" xmltv_id="DorcelTV.nl" site_id="536">DORCEL TV</channel>
<channel lang="fr" xmltv_id="DorcelXXX.nl" site_id="537">DORCEL XXX</channel>
<channel lang="fr" xmltv_id="Equidia.fr" site_id="540">EQUIDIA</channel>
<channel lang="fr" xmltv_id="EuronewsFrench.fr" site_id="324">EURONEWS</channel>
<channel lang="fr" xmltv_id="Eurosport1.fr" site_id="101">EUROSPORT 1</channel>
<channel lang="fr" xmltv_id="Eurosport2.fr" site_id="436">EUROSPORT 2</channel>
<channel lang="fr" xmltv_id="Eurosport3.fr" site_id="985">EUROSPORT 3</channel>
<channel lang="fr" xmltv_id="Eurosport360HD1.fr" site_id="635">EUROSPORT 360 1</channel>
<channel lang="fr" xmltv_id="Eurosport360HD2.fr" site_id="636">EUROSPORT 360 2</channel>
<channel lang="fr" xmltv_id="Eurosport360HD3.fr" site_id="637">EUROSPORT 360 3</channel>
<channel lang="fr" xmltv_id="Eurosport360HD4.fr" site_id="638">EUROSPORT 360 4</channel>
<channel lang="fr" xmltv_id="Eurosport360HD5.fr" site_id="650">EUROSPORT 360 5</channel>
<channel lang="fr" xmltv_id="Eurosport360HD6.fr" site_id="651">EUROSPORT 360 6</channel>
<channel lang="fr" xmltv_id="Eurosport360HD7.fr" site_id="652">EUROSPORT 360 7</channel>
<channel lang="fr" xmltv_id="Eurosport360HD8.fr" site_id="653">EUROSPORT 360 8</channel>
<channel lang="fr" xmltv_id="Eurosport4.fr" site_id="986">EUROSPORT 4</channel>
<channel lang="fr" xmltv_id="Eurosport5.fr" site_id="987">EUROSPORT 5</channel>
<channel lang="fr" xmltv_id="FootPlus.fr" site_id="542">FOOT+ 24/24</channel>
<channel lang="fr" xmltv_id="France2.fr" site_id="26">FRANCE 2</channel>
<channel lang="en" xmltv_id="France24English.fr" site_id="311">FRANCE 24 ENG</channel>
<channel lang="fr" xmltv_id="France24French.fr" site_id="310">FRANCE 24</channel>
<channel lang="fr" xmltv_id="France3.fr" site_id="543">FRANCE 3</channel>
<channel lang="fr" xmltv_id="France3Alpes.fr" site_id="926">F3 ALPES</channel>
<channel lang="fr" xmltv_id="France3Alsace.fr" site_id="941">F3 ALSACE</channel>
<channel lang="fr" xmltv_id="France3Aquitaine.fr" site_id="922">F3 AQUITAINE</channel>
<channel lang="fr" xmltv_id="France3Auvergne.fr" site_id="924">F3 AUVERGNE</channel>
<channel lang="fr" xmltv_id="France3BasseNormandie.fr" site_id="923">F3 BNORMANDIE</channel>
<channel lang="fr" xmltv_id="France3Bourgogne.fr" site_id="925">F3 BOURGOGNE</channel>
<channel lang="fr" xmltv_id="France3Bretagne.fr" site_id="939">F3 BRETAGNE</channel>
<channel lang="fr" xmltv_id="France3CentreValdeLoire.fr" site_id="935">F3 CENTRE</channel>
<channel lang="fr" xmltv_id="France3ChampagneArdenne.fr" site_id="938">F3 CHAMP ARDENNE</channel>
<channel lang="fr" xmltv_id="France3CorseViaStella.fr" site_id="943">F3 CORSEVIASTELLA</channel>
<channel lang="fr" xmltv_id="France3CotedAzur.fr" site_id="934">F3 COTE D&apos;AZUR</channel>
<channel lang="fr" xmltv_id="France3FrancheComte.fr" site_id="921">F3 FRANCHE COMTE</channel>
<channel lang="fr" xmltv_id="France3HauteNormandie.fr" site_id="940">F3 HNORMANDIE</channel>
<channel lang="fr" xmltv_id="France3LanguedocRoussillon.fr" site_id="931">F3 LANGUEDOCROU</channel>
<channel lang="fr" xmltv_id="France3Limousin.fr" site_id="928">F3 LIMOUSIN</channel>
<channel lang="fr" xmltv_id="France3Lorraine.fr" site_id="932">F3 LORRAINE</channel>
<channel lang="fr" xmltv_id="France3MidiPyrenees.fr" site_id="942">F3 MIDI PYRENEES</channel>
<channel lang="fr" xmltv_id="France3NordPasdeCalais.fr" site_id="927">F3 NORD PDC</channel>
<channel lang="fr" xmltv_id="France3NouvelleAquitaine.fr" site_id="998">F3 NOUVELLE AQUITAINE</channel>
<channel lang="fr" xmltv_id="France3ParisIledeFrance.fr" site_id="936">F3 PARIS IDF</channel>
<channel lang="fr" xmltv_id="France3PaysdelaLoire.fr" site_id="933">F3 PAYS DE LA LOIRE</channel>
<channel lang="fr" xmltv_id="France3Picardie.fr" site_id="920">F3 PICARDIE</channel>
<channel lang="fr" xmltv_id="France3PoitouCharentes.fr" site_id="937">F3 POITOUCHAR</channel>
<channel lang="fr" xmltv_id="France3ProvenceAlpes.fr" site_id="930">F3 PROV ALPES</channel>
<channel lang="fr" xmltv_id="France3RhoneAlpes.fr" site_id="929">F3 RHONE ALPES</channel>
<channel lang="fr" xmltv_id="France4.fr" site_id="544">FRANCE 4</channel>
<channel lang="fr" xmltv_id="France5.fr" site_id="545">FRANCE 5</channel>
<channel lang="fr" xmltv_id="Franceinfo.fr" site_id="670">FRANCEINFO:</channel>
<channel lang="fr" xmltv_id="GameOne.fr" site_id="592">GAME ONE</channel>
<channel lang="fr" xmltv_id="GolfPlus.fr" site_id="378">GOLF+</channel>
<channel lang="fr" xmltv_id="Gulli.fr" site_id="549">GULLI</channel>
<channel lang="fr" xmltv_id="HistoireTV.fr" site_id="550">HISTOIRE TV</channel>
<channel lang="fr" xmltv_id="I24NewsFrench.il" site_id="362">I24 NEWS</channel>
<channel lang="fr" xmltv_id="InfosportPlus.fr" site_id="551">INFOSPORT+</channel>
<channel lang="fr" xmltv_id="JacquieMichelTV.fr" site_id="850">JACQUIE &amp; MICHEL TV</channel>
<channel lang="fr" xmltv_id="JOne.fr" site_id="484">J-ONE</channel>
<channel lang="fr" xmltv_id="LaChaineMeteo.fr" site_id="552">LA CHAINE METEO</channel>
<channel lang="fr" xmltv_id="LCI.fr" site_id="553">LCI</channel>
<channel lang="fr" xmltv_id="LCP.fr" site_id="554">LCP</channel>
<channel lang="fr" xmltv_id="LEquipe.fr" site_id="451">L&apos;EQUIPE</channel>
<channel lang="fr" xmltv_id="LFMTV.ch" site_id="879">LFM TV</channel>
<channel lang="fr" xmltv_id="M6.fr" site_id="313">M6</channel>
<channel lang="fr" xmltv_id="M6Music.fr" site_id="352">M6 MUSIC</channel>
<channel lang="fr" xmltv_id="Mangas.fr" site_id="613">MANGAS</channel>
<channel lang="fr" xmltv_id="ManX.be" site_id="672">MAN X</channel>
<channel lang="fr" xmltv_id="MCM.fr" site_id="556">MCM</channel>
<channel lang="fr" xmltv_id="Melody.fr" site_id="580">MELODY</channel>
<channel lang="fr" xmltv_id="Mezzo.fr" site_id="560">MEZZO</channel>
<channel lang="fr" xmltv_id="MezzoLiveHD.fr" site_id="268">MEZZO LIVE</channel>
<channel lang="fr" xmltv_id="MGGTV.fr" site_id="819">MGG TV</channel>
<channel lang="fr" xmltv_id="MTVFrance.fr" site_id="470">MTV</channel>
<channel lang="fr" xmltv_id="MTVHitsFrance.fr" site_id="629">MTV HITS</channel>
<channel lang="fr" xmltv_id="MultiSports1.fr" site_id="562">MULTISPORTS 1</channel>
<channel lang="fr" xmltv_id="MultiSports2.fr" site_id="563">MULTISPORTS 2</channel>
<channel lang="fr" xmltv_id="MultiSports3.fr" site_id="564">MULTISPORTS 3</channel>
<channel lang="fr" xmltv_id="MultiSports4.fr" site_id="565">MULTISPORTS 4</channel>
<channel lang="fr" xmltv_id="MultiSports5.fr" site_id="566">MULTISPORTS 5</channel>
<channel lang="fr" xmltv_id="MultiSports6.fr" site_id="567">MULTISPORTS 6</channel>
<channel lang="fr" xmltv_id="MuseumTV.fr" site_id="678">MUSEUM</channel>
<channel lang="fr" xmltv_id="MyZenTV.fr" site_id="656">MY ZEN TV</channel>
<channel lang="fr" xmltv_id="NationalGeographicFrance.fr" site_id="302">NATIONAL GEO</channel>
<channel lang="fr" xmltv_id="NationalGeographicWildFrance.fr" site_id="290">NATIONAL GEOGRAPHIC WILD</channel>
<channel lang="en" xmltv_id="NHKWorldJapan.jp" site_id="654">NHK WORLD-JAPAN</channel>
<channel lang="fr" xmltv_id="NickelodeonFrance.fr" site_id="591">NICKELODEON</channel>
<channel lang="fr" xmltv_id="NickelodeonJunior.fr" site_id="593">NICKELODEON JUNIOR</channel>
<channel lang="fr" xmltv_id="NickelodeonTeen.fr" site_id="518">NICKELODEON TEEN</channel>
<channel lang="fr" xmltv_id="NollywoodTV.fr" site_id="527">NOLLYWOOD TV</channel>
<channel lang="fr" xmltv_id="NonStopPeople.fr" site_id="434">NON STOP PEOPLE</channel>
<channel lang="fr" xmltv_id="NovelasTV.fr" site_id="693">NOVELAS TV</channel>
<channel lang="fr" xmltv_id="NRJ12.fr" site_id="568">NRJ 12</channel>
<channel lang="fr" xmltv_id="NRJHits.fr" site_id="569">NRJ HITS</channel>
<channel lang="fr" xmltv_id="OCSChoc.fr" site_id="466">OCS CHOC</channel>
<channel lang="fr" xmltv_id="OCSCity.fr" site_id="467">OCS CITY</channel>
<channel lang="fr" xmltv_id="OCSGeants.fr" site_id="468">OCS GEANTS</channel>
<channel lang="fr" xmltv_id="OCSMax.fr" site_id="372">OCS MAX</channel>
<channel lang="fr" xmltv_id="OlympiaTV.fr" site_id="813">OLYMPIA TV</channel>
<channel lang="fr" xmltv_id="OneTV.ch" site_id="880">ONE TV</channel>
<channel lang="fr" xmltv_id="ORF1.at" site_id="783">ORF 1</channel>
<channel lang="fr" xmltv_id="ParamountChannelFrance.fr" site_id="487">PARAMOUNT CHANNEL</channel>
<channel lang="fr" xmltv_id="ParisPremiere.fr" site_id="294">PARIS PREMIERE</channel>
<channel lang="fr" xmltv_id="PenthouseBlack.us" site_id="686">PENTHOUSE BLACK</channel>
<channel lang="fr" xmltv_id="PenthouseGold.us" site_id="167">PENTHOUSE</channel>
<channel lang="fr" xmltv_id="PinkX.fr" site_id="575">PINK X</channel>
<channel lang="fr" xmltv_id="PiwiPlus.fr" site_id="576">PIWI+</channel>
<channel lang="fr" xmltv_id="PlanetePlus.fr" site_id="270">PLANETE+</channel>
<channel lang="fr" xmltv_id="PlanetePlusAE.fr" site_id="588">PLANETE+AVENTURE</channel>
<channel lang="fr" xmltv_id="PlanetePlusCI.fr" site_id="587">PLANETE+CRIME</channel>
<channel lang="fr" xmltv_id="PolarPlus.fr" site_id="692">POLAR+</channel>
<channel lang="fr" xmltv_id="Rai1.it" site_id="782">RAI UNO</channel>
<channel lang="fr" xmltv_id="RFMTV.fr" site_id="557">RFM TV</channel>
<channel lang="fr" xmltv_id="RMCDecouverte.fr" site_id="595">RMC DECOUVERTE</channel>
<channel lang="fr" xmltv_id="RMCSport1.fr" site_id="732">RMC SPORT 1</channel>
<channel lang="fr" xmltv_id="RMCSport2.fr" site_id="733">RMC SPORT 2</channel>
<channel lang="fr" xmltv_id="RMCSport3.fr" site_id="734">RMC SPORT 3</channel>
<channel lang="fr" xmltv_id="RMCSport4.fr" site_id="735">RMC SPORT 4</channel>
<channel lang="fr" xmltv_id="RMCSportLive5.fr" site_id="756">RMC SPORT LIVE 5</channel>
<channel lang="fr" xmltv_id="RMCSportLive6.fr" site_id="757">RMC SPORT LIVE 6</channel>
<channel lang="fr" xmltv_id="RMCSportLive7.fr" site_id="758">RMC SPORT LIVE 7</channel>
<channel lang="fr" xmltv_id="RMCSportLive8.fr" site_id="759">RMC SPORT LIVE 8</channel>
<channel lang="fr" xmltv_id="RMCSportLive9.fr" site_id="760">RMC SPORT LIVE 9</channel>
<channel lang="fr" xmltv_id="RMCSportLive10.fr" site_id="761">RMC SPORT LIVE 10</channel>
<channel lang="fr" xmltv_id="RMCSportLive11.fr" site_id="762">RMC SPORT LIVE 11</channel>
<channel lang="fr" xmltv_id="RMCSportLive12.fr" site_id="763">RMC SPORT LIVE 12</channel>
<channel lang="fr" xmltv_id="RMCSportLive13.fr" site_id="764">RMC SPORT LIVE 13</channel>
<channel lang="fr" xmltv_id="RMCSportLive14.fr" site_id="765">RMC SPORT LIVE 14</channel>
<channel lang="fr" xmltv_id="RMCStory.fr" site_id="571">RMC STORY</channel>
<channel lang="fr" xmltv_id="RougeTV.ch" site_id="878">ROUGE TV</channel>
<channel lang="fr" xmltv_id="RTFrance.fr" site_id="479">RT FRANCE</channel>
<channel lang="fr" xmltv_id="RTL9.lu" site_id="505">RTL9</channel>
<channel lang="fr" xmltv_id="ScienceVieTV.fr" site_id="614">SCIENCE ET VIE TV</channel>
<channel lang="fr" xmltv_id="Seasons.fr" site_id="577">SEASONS</channel>
<channel lang="fr" xmltv_id="SerieClub.fr" site_id="356">SERIE CLUB</channel>
<channel lang="fr" xmltv_id="SRF1.ch" site_id="778">SRF 1</channel>
<channel lang="fr" xmltv_id="StingrayClassica.ca" site_id="165">CLASSICA</channel>
<channel lang="fr" xmltv_id="StingrayDJAZZ.ca" site_id="407">DJAZZ</channel>
<channel lang="fr" xmltv_id="TCMCinema.fr" site_id="374">TCM CINEMA</channel>
<channel lang="fr" xmltv_id="TeleBielingue.ch" site_id="775">TELEBIELINGUE</channel>
<channel lang="fr" xmltv_id="TeletoonPlus.fr" site_id="581">TELETOON+</channel>
<channel lang="fr" xmltv_id="TeletoonPlus1.fr" site_id="582">TELETOON+1</channel>
<channel lang="fr" xmltv_id="Teva.fr" site_id="292">TEVA</channel>
<channel lang="fr" xmltv_id="TF1.fr" site_id="312">TF1</channel>
<channel lang="fr" xmltv_id="TF1SeriesFilms.fr" site_id="526">TF1 SERIES FILMS</channel>
<channel lang="fr" xmltv_id="TFX.fr" site_id="570">TFX</channel>
<channel lang="fr" xmltv_id="TiJi.fr" site_id="583">TIJI</channel>
<channel lang="fr" xmltv_id="TMC.fr" site_id="584">TMC</channel>
<channel lang="fr" xmltv_id="ToonamiFrance.fr" site_id="683">TOONAMI</channel>
<channel lang="fr" xmltv_id="ToutelHistoire.fr" site_id="620">TOUTE L&apos;HISTOIRE</channel>
<channel lang="fr" xmltv_id="TraceUrban.fr" site_id="585">TRACE URBAN</channel>
<channel lang="fr" xmltv_id="TV5MondeFranceBelgiumSwitzerland.fr" site_id="520">TV5 MONDE</channel>
<channel lang="fr" xmltv_id="TVBreizh.fr" site_id="586">TV BREIZH</channel>
<channel lang="fr" xmltv_id="UshuaiaTV.fr" site_id="142">USHUAIA TV</channel>
<channel lang="fr" xmltv_id="VICETV.us" site_id="677">VICE TV</channel>
<channel lang="fr" xmltv_id="VixenTV.ca" site_id="547">VIXEN</channel>
<channel lang="fr" xmltv_id="W9.fr" site_id="296">W9</channel>
<channel lang="fr" xmltv_id="WarnerTVFrance.fr" site_id="694">WARNER TV</channel>
<channel lang="fr" xmltv_id="XXL.fr" site_id="616">XXL</channel>
</channels>
</site>

View File

@@ -0,0 +1,128 @@
const dayjs = require('dayjs')
const axios = require('axios')
// TODO: calculate API_KEY based on the current date
//
// const API_KEY = 'f55e5c7ddf0afba59d1c64581358910d' // 03.2022
//const API_KEY = 'c71b6b8eb30125dab9d10a3850131ac6' // 05.2022
const API_KEY = 'da2291af3b10e9900d1c55e1a65d3388' // 10.2022
module.exports = {
site: 'canalplus.com',
days: 2,
url: function ({ channel, date }) {
const diff = date.diff(dayjs.utc().startOf('d'), 'd')
return `https://hodor.canalplus.pro/api/v2/mycanal/channels/${API_KEY}/${channel.site_id}/broadcasts/day/${diff}`
},
async parser({ content }) {
let programs = []
const items = parseItems(content)
for (let item of items) {
const prev = programs[programs.length - 1]
const details = await loadProgramDetails(item)
const info = parseInfo(details)
const start = parseStart(item)
if (prev) prev.stop = start
const stop = start.add(1, 'h')
programs.push({
title: item.title,
description: parseDescription(info),
icon: parseIcon(info),
actors: parseCast(info,"Avec :"),
director: parseCast(info,"De :"),
writer: parseCast(info,"Scénario :"),
composer: parseCast(info,"Musique :"),
presenter: parseCast(info,"Présenté par :"),
date: paseDate(info),
rating: parseRating(info),
start,
stop
})
}
return programs
},
async channels() {
const data = await axios
.get(`https://secure-webtv-static.canal-plus.com/metadata/cpfra/all/v2.2/globalchannels.json`)
.then(r => r.data)
.catch(console.log)
return data.channels.map(item => {
return {
lang: 'fr',
site_id: item.id,
name: item.name
}
})
}
}
function parseStart(item) {
return item && item.startTime ? dayjs(item.startTime) : null
}
function parseIcon(info) {
return info ? info.URLImage : null
}
function parseDescription(info) {
return info ? info.summary : null
}
function parseInfo(data) {
if (!data || !data.detail || !data.detail.informations) return null
return data.detail.informations
}
async function loadProgramDetails(item) {
if (!item.onClick || !item.onClick.URLPage) return {}
return await axios
.get(item.onClick.URLPage)
.then(r => r.data)
.catch(console.error)
}
function parseItems(content) {
const data = JSON.parse(content)
if (!data || !Array.isArray(data.timeSlices)) return []
return data.timeSlices.reduce((acc, curr) => {
acc = acc.concat(curr.contents)
return acc
}, [])
}
function parseCast(info, type) {
let people = []
if (info && info.personnalities) {
const personnalities = info.personnalities.find(i => i.prefix == type)
if (!personnalities) return people
for(let person of personnalities.personnalitiesList) {
people.push(person.title)
}
}
return people
}
function paseDate(info) {
return (info && info.productionYear) ? info.productionYear : null
}
function parseRating(info) {
if (!info || !info.parentalRatings) return null
let rating = info.parentalRatings.find(i => i.authority === 'CSA')
if (!rating || Array.isArray(rating)) return null
if (rating.value === '1') return null
if (rating.value === '2') rating.value = '-10'
if (rating.value === '3') rating.value = '-12'
if (rating.value === '4') rating.value = '-16'
if (rating.value === '5') rating.value = '-18'
return {
system: rating.authority,
value: rating.value
}
}

View File

@@ -0,0 +1,116 @@
// npm run channels:parse -- --config=./sites/canalplus.com/canalplus.com.config.js --output=./sites/canalplus.com/canalplus.com.channels.xml
// npx epg-grabber --config=sites/canalplus.com/canalplus.com.config.js --channels=sites/canalplus.com/canalplus.com.channels.xml --output=guide.xml --days=2
const { parser, url } = require('./canalplus.com.config.js')
const fs = require('fs')
const path = require('path')
const axios = require('axios')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const customParseFormat = require('dayjs/plugin/customParseFormat')
dayjs.extend(customParseFormat)
dayjs.extend(utc)
jest.mock('axios')
const channel = {
site_id: '198',
xmltv_id: 'CanalPlusCinemaFrance.fr'
}
it('can generate valid url for today', () => {
const today = dayjs.utc().startOf('d')
expect(url({ channel, date: today })).toBe(
'https://hodor.canalplus.pro/api/v2/mycanal/channels/da2291af3b10e9900d1c55e1a65d3388/198/broadcasts/day/0'
)
})
it('can generate valid url for tomorrow', () => {
const tomorrow = dayjs.utc().startOf('d').add(1, 'd')
expect(url({ channel, date: tomorrow })).toBe(
'https://hodor.canalplus.pro/api/v2/mycanal/channels/da2291af3b10e9900d1c55e1a65d3388/198/broadcasts/day/1'
)
})
it('can parse response', done => {
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
axios.get.mockImplementation(url => {
if (
url ===
'https://hodor.canalplus.pro/api/v2/mycanal/detail/da2291af3b10e9900d1c55e1a65d3388/okapi/6564630_50001.json?detailType=detailSeason&objectType=season&broadcastID=PLM_1196447642&episodeId=20482220_50001&brandID=4501558_50001&fromDiff=true'
) {
return Promise.resolve({
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/program1.json')))
})
} else if (
url ===
'https://hodor.canalplus.pro/api/v2/mycanal/detail/da2291af3b10e9900d1c55e1a65d3388/okapi/17230453_50001.json?detailType=detailPage&objectType=unit&broadcastID=PLM_1196447637&fromDiff=true'
) {
return Promise.resolve({
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/program2.json')))
})
} else {
return Promise.resolve({ data: '' })
}
})
parser({ content })
.then(result => {
result.map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2023-01-12T06:28:00.000Z',
stop: '2023-01-12T12:06:00.000Z',
title: 'Le cercle',
description: `Tant qu'il y aura du cinéma, LE CERCLE sera là. C'est la seule émission télévisée de débats critiques 100% consacrée au cinéma et elle rentre dans sa 18e saison. Chaque semaine, elle offre des joutes enflammées, joyeuses et sans condescendance, sur les films à l'affiche ; et invite avec \"Le questionnaire du CERCLE\" les réalisatrices et réalisateurs à venir partager leur passion cinéphile.`,
icon: 'https://thumb.canalplus.pro/http/unsafe/{resolutionXY}/filters:quality({imageQualityPercentage})/img-hapi.canalplus.pro:80/ServiceImage/ImageID/107297573',
presenter: ['Lily Bloom'],
rating: {
system: 'CSA',
value: '-10'
}
},
{
start: '2023-01-12T12:06:00.000Z',
stop: '2023-01-12T13:06:00.000Z',
title: 'Illusions perdues',
description: `Pendant la Restauration, Lucien de Rubempré, jeune provincial d'Angoulême, se rêve poète. Il débarque à Paris en quête de gloire. Il a le soutien de Louise de Bargeton, une aristocrate qui croit en son talent. Pour gagner sa vie, Lucien trouve un emploi dans le journal dirigé par le peu scrupuleux Etienne Lousteau...`,
icon: 'https://thumb.canalplus.pro/http/unsafe/{resolutionXY}/filters:quality({imageQualityPercentage})/img-hapi.canalplus.pro:80/ServiceImage/ImageID/107356485',
director: ['Xavier Giannoli'],
actors: [
'Benjamin Voisin',
'Cécile de France',
'Vincent Lacoste',
'Xavier Dolan',
'Gérard Depardieu',
'Salomé Dewaels',
'Jeanne Balibar',
'Louis-Do de Lencquesaing',
'Alexis Barbosa',
'Jean-François Stévenin',
'André Marcon',
'Marie Cornillon'
],
writer: ['Xavier Giannoli'],
rating: {
system: 'CSA',
value: '-10'
}
}
])
done()
})
.catch(done)
})
it('can handle empty guide', async () => {
const content = fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
const result = await parser({ content })
expect(result).toMatchObject([])
})

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="cgates.lt">
<channels>
<channel lang="lt" xmltv_id="1Plus1.ua" site_id="1plus1">1+1</channel>
<channel lang="lt" xmltv_id="1Plus2.lv" site_id="1plus2">1+2</channel>
<channel lang="lt" xmltv_id="2TV.lt" site_id="2tv">2TV</channel>
<channel lang="lt" xmltv_id="366TV.ua" site_id="36-6-tv">36.6 TV</channel>
<channel lang="lt" xmltv_id="ArirangTV.kr" site_id="arirang-tv">Arirang TV</channel>
<channel lang="en" xmltv_id="BBCWorldNewsEurope.uk" site_id="bbc-world-news">BBC World News</channel>
<channel lang="lt" xmltv_id="BTV.lt" site_id="btv-hd">BTV HD</channel>
<channel lang="en" xmltv_id="BabyTV.uk" site_id="baby-tv">Baby TV</channel>
<channel lang="lt" xmltv_id="BalticumAuksinis.lt" site_id="balticum-auksinis">Balticum Auksinis</channel>
<channel lang="lt" xmltv_id="BalticumPlatinum.lt" site_id="balticum-platinum-hd">Balticum Platinum HD</channel>
<channel lang="lt" xmltv_id="BalticumTV.lt" site_id="balticum-tv">Balticum TV</channel>
<channel lang="en" xmltv_id="BloombergTVEurope.uk" site_id="bloomberg-television">Bloomberg Television</channel>
<channel lang="lt" xmltv_id="BlueHustler.nl" site_id="blue-hustler">Blue Hustler</channel>
<channel lang="en" xmltv_id="CBSRealityEMEA.uk" site_id="cbs-reality">CBS Reality</channel>
<channel lang="en" xmltv_id="CNBCEurope.uk" site_id="cnbc-europe">CNBC Europe</channel>
<channel lang="en" xmltv_id="CNNInternationalEurope.us" site_id="cnn-international">CNN International</channel>
<channel lang="lt" xmltv_id="CurrentTimeTV.cz" site_id="nastojashcheje-vremya">Nastojashcheje Vremya</channel>
<!-- <channel lang="lt" xmltv_id="" site_id="dtx-hd">DTX HD</channel> -->
<channel lang="lt" xmltv_id="Dacha.ua" site_id="dacha">Dacha</channel>
<channel lang="lt" xmltv_id="DelfiTV.ee" site_id="delfi-tv-hd">Delfi TV HD</channel>
<channel lang="en" xmltv_id="DiscoveryChannelLatvia.lv" site_id="discovery-channel-hd">Discovery Channel HD</channel>
<channel lang="en" xmltv_id="DocuBox.nl" site_id="docubox-hd">DocuBox HD</channel>
<channel lang="en" xmltv_id="Duo3.ee" site_id="sony-channel-hd">Duo 3 HD</channel>
<channel lang="en" xmltv_id="Duo6.ee" site_id="sony-turbo-hd">Duo 6 HD</channel>
<channel lang="lt" xmltv_id="Duo7.ee" site_id="duo-7">Kanal 7</channel>
<channel lang="lt" xmltv_id="DzukijosTV.lt" site_id="dzukijos-tv">Dzūkijos TV</channel>
<channel lang="en" xmltv_id="EpicDrama.se" site_id="epic-drama-hd">Epic Drama HD</channel>
<channel lang="en" xmltv_id="Eurochannel.uk" site_id="eurochannel">Eurochannel</channel>
<channel lang="en" xmltv_id="EuronewsRussian.fr" site_id="euronews-2">Euronews RU</channel>
<channel lang="en" xmltv_id="ExtremeSportsChannelEurope.nl" site_id="extreme-sports">Extreme Sports</channel>
<channel lang="en" xmltv_id="FashionTVEurope.fr" site_id="fashion-tv">Fashion TV</channel>
<channel lang="en" xmltv_id="FastFunBox.nl" site_id="fastfun-box-hd">Fast&amp;Fun Box HD</channel>
<channel lang="en" xmltv_id="FightSports.us" site_id="fight-sports-hd">Fight Sports HD</channel>
<channel lang="en" xmltv_id="FilmBoxArthouse.nl" site_id="filmbox-arthouse">FilmBox ArtHouse</channel>
<channel lang="lt" xmltv_id="FilmUADrama.ua" site_id="film-ua-drama">Film UA Drama</channel>
<channel lang="en" xmltv_id="Filmzone.ee" site_id="filmzone">FilmZone</channel>
<channel lang="lt" xmltv_id="FilmzonePlus.ee" site_id="filmzone-hd">FilmZone+ HD</channel>
<channel lang="en" xmltv_id="France24French.fr" site_id="france-24">France 24</channel>
<channel lang="en" xmltv_id="Gametoon.nl" site_id="game-toon-hd">Game Toon HD</channel>
<channel lang="lt" xmltv_id="GulliGirl.ru" site_id="gulli-girl">Gulli Girl</channel>
<channel lang="lt" xmltv_id="InfoTV.lt" site_id="info-tv-hd">Info TV HD</channel>
<channel lang="lt" xmltv_id="InterPlus.ua" site_id="inter-plus">Inter+</channel>
<channel lang="en" xmltv_id="JimJamEurope.uk" site_id="jim-jam">Jim Jam</channel>
<channel lang="en" xmltv_id="KidZoneMini.ee" site_id="kidzone-plus-hd">KidZone Mini HD</channel>
<channel lang="en" xmltv_id="KidZoneTV.ee" site_id="kidzone-tv">KidZone TV</channel>
<channel lang="lt" xmltv_id="KusKus.ua" site_id="kus-kus">Kus-Kus</channel>
<channel lang="lt" xmltv_id="LNK.lt" site_id="lnk-hd">LNK HD</channel>
<channel lang="lt" xmltv_id="LRTLituanica.lt" site_id="lrt-lituanica">LRT Lituanica</channel>
<channel lang="lt" xmltv_id="LRTPlius.lt" site_id="lrt-kultura-hd">LRT Plius HD</channel>
<channel lang="lt" xmltv_id="LRTTV.lt" site_id="lrt-televizija-hd">LRT Televizija HD</channel>
<channel lang="lt" xmltv_id="LietuvosRytasTV.lt" site_id="lietuvos-ryto-tv-hd">Lietuvos ryto TV HD</channel>
<channel lang="en" xmltv_id="LuxeTV.lu" site_id="luxe-tv-hd">Luxe.TV HD</channel>
<channel lang="en" xmltv_id="MTV00s.uk" site_id="vh1">MTV 00s</channel>
<channel lang="en" xmltv_id="MTVHitsEurope.uk" site_id="mtv-hits">MTV Hits</channel>
<channel lang="lt" xmltv_id="MarijampolesTV.lt" site_id="marijampoles-tv">Marijampolės TV</channel>
<channel lang="en" xmltv_id="Mezzo.fr" site_id="mezzo">Mezzo</channel>
<channel lang="en" xmltv_id="PlayboyTVEurope.us" site_id="playboy-tv">Playboy TV</channel>
<channel lang="en" xmltv_id="SetantaSports1Evraziya.ie" site_id="setanta-sports-hd">Setanta Sports 1 HD</channel>
<channel lang="lt" xmltv_id="SiauliuTV.lt" site_id="siauliu-televizija">Šiaulių televizija</channel>
<channel lang="en" xmltv_id="Smartzone.ee" site_id="smartzone-hd">Smartzone HD</channel>
<channel lang="lt" xmltv_id="Sport1.lt" site_id="sport-1-hd">Sport 1 HD</channel>
<channel lang="lt" xmltv_id="StarCinema.ua" site_id="star-cinema">Star Cinema</channel>
<channel lang="lt" xmltv_id="StarFamily.ua" site_id="star-family">Star Family</channel>
<channel lang="en" xmltv_id="TV1000ActionEast.ru" site_id="tv-1000-action">TV 1000 Action</channel>
<channel lang="en" xmltv_id="TV1000East.ru" site_id="tv-1000">TV 1000</channel>
<channel lang="en" xmltv_id="TV1000WorldKino.ru" site_id="tv-1000-world-kino">TV 1000 World Kino</channel>
<channel lang="lt" xmltv_id="TV1.lt" site_id="tv1-hd">TV1 HD</channel>
<channel lang="lt" xmltv_id="TV3Film.lv" site_id="tv-1000-premium-hd">TV3 Film HD</channel>
<channel lang="lt" xmltv_id="TV3Lithuania.lt" site_id="tv3-hd">TV3 HD</channel>
<channel lang="lt" xmltv_id="TV3Plus.lv" site_id="tv3-plus-hd">TV3 Plus HD</channel>
<channel lang="en" xmltv_id="TV3Sport.uk" site_id="viasat-sport-baltic-hd">TV3 Sport HD</channel>
<channel lang="en" xmltv_id="TV3Sport2.uk" site_id="tvplay-sports-plus-hd">TV3 Sport 2 HD</channel>
<channel lang="en" xmltv_id="TV3SportOpen.uk" site_id="tv3-sport-open-hd">TV3 Sport Open HD</channel>
<channel lang="lt" xmltv_id="TV6Lithuania.lt" site_id="tv6-hd">TV6 HD</channel>
<channel lang="lt" xmltv_id="TV8Lithuania.lt" site_id="tv8-hd">TV8 HD</channel>
<channel lang="lt" xmltv_id="TVBolt.ua" site_id="bolt">Bolt</channel>
<channel lang="lt" xmltv_id="TVPInfo.pl" site_id="tvp-info">TVP Info</channel>
<channel lang="lt" xmltv_id="TVPPolonia.pl" site_id="tvp-polonia">TVP Polonia</channel>
<channel lang="lt" xmltv_id="TiJiRussia.ru" site_id="tiji">Tiji</channel>
<channel lang="lt" xmltv_id="VIPComedy.ru" site_id="vip-comedy">ViP Comedy</channel>
<channel lang="en" xmltv_id="VividTouch.uk" site_id="vivid-touch">Vivid Touch</channel>
<!-- <channel lang="lt" xmltv_id="" site_id="amc">AMC</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="animal-planet-hd">Animal Planet HD</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="boomerang">Boomerang</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="cartoon-network">Cartoon Network</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="da-vinci-learning">Da Vinci Learning</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="deutsche-welle">Deutsche Welle</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="discovery-science-hd">Discovery Science HD</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="euronews">Euronews HD</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="eurosport-1-hd">Eurosport 1 HD</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="eurosport-2-hd">Eurosport 2 HD</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="film-ua-live">Film UA Live</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="filmbox">FilmBox</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="food-network">Food Network</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="fox">FOX</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="fox-hd">FOX HD</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="fox-life">FOX Life</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="hgtv-hd">HGTV HD</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="history-channel-hd">History Channel HD</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="id-xtra-hd">Investigation Discovery HD</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="mtv-live-hd">MTV Live HD</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="nat-geo-wild">Nat Geo Wild</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="national-geographic-channel">National Geographic Channel</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="national-geographic-hd">National Geographic HD</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="nick-jr">Nick Jr.</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="nick-toons">Nick Toons</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="nickelodeon">Nickelodeon</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="quiz-tv">Quiz TV</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="rtl">RTL</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="rtv-international">RTV International</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="seimas-tiesiogiai">Seimas tiesiogiai</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="tlc">TLC</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="travel-channel-hd">Travel Channel HD</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="tv7">TV7</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="tvp-wilno">TVP Wilno</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="ukraine-24">Ukraine 24</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="viasat-explore-hd">Viasat Explore HD</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="viasat-history-hd">Viasat History HD</channel> -->
<!-- <channel lang="lt" xmltv_id="" site_id="viasat-nature">Viasat Nature HD</channel> -->
</channels>
</site>

View File

@@ -0,0 +1,92 @@
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: 'cgates.lt',
days: 2,
url: function ({ channel }) {
return `https://www.cgates.lt/tv-kanalai/${channel.site_id}/`
},
parser: function ({ content, date }) {
let programs = []
const items = parseItems(content, date)
items.forEach(item => {
const prev = programs[programs.length - 1]
const $item = cheerio.load(item)
let start = parseStart($item, date)
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),
description: parseDescription($item),
start,
stop
})
})
return programs
},
async channels() {
let html = await axios
.get(`https://www.cgates.lt/televizija/tv-programa-savaitei/`)
.then(r => r.data)
.catch(console.log)
let $ = cheerio.load(html)
const items = $('.kanalas_wrap').toArray()
return items.map(item => {
const name = $(item).find('h6').text().trim()
const link = $(item).find('a').attr('href')
const [_, site_id] = link.match(/\/tv-kanalai\/(.*)\//) || [null, null]
return {
lang: 'lt',
site_id,
name
}
})
}
}
function parseTitle($item) {
const title = $item('td:nth-child(2) > .vc_toggle > .vc_toggle_title').text().trim()
return title || $item('td:nth-child(2)').text().trim()
}
function parseDescription($item) {
return $item('.vc_toggle_content > p').text().trim()
}
function parseStart($item, date) {
const time = $item('.laikas')
return dayjs.tz(`${date.format('YYYY-MM-DD')} ${time}`, 'YYYY-MM-DD HH:mm', 'Europe/Vilnius')
}
function parseItems(content, date) {
const $ = cheerio.load(content)
const section = $(
'article > div:nth-child(2) > div.vc_row.wpb_row.vc_row-fluid > div > div > div > div > div'
)
.filter(function () {
return $(`.dt-fancy-title:contains("${date.format('YYYY-MM-DD')}")`, this).length === 1
})
.first()
return $('.tv_programa tr', section).toArray()
}

View File

@@ -0,0 +1,52 @@
// npm run channels:parse -- --config=./sites/cgates.lt/cgates.lt.config.js --output=./sites/cgates.lt/cgates.lt.channels.xml
// npx epg-grabber --config=sites/cgates.lt/cgates.lt.config.js --channels=sites/cgates.lt/cgates.lt.channels.xml --output=guide.xml --days=2
const { parser, url } = require('./cgates.lt.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-08-30', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: 'lrt-televizija-hd',
xmltv_id: 'LRTTV.lt'
}
it('can generate valid url', () => {
expect(url({ channel, date })).toBe('https://www.cgates.lt/tv-kanalai/lrt-televizija-hd/')
})
it('can parse response', () => {
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'))
const results = parser({ content, date }).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(results.length).toBe(35)
expect(results[0]).toMatchObject({
start: '2022-08-29T21:05:00.000Z',
stop: '2022-08-29T21:30:00.000Z',
title: '31-oji nuovada (District 31), Drama, 2016',
description:
'Seriale pasakojama apie kasdienius policijos išbandymus ir sunkumus. Vadovybė pertvarko Monrealio miesto policijos struktūrą: išskirsto į 36 policijos nuovadas, kad šios būtų arčiau gyventojų. 31-osios nuovados darbuotojams tenka kone sunkiausias darbas: šiame miesto rajone gyvena socialiai remtinos šeimos, nuolat kovojančios su turtingųjų klase, įsipliekia ir rasinių konfliktų. Be to, čia akivaizdus kartų atotrūkis, o tapti nusikalstamo pasaulio dalimi labai lengva. Serialo siužetas intensyvus, nauji nusikaltimai tiriami kiekvieną savaitę. Čia vaizduojamas nepagražintas nusikalstamas pasaulis, jo poveikis rajono gyventojams. Policijos nuovados darbuotojai narplios įvairiausių nusikaltimų schemas. Tai ir pagrobimai, įsilaužimai, žmogžudystės, smurtas artimoje aplinkoje, lytiniai nusikaltimai, prekyba narkotikais, teroristinių išpuolių grėsmė ir pan. Šis serialas leis žiūrovui įsigilinti į policijos pareigūnų realybę, pateiks skirtingą požiūrį į kiekvieną nusikaltimą.'
})
expect(results[34]).toMatchObject({
start: '2022-08-30T20:45:00.000Z',
stop: '2022-08-30T21:15:00.000Z',
title: '31-oji nuovada (District 31), Drama, 2016!'
})
})
it('can handle empty guide', () => {
const result = parser({
content: ''
})
expect(result).toMatchObject([])
})

View File

@@ -0,0 +1,199 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="chaines-tv.orange.fr">
<channels>
<channel lang="fr" xmltv_id="01TV.fr" site_id="2942">01 TV</channel>
<channel lang="fr" xmltv_id="2MInternational.ma" site_id="340">2M Monde</channel>
<channel lang="fr" xmltv_id="3sat.de" site_id="960">3sat</channel>
<channel lang="fr" xmltv_id="6ter.fr" site_id="1403">6ter</channel>
<channel lang="fr" xmltv_id="AB1.fr" site_id="5">AB 1</channel>
<channel lang="fr" xmltv_id="Action.fr" site_id="10">Action</channel>
<channel lang="fr" xmltv_id="AlJazeeraEnglish.qa" site_id="525">Aljazeera English</channel>
<channel lang="fr" xmltv_id="Animaux.fr" site_id="12">Animaux</channel>
<channel lang="fr" xmltv_id="APlusKidsTV.uk" site_id="2293">A+ Kids TV</channel>
<channel lang="fr" xmltv_id="ARTEFrance.fr" site_id="111">ARTE Français</channel>
<channel lang="fr" xmltv_id="Automotolachaine.fr" site_id="15">Automoto la chaîne</channel>
<channel lang="fr" xmltv_id="BBCEntertainment.uk" site_id="18">BBC Entertainment Europe</channel>
<channel lang="fr" xmltv_id="BBCWorldNewsEurope.uk" site_id="19">BBC World News Europe</channel>
<channel lang="fr" xmltv_id="beINSports1France.fr" site_id="1290">BeIn Sports 1 France</channel>
<channel lang="fr" xmltv_id="beINSports2France.fr" site_id="1304">BeIn Sports 2 France</channel>
<channel lang="fr" xmltv_id="beINSports3France.fr" site_id="1335">BeIn Sports 3 France</channel>
<channel lang="fr" xmltv_id="beINSportsMax4France.fr" site_id="1336">BeIn Sports Max 4 France</channel>
<channel lang="fr" xmltv_id="beINSportsMax5France.fr" site_id="1337">BeIn Sports Max 5 France</channel>
<channel lang="fr" xmltv_id="beINSportsMax6France.fr" site_id="1338">BeIn Sports Max 6 France</channel>
<channel lang="fr" xmltv_id="beINSportsMax7France.fr" site_id="1339">BeIn Sports Max 7 France</channel>
<channel lang="fr" xmltv_id="beINSportsMax8France.fr" site_id="1340">BeIn Sports Max 8 France</channel>
<channel lang="fr" xmltv_id="beINSportsMax9France.fr" site_id="1341">BeIn Sports Max 9 France</channel>
<channel lang="fr" xmltv_id="beINSportsMax10France.fr" site_id="1342">BeIn Sports Max 10 France</channel>
<channel lang="fr" xmltv_id="BETFrance.fr" site_id="1960">BET France</channel>
<channel lang="fr" xmltv_id="BFMBusiness.fr" site_id="1073">BFM Business</channel>
<channel lang="fr" xmltv_id="BFMTV.fr" site_id="481">BFM TV</channel>
<channel lang="fr" xmltv_id="BloombergTVEurope.uk" site_id="410">Bloomberg TV Europe</channel>
<channel lang="fr" xmltv_id="BoingFrance.fr" site_id="924">Boing France</channel>
<channel lang="fr" xmltv_id="BoomerangFrance.fr" site_id="321">Boomerang France</channel>
<channel lang="fr" xmltv_id="BoomerangFrancePlus1.fr" site_id="928">Boomerang France +1</channel>
<channel lang="fr" xmltv_id="C8.fr" site_id="445">C8</channel>
<channel lang="fr" xmltv_id="CanalJ.fr" site_id="32">Canal J</channel>
<channel lang="fr" xmltv_id="CanalPlusCinemaFrance.fr" site_id="33">Canal + Cinéma France</channel>
<channel lang="fr" xmltv_id="CanalPlusDecale.fr" site_id="30">Canal + Décalé</channel>
<channel lang="fr" xmltv_id="CanalPlusDocs.fr" site_id="3347">Canal + Docs</channel>
<channel lang="fr" xmltv_id="CanalPlusFrance.fr" site_id="34">Canal + France</channel>
<channel lang="fr" xmltv_id="CanalPlusGrandEcran.fr" site_id="3349">Canal + Grand Ecran</channel>
<channel lang="fr" xmltv_id="CanalPlusKids.fr" site_id="3348">Canal + Kids</channel>
<channel lang="fr" xmltv_id="CanalPlusSeriesFrance.fr" site_id="1563">Canal + Séries</channel>
<channel lang="fr" xmltv_id="CanalPlusSportFrance.fr" site_id="35">Canal + Sport</channel>
<channel lang="fr" xmltv_id="CanalQ.pt" site_id="2046">Canal Q</channel>
<channel lang="fr" xmltv_id="CartoonNetworkFrance.fr" site_id="36">Cartoon Network France</channel>
<channel lang="fr" xmltv_id="ChassePeche.fr" site_id="38">Chasse &amp; Pêche</channel>
<channel lang="fr" xmltv_id="Cherie25.fr" site_id="1399">Chérie 25</channel>
<channel lang="fr" xmltv_id="CinePlusClassic.fr" site_id="287">Cine + Classic</channel>
<channel lang="fr" xmltv_id="CinePlusClub.fr" site_id="285">Cine + Club</channel>
<channel lang="fr" xmltv_id="CinePlusEmotion.fr" site_id="283">Cine + Émotion</channel>
<channel lang="fr" xmltv_id="CinePlusFamiz.fr" site_id="401">Cine + Famiz</channel>
<channel lang="fr" xmltv_id="CinePlusFrisson.fr" site_id="284">Cine + Frisson</channel>
<channel lang="fr" xmltv_id="CinePlusPremier.fr" site_id="282">Cine + Premier</channel>
<channel lang="fr" xmltv_id="CliqueTV.fr" site_id="2781">Clique TV</channel>
<channel lang="fr" xmltv_id="ClubbingTV.fr" site_id="1989">Clubbing TV</channel>
<channel lang="fr" xmltv_id="CNBCEurope.uk" site_id="51">CNBC Europe</channel>
<channel lang="fr" xmltv_id="CNews.fr" site_id="226">C News</channel>
<channel lang="fr" xmltv_id="CNNInternationalEurope.us" site_id="53">CNN International Europe</channel>
<channel lang="fr" xmltv_id="ComediePlus.fr" site_id="54">Comédie +</channel>
<channel lang="fr" xmltv_id="ComedyCentralFrance.fr" site_id="2752">Comedy Central France</channel>
<channel lang="fr" xmltv_id="CrimeDistrict.fr" site_id="2037">Crime District</channel>
<channel lang="fr" xmltv_id="CStar.fr" site_id="458">C Star</channel>
<channel lang="fr" xmltv_id="DasErste.de" site_id="13">Das Erste</channel>
<channel lang="fr" xmltv_id="DemainTV.fr" site_id="57">Demain TV</channel>
<channel lang="fr" xmltv_id="DisneyChannelFrance.fr" site_id="58">Disney Channel France</channel>
<channel lang="fr" xmltv_id="DisneyChannelFrancePlus1.fr" site_id="2974">Disney Channel France +1</channel>
<channel lang="fr" xmltv_id="DisneyJuniorFrance.fr" site_id="300">Disney Junior France</channel>
<channel lang="fr" xmltv_id="DWEnglish.de" site_id="61">DW English</channel>
<channel lang="fr" xmltv_id="Equidia.fr" site_id="64">Equidia</channel>
<channel lang="fr" xmltv_id="MGGTV.fr" site_id="2353">ES1</channel>
<channel lang="fr" xmltv_id="Eurochannel.uk" site_id="1190">Eurochannel</channel>
<channel lang="fr" xmltv_id="EuronewsFrench.fr" site_id="140">EuroNews Français</channel>
<channel lang="fr" xmltv_id="FashionTVEurope.fr" site_id="1996">FashionTV Europe</channel>
<channel lang="fr" xmltv_id="France2.fr" site_id="4">France 2</channel>
<channel lang="fr" xmltv_id="France3.fr" site_id="80">France 3</channel>
<channel lang="fr" xmltv_id="France3Alpes.fr" site_id="655">France 3 Alpes</channel>
<channel lang="fr" xmltv_id="France3Alsace.fr" site_id="249">France 3 Alsace</channel>
<channel lang="fr" xmltv_id="France3Aquitaine.fr" site_id="304">France 3 Aquitaine</channel>
<channel lang="fr" xmltv_id="France3Auvergne.fr" site_id="649">France 3 Auvergne</channel>
<channel lang="fr" xmltv_id="France3Bourgogne.fr" site_id="636">France 3 Bourgogne</channel>
<channel lang="fr" xmltv_id="France3Bretagne.fr" site_id="634">France 3 Bretagne</channel>
<channel lang="fr" xmltv_id="France3CentreValdeLoire.fr" site_id="306">France 3 Centre-Val de Loire</channel>
<channel lang="fr" xmltv_id="France3ChampagneArdenne.fr" site_id="641">France 3 Champagne-Ardenne</channel>
<channel lang="fr" xmltv_id="France3CorseViaStella.fr" site_id="308">France 3 Corse Via Stella</channel>
<channel lang="fr" xmltv_id="France3CotedAzur.fr" site_id="642">France 3 Côte d&apos;Azur</channel>
<channel lang="fr" xmltv_id="France3FrancheComte.fr" site_id="637">France 3 Franche-Comté</channel>
<channel lang="fr" xmltv_id="France3LanguedocRoussillon.fr" site_id="650">France 3 Languedoc-Roussillon</channel>
<channel lang="fr" xmltv_id="France3Limousin.fr" site_id="638">France 3 Limousin</channel>
<channel lang="fr" xmltv_id="France3Lorraine.fr" site_id="640">France 3 Lorraine</channel>
<channel lang="fr" xmltv_id="France3MidiPyrenees.fr" site_id="651">France 3 Midi-Pyrénées</channel>
<channel lang="fr" xmltv_id="France3NordPasdeCalais.fr" site_id="644">France 3 Nord Pas-de-Calais</channel>
<channel lang="fr" xmltv_id="France3ParisIledeFrance.fr" site_id="313">France 3 Paris Ile-de-France</channel>
<channel lang="fr" xmltv_id="France3PaysdelaLoire.fr" site_id="635">France 3 Pays de la Loire</channel>
<channel lang="fr" xmltv_id="France3Picardie.fr" site_id="645">France 3 Picardie</channel>
<channel lang="fr" xmltv_id="France3PoitouCharentes.fr" site_id="639">France 3 Poitou-Charentes</channel>
<channel lang="fr" xmltv_id="France3ProvenceAlpes.fr" site_id="643">France 3 Provence-Alpes</channel>
<channel lang="fr" xmltv_id="France3RhoneAlpes.fr" site_id="648">France 3 Rhône-Alpes</channel>
<channel lang="fr" xmltv_id="France4.fr" site_id="78">France 4</channel>
<channel lang="fr" xmltv_id="France5.fr" site_id="47">France 5</channel>
<channel lang="fr" xmltv_id="France24English.fr" site_id="671">France 24 English</channel>
<channel lang="fr" xmltv_id="France24French.fr" site_id="529">France 24 Français</channel>
<channel lang="fr" xmltv_id="Franceinfo.fr" site_id="2111">Franceinfo:</channel>
<channel lang="fr" xmltv_id="GameOne.fr" site_id="87">Game One</channel>
<channel lang="fr" xmltv_id="GameOnePlus1.fr" site_id="1167">Game One +1</channel>
<channel lang="fr" xmltv_id="GolfChannelFrance.fr" site_id="1166">Golf Channel France</channel>
<channel lang="fr" xmltv_id="Gulli.fr" site_id="482">Gulli</channel>
<channel lang="fr" xmltv_id="HistoireTV.fr" site_id="88">Histoire TV</channel>
<channel lang="fr" xmltv_id="I24NewsFrench.il" site_id="781">I24 News Français</channel>
<channel lang="fr" xmltv_id="JOne.fr" site_id="1585">J-One</channel>
<channel lang="fr" xmltv_id="KTO.fr" site_id="110">KTO</channel>
<channel lang="fr" xmltv_id="LCI.fr" site_id="112">LCI</channel>
<channel lang="fr" xmltv_id="LCP.fr" site_id="992">LCP Assemblée Nationale</channel>
<channel lang="fr" xmltv_id="PublicSenat.fr" site_id="234">LCP Public Sénat</channel>
<channel lang="fr" xmltv_id="LEquipe.fr" site_id="1401">L&apos;Équipe</channel>
<channel lang="fr" xmltv_id="LuckyJacktv.lu" site_id="1061">Lucky Jack.tv</channel>
<channel lang="fr" xmltv_id="LuxeTV.lu" site_id="531">Luxe TV</channel>
<channel lang="fr" xmltv_id="M6.fr" site_id="118">M6</channel>
<channel lang="fr" xmltv_id="M6Music.fr" site_id="453">M6 Music</channel>
<channel lang="fr" xmltv_id="MaisonTravauxTV.fr" site_id="3360">Maison &amp; Travaux TV</channel>
<channel lang="fr" xmltv_id="Mangas.fr" site_id="6">Mangas</channel>
<channel lang="fr" xmltv_id="MCM.fr" site_id="121">MCM France</channel>
<channel lang="fr" xmltv_id="Melody.fr" site_id="265">Melody</channel>
<channel lang="fr" xmltv_id="MelodydAfrique.fr" site_id="2321">Melody d&apos;Afrique</channel>
<channel lang="fr" xmltv_id="Mezzo.fr" site_id="125">Mezzo</channel>
<channel lang="fr" xmltv_id="MezzoLiveHD.fr" site_id="907">Mezzo Live HD</channel>
<channel lang="fr" xmltv_id="MTVFrance.fr" site_id="128">MTV France</channel>
<channel lang="fr" xmltv_id="MTVHitsFrance.fr" site_id="2006">MTV Hits France</channel>
<channel lang="fr" xmltv_id="MuseumTV.fr" site_id="1072">Museum</channel>
<channel lang="fr" xmltv_id="MyZenTV.fr" site_id="829">MyZen TV</channel>
<channel lang="fr" xmltv_id="NationalGeographicFrance.fr" site_id="508">National Geographic France</channel>
<channel lang="fr" xmltv_id="NationalGeographicWildFrance.fr" site_id="719">National Geographic Wild France</channel>
<channel lang="fr" xmltv_id="NHKWorldJapan.jp" site_id="830">NHK World Japan</channel>
<channel lang="fr" xmltv_id="NickelodeonFrance.fr" site_id="473">Nickelodeon France</channel>
<channel lang="fr" xmltv_id="NickelodeonFrancePlus1.fr" site_id="2065">Nickelodeon France +1</channel>
<channel lang="fr" xmltv_id="NickelodeonJunior.fr" site_id="888">Nickelodeon Junior France</channel>
<channel lang="fr" xmltv_id="NickelodeonTeen.fr" site_id="1746">Nickelodeon Teen</channel>
<channel lang="fr" xmltv_id="Nitro.de" site_id="2311">Nitro Deutschland</channel>
<channel lang="fr" xmltv_id="NollywoodTV.fr" site_id="1461">Nollywood TV</channel>
<channel lang="fr" xmltv_id="NovelasTV.fr" site_id="1832">Novelas TV</channel>
<channel lang="fr" xmltv_id="NRJ12.fr" site_id="444">NRJ 12</channel>
<channel lang="fr" xmltv_id="NRJHits.fr" site_id="605">NRJ Hits</channel>
<channel lang="fr" xmltv_id="OCSChoc.fr" site_id="732">OCS choc</channel>
<channel lang="fr" xmltv_id="OCSCity.fr" site_id="733">OCS City</channel>
<channel lang="fr" xmltv_id="OCSGeants.fr" site_id="734">OCS geants</channel>
<channel lang="fr" xmltv_id="OCSMax.fr" site_id="730">OCS max</channel>
<channel lang="fr" xmltv_id="OlympiaTV.fr" site_id="2958">Olympia TV</channel>
<channel lang="fr" xmltv_id="One.de" site_id="979">One</channel>
<channel lang="fr" xmltv_id="ParamountChannelOffset.fr" site_id="2072">Paramount Channel Décalé</channel>
<channel lang="fr" xmltv_id="ParamountChannelFrance.fr" site_id="1562">Paramount Channel France</channel>
<channel lang="fr" xmltv_id="ParisPremiere.fr" site_id="145">Paris Première</channel>
<channel lang="fr" xmltv_id="PiwiPlus.fr" site_id="344">Piwi +</channel>
<channel lang="fr" xmltv_id="PlanetePlus.fr" site_id="147">Planète +</channel>
<channel lang="fr" xmltv_id="PlanetePlusAE.fr" site_id="402">Planète + A&amp;E</channel>
<channel lang="fr" xmltv_id="PlanetePlusCI.fr" site_id="662">Planète + CI</channel>
<channel lang="fr" xmltv_id="PolarPlus.fr" site_id="2326">Polar +</channel>
<channel lang="fr" xmltv_id="ProSieben.de" site_id="964">ProSieben Deutschland</channel>
<channel lang="fr" xmltv_id="Rai1.it" site_id="156">Rai 1</channel>
<channel lang="fr" xmltv_id="Rai2.it" site_id="154">Rai 2</channel>
<channel lang="fr" xmltv_id="Rai3.it" site_id="155">Rai 3</channel>
<channel lang="fr" xmltv_id="RaiNews24.it" site_id="1129">Rai News 24</channel>
<channel lang="fr" xmltv_id="RMCDecouverte.fr" site_id="1400">RMC Découverte</channel>
<channel lang="fr" xmltv_id="RMCStory.fr" site_id="1402">RMC Story</channel>
<channel lang="fr" xmltv_id="RTL9.lu" site_id="115">RTL 9</channel>
<channel lang="fr" xmltv_id="RTLZwei.de" site_id="966">RTL Zwei Deutschland</channel>
<channel lang="fr" xmltv_id="RTPInternacional.pt" site_id="169">RTP Internacional Europa</channel>
<channel lang="fr" xmltv_id="ScienceVieTV.fr" site_id="63">Science &amp; Vie TV</channel>
<channel lang="fr" xmltv_id="SerieClub.fr" site_id="49">Série Club</channel>
<channel lang="fr" xmltv_id="SportenFrance.fr" site_id="2837">Sport en France</channel>
<channel lang="fr" xmltv_id="StingrayClassica.ca" site_id="1353">Stingray Classica</channel>
<channel lang="fr" xmltv_id="SunuYeuf.sn" site_id="2908">Sunu Yeuf</channel>
<channel lang="fr" xmltv_id="SuperRTL.de" site_id="1854">Super RTL Deutschland</channel>
<channel lang="fr" xmltv_id="TCMCinema.fr" site_id="185">TCM Cinéma</channel>
<channel lang="fr" xmltv_id="TeletoonPlus.fr" site_id="197">TéléToon +</channel>
<channel lang="fr" xmltv_id="TeletoonPlus1.fr" site_id="293">TéléToon + 1</channel>
<channel lang="fr" xmltv_id="Teva.fr" site_id="191">Téva</channel>
<channel lang="fr" xmltv_id="TF1.fr" site_id="192">TF 1</channel>
<channel lang="fr" xmltv_id="TF1Plus1.fr" site_id="2441">TF 1 +1</channel>
<channel lang="fr" xmltv_id="TF1SeriesFilms.fr" site_id="1404">TF 1 Séries Films</channel>
<channel lang="fr" xmltv_id="TFX.fr" site_id="446">TFX</channel>
<channel lang="fr" xmltv_id="TheIsraeliNetwork.il" site_id="2000">The Israeli Network</channel>
<channel lang="fr" xmltv_id="TiJi.fr" site_id="229">Tiji</channel>
<channel lang="fr" xmltv_id="TMC.fr" site_id="195">TMC</channel>
<channel lang="fr" xmltv_id="TMCPlus1.fr" site_id="2442">TMC +1</channel>
<channel lang="fr" xmltv_id="ToonamiFrance.fr" site_id="2040">Toonami France</channel>
<channel lang="fr" xmltv_id="ToutelHistoire.fr" site_id="7">Toute l&apos;Histoire</channel>
<channel lang="fr" xmltv_id="TV5MondeFranceBelgiumSwitzerland.fr" site_id="205">TV5Monde France Belgique Suisse</channel>
<channel lang="fr" xmltv_id="TVBreizh.fr" site_id="225">TV Breizh</channel>
<channel lang="fr" xmltv_id="TVEInternacionalEuropeAsia.es" site_id="208">TVE Internacional Europa</channel>
<channel lang="fr" xmltv_id="TVPitchoun.fr" site_id="2803">TV Pitchoun</channel>
<channel lang="fr" xmltv_id="UltraNature.fr" site_id="2094">Ultra Nature</channel>
<channel lang="fr" xmltv_id="UshuaiaTV.fr" site_id="451">Ushuaïa TV</channel>
<channel lang="fr" xmltv_id="VoxAfrica.uk" site_id="1133">Voxafrica Afrique</channel>
<channel lang="fr" xmltv_id="VoxGermany.de" site_id="971">Vox Deutschland</channel>
<channel lang="fr" xmltv_id="W9.fr" site_id="119">W9</channel>
<channel lang="fr" xmltv_id="WarnerTVFrance.fr" site_id="2334">Warner TV France</channel>
<channel lang="fr" xmltv_id="ZDF.de" site_id="219">ZDF</channel>
<channel lang="fr" xmltv_id="ZDFneo.de" site_id="973">ZDF Neo</channel>
</channels>
</site>

View File

@@ -0,0 +1,47 @@
const dayjs = require('dayjs')
module.exports = {
site: 'chaines-tv.orange.fr',
days: 2,
url({ channel, date }) {
return `https://rp-ott-mediation-tv.woopic.com/api-gw/live/v3/applications/STB4PC/programs?groupBy=channel&includeEmptyChannels=false&period=${date.valueOf()},${date
.add(1, 'd')
.valueOf()}&after=${channel.site_id}&limit=1`
},
parser: function ({ content, channel }) {
let programs = []
const items = parseItems(content, channel)
items.forEach(item => {
const start = parseStart(item)
const stop = parseStop(item, start)
programs.push({
title: item.title,
category: item.genreDetailed,
description: item.synopsis,
icon: parseIcon(item),
start: start.toJSON(),
stop: stop.toJSON()
})
})
return programs
}
}
function parseIcon(item) {
return item.covers && item.covers.length ? item.covers[0].url : null
}
function parseStart(item) {
return dayjs.unix(item.diffusionDate)
}
function parseStop(item, start) {
return start.add(item.duration, 's')
}
function parseItems(content, channel) {
const data = JSON.parse(content)
return data && data[channel.site_id] ? data[channel.site_id] : []
}

View File

@@ -0,0 +1,45 @@
// npx epg-grabber --config=sites/chaines-tv.orange.fr/chaines-tv.orange.fr.config.js --channels=sites/chaines-tv.orange.fr/chaines-tv.orange.fr.channels.xml --output=guide.xml --days=2
const { parser, url, request } = require('./chaines-tv.orange.fr.config.js')
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('2021-11-08', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: '192',
xmltv_id: 'TF1.fr'
}
const content = `{"192":[{"id":1635062528017,"programType":"EPISODE","title":"Tête de liste","channelId":"192","channelZappingNumber":11,"covers":[{"format":"RATIO_16_9","url":"https://proxymedia.woopic.com/340/p/169_EMI_9697669.jpg"},{"format":"RATIO_4_3","url":"https://proxymedia.woopic.com/340/p/43_EMI_9697669.jpg"}],"diffusionDate":1636328100,"duration":2700,"csa":2,"synopsis":"Un tueur en série prend un plaisir pervers à prévenir les autorités de Tallahassee avant chaque nouveau meurtre. Rossi apprend le décès d'un de ses vieux amis.","languageVersion":"VM","hearingImpaired":true,"audioDescription":false,"season":{"number":10,"episodesCount":23,"serie":{"title":"Esprits criminels"}},"episodeNumber":12,"definition":"SD","links":[{"rel":"SELF","href":"https://rp-live.orange.fr/live-webapp/v3/applications/STB4PC/programs/1635062528017"}],"dayPart":"OTHER","catchupId":null,"genre":"Série","genreDetailed":"Série Suspense"}]}`
it('can generate valid url', () => {
const result = url({ channel, date })
expect(result).toBe(
'https://rp-ott-mediation-tv.woopic.com/api-gw/live/v3/applications/STB4PC/programs?groupBy=channel&includeEmptyChannels=false&period=1636329600000,1636416000000&after=192&limit=1'
)
})
it('can parse response', () => {
const result = parser({ date, channel, content })
expect(result).toMatchObject([
{
start: '2021-11-07T23:35:00.000Z',
stop: '2021-11-08T00:20:00.000Z',
title: 'Tête de liste',
description: `Un tueur en série prend un plaisir pervers à prévenir les autorités de Tallahassee avant chaque nouveau meurtre. Rossi apprend le décès d'un de ses vieux amis.`,
category: 'Série Suspense',
icon: 'https://proxymedia.woopic.com/340/p/169_EMI_9697669.jpg'
}
])
})
it('can handle empty guide', () => {
const result = parser({
date,
channel,
content: `{"code":60,"message":"Resource not found","param":{},"description":"L'URI demandé ou la ressource demandée n'existe pas.","stackTrace":null}`
})
expect(result).toMatchObject([])
})

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="clickthecity.com">
<channels>
<channel lang="en" xmltv_id="A2Z.ph" site_id="a2z-channel-11">A2Z Channel 11</channel>
<channel lang="en" xmltv_id="ANC.ph" site_id="anc">ANC</channel>
<channel lang="en" xmltv_id="AnimaxPhilippines.ph" site_id="animax">Animax</channel>
<channel lang="en" xmltv_id="AXNPhilippines.ph" site_id="axn">AXN</channel>
<channel lang="en" xmltv_id="CelestialMoviesPinoy.hk" site_id="celestial-movies-pinoy">Celestial Movies Pinoy</channel>
<channel lang="en" xmltv_id="CinemaOneGlobal.ph" site_id="cinema-one">Cinema One</channel>
<channel lang="en" xmltv_id="CinemaxAsia.sg" site_id="cinemax">Cinemax</channel>
<channel lang="en" xmltv_id="CNNPhilippines.ph" site_id="cnn-philippines">CNN Philippines</channel>
<channel lang="en" xmltv_id="CrimePlusInvestigationAsia.sg" site_id="crime-investigation">Crime &amp; Investigation</channel>
<channel lang="en" xmltv_id="IBC13.ph" site_id="ibc-tv-13">IBC 13</channel>
<channel lang="en" xmltv_id="ETC.ph" site_id="etc">ETC</channel>
<channel lang="en" xmltv_id="GEM.sg" site_id="gem">GEM</channel>
<channel lang="en" xmltv_id="GMANewsTV.ph" site_id="gma-news-tv">GMA News TV</channel>
<channel lang="en" xmltv_id="GMATV.ph" site_id="gma">GMA</channel>
<channel lang="en" xmltv_id="GTV.ph" site_id="gtv">GTV</channel>
<channel lang="en" xmltv_id="HBOAsia.sg" site_id="hbo-asia">HBO Asia</channel>
<channel lang="en" xmltv_id="HistoryPhilippines.ph" site_id="history">History</channel>
<channel lang="en" xmltv_id="JeepneyTV.ph" site_id="jeepney-tv">Jeepney TV</channel>
<channel lang="en" xmltv_id="KapamilyaChannel.ph" site_id="kapamilya-channel">Kapamilya Channel</channel>
<channel lang="en" xmltv_id="KMoviesPinoy.ph" site_id="k-movies-pinoy">K Movies Pinoy</channel>
<channel lang="en" xmltv_id="Liga.ph" site_id="liga">Liga</channel>
<channel lang="en" xmltv_id="MetroChannel.ph" site_id="metro-channel">Metro Channel</channel>
<channel lang="en" xmltv_id="MyxPhilippines.ph" site_id="myx">MYX</channel>
<channel lang="en" xmltv_id="NationalGeographicPhilippines.ph" site_id="national-geographic">National Geographic</channel>
<channel lang="en" xmltv_id="Net25.ph" site_id="net-25">Net 25</channel>
<channel lang="en" xmltv_id="NickelodeonPhilippines.ph" site_id="nickelodeon">Nickelodeon</channel>
<channel lang="en" xmltv_id="PBO.ph" site_id="pbo">PBO</channel>
<channel lang="en" xmltv_id="PTV.ph" site_id="ptv">PTV</channel>
<channel lang="en" xmltv_id="ROCKEntertainment.sg" site_id="rock-entertainment">Rock Entertainment</channel>
<channel lang="en" xmltv_id="ROCKExtreme.sg" site_id="rock-extreme">Rock Extreme</channel>
<channel lang="en" xmltv_id="TeleNovelaChannel.ph" site_id="telenovela-channel">TeleNovela Channel</channel>
<channel lang="en" xmltv_id="TV5.ph" site_id="tv5">TV5</channel>
<channel lang="en" xmltv_id="VivaCinema.ph" site_id="viva-tv">VIVA Cinema</channel>
</channels>
</site>

View File

@@ -0,0 +1,105 @@
const cheerio = require('cheerio')
const axios = require('axios')
const dayjs = require('dayjs')
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: 'clickthecity.com',
days: 2,
url({ channel }) {
return `https://www.clickthecity.com/tv/network/${channel.site_id}`
},
request: {
method: 'POST',
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
data({ date }) {
const params = new URLSearchParams()
params.append('optDate', dayjs(date).tz('Asia/Manila').format('YYYY-MM-DD'))
params.append('optTime', '00:00:00')
return params
}
},
parser({ content, date }) {
const programs = []
const items = parseItems(content, date)
items.forEach(item => {
const prev = programs[programs.length - 1]
const $item = cheerio.load(item)
const start = parseStart($item, date)
const stop = parseStop($item, date)
if (stop && prev && stop.isBefore(prev.start)) return
programs.push({
title: parseTitle($item),
start,
stop
})
})
return programs
},
async channels() {
const html = await axios
.get(`https://www.clickthecity.com/tv-networks/`)
.then(r => r.data)
.catch(console.log)
const $ = cheerio.load(html)
const items = $(
'#main > div > div > div > section.elementor-section.elementor-top-section.elementor-element.elementor-element-a3c51b3.elementor-section-boxed.elementor-section-height-default.elementor-section-height-default > div > div > div.elementor-column.elementor-col-50.elementor-top-column.elementor-element.elementor-element-b23e0a8 > div > div > div.elementor-element.elementor-element-b46952e.elementor-posts--align-center.elementor-grid-tablet-3.elementor-grid-mobile-3.elementor-grid-4.elementor-posts--thumbnail-top.elementor-widget.elementor-widget-posts > div > div > article'
).toArray()
return items.map(item => {
const name = $(item).find('div > h3').text().trim()
const url = $(item).find('a').attr('href')
const [_, site_id] = url.match(/network\/(.*)\//) || [null, null]
return {
site_id,
name
}
})
}
}
function parseTitle($item) {
return $item('td > a').text().trim()
}
function parseStart($item, date) {
const url = $item('td > a').attr('href') || ''
const [_, time] = url.match(/starttime=(\d{1,2}%3A\d{2}\+(AM|PM))/) || [null, null]
if (!time) return null
return dayjs.tz(
`${date.format('YYYY-MM-DD')} ${time.replace('%3A', ':')}`,
'YYYY-MM-DD h:mm A',
'Asia/Manila'
)
}
function parseStop($item, date) {
const url = $item('td > a').attr('href') || ''
const [_, time] = url.match(/endtime=(\d{1,2}%3A\d{2}\+(AM|PM))/) || [null, null]
if (!time) return null
return dayjs.tz(
`${date.format('YYYY-MM-DD')} ${time.replace('%3A', ':')}`,
'YYYY-MM-DD h:mm A',
'Asia/Manila'
)
}
function parseItems(content, date) {
const $ = cheerio.load(content)
const stringDate = date.format('MMMM DD')
return $(`#tvlistings > tbody > tr:not(.bg-dark)`).toArray()
}

View File

@@ -0,0 +1,72 @@
// npm run channels:parse -- --config=./sites/clickthecity.com/clickthecity.com.config.js --output=./sites/clickthecity.com/clickthecity.com.channels.xml
// npx epg-grabber --config=sites/clickthecity.com/clickthecity.com.config.js --channels=sites/clickthecity.com/clickthecity.com.channels.xml --output=guide.xml --days=2
const { parser, url, request } = require('./clickthecity.com.config.js')
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-03-05', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: 'tv5',
xmltv_id: 'TV5.ph'
}
it('can generate valid url', () => {
expect(url({ channel })).toBe('https://www.clickthecity.com/tv/network/tv5')
})
it('can generate valid request method', () => {
expect(request.method).toBe('POST')
})
it('can generate valid request headers', () => {
expect(request.headers).toMatchObject({
'content-type': 'application/x-www-form-urlencoded'
})
})
it('can generate valid request data', () => {
const result = request.data({ date })
expect(result.get('optDate')).toBe('2022-03-05')
expect(result.get('optTime')).toBe('00:00:00')
})
it('can parse response', () => {
const content = `<!doctypehtml><html class=html lang=en-US prefix="og: https://ogp.me/ns#"><body class="aa-prefix-click- content-right-sidebar default-breakpoint dropdown-mobile elementor-default elementor-kit-114471 elementor-page-62235 elementor-template-full-width has-breadcrumbs has-sidebar network-template-default oceanwp-theme page-header-disabled postid-62183 single single-network wp-custom-logo wp-embed-responsive"itemscope=itemscope itemtype=https://schema.org/WebPage><div class="clr site"id=outer-wrap><a class="screen-reader-text skip-link"href=#main>Skip to content</a><div class=clr id=wrap><main class="clr site-main"id=main role=main><div class="category-tv elementor elementor-62235 elementor-location-single entry has-media has-post-thumbnail hentry network post-62183 status-publish type-network"data-elementor-id=62235 data-elementor-settings=[] data-elementor-type=single><div class=elementor-section-wrap><section class="elementor-element elementor-section-height-default elementor-section-height-default elementor-element-9dc0219 elementor-section elementor-section-boxed elementor-top-section"data-element_type=section data-id=9dc0219><div class="elementor-column-gap-default elementor-container"><div class=elementor-row><div class="elementor-element elementor-col-50 elementor-column elementor-element-b6192ca elementor-top-column"data-element_type=column data-id=b6192ca data-settings='{"background_background":"classic"}'><div class="elementor-column-wrap elementor-element-populated"><div class=elementor-widget-wrap><div class="elementor-element elementor-element-c4989ed elementor-widget elementor-widget-shortcode"data-element_type=widget data-id=c4989ed data-widget_type=shortcode.default><div class=elementor-widget-container><div class=elementor-shortcode><form class=form-inline id=frmTV method=POST name=frmTV role=form><div class=w-100><table class="card d-table overflow-hidden rounded shadow table table-bordered table-striped"id=tvlistings><tr class="bg-dark text-light"><th colspan=2>Tomorrow, March 05<tr><td class=cTme width=100>12:00 am<td class="cPrg showlnkcon"><a class="font-weight-bold text-dark"href="/tv/tvshow.php?id=109793&amp;starttime=12%3A00+AM&amp;endtime=1%3A00+AM"name=0>CCF Worship Service</a><tr><td class=cTme width=100>06:30 am<td class="cPrg showlnkcon"><a class="font-weight-bold text-dark"href="/tv/tvshow.php?id=94697&amp;starttime=6%3A30+AM&amp;endtime=7%3A30+AM"name=1>Word Of God</a><tr class="bg-dark text-light"><th colspan="2">Tonight, March 05</th></tr><tr> <td class="cTme">08:00 pm</td><td class="cPrg showlnkcon"> <a class="font-weight-bold text-dark" name="10" href="/tv/tvshow.php?id=113538&amp;starttime=8%3A00+PM&amp;endtime=9%3A00+PM">Rated Korina S2 </a> </td></tr><tr class="bg-dark text-light"><th colspan=2>Sunday, March 06<tr><td class=cTme>12:00 am<td class="cPrg showlnkcon"><a class="font-weight-bold text-dark"href="/tv/tvshow.php?id=114754&amp;starttime=12%3A00+AM&amp;endtime=3%3A30+AM"name=13>2021 PBA Governor's Cup</a></table></div></form></div></div></div></div></div></div></div></div></section></div></div></main></div></div>`
const result = parser({ content, date }).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2022-03-04T16:00:00.000Z',
stop: '2022-03-04T17:00:00.000Z',
title: `CCF Worship Service`
},
{
start: '2022-03-04T22:30:00.000Z',
stop: '2022-03-04T23:30:00.000Z',
title: `Word Of God`
},
{
start: '2022-03-05T12:00:00.000Z',
stop: '2022-03-05T13:00:00.000Z',
title: `Rated Korina S2`
}
])
})
it('can handle empty guide', () => {
const result = parser({
date,
channel,
content: `<!DOCTYPE html><html class="html" lang="en-US" prefix="og: https://ogp.me/ns#"><head></head><body></body></html>`
})
expect(result).toMatchObject([])
})

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<site site="compulms.com">
<channels>
<channel lang="es" xmltv_id="EnerGeekAnimate.cl" site_id="EnerGeek Animate">EnerGeek Animate</channel>
<channel lang="es" xmltv_id="EnerGeekFanpop.cl" site_id="EnerGeek Fanpop">EnerGeek Fanpop</channel>
<channel lang="es" xmltv_id="EnerGeekRadio.cl" site_id="EnerGeek Radio TV">EnerGeek Radio TV</channel>
<channel lang="es" xmltv_id="EnerGeekRetro.cl" site_id="EnerGeek Retro">EnerGeek Retro</channel>
</channels>
</site>

Some files were not shown because too many files have changed in this diff Show More