Merge branch 'master' into zap2it.com

This commit is contained in:
Newbiect
2025-08-05 14:28:02 -04:00
committed by GitHub
1309 changed files with 263503 additions and 106197 deletions

View File

@@ -1,69 +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),
image: parseImage($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 parseImage($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()
}
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),
image: parseImage($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 parseImage($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

@@ -1,55 +1,56 @@
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: 'Слепая',
image: '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',
image: '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([])
})
const { parser, url } = require('./9tv.co.il.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-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 = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
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: 'Слепая',
image: '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',
image: 'https://www.9tv.co.il/download/pictures/img_id=23694.jpg',
title: 'Орел и решка. Морской сезон',
description: 'Орел и решка. Морской сезон. Ведущие -Алина Астровская и Коля Серга.'
}
])
})
it('can handle empty guide', () => {
const result = parser({
date,
channel,
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
})
expect(result).toMatchObject([])
})

View File

@@ -0,0 +1 @@
<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>

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html><head></head><body></body></html>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<Error
><code>NoSuchKey</code><Message>The specified key does not exist.</Message
><Key>processed/Sydney_2026-02-04.json</Key><RequestId>A8BGG30W2N9P97Z1</RequestId
><HostId
>4NlYzMSR9t2HPBctGhbCKPEBuFdVxtbuyLIOA7uTL28R6/ooqneS1TTwVa7PkTt7gr9yyopqCKk=</HostId
></Error
>

View File

@@ -1,543 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#SPREE">SPREE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#TENHD">TENHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#7">7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#7HD">7HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#9">9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#9HD">9HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#9Rush">9Rush</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#SPREE">SPREE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#TENHD">TENHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#ASPIR">ASPIR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#PrimS">PrimS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SCA9">SCA9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SCHD">SCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SNR">SNR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#WINHD">WINHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#9">9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#9HD">9HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#ASPIR">ASPIR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#DDT">DDT</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#SC">SC</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#7">7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#7HD">7HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#9">9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#9HD">9HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#10Nth">10Nth</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#NBN">NBN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#Prime">Prime</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#SNR">SNR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SC">SC</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SCA9">SCA9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SCHD">SCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SHD7">SHD7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#TDHD">TDHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#TDT">TDT</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#WINHD">WINHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#7">7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#7HD">7HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#9">9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#9HD">9HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#9Rush">9Rush</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#SPREE">SPREE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#TENHD">TENHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#7">7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#7GTS">7GTS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#10Nth">10Nth</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#ASPIR">ASPIR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#Imp">Imp</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#NBN">NBN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#PrimN">PrimN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#PrimS">PrimS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#SCA9">SCA9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#SCHD">SCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#SNR">SNR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#WINHD">WINHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#7C">7C</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#Imp">Imp</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#7">7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#7HD">7HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#9">9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#9HD">9HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#9Rush">9Rush</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#SPREE">SPREE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#TENHD">TENHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#7C">7C</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#7QLD">7QLD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#7TWOQ">7TWOQ</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#ASPIR">ASPIR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#Imp">Imp</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SCA9">SCA9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SCHD">SCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SNR">SNR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#WINHD">WINHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#7C">7C</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#7GTS">7GTS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#ASPIR">ASPIR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#Imp">Imp</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#SC9">SC9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#SNR">SNR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#WIN9">WIN9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#WIN10">WIN10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#WINHD">WINHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#ASPIR">ASPIR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SC">SC</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SCA9">SCA9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SCHD">SCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SHD7">SHD7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#TDHD">TDHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#TDT">TDT</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#WINHD">WINHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#7">7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#SCA9">SCA9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#SCHD">SCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#WINHD">WINHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#ASPIR">ASPIR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#Prime">Prime</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SCA9">SCA9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SCHD">SCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SNR">SNR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#WINHD">WINHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#WinSA">WinSA</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#GWN">GWN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#WDT">WDT</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#WINHD">WINHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="7bravoAdelaide.au" site_id="Adelaide#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="7bravoSydney.au" site_id="Sydney#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="7flixAdelaide.au" site_id="Adelaide#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="7flixSydney.au" site_id="Sydney#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="7HDAdelaide.au" site_id="Adelaide#7HD">7HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="7mateAdelaide.au" site_id="Adelaide#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="7mateSydney.au" site_id="Sydney#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="7twoAdelaide.au" site_id="Adelaide#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="7twoSydney.au" site_id="Sydney#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="9GemSydney.au" site_id="Sydney#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="9GoSydney.au" site_id="Sydney#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="9HDAdelaide.au" site_id="Adelaide#9HD">9HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="9LifeAdelaide.au" site_id="Adelaide#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="9LifeSydney.au" site_id="Sydney#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="9RushAdelaide.au" site_id="Adelaide#9Rush">9Rush</channel>
<channel site="abc.net.au" lang="en" xmltv_id="9RushSydney.au" site_id="Sydney#9Rush">9Rush</channel>
<channel site="abc.net.au" lang="en" xmltv_id="10BoldSydney.au" site_id="Sydney#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="10PeachSydney.au" site_id="Sydney#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="10ShakeSydney.au" site_id="Sydney#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="ABCAustralia.au" site_id="Sydney#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="ABCKidsSydney.au" site_id="Sydney#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="ABCMESydney.au" site_id="Sydney#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="ABCTVNSW.au" site_id="New South Wales#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="ABCTVNT.au" site_id="Northern Territory#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="ABCTVPlusSydney.au" site_id="Sydney#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="ABCTVQLD.au" site_id="Queensland#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="ABCTVSA.au" site_id="South Australia#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="ABCTVSydney.au" site_id="Sydney#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="ABCTVSydney.au" site_id="Sydney#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="ABCTVTAS.au" site_id="Tasmania#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="ABCTVVIC.au" site_id="Victoria#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="ABCTVWA.au" site_id="Western Australia#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="C31Melbourne.au" site_id="Melbourne#31">31</channel>
<channel site="abc.net.au" lang="en" xmltv_id="Channel7Adelaide.au" site_id="Adelaide#7">7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="Channel7Sydney.au" site_id="Sydney#7">7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="Channel7Sydney.au" site_id="Sydney#7HD">7HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="Channel9Adelaide.au" site_id="Adelaide#9">9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="Channel9Sydney.au" site_id="Sydney#9">9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="Channel9Sydney.au" site_id="Sydney#9HD">9HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="10Adelaide.au" site_id="Adelaide#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="10Sydney.au" site_id="Sydney#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="10Sydney.au" site_id="Sydney#TENHD">TENHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="Channel44.au" site_id="Adelaide#44">44</channel>
<channel site="abc.net.au" lang="en" xmltv_id="NITVAdelaide.au" site_id="Adelaide#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="NITVSydney.au" site_id="Sydney#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="Racingcom.au" site_id="Sydney#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="SBSAdelaide.au" site_id="Adelaide#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="SBSFoodSydney.au" site_id="Sydney#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="SBSSydney.au" site_id="Sydney#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="SBSSydney.au" site_id="Sydney#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="SBSVicelandSydney.au" site_id="Sydney#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="SBSWorldMoviesSydney.au" site_id="Sydney#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="SBSWorldWatchSydney.au" site_id="Sydney#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="SpreeTV.au" site_id="Sydney#SPREE">SPREE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="TVSN.au" site_id="Sydney#TVSN">TVSN</channel>
</channels>

View File

@@ -1,121 +1,122 @@
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: 'abc.net.au',
days: 3,
request: {
cache: {
ttl: 60 * 60 * 1000 // 1 hour
}
},
url({ date, channel }) {
const [region] = channel.site_id.split('#')
return `https://epg.abctv.net.au/processed/${region}_${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),
image: parseImage(item),
start: parseTime(item.start_time),
stop: parseTime(item.end_time)
})
})
return programs
},
async channels() {
const now = dayjs()
const regions = [
'Sydney',
'Melbourne',
'Brisbane',
'GoldCoast',
'Perth',
'Adelaide',
'Hobart',
'Darwin',
'Canberra',
'New South Wales',
'Victoria',
'Townsville',
'Queensland',
'Western Australia',
'South Australia',
'Tasmania',
'Northern Territory'
]
let channels = []
for (let region of regions) {
const data = await axios
.get(`https://epg.abctv.net.au/processed/${region}_${now.format('YYYY-MM-DD')}.json`)
.then(r => r.data)
.catch(console.log)
for (let item of data.schedule) {
channels.push({
lang: 'en',
site_id: `${region}#${item.channel}`,
name: item.channel
})
}
}
return channels
}
}
function parseItems(content, channel) {
try {
const data = JSON.parse(content)
if (!data) return []
if (!Array.isArray(data.schedule)) return []
const [, channelId] = channel.site_id.split('#')
const channelData = data.schedule.find(i => i.channel == channelId)
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 parseImage(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
}
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: 'abc.net.au',
days: 3,
request: {
cache: {
ttl: 60 * 60 * 1000 // 1 hour
}
},
url({ date, channel }) {
const [region] = channel.site_id.split('#')
return `https://cdn.iview.abc.net.au/epg/processed/${region}_${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),
image: parseImage(item),
start: parseTime(item.start_time),
stop: parseTime(item.end_time)
})
})
return programs
},
async channels({ region = 'syd' }) {
const now = dayjs()
const regions = {
syd: 'Sydney',
mel: 'Melbourne',
bri: 'Brisbane',
gc: 'GoldCoast',
per: 'Perth',
adl: 'Adelaide',
hbr: 'Hobart',
drw: 'Darwin',
cbr: 'Canberra',
nsw: 'New South Wales',
vic: 'Victoria',
tsv: 'Townsville',
qld: 'Queensland',
wa: 'Western Australia',
sa: 'South Australia',
tas: 'Tasmania',
nt: 'Northern Territory'
}
let channels = []
const regionName = regions[region]
const data = await axios
.get(
`https://cdn.iview.abc.net.au/epg/processed/${regionName}_${now.format('YYYY-MM-DD')}.json`
)
.then(r => r.data)
.catch(console.log)
for (let item of data.schedule) {
channels.push({
lang: 'en',
site_id: `${regionName}#${item.channel}`,
name: item.channel
})
}
return channels
}
}
function parseItems(content, channel) {
try {
const data = JSON.parse(content)
if (!data) return []
if (!Array.isArray(data.schedule)) return []
const [, channelId] = channel.site_id.split('#')
const channelData = data.schedule.find(i => i.channel == channelId)
return channelData.listing && Array.isArray(channelData.listing) ? channelData.listing : []
} catch {
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 parseImage(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

@@ -1,54 +1,51 @@
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: 'Sydney#ABC1',
xmltv_id: 'ABCTV.au'
}
it('can generate valid url', () => {
expect(url({ date, channel })).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,
image: '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([])
})
const { parser, url } = require('./abc.net.au.config.js')
const fs = require('fs')
const path = require('path')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
dayjs.extend(utc)
const date = dayjs.utc('2025-02-04', 'YYYY-MM-DD').startOf('d')
const channel = { site_id: 'Sydney#ABC1' }
it('can generate valid url', () => {
expect(url({ date, channel })).toBe(
'https://cdn.iview.abc.net.au/epg/processed/Sydney_2025-02-04.json'
)
})
it('can parse response', () => {
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
const results = parser({ content, channel }).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(results.length).toBe(30)
expect(results[0]).toMatchObject({
title: "Julia Zemiro's Home Delivery",
sub_title: 'Maggie Beer',
description:
"The kitchen Maggie Beer made famous in The Cook and the Chef may be in the heart of the Barossa Valley, but our most beloved foodie meets up with Julia where she grew up in Sydney's Lakemba.",
category: ['Entertainment', 'Factual'],
rating: {
system: 'ACB',
value: 'G'
},
season: null,
episode: null,
image: 'https://www.abc.net.au/tv/common/images/publicity/LE1761H002S00_460.jpg',
start: '2025-02-03T12:40:00.000Z',
stop: '2025-02-03T13:09:00.000Z'
})
})
it('can handle empty guide', () => {
const results = parser({
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html')),
channel
})
expect(results).toMatchObject([])
})

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#7">7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#7HD">7HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#9">9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#9HD">9HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#9Rush">9Rush</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#44">44</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#SPREE">SPREE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#TENHD">TENHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Adelaide#YOUTV">YOUTV</channel>
</channels>

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#7">7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#7HD">7HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#9">9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#9HD">9HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#9Rush">9Rush</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#SPREE">SPREE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#TENHD">TENHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Brisbane#YOUTV">YOUTV</channel>
</channels>

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#ASPIR">ASPIR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#PrimS">PrimS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SCA9">SCA9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SCHD">SCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#SNR">SNR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Canberra#WINHD">WINHD</channel>
</channels>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#9">9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#9HD">9HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#ASPIR">ASPIR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#DDT">DDT</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#SC">SC</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Darwin#VICHD">VICHD</channel>
</channels>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#9">9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#9HD">9HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#10Nth">10Nth</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#NBN">NBN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#Prime">Prime</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#SNR">SNR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="GoldCoast#YOUTV">YOUTV</channel>
</channels>

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SC">SC</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SCA9">SCA9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SCHD">SCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#SHD7">SHD7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#TDHD">TDHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#TDT">TDT</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#WINHD">WINHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Hobart#YOUTV">YOUTV</channel>
</channels>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#7">7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#7HD">7HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#9">9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#9HD">9HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#9Rush">9Rush</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#31">31</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#SPREE">SPREE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#TENHD">TENHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Melbourne#YOUTV">YOUTV</channel>
</channels>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#7">7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#7GTS">7GTS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#10Nth">10Nth</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#ASPIR">ASPIR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#Imp">Imp</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#NBN">NBN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#PrimN">PrimN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#PrimS">PrimS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#SCA9">SCA9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#SCHD">SCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#SNR">SNR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#WINHD">WINHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="New South Wales#YOUTV">YOUTV</channel>
</channels>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#7C">7C</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#Imp">Imp</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Northern Territory#VICHD">VICHD</channel>
</channels>

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#7">7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#7HD">7HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#9">9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#9HD">9HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#9Rush">9Rush</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#SPREE">SPREE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#TENHD">TENHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Perth#YOUTV">YOUTV</channel>
</channels>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#7C">7C</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#7QLD">7QLD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#7TWOQ">7TWOQ</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#ASPIR">ASPIR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#Imp">Imp</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SCA9">SCA9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SCHD">SCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#SNR">SNR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Queensland#WINHD">WINHD</channel>
</channels>

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#7C">7C</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#7GTS">7GTS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#ASPIR">ASPIR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#Imp">Imp</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#SC9">SC9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#SNR">SNR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#WIN9">WIN9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#WIN10">WIN10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="South Australia#WINHD">WINHD</channel>
</channels>

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#7">7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#7HD">7HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#9">9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#9HD">9HD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#9Rush">9Rush</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#SPREE">SPREE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#TENHD">TENHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Sydney#YOUTV">YOUTV</channel>
</channels>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#ASPIR">ASPIR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SC">SC</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SCA9">SCA9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SCHD">SCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#SHD7">SHD7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#TDHD">TDHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#TDT">TDT</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#WINHD">WINHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Tasmania#YOUTV">YOUTV</channel>
</channels>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#7">7</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#SCA9">SCA9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#SCHD">SCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Townsville#WINHD">WINHD</channel>
</channels>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#7bravo">7bravo</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#7flix">7flix</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#ASPIR">ASPIR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#Prime">Prime</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SCA9">SCA9</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SCHD">SCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SHAKE">SHAKE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#SNR">SNR</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#TVSN">TVSN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#WINHD">WINHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#WinSA">WinSA</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Victoria#YOUTV">YOUTV</channel>
</channels>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#7MATE">7MATE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#7TWO">7TWO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#9Life">9Life</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#10">10</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#11">11</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#ABC1">ABC1</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#ABC2">ABC2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#ABC3">ABC3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#ABC4KIDS">ABC4KIDS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#ABCHD">ABCHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#ABCN">ABCN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#GEM">GEM</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#GO">GO</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#GWN">GWN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#NITV">NITV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#ONE">ONE</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#RTV">RTV</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#SBS">SBS</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#SBS2">SBS2</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#SBS3">SBS3</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#SBSHD">SBSHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#SBSWW">SBSWW</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#VICHD">VICHD</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#WDT">WDT</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#WIN">WIN</channel>
<channel site="abc.net.au" lang="en" xmltv_id="" site_id="Western Australia#WINHD">WINHD</channel>
</channels>

View File

@@ -2,16 +2,36 @@
https://www.abc.net.au/tv/epg/
| Region | Code |
| ------------------ | ----- |
| Sydney | `syd` |
| Melbourne | `mel` |
| Brisbane | `bri` |
| Gold Coast | `gc` |
| Perth | `per` |
| Adelaide | `adl` |
| Hobart | `hbr` |
| Darwin | `drw` |
| Canberra | `cbr` |
| New South Wales | `nsw` |
| Victoria | `vic` |
| Townsville | `tsv` |
| Queensland | `qld` |
| Western Australia | `wa` |
| South Australia | `sa` |
| Tasmania | `tas` |
| Northern Territory | `nt` |
### Download the guide
```sh
npm run grab --- --site=abc.net.au
npm run grab --- --channels=sites/abc.net.au/abc.net.au_<REGION_CODE>.channels.xml
```
### Update channel list
```sh
npm run channels:parse --- --config=./sites/abc.net.au/abc.net.au.config.js --output=./sites/abc.net.au/abc.net.au.channels.xml
npm run channels:parse --- --config=./sites/abc.net.au/abc.net.au.config.js --output=./sites/abc.net.au/abc.net.au_<REGION_CODE>.channels.xml --set=region:<REGION_CODE>
```
### Test

View File

@@ -0,0 +1 @@
{"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"}}]}]}

View File

@@ -0,0 +1 @@
{"date":"2001-11-17","categories":[],"channels":[]}

View File

@@ -31,18 +31,18 @@
<channel site="allente.dk" lang="da" xmltv_id="" site_id="1074">Discovery Channel HD (D) (T)</channel>
<channel site="allente.dk" lang="da" xmltv_id="" site_id="1075">Eurosport 1 HD (D) (T)</channel>
<channel site="allente.dk" lang="da" xmltv_id="6eren.dk" site_id="568">6'eren HD (D) (T)</channel>
<channel site="allente.dk" lang="en" xmltv_id="AlJazeeraEnglish.qa" site_id="0344">Al Jazeera English -OTT</channel>
<channel site="allente.dk" lang="en" xmltv_id="BBCNewsEurope.uk" site_id="0016">BBC News (T)</channel>
<channel site="allente.dk" lang="en" xmltv_id="AlJazeera.qa@English" site_id="0344">Al Jazeera English -OTT</channel>
<channel site="allente.dk" lang="en" xmltv_id="BBCNews.uk@Europe" site_id="0016">BBC News (T)</channel>
<channel site="allente.dk" lang="da" xmltv_id="BoomerangNordic.uk" site_id="0017">Cartoonito (T)</channel>
<channel site="allente.dk" lang="da" xmltv_id="Canal9.dk" site_id="0368">CANAL9 HD (D) (T)</channel>
<channel site="allente.dk" lang="da" xmltv_id="CartoonNetworkScandinavia.uk" site_id="0028">Cartoon Network (T)</channel>
<channel site="allente.dk" lang="da" xmltv_id="" site_id="0028">Cartoon Network (T)</channel>
<channel site="allente.dk" lang="en" xmltv_id="CNBCEurope.uk" site_id="0032">CNBC (T)</channel>
<channel site="allente.dk" lang="en" xmltv_id="CNNInternationalEurope.us" site_id="0033">CNN (T)</channel>
<channel site="allente.dk" lang="en" xmltv_id="CNNInternational.us@MENA" site_id="0033">CNN (T)</channel>
<channel site="allente.dk" lang="da" xmltv_id="dk4.dk" site_id="0376">dk4 (T)</channel>
<channel site="allente.dk" lang="da" xmltv_id="DR1.dk" site_id="452">DR1 HD (T)</channel>
<channel site="allente.dk" lang="da" xmltv_id="DR2.dk" site_id="0051">DR2 HD (T)</channel>
<channel site="allente.dk" lang="da" xmltv_id="DRRamasjang.dk" site_id="0048">DR Ramasjang (T)</channel>
<channel site="allente.dk" lang="da" xmltv_id="Eurosport2.dk" site_id="0367">Eurosport 2 HD (D) (T)</channel>
<channel site="allente.dk" lang="da" xmltv_id="Eurosport2.fr@Denmark" site_id="0367">Eurosport 2 HD (D) (T)</channel>
<channel site="allente.dk" lang="da" xmltv_id="Kanal4.dk" site_id="0064">Kanal 4 HD (D) (T)</channel>
<channel site="allente.dk" lang="da" xmltv_id="Kanal5.dk" site_id="0065">Kanal 5 HD (D) (T)</channel>
<channel site="allente.dk" lang="en" xmltv_id="MTV00s.uk" site_id="0246">MTV 00s (T)</channel>

View File

@@ -1,65 +1,65 @@
const dayjs = require('dayjs')
module.exports = {
site: 'allente.dk',
days: 2,
request: {
cache: {
ttl: 60 * 60 * 1000 // 1 hour
}
},
url({ date }) {
return `https://cs-vcb.allente.dk/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,
image: item.details.image,
season: parseSeason(item),
episode: parseEpisode(item),
start,
stop
})
})
return programs
},
async channels() {
const axios = require('axios')
const data = await axios
.get(`https://cs-vcb.allente.dk/epg/events?date=${dayjs().format('YYYY-MM-DD')}`)
.then(r => r.data)
.catch(console.log)
return data.channels.map(item => {
return {
lang: 'da',
site_id: item.id,
name: item.name
}
})
}
}
function parseItems(content, channel) {
const data = JSON.parse(content)
if (!data || !Array.isArray(data.channels)) return []
const channelData = data.channels.find(i => i.id === channel.site_id)
return channelData && Array.isArray(channelData.events) ? channelData.events : []
}
function parseSeason(item) {
return item.details.season || null
}
function parseEpisode(item) {
return item.details.episode || null
}
const dayjs = require('dayjs')
module.exports = {
site: 'allente.dk',
days: 2,
request: {
cache: {
ttl: 60 * 60 * 1000 // 1 hour
}
},
url({ date }) {
return `https://cs-vcb.allente.dk/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,
image: item.details.image,
season: parseSeason(item),
episode: parseEpisode(item),
start,
stop
})
})
return programs
},
async channels() {
const axios = require('axios')
const data = await axios
.get(`https://cs-vcb.allente.dk/epg/events?date=${dayjs().format('YYYY-MM-DD')}`)
.then(r => r.data)
.catch(console.log)
return data.channels.map(item => {
return {
lang: 'da',
site_id: item.id,
name: item.name
}
})
}
}
function parseItems(content, channel) {
const data = JSON.parse(content)
if (!data || !Array.isArray(data.channels)) return []
const channelData = data.channels.find(i => i.id === channel.site_id)
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

@@ -1,50 +1,51 @@
const { parser, url } = require('./allente.dk.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: '0148',
xmltv_id: 'SVT1.se'
}
it('can generate valid url', () => {
expect(url({ date, channel })).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.',
image:
'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([])
})
const { parser, url } = require('./allente.dk.config.js')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const customParseFormat = require('dayjs/plugin/customParseFormat')
const { readFileSync } = require('fs')
const { resolve } = require('path')
dayjs.extend(customParseFormat)
dayjs.extend(utc)
const date = dayjs.utc('2021-11-17', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: '0148',
xmltv_id: 'SVT1.se'
}
it('can generate valid url', () => {
expect(url({ date, channel })).toBe('https://cs-vcb.allente.dk/epg/events?date=2021-11-17')
})
it('can parse response', () => {
const content = readFileSync(resolve(__dirname, '__data__/content.json'))
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.',
image:
'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 @@
{"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"}}]}]}

View File

@@ -0,0 +1 @@
{"date":"2001-11-17","categories":[],"channels":[]}

View File

@@ -47,9 +47,9 @@
<channel site="allente.fi" lang="fi" xmltv_id="" site_id="1087">MTV Urheilu 2 HD (F) (T)</channel>
<channel site="allente.fi" lang="fi" xmltv_id="" site_id="1088">Eurosport 1 HD (F) (T)</channel>
<channel site="allente.fi" lang="da" xmltv_id="BoomerangNordic.uk" site_id="0017">Cartoonito (T)</channel>
<channel site="allente.fi" lang="en" xmltv_id="CartoonNetworkScandinavia.uk" site_id="0028">Cartoon Network (T)</channel>
<channel site="allente.fi" lang="en" xmltv_id="" site_id="0028">Cartoon Network (T)</channel>
<channel site="allente.fi" lang="en" xmltv_id="CNBCEurope.uk" site_id="0032">CNBC (T)</channel>
<channel site="allente.fi" lang="en" xmltv_id="CNNInternationalEurope.us" site_id="0033">CNN (T)</channel>
<channel site="allente.fi" lang="en" xmltv_id="CNNInternational.us@MENA" site_id="0033">CNN (T)</channel>
<channel site="allente.fi" lang="en" xmltv_id="MTV00s.uk" site_id="0246">MTV 00s (T)</channel>
<channel site="allente.fi" lang="fi" xmltv_id="MTVGlobal.uk" site_id="0080">MTV (Nordic) (T)</channel>
<channel site="allente.fi" lang="sv" xmltv_id="NationalGeographic.fi" site_id="0084">National Geographic HD (S/F) (T)</channel>
@@ -58,9 +58,9 @@
<channel site="allente.fi" lang="fi" xmltv_id="VFilmFamily.se" site_id="0308">V film family (T)</channel>
<channel site="allente.fi" lang="fi" xmltv_id="VFilmHits.se" site_id="0322">V film hits HD (T)</channel>
<channel site="allente.fi" lang="fi" xmltv_id="VFilmPremiere.se" site_id="0321">V film premiere HD (T)</channel>
<channel site="allente.fi" lang="fi" xmltv_id="VSport1.fi" site_id="0159">V sport 1 Suomi HD (T)</channel>
<channel site="allente.fi" lang="fi" xmltv_id="VSport1.se@Finland" site_id="0159">V sport 1 Suomi HD (T)</channel>
<channel site="allente.fi" lang="fi" xmltv_id="VSport1.se" site_id="0362">V sport 1 HD (S/F) (T)</channel>
<channel site="allente.fi" lang="fi" xmltv_id="VSport2.fi" site_id="488">V sport 2 Suomi HD (T)</channel>
<channel site="allente.fi" lang="fi" xmltv_id="VSport2.se@Finland" site_id="488">V sport 2 Suomi HD (T)</channel>
<channel site="allente.fi" lang="fi" xmltv_id="VSportFootball.se" site_id="0269">V sport football HD (T)</channel>
<channel site="allente.fi" lang="fi" xmltv_id="VSportGolf.se" site_id="0364">V sport golf HD (T)</channel>
<channel site="allente.fi" lang="fi" xmltv_id="VSportLive1.se" site_id="0255">V sport live 1 (T)</channel>

View File

@@ -1,65 +1,65 @@
const dayjs = require('dayjs')
module.exports = {
site: 'allente.fi',
days: 2,
request: {
cache: {
ttl: 60 * 60 * 1000 // 1 hour
}
},
url({ date }) {
return `https://cs-vcb.allente.fi/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,
image: item.details.image,
season: parseSeason(item),
episode: parseEpisode(item),
start,
stop
})
})
return programs
},
async channels() {
const axios = require('axios')
const data = await axios
.get(`https://cs-vcb.allente.fi/epg/events?date=${dayjs().format('YYYY-MM-DD')}`)
.then(r => r.data)
.catch(console.log)
return data.channels.map(item => {
return {
lang: 'fi',
site_id: item.id,
name: item.name
}
})
}
}
function parseItems(content, channel) {
const data = JSON.parse(content)
if (!data || !Array.isArray(data.channels)) return []
const channelData = data.channels.find(i => i.id === channel.site_id)
return channelData && Array.isArray(channelData.events) ? channelData.events : []
}
function parseSeason(item) {
return item.details.season || null
}
function parseEpisode(item) {
return item.details.episode || null
}
const dayjs = require('dayjs')
module.exports = {
site: 'allente.fi',
days: 2,
request: {
cache: {
ttl: 60 * 60 * 1000 // 1 hour
}
},
url({ date }) {
return `https://cs-vcb.allente.fi/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,
image: item.details.image,
season: parseSeason(item),
episode: parseEpisode(item),
start,
stop
})
})
return programs
},
async channels() {
const axios = require('axios')
const data = await axios
.get(`https://cs-vcb.allente.fi/epg/events?date=${dayjs().format('YYYY-MM-DD')}`)
.then(r => r.data)
.catch(console.log)
return data.channels.map(item => {
return {
lang: 'fi',
site_id: item.id,
name: item.name
}
})
}
}
function parseItems(content, channel) {
const data = JSON.parse(content)
if (!data || !Array.isArray(data.channels)) return []
const channelData = data.channels.find(i => i.id === channel.site_id)
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

@@ -1,50 +1,51 @@
const { parser, url } = require('./allente.fi.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: '0148',
xmltv_id: 'SVT1.se'
}
it('can generate valid url', () => {
expect(url({ date, channel })).toBe('https://cs-vcb.allente.fi/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.',
image:
'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([])
})
const { parser, url } = require('./allente.fi.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('2021-11-17', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: '0148',
xmltv_id: 'SVT1.se'
}
it('can generate valid url', () => {
expect(url({ date, channel })).toBe('https://cs-vcb.allente.fi/epg/events?date=2021-11-17')
})
it('can parse response', () => {
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
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.',
image:
'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: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
})
expect(result).toMatchObject([])
})

View File

@@ -0,0 +1 @@
{"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"}}]}]}

View File

@@ -0,0 +1 @@
{"date":"2001-11-17","categories":[],"channels":[]}

View File

@@ -31,15 +31,15 @@
<channel site="allente.no" lang="no" xmltv_id="" site_id="596">Sky News (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="" site_id="668">Horse &amp; Country HD -IP</channel>
<channel site="allente.no" lang="no" xmltv_id="" site_id="972">SF Kanalen (T)</channel>
<channel site="allente.no" lang="en" xmltv_id="AlJazeeraEnglish.qa" site_id="0344">Al Jazeera English -OTT</channel>
<channel site="allente.no" lang="en" xmltv_id="BBCNewsEurope.uk" site_id="0016">BBC News (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="CartoonNetworkScandinavia.uk" site_id="0028">Cartoon Network (T)</channel>
<channel site="allente.no" lang="en" xmltv_id="AlJazeera.qa@English" site_id="0344">Al Jazeera English -OTT</channel>
<channel site="allente.no" lang="en" xmltv_id="BBCNews.uk@Europe" site_id="0016">BBC News (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="" site_id="0028">Cartoon Network (T)</channel>
<channel site="allente.no" lang="en" xmltv_id="CNBCEurope.uk" site_id="0032">CNBC (T)</channel>
<channel site="allente.no" lang="en" xmltv_id="CNNInternationalEurope.us" site_id="0033">CNN (T)</channel>
<channel site="allente.no" lang="en" xmltv_id="CNNInternational.us@MENA" site_id="0033">CNN (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="DiscoveryChannel.no" site_id="532">Discovery Channel HD (N) (T)</channel>
<channel site="allente.no" lang="da" xmltv_id="DR2.dk" site_id="0051">DR2 HD (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="Eurosport.no" site_id="530">Eurosport Norge HD (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="Eurosport1.no" site_id="531">Eurosport 1 HD (N) (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="Eurosport1.fr@Norway" site_id="531">Eurosport 1 HD (N) (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="FEM.no" site_id="0056">FEM HD (T)</channel>
<channel site="allente.no" lang="sv" xmltv_id="Kunskapskanalen.se" site_id="0149">Kunskapskanalen HD (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="MAX.no" site_id="533">MAX HD (T)</channel>
@@ -73,15 +73,15 @@
<channel site="allente.no" lang="no" xmltv_id="ViasatHistory.se" site_id="0357">Viasat History HD (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VOX.no" site_id="535">VOX HD (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VSeries.se" site_id="0320">V series HD (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VSport1.no" site_id="0365">V sport 1 HD (N) (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VSport2.no" site_id="608">V sport 2 HD (N) (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VSport3.no" site_id="609">V sport 3 HD (N) (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VSport1.se@Norway" site_id="0365">V sport 1 HD (N) (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VSport2.se@Norway" site_id="608">V sport 2 HD (N) (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VSport3.se@Norway" site_id="609">V sport 3 HD (N) (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VSportGolf.se" site_id="0364">V sport golf HD (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VSportLive1.se" site_id="0255">V sport live 1 (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VSportLive2.se" site_id="0256">V sport live 2 (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VSportLive3.se" site_id="0257">V sport live 3 (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VSportLive4.se" site_id="0258">V sport live 4 (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VSportLive5.se" site_id="0259">V sport live 5 (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VSportPlus.no" site_id="0271">V sport+ HD (N) (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VSportPlus.se@Norway" site_id="0271">V sport+ HD (N) (T)</channel>
<channel site="allente.no" lang="no" xmltv_id="VSportUltraHD.se" site_id="418">V sport ultra HD (T)</channel>
</channels>

View File

@@ -1,65 +1,65 @@
const dayjs = require('dayjs')
module.exports = {
site: 'allente.no',
days: 2,
request: {
cache: {
ttl: 60 * 60 * 1000 // 1 hour
}
},
url({ date }) {
return `https://cs-vcb.allente.no/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,
image: item.details.image,
season: parseSeason(item),
episode: parseEpisode(item),
start,
stop
})
})
return programs
},
async channels() {
const axios = require('axios')
const data = await axios
.get(`https://cs-vcb.allente.no/epg/events?date=${dayjs().format('YYYY-MM-DD')}`)
.then(r => r.data)
.catch(console.log)
return data.channels.map(item => {
return {
lang: 'no',
site_id: item.id,
name: item.name
}
})
}
}
function parseItems(content, channel) {
const data = JSON.parse(content)
if (!data || !Array.isArray(data.channels)) return []
const channelData = data.channels.find(i => i.id === channel.site_id)
return channelData && Array.isArray(channelData.events) ? channelData.events : []
}
function parseSeason(item) {
return item.details.season || null
}
function parseEpisode(item) {
return item.details.episode || null
}
const dayjs = require('dayjs')
module.exports = {
site: 'allente.no',
days: 2,
request: {
cache: {
ttl: 60 * 60 * 1000 // 1 hour
}
},
url({ date }) {
return `https://cs-vcb.allente.no/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,
image: item.details.image,
season: parseSeason(item),
episode: parseEpisode(item),
start,
stop
})
})
return programs
},
async channels() {
const axios = require('axios')
const data = await axios
.get(`https://cs-vcb.allente.no/epg/events?date=${dayjs().format('YYYY-MM-DD')}`)
.then(r => r.data)
.catch(console.log)
return data.channels.map(item => {
return {
lang: 'no',
site_id: item.id,
name: item.name
}
})
}
}
function parseItems(content, channel) {
const data = JSON.parse(content)
if (!data || !Array.isArray(data.channels)) return []
const channelData = data.channels.find(i => i.id === channel.site_id)
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

@@ -1,50 +1,51 @@
const { parser, url } = require('./allente.no.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: '0148',
xmltv_id: 'SVT1.se'
}
it('can generate valid url', () => {
expect(url({ date, channel })).toBe('https://cs-vcb.allente.no/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.',
image:
'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([])
})
const { parser, url } = require('./allente.no.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('2021-11-17', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: '0148',
xmltv_id: 'SVT1.se'
}
it('can generate valid url', () => {
expect(url({ date, channel })).toBe('https://cs-vcb.allente.no/epg/events?date=2021-11-17')
})
it('can parse response', () => {
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
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.',
image:
'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: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
})
expect(result).toMatchObject([])
})

View File

@@ -0,0 +1 @@
{"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"}}]}]}

View File

@@ -0,0 +1 @@
{"date":"2001-11-17","categories":[],"channels":[]}

View File

@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="allente.se" lang="en" xmltv_id="AlJazeeraEnglish.qa" site_id="0344">Al Jazeera English -OTT</channel>
<channel site="allente.se" lang="sv" xmltv_id="AnimalPlanetNordicHD.uk" site_id="1005">Animal Planet HD (T)</channel>
<channel site="allente.se" lang="en" xmltv_id="AlJazeera.qa@English" site_id="0344">Al Jazeera English -OTT</channel>
<channel site="allente.se" lang="sv" xmltv_id="AnimalPlanetNordic.uk@HD" site_id="1005">Animal Planet HD (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="ATGLive.se" site_id="1000">ATG Live HD (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="AxessTV.se" site_id="1053">Axess TV HD -IP</channel>
<channel site="allente.se" lang="sv" xmltv_id="BBCBrit.se" site_id="1016">BBC Nordic HD (S/D/F) (T)</channel>
<channel site="allente.se" lang="en" xmltv_id="BBCNewsEurope.uk" site_id="0016">BBC News (T)</channel>
<channel site="allente.se" lang="en" xmltv_id="BloombergTVEurope.uk" site_id="1008">Bloomberg (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="BBCBrit.uk@Sweden" site_id="1016">BBC Nordic HD (S/D/F) (T)</channel>
<channel site="allente.se" lang="en" xmltv_id="BBCNews.uk@Europe" site_id="0016">BBC News (T)</channel>
<channel site="allente.se" lang="en" xmltv_id="BloombergTV.us@Europe" site_id="1008">Bloomberg (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="BoomerangNordic.uk" site_id="0017">Cartoonito (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="CartoonNetworkScandinavia.uk" site_id="0028">Cartoon Network (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="" site_id="0028">Cartoon Network (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="TV4Fotboll.se" site_id="657">TV4 Fotboll (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="TV4Hits.se" site_id="969">TV4 Hits (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="TV4Hockey.se" site_id="656">TV4 Hockey (T)</channel>
@@ -19,16 +19,16 @@
<channel site="allente.se" lang="sv" xmltv_id="TV4Motor.se" site_id="658">TV4 Motor (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="TV4Stars.se" site_id="970">TV4 Stars (T)</channel>
<channel site="allente.se" lang="en" xmltv_id="CNBCEurope.uk" site_id="0032">CNBC (T)</channel>
<channel site="allente.se" lang="en" xmltv_id="CNNInternationalEurope.us" site_id="0033">CNN (T)</channel>
<channel site="allente.se" lang="en" xmltv_id="CNNInternational.us@MENA" site_id="0033">CNN (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="DiscoveryChannel.se" site_id="493">Discovery Channel HD (S) (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="DiscoveryScience.se" site_id="1006">Discovery Science (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="DiscoveryScienceEurope.uk@Sweden" site_id="1006">Discovery Science (T)</channel>
<channel site="allente.se" lang="da" xmltv_id="DR1.dk" site_id="452">DR1 HD (T)</channel>
<channel site="allente.se" lang="da" xmltv_id="DR2.dk" site_id="0051">DR2 HD (T)</channel>
<channel site="allente.se" lang="da" xmltv_id="DRRamasjang.dk" site_id="0048">DR Ramasjang (T)</channel>
<channel site="allente.se" lang="en" xmltv_id="DWEnglish.de" site_id="1007">DW English (T)</channel>
<channel site="allente.se" lang="en" xmltv_id="DW.de@English" site_id="1007">DW English (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="Eurosport1.fr" site_id="1023">Eurosport 1 HD (S) (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="Eurosport2.fr" site_id="1024">Eurosport 2 HD (S/F) (T)</channel>
<channel site="allente.se" lang="en" xmltv_id="France24English.fr" site_id="1033">France 24 (T)</channel>
<channel site="allente.se" lang="en" xmltv_id="France24.fr@English" site_id="1033">France 24 (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="Godare.se" site_id="722">Godare HD -IP</channel>
<channel site="allente.se" lang="sv" xmltv_id="History2Nordic.us" site_id="1004">HISTORY 2 HD (T)</channel>
<channel site="allente.se" lang="sv" xmltv_id="History.se" site_id="652">HISTORY HD (S) (T)</channel>

View File

@@ -1,65 +1,65 @@
const dayjs = require('dayjs')
module.exports = {
site: 'allente.se',
days: 2,
request: {
cache: {
ttl: 60 * 60 * 1000 // 1 hour
}
},
url({ date }) {
return `https://cs-vcb.allente.se/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,
image: item.details.image,
season: parseSeason(item),
episode: parseEpisode(item),
start,
stop
})
})
return programs
},
async channels() {
const axios = require('axios')
const data = await axios
.get(`https://cs-vcb.allente.se/epg/events?date=${dayjs().format('YYYY-MM-DD')}`)
.then(r => r.data)
.catch(console.log)
return data.channels.map(item => {
return {
lang: 'sv',
site_id: item.id,
name: item.name
}
})
}
}
function parseItems(content, channel) {
const data = JSON.parse(content)
if (!data || !Array.isArray(data.channels)) return []
const channelData = data.channels.find(i => i.id === channel.site_id)
return channelData && Array.isArray(channelData.events) ? channelData.events : []
}
function parseSeason(item) {
return item.details.season || null
}
function parseEpisode(item) {
return item.details.episode || null
}
const dayjs = require('dayjs')
module.exports = {
site: 'allente.se',
days: 2,
request: {
cache: {
ttl: 60 * 60 * 1000 // 1 hour
}
},
url({ date }) {
return `https://cs-vcb.allente.se/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,
image: item.details.image,
season: parseSeason(item),
episode: parseEpisode(item),
start,
stop
})
})
return programs
},
async channels() {
const axios = require('axios')
const data = await axios
.get(`https://cs-vcb.allente.se/epg/events?date=${dayjs().format('YYYY-MM-DD')}`)
.then(r => r.data)
.catch(console.log)
return data.channels.map(item => {
return {
lang: 'sv',
site_id: item.id,
name: item.name
}
})
}
}
function parseItems(content, channel) {
const data = JSON.parse(content)
if (!data || !Array.isArray(data.channels)) return []
const channelData = data.channels.find(i => i.id === channel.site_id)
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

@@ -1,50 +1,51 @@
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: '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 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.',
image:
'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([])
})
const { parser, url } = require('./allente.se.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('2021-11-17', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: '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 parse response', () => {
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
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.',
image:
'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: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
})
expect(result).toMatchObject([])
})

View File

@@ -1,59 +1,59 @@
const cheerio = require('cheerio')
const { DateTime } = require('luxon')
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 < prev.start) {
start = start.plus({ days: 1 })
date = date.add(1, 'd')
}
prev.stop = start
}
const stop = start.plus({ hours: 1 })
programs.push({
title: item.title,
start,
stop
})
})
return programs
}
}
function parseStart(item, date) {
const dateString = `${date.format('MM/DD/YYYY')} ${item.time}`
return DateTime.fromFormat(dateString, 'MM/dd/yyyy HH:mm', { zone: 'Europe/Madrid' }).toUTC()
}
function parseItems(content, date) {
const $ = cheerio.load(content)
const day = DateTime.fromMillis(date.valueOf()).setLocale('ca').toFormat('dd LLLL').toLowerCase()
const column = $('.programacio-dia > h3 > .dia')
.filter((i, el) => $(el).text() === day.slice(0, 6) + '.')
.first()
.parent()
.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
}
const cheerio = require('cheerio')
const { DateTime } = require('luxon')
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 < prev.start) {
start = start.plus({ days: 1 })
date = date.add(1, 'd')
}
prev.stop = start
}
const stop = start.plus({ hours: 1 })
programs.push({
title: item.title,
start,
stop
})
})
return programs
}
}
function parseStart(item, date) {
const dateString = `${date.format('MM/DD/YYYY')} ${item.time}`
return DateTime.fromFormat(dateString, 'MM/dd/yyyy HH:mm', { zone: 'Europe/Madrid' }).toUTC()
}
function parseItems(content, date) {
const $ = cheerio.load(content)
const day = DateTime.fromMillis(date.valueOf()).setLocale('ca').toFormat('dd LLLL').toLowerCase()
const column = $('.programacio-dia > h3 > .dia')
.filter((i, el) => $(el).text() === day.slice(0, 6) + '.')
.first()
.parent()
.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

@@ -1,47 +1,47 @@
const { parser, url } = require('./andorradifusio.ad.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-06-07', '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 = 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[0]).toMatchObject({
start: '2023-06-07T05:00:00.000Z',
stop: '2023-06-07T06:00:00.000Z',
title: 'Club Piolet'
})
expect(results[20]).toMatchObject({
start: '2023-06-07T23:00:00.000Z',
stop: '2023-06-08T00:00:00.000Z',
title: 'Àrea Andorra Difusió'
})
})
it('can handle empty guide', () => {
const result = parser({
date,
content: '<!DOCTYPE html><html><head></head><body></body></html>'
})
expect(result).toMatchObject([])
})
const { parser, url } = require('./andorradifusio.ad.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-06-07', '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 = 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[0]).toMatchObject({
start: '2023-06-07T05:00:00.000Z',
stop: '2023-06-07T06:00:00.000Z',
title: 'Club Piolet'
})
expect(results[20]).toMatchObject({
start: '2023-06-07T23:00:00.000Z',
stop: '2023-06-08T00:00:00.000Z',
title: 'Àrea Andorra Difusió'
})
})
it('can handle empty guide', () => {
const result = parser({
date,
content: '<!DOCTYPE html><html><head></head><body></body></html>'
})
expect(result).toMatchObject([])
})

View File

@@ -35,7 +35,7 @@
<channel site="anteltv.com.uy" lang="es" xmltv_id="Canal23Florida.uy" site_id="2s6n6">Canal 23 Florida</channel>
<channel site="anteltv.com.uy" lang="es" xmltv_id="CardinalTV.uy" site_id="2s6pw">Cardinal TV</channel>
<channel site="anteltv.com.uy" lang="es" xmltv_id="DuraznoTV.uy" site_id="2s6rm">Durazno TV</channel>
<channel site="anteltv.com.uy" lang="es" xmltv_id="DWEspanol.de" site_id="2s689">DW (Español)</channel>
<channel site="anteltv.com.uy" lang="es" xmltv_id="DW.de@Espanol" site_id="2s689">DW (Español)</channel>
<channel site="anteltv.com.uy" lang="es" xmltv_id="ElCanaldelaRegion.uy" site_id="2s6rb">El Canal de la Región - Noreste Canelones</channel>
<channel site="anteltv.com.uy" lang="es" xmltv_id="FTC.uy" site_id="2s6rj">Florida Televisora Color HD</channel>
<channel site="anteltv.com.uy" lang="es" xmltv_id="LatinaTVPaysandu.uy" site_id="2s6rd">Latina TV Paysandú</channel>

View File

@@ -1,108 +1,108 @@
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://cds-frontend.vera.com.uy/api-contenidos'
module.exports = {
site: 'anteltv.com.uy',
days: 2,
async url({ date, channel }) {
const session = await loadSessionDetails()
if (!session || !session.token) return null
return `${API_ENDPOINT}/canales/epg/${
channel.site_id
}?limit=500&dias_siguientes=0&fecha=${date.format('YYYY-MM-DD')}&token=${session.token}`
},
request: {
async headers() {
const session = await loadSessionDetails()
if (!session || !session.jwt) return null
return {
authorization: `Bearer ${session.jwt}`,
'x-frontend-id': 1196,
'x-service-id': 3,
'x-system-id': 1
}
}
},
parser({ content }) {
let programs = []
let items = parseItems(content)
items.forEach(item => {
programs.push({
title: item.nombre_programa,
sub_title: item.subtitle,
description: item.descripcion_programa,
start: parseStart(item),
stop: parseStop(item)
})
})
return programs
},
async channels() {
const session = await loadSessionDetails()
if (!session || !session.jwt || !session.token) return null
const data = await axios
.get(`${API_ENDPOINT}/listas/68?token=${session.token}`, {
headers: {
authorization: `Bearer ${session.jwt}`,
'x-frontend-id': 1196,
'x-service-id': 3,
'x-system-id': 1
}
})
.then(r => r.data)
.catch(console.error)
return data.contenidos.map(c => {
return {
lang: 'es',
site_id: c.public_id,
name: c.nombre
}
})
}
}
function parseStart(item) {
return dayjs.tz(item.fecha_hora_inicio, 'YYYY-MM-DD HH:mm:ss', 'America/Montevideo')
}
function parseStop(item) {
return dayjs.tz(item.fecha_hora_fin, 'YYYY-MM-DD HH:mm:ss', 'America/Montevideo')
}
function parseItems(content) {
const data = JSON.parse(content)
if (!data || !Array.isArray(data.data)) return []
return data.data
}
function loadSessionDetails() {
return axios
.post(
'https://veratv-be.vera.com.uy/api/sesiones',
{
tipo: 'anonima'
},
{
headers: {
'Content-Type': 'application/json'
}
}
)
.then(r => r.data)
.catch(console.log)
}
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://cds-frontend.vera.com.uy/api-contenidos'
module.exports = {
site: 'anteltv.com.uy',
days: 2,
async url({ date, channel }) {
const session = await loadSessionDetails()
if (!session || !session.token) return null
return `${API_ENDPOINT}/canales/epg/${
channel.site_id
}?limit=500&dias_siguientes=0&fecha=${date.format('YYYY-MM-DD')}&token=${session.token}`
},
request: {
async headers() {
const session = await loadSessionDetails()
if (!session || !session.jwt) return null
return {
authorization: `Bearer ${session.jwt}`,
'x-frontend-id': 1196,
'x-service-id': 3,
'x-system-id': 1
}
}
},
parser({ content }) {
let programs = []
let items = parseItems(content)
items.forEach(item => {
programs.push({
title: item.nombre_programa,
sub_title: item.subtitle,
description: item.descripcion_programa,
start: parseStart(item),
stop: parseStop(item)
})
})
return programs
},
async channels() {
const session = await loadSessionDetails()
if (!session || !session.jwt || !session.token) return null
const data = await axios
.get(`${API_ENDPOINT}/listas/68?token=${session.token}`, {
headers: {
authorization: `Bearer ${session.jwt}`,
'x-frontend-id': 1196,
'x-service-id': 3,
'x-system-id': 1
}
})
.then(r => r.data)
.catch(console.error)
return data.contenidos.map(c => {
return {
lang: 'es',
site_id: c.public_id,
name: c.nombre
}
})
}
}
function parseStart(item) {
return dayjs.tz(item.fecha_hora_inicio, 'YYYY-MM-DD HH:mm:ss', 'America/Montevideo')
}
function parseStop(item) {
return dayjs.tz(item.fecha_hora_fin, 'YYYY-MM-DD HH:mm:ss', 'America/Montevideo')
}
function parseItems(content) {
const data = JSON.parse(content)
if (!data || !Array.isArray(data.data)) return []
return data.data
}
function loadSessionDetails() {
return axios
.post(
'https://veratv-be.vera.com.uy/api/sesiones',
{
tipo: 'anonima'
},
{
headers: {
'Content-Type': 'application/json'
}
}
)
.then(r => r.data)
.catch(console.log)
}

View File

@@ -1,85 +1,85 @@
const { parser, url, request } = require('./anteltv.com.uy.config.js')
const fs = require('fs')
const axios = require('axios')
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)
jest.mock('axios')
axios.post.mockImplementation((url, data, opts) => {
if (
url === 'https://veratv-be.vera.com.uy/api/sesiones' &&
JSON.stringify(opts.headers) ===
JSON.stringify({
'Content-Type': 'application/json'
}) &&
JSON.stringify(data) ===
JSON.stringify({
tipo: 'anonima'
})
) {
return Promise.resolve({
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/session.json')))
})
} else {
return Promise.resolve({
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/no_session.json')))
})
}
})
const date = dayjs.utc('2023-02-11', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: '2s6nd',
xmltv_id: 'Canal5.uy'
}
it('can generate valid url', async () => {
const result = await url({ date, channel })
expect(result).toBe(
'https://cds-frontend.vera.com.uy/api-contenidos/canales/epg/2s6nd?limit=500&dias_siguientes=0&fecha=2023-02-11&token=MpDY52p1V6g511VSABp1015B'
)
})
it('can generate valid request headers', async () => {
const result = await request.headers()
expect(result).toMatchObject({
authorization:
'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOnsidGlwbyI6ImFub25pbWEifSwic3ViIjoiTXBEWTUycDFWNmc1MTFWU0FCcDEwMTVCIiwicHJuIjp7ImlkX3NlcnZpY2lvIjozLCJpZF9mcm9udGVuZCI6MTE5NiwiaXAiOiIxNzkuMjcuMTU0LjI0MiIsImlwX3JlZmVyZW5jaWFkYSI6IjE4OC4yNDIuNDguOTMiLCJpZF9kaXNwb3NpdGl2byI6MH0sImF1ZCI6IkFwcHNcL1dlYnMgRnJvbnRlbmRzIiwiaWF0IjoxNjc1ODI3NDU2LCJleHAiOjE2NzU4NDkwNTZ9.8bAQciQl5DOIZF7GgCl6ad-KJUSpqQREetozGv_IH5s',
'x-frontend-id': 1196,
'x-service-id': 3,
'x-system-id': 1
})
})
it('can parse response', () => {
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'), 'utf8')
let results = parser({ content })
results = results.map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(results[0]).toMatchObject({
start: '2023-02-11T02:30:00.000Z',
stop: '2023-02-11T04:00:00.000Z',
title: 'Canal 5 Noticias rep.',
sub_title: '',
description: ''
})
})
it('can handle empty guide', () => {
const results = parser({
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'), 'utf8')
})
expect(results).toMatchObject([])
})
const { parser, url, request } = require('./anteltv.com.uy.config.js')
const fs = require('fs')
const axios = require('axios')
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)
jest.mock('axios')
axios.post.mockImplementation((url, data, opts) => {
if (
url === 'https://veratv-be.vera.com.uy/api/sesiones' &&
JSON.stringify(opts.headers) ===
JSON.stringify({
'Content-Type': 'application/json'
}) &&
JSON.stringify(data) ===
JSON.stringify({
tipo: 'anonima'
})
) {
return Promise.resolve({
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/session.json')))
})
} else {
return Promise.resolve({
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/no_session.json')))
})
}
})
const date = dayjs.utc('2023-02-11', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: '2s6nd',
xmltv_id: 'Canal5.uy'
}
it('can generate valid url', async () => {
const result = await url({ date, channel })
expect(result).toBe(
'https://cds-frontend.vera.com.uy/api-contenidos/canales/epg/2s6nd?limit=500&dias_siguientes=0&fecha=2023-02-11&token=MpDY52p1V6g511VSABp1015B'
)
})
it('can generate valid request headers', async () => {
const result = await request.headers()
expect(result).toMatchObject({
authorization:
'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOnsidGlwbyI6ImFub25pbWEifSwic3ViIjoiTXBEWTUycDFWNmc1MTFWU0FCcDEwMTVCIiwicHJuIjp7ImlkX3NlcnZpY2lvIjozLCJpZF9mcm9udGVuZCI6MTE5NiwiaXAiOiIxNzkuMjcuMTU0LjI0MiIsImlwX3JlZmVyZW5jaWFkYSI6IjE4OC4yNDIuNDguOTMiLCJpZF9kaXNwb3NpdGl2byI6MH0sImF1ZCI6IkFwcHNcL1dlYnMgRnJvbnRlbmRzIiwiaWF0IjoxNjc1ODI3NDU2LCJleHAiOjE2NzU4NDkwNTZ9.8bAQciQl5DOIZF7GgCl6ad-KJUSpqQREetozGv_IH5s',
'x-frontend-id': 1196,
'x-service-id': 3,
'x-system-id': 1
})
})
it('can parse response', () => {
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'), 'utf8')
let results = parser({ content })
results = results.map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(results[0]).toMatchObject({
start: '2023-02-11T02:30:00.000Z',
stop: '2023-02-11T04:00:00.000Z',
title: 'Canal 5 Noticias rep.',
sub_title: '',
description: ''
})
})
it('can handle empty guide', () => {
const results = parser({
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'), 'utf8')
})
expect(results).toMatchObject([])
})

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,877 @@
<!doctype html>
<!--[if IE 7]><html class="ie7" lang="el"> <!
[endif]-->[endif]--><!--[if IE 8]><html class="ie8" lang="el"> <!
[endif]-->[endif]--><!--[if IE 9]><html class="ie9" lang="el"> <![endif]-->
<!--[if !IE]><!--><html lang="el" itemscope itemtype="http://schema.org/WebPage"><!--<![endif]-->
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" lang="el" />
<meta http-equiv="content-language" content="el-gr" />
<title>Πρόγραμμα</title>
<meta name="description" content="cms39" />
<meta name="keywords" content="" />
<meta name="ROBOTS" content="INDEX, FOLLOW" />
<link
rel="search"
type="application/opensearchdescription+xml"
href="https://www.antennaeurope.gr/opensearch.php"
title="Website search"
/>
<link href="" rel="publisher" />
<meta http-equiv="Cache-control" content="public" />
<meta http-equiv="Cache-control" content="max-age=86400" />
<meta name="designer" content="www.cdl.gr" />
<meta name="generator" content="CMS39 FRAMEWORK v8.9.9.1" />
<meta name="copyright" content="antennaeurope.gr" />
<link rel="alternate" hreflang="el" href="https://www.antennaeurope.gr/el/tvguide.html" />
<link rel="alternate" hreflang="en" href="https://www.antennaeurope.gr/en/tvguide.html" />
<meta property="fb:app_id" content="966242223397117" />
<meta property="og:locale" content="el" />
<meta property="og:type" content="website" />
<meta
property="og:url"
content="https://www.antennaeurope.gr/el/tvguide.html?date=2026-01-21"
/>
<meta property="og:site_name" content="antennaeurope.gr" />
<meta property="og:title" content="Πρόγραμμα" />
<meta property="og:description" content="cms39" />
<meta
property="og:image"
content="https://www.antennaeurope.gr/media/upload-files/cache/4eb/4eb861bdce3a42bab32e27c55aecbcfa_europelogo.jpg"
/>
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<script type="text/javascript">
var Durl = 'https://www.antennaeurope.gr/el'
var Turl = 'https://www.antennaeurope.gr/themes/default'
var url = 'https://www.antennaeurope.gr'
var Aurl = 'https://www.antennaeurope.gr/administrator/cp_ajax?f='
var lang = 'el'
var lang_symbol = 'el'
var siteName = 'antennaeurope.gr'
var siteV = '5.7.3'
var Purl = 'https://www.antennaeurope.gr/public/plugins'
</script>
<link
rel="alternate"
type="application/rss+xml"
title="antennaeurope.gr Feed"
href="https://www.antennaeurope.gr/rss.php"
/>
<link
rel="apple-touch-icon"
sizes="57x57"
href="https://www.antennaeurope.gr/themes/default/img/ico/apple-icon-57x57.png"
/>
<link
rel="apple-touch-icon"
sizes="60x60"
href="https://www.antennaeurope.gr/themes/default/img/ico/apple-icon-60x60.png"
/>
<link
rel="apple-touch-icon"
sizes="72x72"
href="https://www.antennaeurope.gr/themes/default/img/ico/apple-icon-72x72.png"
/>
<link
rel="apple-touch-icon"
sizes="76x76"
href="https://www.antennaeurope.gr/themes/default/img/ico/apple-icon-76x76.png"
/>
<link
rel="apple-touch-icon"
sizes="114x114"
href="https://www.antennaeurope.gr/themes/default/img/ico/apple-icon-114x114.png"
/>
<link
rel="apple-touch-icon"
sizes="120x120"
href="https://www.antennaeurope.gr/themes/default/img/ico/apple-icon-120x120.png"
/>
<link
rel="apple-touch-icon"
sizes="144x144"
href="https://www.antennaeurope.gr/themes/default/img/ico/apple-icon-144x144.png"
/>
<link
rel="apple-touch-icon"
sizes="152x152"
href="https://www.antennaeurope.gr/themes/default/img/ico/apple-icon-152x152.png"
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="https://www.antennaeurope.gr/themes/default/img/ico/apple-icon-180x180.png"
/>
<link
rel="icon"
type="image/png"
sizes="192x192"
href="https://www.antennaeurope.gr/themes/default/img/ico/android-icon-192x192.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="https://www.antennaeurope.gr/themes/default/img/ico/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="96x96"
href="https://www.antennaeurope.gr/themes/default/img/ico/favicon-96x96.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="https://www.antennaeurope.gr/themes/default/img/ico/favicon-16x16.png"
/>
<link rel="manifest" href="https://www.antennaeurope.gr/themes/default/manifest.json" />
<meta
name="msapplication-TileImage"
content="https://www.antennaeurope.gr/themes/default/img/ico/ms-icon-144x144.png"
/>
<meta name="theme-color" content="#000000" />
<meta name="msapplication-navbutton-color" content="#000000" />
<meta name="apple-mobile-web-app-status-bar-style" content="#000000" />
<script type="text/javascript">
var contact_url = 'https://www.antennaeurope.gr'
var contact_field_message_min = '20'
var contact_field_message_max = '100'
var contact_lang = 'el'
</script>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/owl.carousel@2.2.0/dist/assets/owl.carousel.min.css"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/owl.carousel@2.2.0/dist/assets/owl.theme.default.min.css"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/jquery-typeahead@2.11.1/dist/jquery.typeahead.min.css"
/>
<link
rel="stylesheet"
href="https://www.antennaeurope.gr/plugins/cms39_search/cms39_search.css?v=4.5"
/>
<link rel="stylesheet" href="https://www.antennaeurope.gr/plugins/contactform/contact.css" />
<script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-118808483-1"></script>
<script>
window.dataLayer = window.dataLayer || []
function gtag() {
dataLayer.push(arguments)
}
gtag('js', new Date())
gtag('config', 'UA-118808483-1')
</script>
<link
rel="stylesheet"
type="text/css"
href="https://www.antennaeurope.gr/themes/default/style.css?version=5.7.3"
/>
<!--[if lt IE 9]>
<script src="//cdn.jsdelivr.net/html5shiv/3.7.2/html5shiv-printshiv.min.js"></script>
<script src="//cdn.jsdelivr.net/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body class="el css_100 css_tvguide css_0 css_page css_page css_root_100 desktop">
<div class="masterWraper">
<header>
<div class="container-fluid">
<a class="logo" href="https://www.antennaeurope.gr/el/home.html" title="antennaeurope.gr"
><img
alt="logo antennaeurope.gr"
src="https://www.antennaeurope.gr/themes/default/img/eur.svg"
/></a>
<div class="colarea1">
<div class="col1inner">
<div class="text-right colmenu">
<button
class="menu-toggle"
data-toggle="collapse"
data-target="#collapseMenu"
aria-expanded="false"
aria-controls="collapseMenu"
>
<span class="menu-icon">
<span class="first"></span> <span class="second"></span>
<span class="third"></span>
</span>
</button>
</div>
<div class="col-sitesearch text-left">
<div
class="site-search grid__col-auto grid--justify-center grid--align-center visible__sm"
>
<button
class="search-btn"
data-toggle="collapse"
data-target="#collapseSearch"
aria-expanded="false"
aria-controls="collapseSearch"
>
<i class="fa fa-search" aria-hidden="true"></i>
</button>
</div>
</div>
</div>
</div>
<div class="colarea2"><ul class="list-inline"></ul></div>
<div class="colarea3 col-live-now text-right">
<a class="playnow" title="more information" data-bid="" data-dum="" href="#"
><span class="highlight">Παίζει τώρα</span></a
>
<ul class="list-inline lang-list">
<li class="cms39_language_loop cms39_language_loop_li_el active">
<a
class="cms39_language_link_el active"
title="Ελληνικά"
href="https://www.antennaeurope.gr/el/tvguide.html"
>Ελληνικά</a
>
</li>
<li class="cms39_language_loop cms39_language_loop_li_en">
<a
class="cms39_language_link_en"
title="English"
href="https://www.antennaeurope.gr/en/tvguide.html"
>English</a
>
</li>
</ul>
</div>
</div>
</header>
<div id="collapseMenu" class="collapse">
<form
role="search"
class="searchform"
id="searchform"
action="https://www.antennaeurope.gr/el/search.html"
method="GET"
>
<div class="typeahead__container">
<div class="typeahead__field">
<span class="typeahead__query">
<label for="searchform_q" class="hidden">εύρεση</label>
<input
class="js-typeahead searchformField form-control"
type="search"
autocomplete="off"
placeholder="Αναζήτηση"
value=""
name="q"
id="searchform_q"
required
/>
</span>
<span class="typeahead__button">
<button type="submit" class="searchformSubmit btn btn-default" title="search site">
<span class="typeahead__search-icon"></span>
</button>
</span>
<input data-storage="false" type="hidden" name="date" value="2026-01-21" />
</div>
</div>
</form>
<nav class="cms39-header-nav">
<ul id="cms39-header-nav" class="cms39-navbar-nav ul-29">
<li class="active">
<a
title="Πρόγραμμα"
href="https://www.antennaeurope.gr/el/tvguide.html"
class="active"
>Πρόγραμμα</a
>
</li>
<li class="">
<a title="Εκπομπές" href="https://www.antennaeurope.gr/el/shows.html" class=""
>Εκπομπές</a
>
</li>
<li class="">
<a title="Συνδεθείτε " href="https://www.antennaeurope.gr/el/connect.html" class=""
>Συνδεθείτε
</a>
</li>
<li class="">
<a title="Links" href="https://www.antennaeurope.gr/el/links.html" class="">Links</a>
</li>
<li class="">
<a title="Επικοινωνία" href="https://www.antennaeurope.gr/el/contact.html" class=""
>Επικοινωνία</a
>
</li>
</ul>
</nav>
<div class="site-social grid__cell-footer">
<ul class="grid">
<li>
<a href="https://www.facebook.com/antenna.europe/" target="_blank">
<span class="icon icon-facebook"
><span class="screen-reader-text"><i class="fab fa-facebook-f"></i></span
></span>
</a>
</li>
<li>
<a href="" target="_blank">
<span class="icon icon-twitter"
><span class="screen-reader-text"><i class="fab fa-twitter"></i></span
></span>
</a>
</li>
<li>
<a href="https://www.instagram.com/antenna.europe/" target="_blank">
<span class="icon icon-instagram"
><span class="screen-reader-text"><i class="fab fa-instagram"></i></span
></span>
</a>
</li>
<li>
<a href="" target="_blank">
<span class="icon icon-youtube"
><span class="screen-reader-text"><i class="fab fa-youtube"></i></span
></span>
</a>
</li>
</ul>
<!-- .site-social -->
</div>
<ul class="list-inline lang-list">
<li class="cms39_language_loop cms39_language_loop_li_el active">
<a
class="cms39_language_link_el active"
title="Ελληνικά"
href="https://www.antennaeurope.gr/el/tvguide.html"
>Ελληνικά</a
>
</li>
<li class="cms39_language_loop cms39_language_loop_li_en">
<a
class="cms39_language_link_en"
title="English"
href="https://www.antennaeurope.gr/en/tvguide.html"
>English</a
>
</li>
</ul>
</div>
<div id="collapseSearch" class="collapse">
<div class="inner">
<div class="container-fluid">
<form
role="search"
class="searchform"
id="searchform"
action="https://www.antennaeurope.gr/el/search.html"
method="GET"
>
<div class="typeahead__container">
<div class="typeahead__field">
<span class="typeahead__query">
<label for="searchform_q" class="hidden">εύρεση</label>
<input
class="js-typeahead searchformField form-control"
type="search"
autocomplete="off"
placeholder="Αναζήτηση"
value=""
name="q"
id="searchform_q"
required
/>
</span>
<span class="typeahead__button">
<button
type="submit"
class="searchformSubmit btn btn-default"
title="search site"
>
<span class="typeahead__search-icon"></span>
</button>
</span>
<input data-storage="false" type="hidden" name="date" value="2026-01-21" />
</div>
</div>
</form>
<div class="info">Άρχισε να πληκτρολογείς οτιδήποτε</div>
</div>
</div>
</div>
<div class="ant1col2">
<div class="featuredContentContainer container-fluid">
<div class="row">
<div class="col-12 col-sm-8">
<article class="programme-container">
<div id="programmeCalendar" class="calendar-horizontal">
<div class="showCarousel owl-carousel">
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennaeurope.gr/el/tvguide.html?date=2025-01-16"
>Πέμπτη <span>16/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennaeurope.gr/el/tvguide.html?date=2025-01-17"
>Παρασκευή <span>17/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennaeurope.gr/el/tvguide.html?date=2025-01-18"
>Σάββατο <span>18/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennaeurope.gr/el/tvguide.html?date=2025-01-19"
>Κυριακή <span>19/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennaeurope.gr/el/tvguide.html?date=2025-01-20"
>Δευτέρα <span>20/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennaeurope.gr/el/tvguide.html?date=2025-01-21"
>Τρίτη <span>21/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennaeurope.gr/el/tvguide.html?date=2025-01-22"
>Τετάρτη <span>22/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennaeurope.gr/el/tvguide.html?date=2025-01-23"
>Πέμπτη <span>23/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennaeurope.gr/el/tvguide.html?date=2025-01-24"
>Παρασκευή <span>24/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennaeurope.gr/el/tvguide.html?date=2025-01-25"
>Σάββατο <span>25/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennaeurope.gr/el/tvguide.html?date=2025-01-26"
>Κυριακή <span>26/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennaeurope.gr/el/tvguide.html?date=2025-01-27"
>Δευτέρα <span>27/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennaeurope.gr/el/tvguide.html?date=2025-01-28"
>Τρίτη <span>28/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennaeurope.gr/el/tvguide.html?date=2025-01-29"
>Τετάρτη <span>29/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennaeurope.gr/el/tvguide.html?date=2025-01-30"
>Πέμπτη <span>30/1</span></a
>
</div>
</div>
</div>
<div id="programmeContent" class="programme-content">
<div class="row">
<div class="day col-12 col-sm-2">
<p>Τετάρτη<br />21/1</p>
</div>
<div class="shows col-12 col-sm-10 sentoni">
<div id="earlierContainer" class="programme-earlier-container"></div>
</div>
</div>
</div>
</article>
</div>
<div class="col-12 col-sm-4 sidebararea">
<div class="banner-placeholder vertical light">
<ins
data-revive-zoneid="8"
data-revive-target="_blank"
data-revive-ct0="80535266"
data-revive-block="1"
data-revive-blockcampaign="1"
data-revive-id="30a34a2302634ff5d170d39f518891d2"
></ins>
<script async src="//dfp.cdl.gr/www/delivery/asyncjs.php"></script>
<div class="banner2">
<ins
data-revive-zoneid="8"
data-revive-target="_blank"
data-revive-ct0="83289214"
data-revive-block="1"
data-revive-blockcampaign="1"
data-revive-id="30a34a2302634ff5d170d39f518891d2"
></ins>
<script async src="//dfp.cdl.gr/www/delivery/asyncjs.php"></script>
</div>
</div>
<div class="sidebararea-promo"><h1 class="h1">Δες επίσης</h1></div>
<div class="sidebararea-promo"></div>
</div>
</div>
</div>
</div>
<div class="new-episodes">
<h1 class="h1">Νέο Πρόγραμμα</h1>
<div id="footerFshows" class="owl-carousel owl-theme">
<div class="show">
<div class="inner">
<img
alt="ΥΓΕΙΑ ΠΑΝΩ ΑΠ’ ΟΛΑ"
src="https://www.antennaeurope.gr/media/upload-files/cache/42a/42a69c6936c865b6cb1555da86b8101f_ygeiapanwapolaprogramma.jpg"
/>
<div class="content">
<h2>ΥΓΕΙΑ ΠΑΝΩ ΑΠ’ ΟΛΑ</h2>
<p class="excerpt">
Το «Υγεία πάνω απ’ όλα» με τη Φωτεινή Γεωργίου, συνεχίζει για 13η χρονιά!
</p>
<a
title="ΥΓΕΙΑ ΠΑΝΩ ΑΠ’ ΟΛΑ"
class="more"
href="https://www.antennaeurope.gr/el/igia-pano-ap-ola.html"
>Δες περισσότερα</a
>
</div>
</div>
</div>
<div class="show">
<div class="inner">
<img
alt="ΡΟΥΚ ΖΟΥΚ"
src="https://www.antennaeurope.gr/media/upload-files/cache/7dc/7dcad32b0490fd5e2f4eb944fdd13d4c_roukzoukprogramma.jpg"
/>
<div class="content">
<h2>ΡΟΥΚ ΖΟΥΚ</h2>
<p class="excerpt">
Το «Rouk Zouk» για  χρονιά με την απολαυστική Ζέτα Μακρυπούλια στα «decks» του
αγαπημένου παιχνιδιού!
</p>
<a
title="ΡΟΥΚ ΖΟΥΚ"
class="more"
href="https://www.antennaeurope.gr/el/rouk-zouk.html"
>Δες περισσότερα</a
>
</div>
</div>
</div>
<div class="show">
<div class="inner">
<img
alt="ΡΑΔΙΟ ΑΡΒΥΛΑ"
src="https://www.antennaeurope.gr/media/upload-files/cache/356/356e9b3db418c002aa7bb59095c2887d_radioarvylaprogramma.jpg"
/>
<div class="content">
<h2>ΡΑΔΙΟ ΑΡΒΥΛΑ</h2>
<p class="excerpt">
Όλοι οι τηλεοπτικοί δρόμοι οδηγούν στην καυστική σάτιρα και στους μοναδικούς
«Ράδιο Αρβύλα» για 18η χρονιά!  
</p>
<a
title="ΡΑΔΙΟ ΑΡΒΥΛΑ"
class="more"
href="https://www.antennaeurope.gr/el/radio-arvila.html"
>Δες περισσότερα</a
>
</div>
</div>
</div>
<div class="show">
<div class="inner">
<img
alt=" THE 2NIGHT SHOW"
src="https://www.antennaeurope.gr/media/upload-files/cache/f30/f3041bf52188897fbb8a57509f5a1207_2nightshowprogramma.jpg"
/>
<div class="content">
<h2>THE 2NIGHT SHOW</h2>
<p class="excerpt">
Οι πιο ενδιαφέρουσες νυχτερινές εξομολογήσεις με τον Γρηγόρη Αρναούτογλου!
</p>
<a
title=" THE 2NIGHT SHOW"
class="more"
href="https://www.antennaeurope.gr/el/the-2night-show.html"
>Δες περισσότερα</a
>
</div>
</div>
</div>
<div class="show">
<div class="inner">
<img
alt="THE REUNION"
src="https://www.antennaeurope.gr/media/upload-files/cache/7f5/7f5502d928d0d36f21be192aa53f062e_thereunionprogramma.jpg"
/>
<div class="content">
<h2>THE REUNION</h2>
<p class="excerpt">
Πριν από 10 χρόνια, δύο φίλοι, ο Σάκης Τανιμανίδης και ο Γιώργος Μαυρίδης,
ξεκίνησαν ένα ταξίδι που άλλαξε τη ζωή τους για πάντα. Σήμερα, ένας πατέρας,
πλέον, και ένας
</p>
<a
title="THE REUNION"
class="more"
href="https://www.antennaeurope.gr/el/the-reunion.html"
>Δες περισσότερα</a
>
</div>
</div>
</div>
</div>
</div>
<footer>
<div class="container-fluid">
<div class="row">
<div class="col-12 col-sm-8 foot_1">
<h2>Εγγραφή στο ενημερωτικό δελτίο</h2>
<form action="#" id="subscribeform" name="newsletter" method="post">
<label for="newsletterEmail" class="screen-reader-text">Το email σου</label>
<input
id="newsletterEmail"
type="email"
name="email"
placeholder="Το email σου"
required
/>
<input type="submit" name="submit" value="Εγγραφή" />
<input type="hidden" name="__mail_required" value="email" />
<input type="hidden" name="__mail_subject" value="Antenna Europe Newsletter form" />
<input
type="hidden"
name="__mail_success"
value="Thank you and welcome to our Newsletter Service!"
/>
<input
type="hidden"
name="url"
value="https://www.antennaeurope.gr/el/tvguide.html?date=2026-01-21"
/>
<input type="hidden" name="datetime" value="2025-01-17 00:34:36" />
<div id="subscribeformMSG"></div>
</form>
</div>
<div class="col-12 col-sm-4 foot_2">
<h2>Ακολουθήστε μας</h2>
<ul class="site-social grid">
<li>
<a href="https://www.facebook.com/antenna.europe/" target="_blank">
<span class="icon icon-facebook">
<span class="screen-reader-text"><i class="fab fa-facebook-f"></i></span>
</span>
</a>
</li>
<li>
<a href="https://www.instagram.com/antenna.europe/" target="_blank">
<span class="icon icon-instagram">
<span class="screen-reader-text"><i class="fab fa-instagram"></i></span>
</span>
</a>
</li>
</ul>
<nav class="cms39-footer-nav">
<ul id="cms39-footer-nav" class="cms39-footer-nav ul-106">
<li class="">
<a
title="Επικοινωνία"
href="https://www.antennaeurope.gr/el/contact.html"
class=""
>Επικοινωνία</a
>
</li>
<li class="">
<a
title="Συνδεθείτε "
href="https://www.antennaeurope.gr/el/connect.html"
class=""
>Συνδεθείτε
</a>
</li>
<li class="">
<a
title="Εργασία"
href="https://www.antennaeurope.gr/el/workwithus.html"
class=""
>Εργασία</a
>
</li>
<li class="">
<a
title="Διαφημιστείτε"
href="https://www.antennaeurope.gr/el/advertise.html"
class=""
>Διαφημιστείτε</a
>
</li>
<li class="">
<a title="Για εμάς" href="https://www.antennaeurope.gr/el/about.html" class=""
>Για εμάς</a
>
</li>
<li class="">
<a title="Links" href="https://www.antennaeurope.gr/el/links.html" class=""
>Links</a
>
</li>
<li class="">
<a
title="Όροι χρήσης"
href="https://www.antennaeurope.gr/el/terms.html"
class=""
>Όροι χρήσης</a
>
</li>
<li class="">
<a title="FAQ" href="https://www.antennaeurope.gr/el/faq.html" class="">FAQ</a>
</li>
<li class="">
<a
title="Δελτία Τύπου"
href="https://www.antennaeurope.gr/el/press.html"
class=""
>Δελτία Τύπου</a
>
</li>
</ul>
</nav>
</div>
<div class="col-12 foot_3 text-dark text-theme-copyright">
© 2025 ANT1 TV | 2025-01-17 00:34:36
</div>
</div>
</div>
</footer>
<div class="copyright text-center">
<div id="cdl" style="display: inline-block">
<span style="width: 49px; height: 43px; overflow: hidden; display: block">
<a
rel="external"
style="display: block; margin: 0px"
target="_blank"
title="Array"
href="https://www.cdl.gr"
>
<img
width="49"
height="43"
alt="Array"
src="https://www.cdl.gr/media/upload-files/cdl-logo-white.png"
/>
</a>
<a
rel="external"
style="visibility: hidden; display: none margin: 0px;"
title="Θέλεις κονκάρδες από το αγαπημένο σου συγκρότημα, κονκάρδες για το bachelor σου, κονκάρδες για τους καλεσμένους σου, κονκάρδες για το party των παιδιών σου, κονκάρδες για την προώθηση της επιχειρησης σου; Τα πάντα για κονκάρδες μόνο στο concarda.com"
href="http://www.concarda.com"
target="_blank"
>για κονκάρδες μόνο στο concarda.com</a
>
</span>
</div>
</div>
</div>
<!-- created by https://www.cdl.gr Creative Studio, κατασκευή ιστοσελίδων, ιστοσελίδες, digital agency. -->
<script type="text/javascript">
var search_autocomplete_template = '<span>{{title}}</span>'
var search_autocomplete_limit = '10'
var search_autocomplete_minLength = '3'
var search_autocomplete_emptyTemplate = 'No results found for {{query}}'
</script>
<script
type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
></script>
<script
type="text/javascript"
src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/block-ui@2.70.1/jquery.blockUI.min.js"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/owl.carousel@2.2.0/dist/owl.carousel.min.js"
></script>
<script
type="text/javascript"
src="https://use.fontawesome.com/releases/v5.0.8/js/all.js"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/jquery-form@4.2.2/dist/jquery.form.min.js"
></script>
<script
type="text/javascript"
src="https://www.antennaeurope.gr/themes/default/js/plugins.js"
></script>
<script
type="text/javascript"
src="https://www.antennaeurope.gr/themes/default/js/app.js?sha=b0deb72809b9bb08cdd172c16fb29669"
></script>
<script
async
defer
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/jquery-typeahead@2.11.1/dist/jquery.typeahead.min.js"
></script>
<script
async
defer
type="text/javascript"
src="https://www.antennaeurope.gr/plugins/cms39_search/cms39_search.js?v=4.5"
></script>
</body>
</html>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="antennaeurope.gr" lang="el" xmltv_id="ANT1Europe.gr" site_id="#">ANT1 Europe</channel>
</channels>

View File

@@ -1,57 +1,59 @@
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: 'hd-plus.de',
days: 2,
url({ date, channel }) {
const today = dayjs().utc().startOf('d')
const day = date.diff(today, 'd')
return `https://www.hd-plus.de/epg/channel/${channel.site_id}?d=${day}`
},
parser({ content, date }) {
const programs = []
const items = parseItems(content)
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(1, 'h')
programs.push({ title: parseTitle($item), start, stop })
})
return programs
}
}
function parseStart($item, date) {
const timeString = $item('td:nth-child(2)').text().split(' ').pop()
const dateString = `${date.format('YYYY-MM-DD')} ${timeString}`
return dayjs.tz(dateString, 'YYYY-MM-DD HH:mm', 'Europe/Berlin')
}
function parseTitle($item) {
return $item('td:nth-child(1) > a').text()
}
function parseItems(content) {
const $ = cheerio.load(content)
return $('table > tbody > tr').toArray()
}
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: 'antennaeurope.gr',
days: 2,
url({ date }) {
return `https://www.antennaeurope.gr/el/tvguide.html?date=${date.format('YYYY-MM-DD')}`
},
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),
start,
stop
})
})
return programs
}
}
function parseTitle($item) {
return $item('.title').text().trim()
}
function parseStart($item, date) {
const time = $item('dt.col-time').clone().children().remove().end().text().trim()
return time
? dayjs.tz(`${date.format('YYYY-MM-DD')} ${time}`, 'YYYY-MM-DD HH:mm', 'Europe/Athens')
: null
}
function parseItems(content) {
const $ = cheerio.load(content)
return $('dl.show').toArray()
}

View File

@@ -0,0 +1,46 @@
const { parser, url } = require('./antennaeurope.gr.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('2025-01-21', 'YYYY-MM-DD').startOf('d')
it('can generate valid url', () => {
expect(url({ date })).toBe('https://www.antennaeurope.gr/el/tvguide.html?date=2025-01-21')
})
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(16)
expect(results[0]).toMatchObject({
start: '2025-01-21T03:45:00.000Z',
stop: '2025-01-21T07:50:00.000Z',
title: 'ΚΑΛΗΜΕΡΑ ΕΛΛΑΔΑ'
})
expect(results[15]).toMatchObject({
start: '2025-01-22T01:30:00.000Z',
stop: '2025-01-22T02:00:00.000Z',
title: 'ΤΟ ΠΡΩΙΝΟ'
})
})
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,15 @@
# antennaeurope.gr
https://www.antennaeurope.gr/el/tvguide.html
### Download the guide
```sh
npm run grab --- --site=antennaeurope.gr
```
### Test
```sh
npm test --- antennaeurope.gr
```

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,916 @@
<!doctype html>
<!--[if IE 7]>
<html class="ie7" lang="el"> <![endif]-->
<!--[if IE 8]>
<html class="ie8" lang="el"> <![endif]-->
<!--[if IE 9]>
<html class="ie9" lang="el"> <![endif]-->
<!--[if !IE]><!-->
<html lang="el" itemscope itemtype="http://schema.org/WebPage">
<!--<![endif]-->
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" lang="el" />
<meta http-equiv="content-language" content="el-gr" />
<title>Πρόγραμμα</title>
<meta name="description" content="cms39" />
<meta name="keywords" content="" />
<meta name="ROBOTS" content="INDEX, FOLLOW" />
<link
rel="search"
type="application/opensearchdescription+xml"
href="https://www.antennapacific.gr/opensearch.php"
title="Website search"
/>
<link href="" rel="publisher" />
<meta http-equiv="Cache-control" content="public" />
<meta http-equiv="Cache-control" content="max-age=86400" />
<meta name="designer" content="www.cdl.gr" />
<meta name="generator" content="CMS39 FRAMEWORK v8.9.9.1" />
<meta name="copyright" content="antennapacific.gr" />
<link rel="alternate" hreflang="el" href="https://www.antennapacific.gr/el/tvguide.html" />
<link rel="alternate" hreflang="en" href="https://www.antennapacific.gr/en/tvguide.html" />
<meta property="fb:app_id" content="966242223397117" />
<meta property="og:locale" content="el" />
<meta property="og:type" content="website" />
<meta
property="og:url"
content="https://www.antennapacific.gr/el/tvguide.html?date=2026-01-21"
/>
<meta property="og:site_name" content="antennapacific.gr" />
<meta property="og:title" content="Πρόγραμμα" />
<meta property="og:description" content="cms39" />
<meta
property="og:image"
content="https://www.antennapacific.gr/media/upload-files/cache/646/6461bfb90f8f41ad34e74a3396e1edfa_pacificlogo.jpg"
/>
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<script type="text/javascript">
var Durl = 'https://www.antennapacific.gr/el'
var Turl = 'https://www.antennapacific.gr/themes/default'
var url = 'https://www.antennapacific.gr'
var Aurl = 'https://www.antennapacific.gr/administrator/cp_ajax?f='
var lang = 'el'
var lang_symbol = 'el'
var siteName = 'antennapacific.gr'
var siteV = '5.7.4'
var Purl = 'https://www.antennapacific.gr/public/plugins'
</script>
<link
rel="alternate"
type="application/rss+xml"
title="antennapacific.gr Feed"
href="https://www.antennapacific.gr/rss.php"
/>
<link
rel="apple-touch-icon"
sizes="57x57"
href="https://www.antennapacific.gr/themes/default/img/ico/apple-icon-57x57.png"
/>
<link
rel="apple-touch-icon"
sizes="60x60"
href="https://www.antennapacific.gr/themes/default/img/ico/apple-icon-60x60.png"
/>
<link
rel="apple-touch-icon"
sizes="72x72"
href="https://www.antennapacific.gr/themes/default/img/ico/apple-icon-72x72.png"
/>
<link
rel="apple-touch-icon"
sizes="76x76"
href="https://www.antennapacific.gr/themes/default/img/ico/apple-icon-76x76.png"
/>
<link
rel="apple-touch-icon"
sizes="114x114"
href="https://www.antennapacific.gr/themes/default/img/ico/apple-icon-114x114.png"
/>
<link
rel="apple-touch-icon"
sizes="120x120"
href="https://www.antennapacific.gr/themes/default/img/ico/apple-icon-120x120.png"
/>
<link
rel="apple-touch-icon"
sizes="144x144"
href="https://www.antennapacific.gr/themes/default/img/ico/apple-icon-144x144.png"
/>
<link
rel="apple-touch-icon"
sizes="152x152"
href="https://www.antennapacific.gr/themes/default/img/ico/apple-icon-152x152.png"
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="https://www.antennapacific.gr/themes/default/img/ico/apple-icon-180x180.png"
/>
<link
rel="icon"
type="image/png"
sizes="192x192"
href="https://www.antennapacific.gr/themes/default/img/ico/android-icon-192x192.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="https://www.antennapacific.gr/themes/default/img/ico/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="96x96"
href="https://www.antennapacific.gr/themes/default/img/ico/favicon-96x96.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="https://www.antennapacific.gr/themes/default/img/ico/favicon-16x16.png"
/>
<link rel="manifest" href="https://www.antennapacific.gr/themes/default/manifest.json" />
<meta
name="msapplication-TileImage"
content="https://www.antennapacific.gr/themes/default/img/ico/ms-icon-144x144.png"
/>
<meta name="theme-color" content="#000000" />
<meta name="msapplication-navbutton-color" content="#000000" />
<meta name="apple-mobile-web-app-status-bar-style" content="#000000" />
<script type="text/javascript">
var contact_url = 'https://www.antennapacific.gr'
var contact_field_message_min = '20'
var contact_field_message_max = '100'
var contact_lang = 'el'
</script>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/owl.carousel@2.2.0/dist/assets/owl.carousel.min.css"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/owl.carousel@2.2.0/dist/assets/owl.theme.default.min.css"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/jquery-typeahead@2.11.1/dist/jquery.typeahead.min.css"
/>
<link
rel="stylesheet"
href="https://www.antennapacific.gr/plugins/cms39_search/cms39_search.css?v=4.5"
/>
<link rel="stylesheet" href="https://www.antennapacific.gr/plugins/contactform/contact.css" />
<script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-118766183-1"></script>
<script>
window.dataLayer = window.dataLayer || []
function gtag() {
dataLayer.push(arguments)
}
gtag('js', new Date())
gtag('config', 'UA-118766183-1')
</script>
<link
rel="stylesheet"
type="text/css"
href="https://www.antennapacific.gr/themes/default/style.css?version=5.7.4"
/>
<!--[if lt IE 9]>
<script src="//cdn.jsdelivr.net/html5shiv/3.7.2/html5shiv-printshiv.min.js"></script>
<script src="//cdn.jsdelivr.net/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=AW-16697709160"></script>
<script>
window.dataLayer = window.dataLayer || []
function gtag() {
dataLayer.push(arguments)
}
gtag('js', new Date())
gtag('config', 'AW-16697709160')
</script>
</head>
<body class="el css_100 css_tvguide css_0 css_page css_page css_root_100 desktop">
<div class="masterWraper">
<header>
<div class="container-fluid">
<a
class="logo"
href="https://www.antennapacific.gr/el/home.html"
title="antennapacific.gr"
><img
alt="logo antennapacific.gr"
src="https://www.antennapacific.gr/themes/default/img/pac.svg"
/></a>
<div class="colarea1">
<div class="col1inner">
<div class="text-right colmenu">
<button
class="menu-toggle"
data-toggle="collapse"
data-target="#collapseMenu"
aria-expanded="false"
aria-controls="collapseMenu"
>
<span class="menu-icon">
<span class="first"></span>
<span class="second"></span>
<span class="third"></span>
</span>
</button>
</div>
<div class="col-sitesearch text-left">
<div
class="site-search grid__col-auto grid--justify-center grid--align-center visible__sm"
>
<button
class="search-btn"
data-toggle="collapse"
data-target="#collapseSearch"
aria-expanded="false"
aria-controls="collapseSearch"
>
<i class="fa fa-search" aria-hidden="true"></i>
</button>
</div>
</div>
</div>
</div>
<div class="colarea2">
<ul class="list-inline"></ul>
</div>
<div class="colarea3 col-live-now text-right">
<a
class="playnow"
title="more information"
data-bid="8136"
data-dum="273743"
href="https://www.antennapacific.gr/el/to-proino.html"
><span class="highlight">Παίζει τώρα</span>ΤΟ ΠΡΩΙΝΟ</a
>
<ul class="list-inline lang-list">
<li class="cms39_language_loop cms39_language_loop_li_el active">
<a
class="cms39_language_link_el active"
title="Ελληνικά"
href="https://www.antennapacific.gr/el/tvguide.html"
>Ελληνικά</a
>
</li>
<li class="cms39_language_loop cms39_language_loop_li_en">
<a
class="cms39_language_link_en"
title="English"
href="https://www.antennapacific.gr/en/tvguide.html"
>English</a
>
</li>
</ul>
</div>
</div>
</header>
<div id="collapseMenu" class="collapse">
<form
role="search"
class="searchform"
id="searchform"
action="https://www.antennapacific.gr/el/search.html"
method="GET"
>
<div class="typeahead__container">
<div class="typeahead__field">
<span class="typeahead__query">
<label for="searchform_q" class="hidden">εύρεση</label>
<input
class="js-typeahead searchformField form-control"
type="search"
autocomplete="off"
placeholder="Αναζήτηση"
value=""
name="q"
id="searchform_q"
required
/>
</span>
<span class="typeahead__button">
<button type="submit" class="searchformSubmit btn btn-default" title="search site">
<span class="typeahead__search-icon"></span>
</button>
</span>
<input data-storage="false" type="hidden" name="date" value="2026-01-21" />
</div>
</div>
</form>
<nav class="cms39-header-nav">
<ul id="cms39-header-nav" class="cms39-navbar-nav ul-29">
<li class="active">
<a
title="Πρόγραμμα"
href="https://www.antennapacific.gr/el/tvguide.html"
class="active"
>Πρόγραμμα</a
>
</li>
<li class="">
<a title="Εκπομπές" href="https://www.antennapacific.gr/el/shows.html" class=""
>Εκπομπές</a
>
</li>
<li class="">
<a title="Αθλητικά" href="https://www.antennapacific.gr/el/sports.html" class=""
>Αθλητικά</a
>
</li>
<li class="">
<a title="Συνδεθείτε " href="https://www.antennapacific.gr/el/connect.html" class=""
>Συνδεθείτε
</a>
</li>
<li class="">
<a title="Links" href="https://www.antennapacific.gr/el/links.html" class="">Links</a>
</li>
<li class="">
<a title="Επικοινωνία" href="https://www.antennapacific.gr/el/contact.html" class=""
>Επικοινωνία</a
>
</li>
</ul>
</nav>
<div class="site-social grid__cell-footer">
<ul class="grid">
<li>
<a href="https://www.facebook.com/antenna.pacific/" target="_blank">
<span class="icon icon-facebook"
><span class="screen-reader-text"><i class="fab fa-facebook-f"></i></span
></span>
</a>
</li>
<li>
<a href="" target="_blank">
<span class="icon icon-twitter"
><span class="screen-reader-text"><i class="fab fa-twitter"></i></span
></span>
</a>
</li>
<li>
<a href="https://www.instagram.com/antenna_pacific/" target="_blank">
<span class="icon icon-instagram"
><span class="screen-reader-text"><i class="fab fa-instagram"></i></span
></span>
</a>
</li>
<li>
<a href="" target="_blank">
<span class="icon icon-youtube"
><span class="screen-reader-text"><i class="fab fa-youtube"></i></span
></span>
</a>
</li>
</ul>
<!-- .site-social -->
</div>
<ul class="list-inline lang-list">
<li class="cms39_language_loop cms39_language_loop_li_el active">
<a
class="cms39_language_link_el active"
title="Ελληνικά"
href="https://www.antennapacific.gr/el/tvguide.html"
>Ελληνικά</a
>
</li>
<li class="cms39_language_loop cms39_language_loop_li_en">
<a
class="cms39_language_link_en"
title="English"
href="https://www.antennapacific.gr/en/tvguide.html"
>English</a
>
</li>
</ul>
</div>
<div id="collapseSearch" class="collapse">
<div class="inner">
<div class="container-fluid">
<form
role="search"
class="searchform"
id="searchform"
action="https://www.antennapacific.gr/el/search.html"
method="GET"
>
<div class="typeahead__container">
<div class="typeahead__field">
<span class="typeahead__query">
<label for="searchform_q" class="hidden">εύρεση</label>
<input
class="js-typeahead searchformField form-control"
type="search"
autocomplete="off"
placeholder="Αναζήτηση"
value=""
name="q"
id="searchform_q"
required
/>
</span>
<span class="typeahead__button">
<button
type="submit"
class="searchformSubmit btn btn-default"
title="search site"
>
<span class="typeahead__search-icon"></span>
</button>
</span>
<input data-storage="false" type="hidden" name="date" value="2026-01-21" />
</div>
</div>
</form>
<div class="info">Άρχισε να πληκτρολογείς οτιδήποτε</div>
</div>
</div>
</div>
<div class="ant1col2">
<div class="featuredContentContainer container-fluid">
<div class="row">
<div class="col-12 col-sm-8">
<article class="programme-container">
<div id="programmeCalendar" class="calendar-horizontal">
<div class="showCarousel owl-carousel">
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennapacific.gr/el/tvguide.html?date=2025-01-17"
>Παρασκευή <span>17/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennapacific.gr/el/tvguide.html?date=2025-01-18"
>Σάββατο <span>18/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennapacific.gr/el/tvguide.html?date=2025-01-19"
>Κυριακή <span>19/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennapacific.gr/el/tvguide.html?date=2025-01-20"
>Δευτέρα <span>20/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennapacific.gr/el/tvguide.html?date=2025-01-21"
>Τρίτη <span>21/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennapacific.gr/el/tvguide.html?date=2025-01-22"
>Τετάρτη <span>22/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennapacific.gr/el/tvguide.html?date=2025-01-23"
>Πέμπτη <span>23/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennapacific.gr/el/tvguide.html?date=2025-01-24"
>Παρασκευή <span>24/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennapacific.gr/el/tvguide.html?date=2025-01-25"
>Σάββατο <span>25/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennapacific.gr/el/tvguide.html?date=2025-01-26"
>Κυριακή <span>26/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennapacific.gr/el/tvguide.html?date=2025-01-27"
>Δευτέρα <span>27/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennapacific.gr/el/tvguide.html?date=2025-01-28"
>Τρίτη <span>28/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennapacific.gr/el/tvguide.html?date=2025-01-29"
>Τετάρτη <span>29/1</span></a
>
</div>
<div class="carousel-cell">
<a
title="view the program"
href="https://www.antennapacific.gr/el/tvguide.html?date=2025-01-30"
>Πέμπτη <span>30/1</span></a
>
</div>
</div>
</div>
<div id="programmeContent" class="programme-content">
<div class="row">
<div class="day col-12 col-sm-2">
<p>Τετάρτη<br />21/1</p>
</div>
<div class="shows col-12 col-sm-10 sentoni">
<div id="earlierContainer" class="programme-earlier-container"></div>
</div>
</div>
</div>
</article>
</div>
<div class="col-12 col-sm-4 sidebararea">
<div class="banner-placeholder vertical light">
<ins
data-revive-zoneid="1"
data-revive-target="_blank"
data-revive-ct0="26359802"
data-revive-block="1"
data-revive-blockcampaign="1"
data-revive-id="30a34a2302634ff5d170d39f518891d2"
></ins>
<script async src="//dfp.cdl.gr/www/delivery/asyncjs.php"></script>
<div class="banner2">
<ins
data-revive-zoneid="1"
data-revive-target="_blank"
data-revive-ct0="34315738"
data-revive-block="1"
data-revive-blockcampaign="1"
data-revive-id="30a34a2302634ff5d170d39f518891d2"
></ins>
<script async src="//dfp.cdl.gr/www/delivery/asyncjs.php"></script>
</div>
</div>
<div class="sidebararea-promo">
<h1 class="h1">Δες επίσης</h1>
</div>
<div class="sidebararea-promo"></div>
</div>
</div>
</div>
</div>
<div class="new-episodes">
<h1 class="h1">Πρόγραμμα</h1>
<div id="footerFshows" class="owl-carousel owl-theme">
<div class="show">
<div class="inner">
<img
alt="ΡΟΥΚ ΖΟΥΚ"
src="https://www.antennapacific.gr/media/upload-files/cache/7dc/7dcad32b0490fd5e2f4eb944fdd13d4c_roukzoukprogramma.jpg"
/>
<div class="content">
<h2>ΡΟΥΚ ΖΟΥΚ</h2>
<p class="excerpt">
Η Ζέτα Μακρυπούλια μας χαρίζει για 7η σεζόν ακόμα περισσότερες στιγμές γέλιου και
διασκέδασης! 
</p>
<a
title="ΡΟΥΚ ΖΟΥΚ"
class="more"
href="https://www.antennapacific.gr/el/rouk-zouk.html"
>Δες περισσότερα</a
>
</div>
</div>
</div>
<div class="show">
<div class="inner">
<img
alt="ΥΓΕΙΑ ΠΑΝΩ ΑΠ’ ΟΛΑ"
src="https://www.antennapacific.gr/media/upload-files/cache/42a/42a69c6936c865b6cb1555da86b8101f_ygeiapanwapolaprogramma.jpg"
/>
<div class="content">
<h2>ΥΓΕΙΑ ΠΑΝΩ ΑΠ’ ΟΛΑ</h2>
<p class="excerpt">
Το «Υγεία πάνω απ’ όλα» με τη Φωτεινή Γεωργίου, συνεχίζει για 13η χρονιά!
</p>
<a
title="ΥΓΕΙΑ ΠΑΝΩ ΑΠ’ ΟΛΑ"
class="more"
href="https://www.antennapacific.gr/el/igia-pano-ap-ola.html"
>Δες περισσότερα</a
>
</div>
</div>
</div>
<div class="show">
<div class="inner">
<img
alt="ΡΑΔΙΟ ΑΡΒΥΛΑ"
src="https://www.antennapacific.gr/media/upload-files/cache/356/356e9b3db418c002aa7bb59095c2887d_radioarvylaprogramma.jpg"
/>
<div class="content">
<h2>ΡΑΔΙΟ ΑΡΒΥΛΑ</h2>
<p class="excerpt">
Όλοι οι τηλεοπτικοί δρόμοι οδηγούν στην καυστική σάτιρα και στους μοναδικούς
«Ράδιο Αρβύλα» για 18η χρονιά!  
</p>
<a
title="ΡΑΔΙΟ ΑΡΒΥΛΑ"
class="more"
href="https://www.antennapacific.gr/el/radio-arvila.html"
>Δες περισσότερα</a
>
</div>
</div>
</div>
<div class="show">
<div class="inner">
<img
alt=" THE 2NIGHT SHOW "
src="https://www.antennapacific.gr/media/upload-files/cache/94a/94a25d7a699a00776d161c35558f1d8f_2nightshowprogramma.jpeg"
/>
<div class="content">
<h2>THE 2NIGHT SHOW</h2>
<p class="excerpt">
Οι πιο ενδιαφέρουσες νυχτερινές εξομολογήσεις με τον Γρηγόρη Αρναούτογλου!
</p>
<a
title=" THE 2NIGHT SHOW "
class="more"
href="https://www.antennapacific.gr/el/the-2night-show.html"
>Δες περισσότερα</a
>
</div>
</div>
</div>
<div class="show">
<div class="inner">
<img
alt="THE REUNION"
src="https://www.antennapacific.gr/media/upload-files/cache/7f5/7f5502d928d0d36f21be192aa53f062e_thereunionprogramma.jpg"
/>
<div class="content">
<h2>THE REUNION</h2>
<p class="excerpt">
O Σάκης Τανιμανίδης και ο Γιώργος Μαυρίδης μας ταξιδεύουν σε μοναδικούς
προορισμούς και εμπειρίες ζωής!
</p>
<a
title="THE REUNION"
class="more"
href="https://www.antennapacific.gr/el/the-reunion.html"
>Δες περισσότερα</a
>
</div>
</div>
</div>
</div>
</div>
<footer>
<div class="container-fluid">
<div class="row">
<div class="col-12 col-sm-8 foot_1">
<h2>Εγγραφή στο ενημερωτικό δελτίο</h2>
<form action="#" id="subscribeform" name="newsletter" method="post">
<label for="newsletterEmail" class="screen-reader-text">Το email σου</label>
<input
id="newsletterEmail"
type="email"
name="email"
placeholder="Το email σου"
required
/>
<input type="submit" name="submit" value="Εγγραφή" />
<input type="hidden" name="__mail_required" value="email" />
<input
type="hidden"
name="__mail_subject"
value="Antenna Pacific Newsletter form"
/>
<input
type="hidden"
name="__mail_success"
value="Thank you and welcome to our Newsletter Service!"
/>
<input
type="hidden"
name="url"
value="https://www.antennapacific.gr/el/tvguide.html?date=2026-01-21"
/>
<input type="hidden" name="datetime" value="2025-01-17 09:57:45" />
<div id="subscribeformMSG"></div>
</form>
</div>
<div class="col-12 col-sm-4 foot_2">
<h2>Ακολουθήστε μας</h2>
<ul class="site-social grid">
<li>
<a href="https://www.facebook.com/antenna.pacific/" target="_blank">
<span class="icon icon-facebook">
<span class="screen-reader-text"><i class="fab fa-facebook-f"></i></span>
</span>
</a>
</li>
<li>
<a href="https://www.instagram.com/antenna_pacific/" target="_blank">
<span class="icon icon-instagram">
<span class="screen-reader-text"><i class="fab fa-instagram"></i></span>
</span>
</a>
</li>
</ul>
<nav class="cms39-footer-nav">
<ul id="cms39-footer-nav" class="cms39-footer-nav ul-106">
<li class="">
<a
title="Επικοινωνία"
href="https://www.antennapacific.gr/el/contact.html"
class=""
>Επικοινωνία</a
>
</li>
<li class="">
<a
title="Συνδεθείτε "
href="https://www.antennapacific.gr/el/connect.html"
class=""
>Συνδεθείτε
</a>
</li>
<li class="">
<a
title="Εργασία"
href="https://www.antennapacific.gr/el/workwithus.html"
class=""
>Εργασία</a
>
</li>
<li class="">
<a
title="Διαφημιστείτε"
href="https://www.antennapacific.gr/el/advertise.html"
class=""
>Διαφημιστείτε</a
>
</li>
<li class="">
<a title="Για εμάς" href="https://www.antennapacific.gr/el/about.html" class=""
>Για εμάς</a
>
</li>
<li class="">
<a title="Links" href="https://www.antennapacific.gr/el/links.html" class=""
>Links</a
>
</li>
<li class="">
<a
title="Όροι χρήσης"
href="https://www.antennapacific.gr/el/terms.html"
class=""
>Όροι χρήσης</a
>
</li>
<li class="">
<a title="FAQ" href="https://www.antennapacific.gr/el/faq.html" class="">FAQ</a>
</li>
<li class="">
<a
title="Δελτία Τύπου"
href="https://www.antennapacific.gr/el/press.html"
class=""
>Δελτία Τύπου</a
>
</li>
</ul>
</nav>
</div>
<div class="col-12 foot_3 text-dark text-theme-copyright">
© 2025 ANT1 TV | 2025-01-17 09:57:45
</div>
</div>
</div>
</footer>
<div class="copyright text-center">
<div id="cdl" style="display: inline-block">
<span style="width: 49px; height: 43px; overflow: hidden; display: block">
<a
rel="external"
style="display: block; margin: 0px"
target="_blank"
title="Array"
href="https://www.cdl.gr"
>
<img
width="49"
height="43"
alt="Array"
src="https://www.cdl.gr/media/upload-files/cdl-logo-white.png"
/>
</a>
<a
rel="external"
style="visibility: hidden; display: none margin: 0px;"
title="Θέλεις κονκάρδες από το αγαπημένο σου συγκρότημα, κονκάρδες για το bachelor σου, κονκάρδες για τους καλεσμένους σου, κονκάρδες για το party των παιδιών σου, κονκάρδες για την προώθηση της επιχειρησης σου; Τα πάντα για κονκάρδες μόνο στο concarda.com"
href="http://www.concarda.com"
target="_blank"
>για κονκάρδες μόνο στο concarda.com</a
>
</span>
</div>
</div>
</div>
<!-- created by https://www.cdl.gr Creative Studio, κατασκευή ιστοσελίδων, ιστοσελίδες, digital agency. -->
<script type="text/javascript">
var search_autocomplete_template = '<span>{{title}}</span>'
var search_autocomplete_limit = '10'
var search_autocomplete_minLength = '3'
var search_autocomplete_emptyTemplate = 'No results found for {{query}}'
</script>
<script
type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
></script>
<script
type="text/javascript"
src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/block-ui@2.70.1/jquery.blockUI.min.js"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/owl.carousel@2.2.0/dist/owl.carousel.min.js"
></script>
<script
type="text/javascript"
src="https://use.fontawesome.com/releases/v5.0.8/js/all.js"
></script>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/jquery-form@4.2.2/dist/jquery.form.min.js"
></script>
<script
type="text/javascript"
src="https://www.antennapacific.gr/themes/default/js/plugins.js"
></script>
<script
type="text/javascript"
src="https://www.antennapacific.gr/themes/default/js/app.js?sha=392fd813650ad1d0420e373638676083"
></script>
<script
async
defer
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/jquery-typeahead@2.11.1/dist/jquery.typeahead.min.js"
></script>
<script
async
defer
type="text/javascript"
src="https://www.antennapacific.gr/plugins/cms39_search/cms39_search.js?v=4.5"
></script>
</body>
</html>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="antennapacific.gr" lang="el" xmltv_id="ANT1Pacific.gr" site_id="#">ANT1 PACIFIC</channel>
</channels>

View File

@@ -0,0 +1,59 @@
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: 'antennapacific.gr',
days: 2,
url({ date }) {
return `https://www.antennapacific.gr/el/tvguide.html?date=${date.format('YYYY-MM-DD')}`
},
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),
start,
stop
})
})
return programs
}
}
function parseTitle($item) {
return $item('.title').text().trim()
}
function parseStart($item, date) {
const time = $item('dt.col-time').clone().children().remove().end().text().trim()
return time
? dayjs.tz(`${date.format('YYYY-MM-DD')} ${time}`, 'YYYY-MM-DD HH:mm', 'Europe/Athens')
: null
}
function parseItems(content) {
const $ = cheerio.load(content)
return $('dl.show').toArray()
}

View File

@@ -0,0 +1,46 @@
const { parser, url } = require('./antennapacific.gr.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('2025-01-21', 'YYYY-MM-DD').startOf('d')
it('can generate valid url', () => {
expect(url({ date })).toBe('https://www.antennapacific.gr/el/tvguide.html?date=2025-01-21')
})
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(17)
expect(results[0]).toMatchObject({
start: '2025-01-21T05:00:00.000Z',
stop: '2025-01-21T06:00:00.000Z',
title: 'ANT1 NEWS - ΚΕΝΤΡΙΚΟ ΔΕΛΤΙΟ'
})
expect(results[16]).toMatchObject({
start: '2025-01-22T02:45:00.000Z',
stop: '2025-01-22T03:15:00.000Z',
title: 'ΚΑΛΗΜΕΡΑ ΕΛΛΑΔΑ'
})
})
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,15 @@
# antennapacific.gr
https://www.antennapacific.gr/el/tvguide.html
### Download the guide
```sh
npm run grab --- --site=antennapacific.gr
```
### Test
```sh
npm test --- antennapacific.gr
```

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,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="antennasatellite.gr" lang="el" xmltv_id="ANT1Satellite.gr" site_id="#">ANT1 SATELLITE</channel>
</channels>

View File

@@ -0,0 +1,59 @@
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: 'antennasatellite.gr',
days: 2,
url({ date }) {
return `https://www.antennasatellite.gr/el/tvguide.html?date=${date.format('YYYY-MM-DD')}`
},
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),
start,
stop
})
})
return programs
}
}
function parseTitle($item) {
return $item('.title').text().trim()
}
function parseStart($item, date) {
const time = $item('dt.col-time').clone().children().remove().end().text().trim()
return time
? dayjs.tz(`${date.format('YYYY-MM-DD')} ${time}`, 'YYYY-MM-DD HH:mm', 'Europe/Athens')
: null
}
function parseItems(content) {
const $ = cheerio.load(content)
return $('dl.show').toArray()
}

View File

@@ -0,0 +1,46 @@
const { parser, url } = require('./antennasatellite.gr.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('2025-01-21', 'YYYY-MM-DD').startOf('d')
it('can generate valid url', () => {
expect(url({ date })).toBe('https://www.antennasatellite.gr/el/tvguide.html?date=2025-01-21')
})
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(16)
expect(results[0]).toMatchObject({
start: '2025-01-21T04:00:00.000Z',
stop: '2025-01-21T04:40:00.000Z',
title: 'ANT1 NEWS'
})
expect(results[15]).toMatchObject({
start: '2025-01-22T00:50:00.000Z',
stop: '2025-01-22T01:20:00.000Z',
title: 'ΤΟ ΠΡΩΙΝΟ'
})
})
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,15 @@
# antennasatellite.gr
https://www.antennasatellite.gr/el/tvguide.html
### Download the guide
```sh
npm run grab --- --site=antennasatellite.gr
```
### Test
```sh
npm test --- antennasatellite.gr
```

View File

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

View File

@@ -1,82 +0,0 @@
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: '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

@@ -1,15 +0,0 @@
# arianaafgtv.com
https://arianaafgtv.com/#ariana-afghanistan-television-tv-guide
### Download the guide
```sh
npm run grab --- --site=arianaafgtv.com
```
### Test
```sh
npm test --- arianaafgtv.com
```

View File

@@ -0,0 +1 @@
<!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>

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html><head></head><body><textarea data-jtrt-table-id="508" id="jtrt_table_settings_508" cols="30" rows="10"></textarea></body></html>

View File

@@ -1,60 +1,60 @@
const cheerio = require('cheerio')
const { DateTime } = require('luxon')
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 < prev.start) {
start = start.plus({ days: 1 })
date = date.add(1, 'd')
}
prev.stop = start
}
const stop = start.plus({ minutes: 30 })
programs.push({
title: item.title,
start,
stop
})
})
return programs
}
}
function parseStart(item, date) {
const time = `${date.format('YYYY-MM-DD')} ${item.start}`
return DateTime.fromFormat(time, 'yyyy-MM-dd H:mm', { zone: 'Asia/Kabul' }).toUTC()
}
function parseItems(content, date) {
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
}
const cheerio = require('cheerio')
const { DateTime } = require('luxon')
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 < prev.start) {
start = start.plus({ days: 1 })
date = date.add(1, 'd')
}
prev.stop = start
}
const stop = start.plus({ minutes: 30 })
programs.push({
title: item.title,
start,
stop
})
})
return programs
}
}
function parseStart(item, date) {
const time = `${date.format('YYYY-MM-DD')} ${item.start}`
return DateTime.fromFormat(time, 'yyyy-MM-dd H:mm', { zone: 'Asia/Kabul' }).toUTC()
}
function parseItems(content, date) {
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

@@ -1,59 +1,59 @@
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([])
})
const { parser, url } = require('./arianatelevision.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('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 = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
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: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
})
expect(result).toMatchObject([])
})

View File

@@ -1,187 +1,159 @@
{
"resultCode": {
"code": 200000,
"http_status": 200,
"timestamp": 0,
"message": null,
"trace": null,
"access_token": null,
"expire_time": 0
"resultCode": {
"code": 200000,
"http_status": 200,
"timestamp": 0,
"message": null,
"trace": null,
"access_token": null,
"expire_time": 0
},
"program_id": 230,
"order": 10070,
"is_news_allow": false,
"bis_program": [
{
"bis_program_code": "2025006T",
"bis_program_title": "DIPLOMAT'S ARCHIVE: HIDDEN STORIES"
}
],
"bis_bundle_program_code": "2025006T",
"bis_category_code": "교양",
"program_type": "tv",
"category_Info": [
{
"category_id": 29,
"local": "en",
"title": "Current Affairs"
},
"program_id": 173,
"order": 21,
"is_news_allow": true,
"bis_program": [
{
"bis_program_code": "2023003T",
"bis_program_title": "WITHIN THE FRAME [L]"
},
{
"bis_program_code": "2023004T",
"bis_program_title": "WITHIN THE FRAME [R]"
}
],
"bis_bundle_program_code": "2023003T",
"bis_category_code": "시사보도",
"program_type": "tv",
"category_Info": [
{
"category_id": 29,
"local": "en",
"title": "Current Affairs"
},
{
"category_id": 29,
"local": "ko",
"title": "Current Affairs"
}
],
"title": [
{
"lan_code": "en",
"text": "WITHIN THE FRAME [L]"
},
{
"lan_code": "ko",
"text": "WITHIN THE FRAME [L]"
}
],
"content": [
{
"lan_code": "en",
"text": "NEWS<div></div>"
},
{
"lan_code": "ko",
"text": "NEWS 대담<div></div>"
}
],
"property": {
"open_status": {
"is_allow": true,
"is_origin_allow": null,
"start_date": null,
"end_date": null
},
"is_onair": true,
"is_teaser_allow": false,
"running_time": 30,
"schedule": [
{
"week": [
"Mon",
"Tue",
"Wed",
"Thu",
"Fri"
],
"start_time": 1110
},
{
"week": [
""
],
"start_time": -1
},
{
"week": [
""
],
"start_time": -1
},
{
"week": [
""
],
"start_time": -1
},
{
"week": [
""
],
"start_time": -1
},
{
"week": [
""
],
"start_time": -1
},
{
"week": [
""
],
"start_time": -1
},
{
"week": [
""
],
"start_time": -1
},
{
"week": [
""
],
"start_time": -1
},
{
"week": [
""
],
"start_time": -1
}
]
{
"category_id": 29,
"local": "ko",
"title": "Current Affairs"
}
],
"title": [
{
"lan_code": "en",
"text": "Diplomat Archives: Hidden Stories"
},
"platform": {
"is_aos_allow": true,
"is_ios_allow": true,
"is_smat_tv_allow": true
{
"lan_code": "ko",
"text": "Diplomat Archives: Hidden Stories"
}
],
"content": [
{
"lan_code": "en",
"text": "As of April 2025, S. Korea has established diplomatic relations with a total of 194 countries.\nAmong them are countries that have had ties and exchanges with Korea for hundreds of years.\nWith such long-standing relationships with so many nations,\nmight there be fascinating hidden stories between Korea and the rest of the world that we dont know yet? \n\n\"Diplomats Archives: Hidden Stories\" begins with this very question.\nTogether with foreign embassies in Korea, the series uncovers and sheds light on meaningful yet lesser-known stories between Korea and other countries.\nThrough this, we aim to reaffirm the deep friendships that have been built over time, highlight how countries are interconnected—bilaterally and multilaterally—\nand emphasize the importance of cooperation on the global stage today."
},
"image": [
{
"order": 0,
"type": "horizontal",
"name": "2080840096998752900.png",
"action": null,
"url": "https://img.arirang.com/v1/AUTH_d52449c16d3b4bbca17d4fffd9fc44af/public/images/202308/2080840096998752900.png"
},
{
"order": 0,
"type": "vertical",
"name": "1773516657138860509.png",
"action": null,
"url": "https://img.arirang.com/v1/AUTH_d52449c16d3b4bbca17d4fffd9fc44af/public/images/202301/1773516657138860509.png"
},
{
"order": 0,
"type": "mobile",
"name": "1773516657893835229.png",
"action": null,
"url": "https://img.arirang.com/v1/AUTH_d52449c16d3b4bbca17d4fffd9fc44af/public/images/202301/1773516657893835229.png"
},
{
"order": 0,
"type": "pc",
"name": "1773742773929771485.png",
"action": null,
"url": "https://img.arirang.com/v1/AUTH_d52449c16d3b4bbca17d4fffd9fc44af/public/images/202301/1773742773929771485.png"
},
{
"order": 0,
"type": "smarttv",
"name": "1773742775607493085.png",
"action": null,
"url": "https://img.arirang.com/v1/AUTH_d52449c16d3b4bbca17d4fffd9fc44af/public/images/202301/1773742775607493085.png"
},
{
"order": 0,
"type": "square",
"name": "1773742767839642077.png",
"action": null,
"url": "https://img.arirang.com/v1/AUTH_d52449c16d3b4bbca17d4fffd9fc44af/public/images/202301/1773742767839642077.png"
}
],
"reg_date": "2023-01-03 10:21:56.0",
"update_date": "2023-08-03 10:55:34.0"
}
{
"lan_code": "ko",
"text": "<div> 2025년 1월 기준, 대한민국과 수교를 맺고 있는 국가 총 193개... \n 이 중 몇몇 국가는 한국과 이미 몇백 년 전부터 \n 관계를 맺어오고 교류해 오기도 했다.\n \n 이렇게 많은 국가들과 오랜 기간 관계를 맺어온 한국...\n 한국과 다른 국가들 사이 \n 우리가 모르는 흥미로운 숨겨진 이야기가 잊지 않을까?\n \n Diplomats Archives: Hidden Stories는 \n 이 질문으로부터 시작해, 사람들이 많이 모르고 있는, \n 한국과 다른 국가들 사이의 의미 있는 이야기들을 주한 대사관들과 함께 찾고 깊이 있게 조명한다.\n 이를 통해 한국과 다른 나라들 사이, 오랜 기간 이어온 돈독한 우정을 재확인하고\n 양자적, 또 다자적으로 각국이 어떻게 연결되어 있는지,\n 오늘날 세계 무대에서의 협력이 왜 중요한가를 강조하고자 한다. <div></div></div>"
}
],
"property": {
"open_status": {
"is_allow": true,
"is_origin_allow": null,
"start_date": null,
"end_date": null
},
"is_onair": true,
"is_teaser_allow": false,
"running_time": 30,
"schedule": [
{
"week": ["Mon"],
"start_time": 900
},
{
"week": [""],
"start_time": -1
},
{
"week": [""],
"start_time": -1
},
{
"week": [""],
"start_time": -1
},
{
"week": [""],
"start_time": -1
},
{
"week": [""],
"start_time": -1
},
{
"week": [""],
"start_time": -1
},
{
"week": [""],
"start_time": -1
},
{
"week": [""],
"start_time": -1
},
{
"week": [""],
"start_time": -1
}
]
},
"platform": {
"is_aos_allow": true,
"is_ios_allow": true,
"is_smat_tv_allow": true
},
"image": [
{
"order": 0,
"type": "horizontal",
"name": "2985531324875408146.jpg",
"action": null,
"url": "https://img.arirang.com/v1/AUTH_d52449c16d3b4bbca17d4fffd9fc44af/public/images/202504/2985531324875408146.jpg"
},
{
"order": 0,
"type": "vertical",
"name": "2985531391564841746.jpg",
"action": null,
"url": "https://img.arirang.com/v1/AUTH_d52449c16d3b4bbca17d4fffd9fc44af/public/images/202504/2985531391564841746.jpg"
},
{
"order": 0,
"type": "mobile",
"name": "2985531460485645074.jpg",
"action": null,
"url": "https://img.arirang.com/v1/AUTH_d52449c16d3b4bbca17d4fffd9fc44af/public/images/202504/2985531460485645074.jpg"
},
{
"order": 0,
"type": "pc",
"name": "2985531491473163026.jpg",
"action": null,
"url": "https://img.arirang.com/v1/AUTH_d52449c16d3b4bbca17d4fffd9fc44af/public/images/202504/2985531491473163026.jpg"
},
{
"order": 0,
"type": "smarttv",
"name": "2985531522460680978.jpg",
"action": null,
"url": "https://img.arirang.com/v1/AUTH_d52449c16d3b4bbca17d4fffd9fc44af/public/images/202504/2985531522460680978.jpg"
},
{
"order": 0,
"type": "square",
"name": "2985531423240225554.png",
"action": null,
"url": "https://img.arirang.com/v1/AUTH_d52449c16d3b4bbca17d4fffd9fc44af/public/images/202504/2985531423240225554.png"
}
],
"reg_date": "2025-04-11 15:57:44.0",
"update_date": "2025-04-18 13:46:04.0"
}

View File

@@ -1,93 +1,385 @@
{
"resultCode": {
"code": 200000,
"http_status": 200,
"timestamp": 0,
"message": null,
"trace": null,
"access_token": null,
"expire_time": 0
},
"responseBody": {
"dsSchWeek": [
{
"chanId": "CH_W",
"broadYmd": "20230825",
"planNo": 1,
"scheduleSeq": 1,
"broadHm": "0000",
"viewHm": "0000",
"broadRun": 30,
"timeGrade": "1",
"pgmCd": "2023004T",
"broadType": "R",
"displayNm": "WITHIN THE FRAME [R]",
"episodeNo": 4,
"episodeNm": "#4",
"displayEpisodeNm": null,
"partNo": 0,
"firstClf": "02",
"broadClf": "02",
"scheduleClf": "0",
"scheduleGrp": "01",
"videoClf": "H",
"audioClf": "0",
"liveClf": null,
"captionYn": "N",
"signLangYn": "N",
"dvsYn": "N",
"captionExceptClf": "N",
"signLangExceptClf": "N",
"dvsExceptClf": "N",
"delibGrade": "00",
"delibTopicYn": "N",
"delibLanguageYn": "N",
"delibCopyYn": "N",
"delibViolenceYn": "N",
"delibSexualYn": "N",
"infoGrade": "0+",
"episodeRun": null,
"bandCd": null,
"bandNm": null,
"keepYn": "N",
"firstYn": "N",
"addInfo": null,
"viewRating": null,
"scheduleColor": null,
"bgColor": null,
"bgColorR": null,
"bgColorG": null,
"bgColorB": null,
"textColorCd": null,
"textColorR": null,
"textColorG": null,
"textColorB": null,
"textColorHex": null,
"scheduleLineYn": "N",
"mediaInfo": null,
"regClf": "0",
"uuid": null,
"regUserId": "kylek",
"regDt": "20230816112556023",
"updUserId": "kylek",
"updDt": "20230817094411 ",
"weekDay": null,
"mtrlYn": null,
"timeGradeColor": null,
"timeGradeNm": "SA",
"broadClfNm": "재방",
"broadTypeNm": null,
"delibGradeNm": null,
"newsYn": "Y",
"bundlePgmCd": "2023003T",
"bundlePgmNm": "WITHIN THE FRAME",
"pgmOnm": "WITHIN THE FRAME [R]"
}
],
"dmResult": {
"resultCode": "0",
"resultMsg": "success"
}
},
"responseXML": null
}
"resultCode": {
"code": 200000,
"http_status": 200,
"timestamp": 0,
"message": null,
"trace": null,
"access_token": null,
"expire_time": 0
},
"responseBody": {
"dsSchWeek": [
{
"chanId": "CH_W",
"broadYmd": "20250420",
"planNo": 1,
"scheduleSeq": 1,
"broadHm": "0000",
"viewHm": "0000",
"broadRun": 30,
"timeGrade": "1",
"pgmCd": "2025006T",
"broadType": "R",
"displayNm": "DIPLOMAT'S ARCHIVE: HIDDEN STORIES",
"episodeNo": 1,
"episodeNm": "#1",
"displayEpisodeNm": null,
"partNo": 0,
"firstClf": "02",
"broadClf": "02",
"scheduleClf": "0",
"scheduleGrp": "01",
"videoClf": "H",
"audioClf": "0",
"liveClf": null,
"captionYn": "N",
"signLangYn": "N",
"dvsYn": "N",
"captionExceptClf": "N",
"signLangExceptClf": "N",
"dvsExceptClf": "N",
"delibGrade": "00",
"delibTopicYn": "N",
"delibLanguageYn": "N",
"delibCopyYn": "N",
"delibViolenceYn": "N",
"delibSexualYn": "N",
"infoGrade": "0+",
"episodeRun": null,
"bandCd": null,
"bandNm": null,
"keepYn": "N",
"firstYn": "N",
"addInfo": null,
"viewRating": null,
"scheduleColor": null,
"bgColor": null,
"bgColorR": null,
"bgColorG": null,
"bgColorB": null,
"textColorCd": null,
"textColorR": null,
"textColorG": null,
"textColorB": null,
"textColorHex": null,
"scheduleLineYn": "N",
"mediaInfo": null,
"regClf": "0",
"uuid": null,
"regUserId": "kylek",
"regDt": "20250403101624121",
"updUserId": "kylek",
"updDt": "20250408132842 ",
"weekDay": null,
"mtrlYn": null,
"timeGradeColor": null,
"timeGradeNm": "SA",
"broadClfNm": "재방",
"broadTypeNm": null,
"delibGradeNm": null,
"newsYn": "N",
"bundlePgmCd": "2025006T",
"bundlePgmNm": "DIPLOMAT'S ARCHIVE: HIDDEN STORIES",
"pgmOnm": "DIPLOMAT'S ARCHIVE: HIDDEN STORIES"
},
{
"chanId": "CH_W",
"broadYmd": "20250420",
"planNo": 1,
"scheduleSeq": 173,
"broadHm": "0030",
"viewHm": "0030",
"broadRun": 30,
"timeGrade": "1",
"pgmCd": "PG2170032K",
"broadType": "R",
"displayNm": "PEACE INSIGHT(30분)",
"episodeNo": 444,
"episodeNm": "#444",
"displayEpisodeNm": null,
"partNo": 0,
"firstClf": "02",
"broadClf": "02",
"scheduleClf": "0",
"scheduleGrp": null,
"videoClf": "H",
"audioClf": "0",
"liveClf": null,
"captionYn": "N",
"signLangYn": "N",
"dvsYn": "N",
"captionExceptClf": null,
"signLangExceptClf": null,
"dvsExceptClf": null,
"delibGrade": "00",
"delibTopicYn": "N",
"delibLanguageYn": "N",
"delibCopyYn": "N",
"delibViolenceYn": "N",
"delibSexualYn": "N",
"infoGrade": "0+",
"episodeRun": null,
"bandCd": null,
"bandNm": null,
"keepYn": null,
"firstYn": null,
"addInfo": null,
"viewRating": null,
"scheduleColor": null,
"bgColor": null,
"bgColorR": null,
"bgColorG": null,
"bgColorB": null,
"textColorCd": null,
"textColorR": null,
"textColorG": null,
"textColorB": null,
"textColorHex": null,
"scheduleLineYn": null,
"mediaInfo": null,
"regClf": null,
"uuid": null,
"regUserId": "kylek",
"regDt": "20250403101624271",
"updUserId": "kylek",
"updDt": "20250408140758 ",
"weekDay": null,
"mtrlYn": null,
"timeGradeColor": null,
"timeGradeNm": "SA",
"broadClfNm": "재방",
"broadTypeNm": null,
"delibGradeNm": null,
"newsYn": "N",
"bundlePgmCd": "PG2160006K",
"bundlePgmNm": "PEACE INSIGHT(30분)",
"pgmOnm": "PEACE INSIGHT"
},
{
"chanId": "CH_W",
"broadYmd": "20250420",
"planNo": 1,
"scheduleSeq": 111,
"broadHm": "0100",
"viewHm": "0100",
"broadRun": 60,
"timeGrade": "1",
"pgmCd": "2025004T",
"broadType": "R",
"displayNm": "SIMPLY K-POP GATEWAY TO KOREA",
"episodeNo": 5,
"episodeNm": "#5",
"displayEpisodeNm": null,
"partNo": 0,
"firstClf": "02",
"broadClf": "02",
"scheduleClf": "0",
"scheduleGrp": null,
"videoClf": "H",
"audioClf": "0",
"liveClf": null,
"captionYn": "N",
"signLangYn": "N",
"dvsYn": "N",
"captionExceptClf": null,
"signLangExceptClf": null,
"dvsExceptClf": null,
"delibGrade": "15",
"delibTopicYn": "N",
"delibLanguageYn": "N",
"delibCopyYn": "N",
"delibViolenceYn": "N",
"delibSexualYn": "N",
"infoGrade": "16+",
"episodeRun": null,
"bandCd": null,
"bandNm": null,
"keepYn": null,
"firstYn": null,
"addInfo": null,
"viewRating": null,
"scheduleColor": null,
"bgColor": null,
"bgColorR": null,
"bgColorG": null,
"bgColorB": null,
"textColorCd": null,
"textColorR": null,
"textColorG": null,
"textColorB": null,
"textColorHex": null,
"scheduleLineYn": null,
"mediaInfo": null,
"regClf": null,
"uuid": null,
"regUserId": "kylek",
"regDt": "20250403101624315",
"updUserId": "kylek",
"updDt": "20250408140632 ",
"weekDay": null,
"mtrlYn": null,
"timeGradeColor": null,
"timeGradeNm": "SA",
"broadClfNm": "재방",
"broadTypeNm": null,
"delibGradeNm": null,
"newsYn": "N",
"bundlePgmCd": "2025004T",
"bundlePgmNm": "SIMPLY K-POP GATEWAY TO KOREA",
"pgmOnm": "SIMPLY K-POP GATEWAY TO KOREA"
},
{
"chanId": "CH_W",
"broadYmd": "20250420",
"planNo": 1,
"scheduleSeq": 3,
"broadHm": "0200",
"viewHm": "0200",
"broadRun": 10,
"timeGrade": "1",
"pgmCd": "2024017T",
"broadType": "R",
"displayNm": "SPOTLIGHT - ROOKIES",
"episodeNo": 27,
"episodeNm": "#27",
"displayEpisodeNm": null,
"partNo": 0,
"firstClf": "02",
"broadClf": "02",
"scheduleClf": "0",
"scheduleGrp": "01",
"videoClf": "H",
"audioClf": "0",
"liveClf": null,
"captionYn": "N",
"signLangYn": "N",
"dvsYn": "N",
"captionExceptClf": "N",
"signLangExceptClf": "N",
"dvsExceptClf": "N",
"delibGrade": "15",
"delibTopicYn": "N",
"delibLanguageYn": "N",
"delibCopyYn": "N",
"delibViolenceYn": "N",
"delibSexualYn": "N",
"infoGrade": "16+",
"episodeRun": null,
"bandCd": null,
"bandNm": null,
"keepYn": "N",
"firstYn": "N",
"addInfo": null,
"viewRating": null,
"scheduleColor": null,
"bgColor": null,
"bgColorR": null,
"bgColorG": null,
"bgColorB": null,
"textColorCd": null,
"textColorR": null,
"textColorG": null,
"textColorB": null,
"textColorHex": null,
"scheduleLineYn": "N",
"mediaInfo": null,
"regClf": "0",
"uuid": null,
"regUserId": "kylek",
"regDt": "20250403101624366",
"updUserId": "kylek",
"updDt": "20250411135045 ",
"weekDay": null,
"mtrlYn": null,
"timeGradeColor": null,
"timeGradeNm": "SA",
"broadClfNm": "재방",
"broadTypeNm": null,
"delibGradeNm": null,
"newsYn": "N",
"bundlePgmCd": "2024017T",
"bundlePgmNm": "SPOTLIGHT - ROOKIES",
"pgmOnm": "SPOTLIGHT - ROOKIES"
},
{
"chanId": "CH_W",
"broadYmd": "20250420",
"planNo": 1,
"scheduleSeq": 56,
"broadHm": "0210",
"viewHm": "0210",
"broadRun": 20,
"timeGrade": "1",
"pgmCd": "2022030T",
"broadType": "R",
"displayNm": "THE GLOBALISTS",
"episodeNo": 133,
"episodeNm": "#133",
"displayEpisodeNm": null,
"partNo": 0,
"firstClf": "02",
"broadClf": "02",
"scheduleClf": "0",
"scheduleGrp": null,
"videoClf": "H",
"audioClf": "0",
"liveClf": null,
"captionYn": "N",
"signLangYn": "N",
"dvsYn": "N",
"captionExceptClf": null,
"signLangExceptClf": null,
"dvsExceptClf": null,
"delibGrade": "00",
"delibTopicYn": "N",
"delibLanguageYn": "N",
"delibCopyYn": "N",
"delibViolenceYn": "N",
"delibSexualYn": "N",
"infoGrade": "0+",
"episodeRun": null,
"bandCd": null,
"bandNm": null,
"keepYn": null,
"firstYn": null,
"addInfo": null,
"viewRating": null,
"scheduleColor": null,
"bgColor": null,
"bgColorR": null,
"bgColorG": null,
"bgColorB": null,
"textColorCd": null,
"textColorR": null,
"textColorG": null,
"textColorB": null,
"textColorHex": null,
"scheduleLineYn": null,
"mediaInfo": null,
"regClf": null,
"uuid": null,
"regUserId": "kylek",
"regDt": "20250403101624426",
"updUserId": "kylek",
"updDt": "20250411135022 ",
"weekDay": null,
"mtrlYn": null,
"timeGradeColor": null,
"timeGradeNm": "SA",
"broadClfNm": "재방",
"broadTypeNm": null,
"delibGradeNm": null,
"newsYn": "N",
"bundlePgmCd": "2022030T",
"bundlePgmNm": "THE GLOBALISTS",
"pgmOnm": "THE GLOBALISTS"
}
],
"dmResult": {
"resultCode": "0",
"resultMsg": "success"
}
},
"responseXML": null
}

View File

@@ -1,153 +1,163 @@
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: 'arirang.com',
output: 'arirang.com.guide.xml',
channels: 'arirang.com.channels.xml',
lang: 'en',
days: 7,
delay: 5000,
url: 'https://www.arirang.com/v1.0/open/external/proxy',
request: {
method: 'POST',
timeout: 5000,
cache: { ttl: 60 * 60 * 1000 },
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
Origin: 'https://www.arirang.com',
Referer: 'https://www.arirang.com/schedule',
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
},
data: function (context) {
const { channel, date } = context
return {
address: 'https://script.arirang.com/api/v1/bis/listScheduleV3.do',
method: 'POST',
headers: {},
body: {
data: {
dmParam: {
chanId: channel.site_id,
broadYmd: dayjs.tz(date, 'Asia/Seoul').format('YYYYMMDD'),
planNo: '1'
}
}
}
}
}
},
logo: function (context) {
return context.channel.logo
},
async parser(context) {
const programs = []
const items = parseItems(context.content)
for (let item of items) {
const programDetail = await parseProgramDetail(item)
programs.push({
title: item.displayNm,
start: parseStart(item),
stop: parseStop(item),
image: parseImage(programDetail),
category: parseCategory(programDetail),
description: parseDescription(programDetail)
})
}
return programs
}
}
function parseItems(content) {
if (content != '') {
const data = JSON.parse(content)
return !data || !data.responseBody || !Array.isArray(data.responseBody.dsSchWeek)
? []
: data.responseBody.dsSchWeek
} else {
return []
}
}
function parseStart(item) {
return dayjs.tz(item.broadYmd + ' ' + item.broadHm, 'YYYYMMDD HHmm', 'Asia/Seoul')
}
function parseStop(item) {
return dayjs
.tz(item.broadYmd + ' ' + item.broadHm, 'YYYYMMDD HHmm', 'Asia/Seoul')
.add(item.broadRun, 'minute')
}
async function parseProgramDetail(item) {
return axios
.post(
'https://www.arirang.com/v1.0/open/program/detail',
{
bis_program_code: item.pgmCd
},
{
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
Origin: 'https://www.arirang.com',
Referer: 'https://www.arirang.com/schedule',
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
},
timeout: 5000,
cache: { ttl: 60 * 1000 }
}
)
.then(response => {
return response.data
})
.catch(error => {
console.log(error)
})
}
function parseImage(programDetail) {
if (programDetail && programDetail.image && programDetail.image[0].url) {
return programDetail.image[0].url
} else {
return ''
}
}
function parseCategory(programDetail) {
if (programDetail && programDetail.category_Info && programDetail.category_Info[0].title) {
return programDetail.category_Info[0].title
} else {
return ''
}
}
function parseDescription(programDetail) {
if (
programDetail &&
programDetail.content &&
programDetail.content[0] &&
programDetail.content[0].text
) {
let description = programDetail.content[0].text
let regex = /(<([^>]+)>)/gi
return description.replace(regex, '')
} else {
return ''
}
}
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: 'arirang.com',
output: 'arirang.com.guide.xml',
channels: 'arirang.com.channels.xml',
lang: 'en',
days: 7,
delay: 5000,
url: 'https://www.arirang.com/v1.0/open/external/proxy',
request: {
method: 'POST',
timeout: 5000,
cache: { ttl: 60 * 60 * 1000 },
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
Origin: 'https://www.arirang.com',
Referer: 'https://www.arirang.com/schedule',
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
},
data: function (context) {
const { channel, date } = context
return {
address: 'https://script.arirang.com/api/v1/bis/listScheduleV3.do',
method: 'POST',
headers: {},
body: {
data: {
dmParam: {
chanId: channel.site_id,
broadYmd: dayjs.tz(date, 'Asia/Seoul').format('YYYYMMDD'),
planNo: '1'
}
}
}
}
}
},
logo: function (context) {
return context.channel.logo
},
async parser(context) {
const programs = []
const items = parseItems(context.content)
for (let item of items) {
const programDetail = await parseProgramDetail(item)
programs.push({
title: parseTitle(programDetail),
start: parseStart(item),
stop: parseStop(item),
image: parseImage(programDetail),
category: parseCategory(programDetail),
description: parseDescription(programDetail)
})
}
return programs
}
}
function parseItems(content) {
if (content != '') {
const data = JSON.parse(content)
return !data || !data.responseBody || !Array.isArray(data.responseBody.dsSchWeek)
? []
: data.responseBody.dsSchWeek
} else {
return []
}
}
function parseStart(item) {
return dayjs.tz(item.broadYmd + ' ' + item.broadHm, 'YYYYMMDD HHmm', 'Asia/Seoul')
}
function parseStop(item) {
return dayjs
.tz(item.broadYmd + ' ' + item.broadHm, 'YYYYMMDD HHmm', 'Asia/Seoul')
.add(item.broadRun, 'minute')
}
async function parseProgramDetail(item) {
return axios
.post(
'https://www.arirang.com/v1.0/open/program/detail',
{
bis_program_code: item.pgmCd
},
{
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
Origin: 'https://www.arirang.com',
Referer: 'https://www.arirang.com/schedule',
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
},
timeout: 5000,
cache: { ttl: 60 * 1000 }
}
)
.then(response => {
// console.log('Retrieved program detail: bis_program_code ' + item.pgmCd)
return response.data
})
.catch(function () {
// The provider/server may not have details on every single programs.
// console.log('Unavailable program detail: bis_program_code ' + item.pgmCd)
})
}
function parseTitle(programDetail) {
if (programDetail && programDetail.title && programDetail.title[0] && programDetail.title[0].text) {
return programDetail.title[0].text
} else {
return ''
}
}
function parseImage(programDetail) {
if (programDetail && programDetail.image && programDetail.image[0].url) {
return programDetail.image[0].url
} else {
return ''
}
}
function parseCategory(programDetail) {
if (programDetail && programDetail.category_Info && programDetail.category_Info[0].title) {
return programDetail.category_Info[0].title
} else {
return ''
}
}
function parseDescription(programDetail) {
if (
programDetail &&
programDetail.content &&
programDetail.content[0] &&
programDetail.content[0].text
) {
let description = programDetail.content[0].text
let regex = /(<([^>]+)>)/gi
return description.replace(regex, '')
} else {
return ''
}
}

View File

@@ -1,72 +1,72 @@
const { url, parser } = require('./arirang.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')
dayjs.extend(utc)
jest.mock('axios')
const date = dayjs.tz('2023-08-25', 'Asia/Seoul').startOf('d')
const channel = {
xmltv_id: 'ArirangWorld.kr',
site_id: 'CH_W',
name: 'Arirang World',
lang: 'en',
logo: 'https://i.imgur.com/5Aoithj.png'
}
const content = fs.readFileSync(path.resolve(__dirname, '__data__/schedule.json'), 'utf8')
const programDetail = fs.readFileSync(path.resolve(__dirname, '__data__/detail.json'), 'utf8')
const context = { channel: channel, content: content, date: date }
it('can generate valid url', () => {
expect(url).toBe('https://www.arirang.com/v1.0/open/external/proxy')
})
it('can handle empty guide', async () => {
const results = await parser({ channel: channel, content: '', date: date })
expect(results).toMatchObject([])
})
it('can parse response', async () => {
axios.post.mockImplementation((url, data) => {
if (
url === 'https://www.arirang.com/v1.0/open/external/proxy' &&
JSON.stringify(data) ===
JSON.stringify({
address: 'https://script.arirang.com/api/v1/bis/listScheduleV3.do',
method: 'POST',
headers: {},
body: { data: { dmParam: { chanId: 'CH_W', broadYmd: '20230825', planNo: '1' } } }
})
) {
return Promise.resolve({
data: JSON.parse(content)
})
} else if (
url === 'https://www.arirang.com/v1.0/open/program/detail' &&
JSON.stringify(data) === JSON.stringify({ bis_program_code: '2023004T' })
) {
return Promise.resolve({
data: JSON.parse(programDetail)
})
} else {
return Promise.resolve({
data: ''
})
}
})
const results = await parser(context)
expect(results[0]).toMatchObject({
title: 'WITHIN THE FRAME [R]',
start: dayjs.tz(date, 'Asia/Seoul'),
stop: dayjs.tz(date, 'Asia/Seoul').add(30, 'minute'),
image:
'https://img.arirang.com/v1/AUTH_d52449c16d3b4bbca17d4fffd9fc44af/public/images/202308/2080840096998752900.png',
description: 'NEWS',
category: 'Current Affairs'
})
})
const { url, parser } = require('./arirang.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')
dayjs.extend(utc)
jest.mock('axios')
const date = dayjs.tz('2025-04-20', 'Asia/Seoul').startOf('d')
const channel = {
xmltv_id: 'ArirangWorld.kr',
site_id: 'CH_W',
name: 'Arirang World',
lang: 'en',
logo: 'https://i.imgur.com/5Aoithj.png'
}
const content = fs.readFileSync(path.resolve(__dirname, '__data__/schedule.json'), 'utf8')
const programDetail = fs.readFileSync(path.resolve(__dirname, '__data__/detail.json'), 'utf8')
const context = { channel: channel, content: content, date: date }
it('can generate valid url', () => {
expect(url).toBe('https://www.arirang.com/v1.0/open/external/proxy')
})
it('can handle empty guide', async () => {
const results = await parser({ channel: channel, content: '', date: date })
expect(results).toMatchObject([])
})
it('can parse response', async () => {
axios.post.mockImplementation((url, data) => {
if (
url === 'https://www.arirang.com/v1.0/open/external/proxy' &&
JSON.stringify(data) ===
JSON.stringify({
address: 'https://script.arirang.com/api/v1/bis/listScheduleV3.do',
method: 'POST',
headers: {},
body: { data: { dmParam: { chanId: 'CH_W', broadYmd: '20250420', planNo: '1' } } }
})
) {
return Promise.resolve({
data: JSON.parse(content)
})
} else if (
url === 'https://www.arirang.com/v1.0/open/program/detail' &&
JSON.stringify(data) === JSON.stringify({ bis_program_code: '2025006T' })
) {
return Promise.resolve({
data: JSON.parse(programDetail)
})
} else {
return Promise.resolve({
data: ''
})
}
})
const results = await parser(context)
expect(results[0]).toMatchObject({
title: 'Diplomat Archives: Hidden Stories',
start: dayjs.tz(date, 'Asia/Seoul'),
stop: dayjs.tz(date, 'Asia/Seoul').add(30, 'minute'),
image:
'https://img.arirang.com/v1/AUTH_d52449c16d3b4bbca17d4fffd9fc44af/public/images/202504/2985531324875408146.jpg',
description: 'As of April 2025, S. Korea has established diplomatic relations with a total of 194 countries.\nAmong them are countries that have had ties and exchanges with Korea for hundreds of years.\nWith such long-standing relationships with so many nations,\nmight there be fascinating hidden stories between Korea and the rest of the world that we dont know yet? \n\n"Diplomats Archives: Hidden Stories" begins with this very question.\nTogether with foreign embassies in Korea, the series uncovers and sheds light on meaningful yet lesser-known stories between Korea and other countries.\nThrough this, we aim to reaffirm the deep friendships that have been built over time, highlight how countries are interconnected—bilaterally and multilaterally—\nand emphasize the importance of cooperation on the global stage today.',
category: 'Current Affairs'
})
})

View File

@@ -0,0 +1 @@
[{"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}]

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="artonline.tv" lang="ar" xmltv_id="ARTAflam1.sa" site_id="">افلام 1</channel>
<channel site="artonline.tv" lang="ar" xmltv_id="ARTAflam2.sa" site_id="Aflam2">افلام 2</channel>
<channel site="artonline.tv" lang="ar" xmltv_id="ARTCinema.sa" site_id="Cinema">سينما</channel>
<channel site="artonline.tv" lang="ar" xmltv_id="ARTHekayat.sa" site_id="Hekayat">حكايات</channel>
<channel site="artonline.tv" lang="ar" xmltv_id="ARTHekayat2.sa" site_id="Hekayat2">حكايات 2</channel>
<channel site="artonline.tv" lang="ar" xmltv_id="ARTAflam1.sa" site_id="#">افلام 1</channel>
<channel site="artonline.tv" lang="ar" xmltv_id="ARTAflam2.sa" site_id="#Aflam2">افلام 2</channel>
<channel site="artonline.tv" lang="ar" xmltv_id="ARTCinema.sa" site_id="#Cinema">سينما</channel>
<channel site="artonline.tv" lang="ar" xmltv_id="ARTHekayat.sa" site_id="#Hekayat">حكايات</channel>
<channel site="artonline.tv" lang="ar" xmltv_id="ARTHekayat2.sa" site_id="#Hekayat2">حكايات 2</channel>
</channels>

View File

@@ -1,68 +1,70 @@
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 image = parseImage(item)
const start = parseStart(item)
const duration = parseDuration(item)
const stop = start.add(duration, 's')
programs.push({
title: item.title,
description: item.description,
image,
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 parseImage(item) {
return item.thumbnail ? `https://www.artonline.tv${item.thumbnail}` : null
}
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 }) {
const [, site_id] = channel.site_id.split('#')
return `https://www.artonline.tv/Home/Tvlist${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 image = parseImage(item)
const start = parseStart(item)
const duration = parseDuration(item)
const stop = start.add(duration, 's')
programs.push({
title: item.title,
description: item.description,
image,
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 parseImage(item) {
return item.thumbnail ? `https://www.artonline.tv${item.thumbnail}` : null
}

View File

@@ -1,65 +1,66 @@
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:
'تقرر الراقصه سونيا انشاء دار حضانه للأطفال اليتامى و عندما تتقدم بمشورعها للمسئول يرفض فتتحداه ، تلجأ للوزير عبد الحميد رأفت تربطه بها علاقة قديمة ، يخشى على مركزه و يرفض مساعدتها فتقرر كتابة مذكراتها بمساعدة أحد الصحفيين ، يتخوف عبد الحميد و المسئولين ثم يفاجأ عبد الحميد بحصول سونيا على الموافقه للمشورع و البدء في تنفيذه و ذلك لعلاقتها بأحد كبار المسئولين .',
image: 'https://www.artonline.tv/UploadImages/Channel/ARTAFLAM1/03/AlRaqesaWaAlSeyasi.jpg'
}
])
})
it('can handle empty guide', () => {
const result = parser({
content: ''
})
expect(result).toMatchObject([])
})
const { parser, url, request } = require('./artonline.tv.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 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 = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
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:
'تقرر الراقصه سونيا انشاء دار حضانه للأطفال اليتامى و عندما تتقدم بمشورعها للمسئول يرفض فتتحداه ، تلجأ للوزير عبد الحميد رأفت تربطه بها علاقة قديمة ، يخشى على مركزه و يرفض مساعدتها فتقرر كتابة مذكراتها بمساعدة أحد الصحفيين ، يتخوف عبد الحميد و المسئولين ثم يفاجأ عبد الحميد بحصول سونيا على الموافقه للمشورع و البدء في تنفيذه و ذلك لعلاقتها بأحد كبار المسئولين .',
image: 'https://www.artonline.tv/UploadImages/Channel/ARTAFLAM1/03/AlRaqesaWaAlSeyasi.jpg'
}
])
})
it('can handle empty guide', () => {
const result = parser({
content: ''
})
expect(result).toMatchObject([])
})

View File

@@ -1,86 +1,86 @@
const cheerio = require('cheerio')
const axios = require('axios')
const { DateTime } = require('luxon')
module.exports = {
site: 'awilime.com',
days: 2,
url({ channel, date }) {
return `https://www.awilime.com/tv/napi_musor/${channel.site_id}/${date.format('YYYY_MM_DD')}`
},
parser({ content, date }) {
const programs = []
const items = parseItems(content)
items.forEach(item => {
const prev = programs[programs.length - 1]
const $item = cheerio.load(item)
let start = parseStart($item, date)
if (!start) return
if (prev) {
prev.stop = start
}
const stop = start.plus({ minute: 30 })
programs.push({
title: parseTitle($item),
sub_title: parseSubTitle($item),
description: parseDescription($item),
start,
stop
})
})
return programs
},
async channels() {
const html = await axios
.get('https://www.awilime.com/tv/napi_musor')
.then(r => r.data)
.catch(console.log)
const $ = cheerio.load(html)
const items = $('#body > div.tk > div > div').toArray()
const channels = []
items.forEach(item => {
const name = $(item).find('a').text().trim()
const url = $(item).find('a').attr('href')
const [, site_id] = url.match(/\/tv\/napi_musor\/(.*)/) || [null, null]
if (!site_id) return
if (channels.find(channel => channel.site_id === site_id)) return
channels.push({
lang: 'hu',
site_id,
name
})
})
return channels
}
}
function parseTitle($item) {
return $item('b > a').text().trim()
}
function parseSubTitle($item) {
return $item('i').clone().children().remove('s').end().text().trim()
}
function parseDescription($item) {
return $item('p').text().trim()
}
function parseStart($item, date) {
let time = $item('b').clone().children().remove().end().text().trim()
if (!time || !/^\d/.test(time)) return null
time = `${date.format('YYYY-MM-DD')} ${time}`
return DateTime.fromFormat(time, 'yyyy-MM-dd HH:mm', { zone: 'Europe/Budapest' }).toUTC()
}
function parseItems(content) {
const $ = cheerio.load(content)
return $('#body > div.tdc > div.td2 > div').toArray()
}
const cheerio = require('cheerio')
const axios = require('axios')
const { DateTime } = require('luxon')
module.exports = {
site: 'awilime.com',
days: 2,
url({ channel, date }) {
return `https://www.awilime.com/tv/napi_musor/${channel.site_id}/${date.format('YYYY_MM_DD')}`
},
parser({ content, date }) {
const programs = []
const items = parseItems(content)
items.forEach(item => {
const prev = programs[programs.length - 1]
const $item = cheerio.load(item)
let start = parseStart($item, date)
if (!start) return
if (prev) {
prev.stop = start
}
const stop = start.plus({ minute: 30 })
programs.push({
title: parseTitle($item),
sub_title: parseSubTitle($item),
description: parseDescription($item),
start,
stop
})
})
return programs
},
async channels() {
const html = await axios
.get('https://www.awilime.com/tv/napi_musor')
.then(r => r.data)
.catch(console.log)
const $ = cheerio.load(html)
const items = $('#body > div.tk > div > div').toArray()
const channels = []
items.forEach(item => {
const name = $(item).find('a').text().trim()
const url = $(item).find('a').attr('href')
const [, site_id] = url.match(/\/tv\/napi_musor\/(.*)/) || [null, null]
if (!site_id) return
if (channels.find(channel => channel.site_id === site_id)) return
channels.push({
lang: 'hu',
site_id,
name
})
})
return channels
}
}
function parseTitle($item) {
return $item('b > a').text().trim()
}
function parseSubTitle($item) {
return $item('i').clone().children().remove('s').end().text().trim()
}
function parseDescription($item) {
return $item('p').text().trim()
}
function parseStart($item, date) {
let time = $item('b').clone().children().remove().end().text().trim()
if (!time || !/^\d/.test(time)) return null
time = `${date.format('YYYY-MM-DD')} ${time}`
return DateTime.fromFormat(time, 'yyyy-MM-dd HH:mm', { zone: 'Europe/Budapest' }).toUTC()
}
function parseItems(content) {
const $ = cheerio.load(content)
return $('#body > div.tdc > div.td2 > div').toArray()
}

View File

@@ -1,49 +1,49 @@
const { parser, url, request } = require('./awilime.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('2024-06-26', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: 'budapest_europa_tv',
xmltv_id: 'BudapestEuropaTelevizio.hu'
}
it('can generate valid url', () => {
expect(url({ channel, date })).toBe(
'https://www.awilime.com/tv/napi_musor/budapest_europa_tv/2024_06_26'
)
})
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(15)
expect(results[3]).toMatchObject({
start: '2024-06-26T07:00:00.000Z',
stop: '2024-06-26T08:00:00.000Z',
title: 'Ébredés',
sub_title: 'Amerikai dokumentumfilm (2018)',
description: 'Balla Tibor misszionárius'
})
})
it('can handle empty guide', () => {
const result = parser({
date,
channel,
content:
'<html><head><title>Object moved</title></head><body><h2>Object moved to <a href="/tv/napi_musor/budapest_europa_tv/2024_06_24">here</a>.</h2></body></html>'
})
expect(result).toMatchObject([])
})
const { parser, url } = require('./awilime.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('2024-06-26', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: 'budapest_europa_tv',
xmltv_id: 'BudapestEuropaTelevizio.hu'
}
it('can generate valid url', () => {
expect(url({ channel, date })).toBe(
'https://www.awilime.com/tv/napi_musor/budapest_europa_tv/2024_06_26'
)
})
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(15)
expect(results[3]).toMatchObject({
start: '2024-06-26T07:00:00.000Z',
stop: '2024-06-26T08:00:00.000Z',
title: 'Ébredés',
sub_title: 'Amerikai dokumentumfilm (2018)',
description: 'Balla Tibor misszionárius'
})
})
it('can handle empty guide', () => {
const result = parser({
date,
channel,
content:
'<html><head><title>Object moved</title></head><body><h2>Object moved to <a href="/tv/napi_musor/budapest_europa_tv/2024_06_24">here</a>.</h2></body></html>'
})
expect(result).toMatchObject([])
})

View File

@@ -1,110 +1,110 @@
const axios = require('axios')
const dayjs = require('dayjs')
const cheerio = require('cheerio')
const { DateTime } = require('luxon')
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 = DateTime.fromMillis(date.valueOf()).minus({ days: 1 })
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 < prev.start) {
start = start.plus({ days: 1 })
date = date.plus({ days: 1 })
}
prev.stop = start
}
let stop = parseTime($item, start)
if (stop < start) {
stop = stop.plus({ days: 1 })
}
programs.push({
title,
category,
start,
stop
})
})
return programs
},
async channels({ lang }) {
const categories = ['entertainment', 'sports']
let channels = []
for (let category of categories) {
const url = `https://www.bein.com/en/epg-ajax-template/?action=epg_fetch&offset=0&category=${category}&serviceidentity=bein.net&mins=00&cdate=${dayjs().format(
'YYYY-MM-DD'
)}&language=${lang.toUpperCase()}&postid=25356&loadindex=0`
const data = await axios
.get(url)
.then(r => r.data)
.catch(console.log)
const $ = cheerio.load(data)
$('.container-tvguide > div').each((i, el) => {
const id = $(el).attr('id')
if (!id || !/^channels_\d+/.test(id)) return
const [, channelId] = id.split('_')
channels.push({
lang,
site_id: `${category}#${channelId}`,
name: channelId
})
})
}
return channels
}
}
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.toFormat('yyyy-MM-dd')} ${time}`
return DateTime.fromFormat(time, 'yyyy-MM-dd HH:mm', { zone: 'Asia/Qatar' }).toUTC()
}
function parseItems(content, channel) {
const [, channelId] = channel.site_id.split('#')
const $ = cheerio.load(content)
return $(`#channels_${channelId} .slider > ul:first-child > li`).toArray()
}
const axios = require('axios')
const dayjs = require('dayjs')
const cheerio = require('cheerio')
const { DateTime } = require('luxon')
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 = DateTime.fromMillis(date.valueOf()).minus({ days: 1 })
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 < prev.start) {
start = start.plus({ days: 1 })
date = date.plus({ days: 1 })
}
prev.stop = start
}
let stop = parseTime($item, start)
if (stop < start) {
stop = stop.plus({ days: 1 })
}
programs.push({
title,
category,
start,
stop
})
})
return programs
},
async channels({ lang }) {
const categories = ['entertainment', 'sports']
let channels = []
for (let category of categories) {
const url = `https://www.bein.com/en/epg-ajax-template/?action=epg_fetch&offset=0&category=${category}&serviceidentity=bein.net&mins=00&cdate=${dayjs().format(
'YYYY-MM-DD'
)}&language=${lang.toUpperCase()}&postid=25356&loadindex=0`
const data = await axios
.get(url)
.then(r => r.data)
.catch(console.log)
const $ = cheerio.load(data)
$('.container-tvguide > div').each((i, el) => {
const id = $(el).attr('id')
if (!id || !/^channels_\d+/.test(id)) return
const [, channelId] = id.split('_')
channels.push({
lang,
site_id: `${category}#${channelId}`,
name: channelId
})
})
}
return channels
}
}
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.toFormat('yyyy-MM-dd')} ${time}`
return DateTime.fromFormat(time, 'yyyy-MM-dd HH:mm', { zone: 'Asia/Qatar' }).toUTC()
}
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

@@ -1,58 +1,58 @@
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([])
})
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

@@ -12,7 +12,7 @@
<channel site="bein.com" lang="ar" xmltv_id="AlkassTwo.qa" site_id="sports#35">35</channel>
<channel site="bein.com" lang="ar" xmltv_id="BabyTV.uk" site_id="entertainment#32">32</channel>
<channel site="bein.com" lang="ar" xmltv_id="Baraem.qa" site_id="entertainment#30">30</channel>
<channel site="bein.com" lang="ar" xmltv_id="BBCEarthMiddleEast.uk" site_id="entertainment#25">25</channel>
<channel site="bein.com" lang="ar" xmltv_id="BBCEarth.uk@MiddleEast" site_id="entertainment#25">25</channel>
<channel site="bein.com" lang="ar" xmltv_id="beIN4K.qa" site_id="sports#15">15</channel>
<channel site="bein.com" lang="ar" xmltv_id="beINDrama1.qa" site_id="entertainment#10">10</channel>
<channel site="bein.com" lang="ar" xmltv_id="beINGourmet.qa" site_id="entertainment#11">11</channel>
@@ -54,10 +54,10 @@
<channel site="bein.com" lang="ar" xmltv_id="beINSportsXtra1.qa" site_id="sports#13">13</channel>
<channel site="bein.com" lang="ar" xmltv_id="beINSportsXtra2.qa" site_id="sports#14">14</channel>
<channel site="bein.com" lang="ar" xmltv_id="BeJunior.qa" site_id="entertainment#21">21</channel>
<channel site="bein.com" lang="ar" xmltv_id="BloombergTVMiddleEast.ae" site_id="entertainment#22">22</channel>
<channel site="bein.com" lang="ar" xmltv_id="BloombergTV.us@MiddleEast" site_id="entertainment#22">22</channel>
<channel site="bein.com" lang="ar" xmltv_id="CartoonitoMENA.uk" site_id="entertainment#38">38</channel>
<channel site="bein.com" lang="ar" xmltv_id="CartoonNetworkArabic.ae" site_id="entertainment#34">34</channel>
<channel site="bein.com" lang="ar" xmltv_id="CartoonNetworkHindi.in" site_id="entertainment#35">35</channel>
<channel site="bein.com" lang="ar" xmltv_id="CartoonNetwork.in@Hindi" site_id="entertainment#35">35</channel>
<channel site="bein.com" lang="ar" xmltv_id="CartoonNetworkMENA.uk" site_id="entertainment#33">33</channel>
<channel site="bein.com" lang="ar" xmltv_id="CBeebiesMiddleEast.uk" site_id="entertainment#31">31</channel>
<channel site="bein.com" lang="ar" xmltv_id="ClubMTVEurope.uk" site_id="entertainment#20">20</channel>

View File

@@ -13,7 +13,7 @@
<channel site="bein.com" lang="en" xmltv_id="AlkassTwo.qa" site_id="sports#34">34</channel>
<channel site="bein.com" lang="en" xmltv_id="BabyTV.uk" site_id="entertainment#35">35</channel>
<channel site="bein.com" lang="en" xmltv_id="Baraem.qa" site_id="entertainment#31">31</channel>
<channel site="bein.com" lang="en" xmltv_id="BBCEarthMiddleEast.uk" site_id="entertainment#25">25</channel>
<channel site="bein.com" lang="en" xmltv_id="BBCEarth.uk@MiddleEast" site_id="entertainment#25">25</channel>
<channel site="bein.com" lang="en" xmltv_id="beIN4K.qa" site_id="sports#15">15</channel>
<channel site="bein.com" lang="en" xmltv_id="beINDrama1.qa" site_id="entertainment#10">10</channel>
<channel site="bein.com" lang="en" xmltv_id="beINGourmet.qa" site_id="entertainment#11">11</channel>
@@ -55,10 +55,10 @@
<channel site="bein.com" lang="en" xmltv_id="beINSportsXtra1.qa" site_id="sports#13">13</channel>
<channel site="bein.com" lang="en" xmltv_id="beINSportsXtra2.qa" site_id="sports#14">14</channel>
<channel site="bein.com" lang="en" xmltv_id="BeJunior.qa" site_id="entertainment#29">29</channel>
<channel site="bein.com" lang="en" xmltv_id="BloombergTVMiddleEast.ae" site_id="entertainment#22">22</channel>
<channel site="bein.com" lang="en" xmltv_id="BloombergTV.us@MiddleEast" site_id="entertainment#22">22</channel>
<channel site="bein.com" lang="en" xmltv_id="CartoonitoMENA.uk" site_id="entertainment#38">38</channel>
<channel site="bein.com" lang="en" xmltv_id="CartoonNetworkArabic.ae" site_id="entertainment#33">33</channel>
<channel site="bein.com" lang="en" xmltv_id="CartoonNetworkHindi.in" site_id="entertainment#34">34</channel>
<channel site="bein.com" lang="en" xmltv_id="CartoonNetwork.in@Hindi" site_id="entertainment#34">34</channel>
<channel site="bein.com" lang="en" xmltv_id="CartoonNetworkMENA.uk" site_id="entertainment#32">32</channel>
<channel site="bein.com" lang="en" xmltv_id="CBeebiesMiddleEast.uk" site_id="entertainment#36">36</channel>
<channel site="bein.com" lang="en" xmltv_id="ClubMTVEurope.uk" site_id="entertainment#21">21</channel>

View File

@@ -1,74 +1,73 @@
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: {
headers: {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
}
},
url: function ({ date, channel }) {
return `https://www.beinsports.com/api/opta/tv-event?&startBefore=${date
.add(1, 'd')
.format('YYYY-MM-DDTHH:mm:ss.SSS')}Z&endAfter=${date.format(
'YYYY-MM-DDTHH:mm:ss.SSS'
)}Z&channelIds=${channel.site_id}`
},
parser: function ({ content }) {
let programs = []
const items = parseItems(content)
if (!items.length == 0) {
items.forEach(item => {
const start = dayjs.utc(item.startDate)
const stop = dayjs.utc(item.endDate)
programs.push({
title: item.title,
description: item.description,
start,
stop
})
})
}
return programs
},
async channels({ region, lang }) {
const data = await axios
.get(`https://www.beinsports.com/api/opta/tv-channel?region=${lang}-${region}`, this.request)
.then(r => r.data)
.catch(console.log)
return data.rows.map(item => {
return {
lang,
site_id: item.id,
name: item.name
}
})
}
}
function parseItems(content) {
let data
try {
data = JSON.parse(content)
} catch (error) {
return []
}
if (!data || !data['rows']) {
return []
}
return data.rows
}
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: 'beinsports.com',
days: 2,
request: {
headers: {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
}
},
url: function ({ date, channel }) {
return `https://www.beinsports.com/api/opta/tv-event?&startBefore=${date
.add(1, 'd')
.format('YYYY-MM-DDTHH:mm:ss.SSS')}Z&endAfter=${date.format(
'YYYY-MM-DDTHH:mm:ss.SSS'
)}Z&channelIds=${channel.site_id}`
},
parser: function ({ content }) {
let programs = []
const items = parseItems(content)
if (!items.length == 0) {
items.forEach(item => {
const start = dayjs.utc(item.startDate)
const stop = dayjs.utc(item.endDate)
programs.push({
title: item.title,
description: item.description,
start,
stop
})
})
}
return programs
},
async channels({ region, lang }) {
const data = await axios
.get(`https://www.beinsports.com/api/opta/tv-channel?region=${lang}-${region}`, this.request)
.then(r => r.data)
.catch(console.log)
return data.rows.map(item => {
return {
lang,
site_id: item.id,
name: item.name
}
})
}
}
function parseItems(content) {
let data
try {
data = JSON.parse(content)
} catch {
return []
}
if (!data || !data['rows']) {
return []
}
return data.rows
}

View File

@@ -1,45 +1,43 @@
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('2023-10-22T00:00:00.000', '"YYYY-MM-DDTHH:mm:ss.SSS').startOf('d')
const channel = { site_id: 'C244C48D-3B54-406A-94C9-D63B16318267', xmltv_id: 'beINSportsUSA.us' }
it('can generate valid url', () => {
const result = url({ date, channel })
expect(result).toBe(
'https://www.beinsports.com/api/opta/tv-event?&startBefore=2023-10-23T00:00:00.000Z&endAfter=2023-10-22T00:00:00.000Z&channelIds=C244C48D-3B54-406A-94C9-D63B16318267'
)
})
const content =
'{"count":1,"rows":[{"data":{"eventId":"2028126","eventDate":"2023-10-21T10:30:00","utcEventDate":"2023-10-20T23:30:00","duration":"90","programId":"106230","programTypeId":"5","title":"ATP 500"},"duration":5400000,"title":"Tokyo Day 5 QF 2","startDate":"2023-10-20T23:30:00.000Z","endDate":"2023-10-21T01:00:00.000Z","description":"Exclusive coverage of the 2023 ATP Tour on beIN SPORTS","channelId":"164C0EDA-EBCE-4AA6-9DDA-D603E0948B9F"}]}'
it('can parse response', () => {
const result = parser({ content, channel, date }).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2023-10-20T23:30:00.000Z',
stop: '2023-10-21T01:00:00.000Z',
title: 'Tokyo Day 5 QF 2',
description: 'Exclusive coverage of the 2023 ATP Tour on beIN SPORTS'
}
])
})
it('can handle empty guide', () => {
const result = parser({
content: '[]'
})
expect(result).toMatchObject([])
})
const { parser, url } = require('./beinsports.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-10-22T00:00:00.000', '"YYYY-MM-DDTHH:mm:ss.SSS').startOf('d')
const channel = { site_id: 'C244C48D-3B54-406A-94C9-D63B16318267', xmltv_id: 'beINSportsUSA.us' }
it('can generate valid url', () => {
const result = url({ date, channel })
expect(result).toBe(
'https://www.beinsports.com/api/opta/tv-event?&startBefore=2023-10-23T00:00:00.000Z&endAfter=2023-10-22T00:00:00.000Z&channelIds=C244C48D-3B54-406A-94C9-D63B16318267'
)
})
const content =
'{"count":1,"rows":[{"data":{"eventId":"2028126","eventDate":"2023-10-21T10:30:00","utcEventDate":"2023-10-20T23:30:00","duration":"90","programId":"106230","programTypeId":"5","title":"ATP 500"},"duration":5400000,"title":"Tokyo Day 5 QF 2","startDate":"2023-10-20T23:30:00.000Z","endDate":"2023-10-21T01:00:00.000Z","description":"Exclusive coverage of the 2023 ATP Tour on beIN SPORTS","channelId":"164C0EDA-EBCE-4AA6-9DDA-D603E0948B9F"}]}'
it('can parse response', () => {
const result = parser({ content, channel, date }).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2023-10-20T23:30:00.000Z',
stop: '2023-10-21T01:00:00.000Z',
title: 'Tokyo Day 5 QF 2',
description: 'Exclusive coverage of the 2023 ATP Tour on beIN SPORTS'
}
])
})
it('can handle empty guide', () => {
const result = parser({
content: '[]'
})
expect(result).toMatchObject([])
})

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports2.au" site_id="63A30D9C-609D-4A30-8730-2CA391DF287A">beIN SPORTS 2</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports1.au" site_id="164C0EDA-EBCE-4AA6-9DDA-D603E0948B9F">beIN SPORTS 1</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports3.au" site_id="2E8A6222-8D90-4291-81E3-AF2F72557746">beIN SPORTS 3</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports2.qa@Australia" site_id="63A30D9C-609D-4A30-8730-2CA391DF287A">beIN SPORTS 2</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports1.qa@Australia" site_id="164C0EDA-EBCE-4AA6-9DDA-D603E0948B9F">beIN SPORTS 1</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports3.qa@Australia" site_id="2E8A6222-8D90-4291-81E3-AF2F72557746">beIN SPORTS 3</channel>
</channels>

View File

@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSports1.fr" site_id="66265DD1-D2AA-4A89-9412-2455186E90ED">beIN SPORTS 1</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSports2.fr" site_id="1E886E98-3104-4D8E-A97F-734B23108E8A">beIN SPORTS 2</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSports3.fr" site_id="6DB008B8-66DA-423E-805D-616211D4B174">beIN SPORTS 3</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSportsMax4.fr" site_id="EF7E0369-CFD9-4607-9238-EC483E6D58A3">beIN SPORTS MAX 4</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSportsMax5.fr" site_id="A4425E44-B004-4137-ACB4-458BA4D710F8">beIN SPORTS MAX 5</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSportsMax6.fr" site_id="BBD26D71-897D-4799-87A1-A87120130D48">beIN SPORTS MAX 6</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSportsMax7.fr" site_id="9B4708C5-F5F0-452A-8157-4661C30FAE6A">beIN SPORTS MAX 7</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSportsMax8.fr" site_id="76D2430C-8BCB-41BD-A1DE-FBA0D58C5E8A">beIN SPORTS MAX 8</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSportsMax9.fr" site_id="FB208953-1C70-4D1E-B918-103AB02AB181">beIN SPORTS MAX 9</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSportsMax10.fr" site_id="6F425028-14F0-4E38-B776-71A9DB3F3493">beIN SPORTS MAX 10</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSports1.qa@France" site_id="66265DD1-D2AA-4A89-9412-2455186E90ED">beIN SPORTS 1</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSports2.qa@France" site_id="1E886E98-3104-4D8E-A97F-734B23108E8A">beIN SPORTS 2</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSports3.qa@France" site_id="6DB008B8-66DA-423E-805D-616211D4B174">beIN SPORTS 3</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSportsMax4.qa@France" site_id="EF7E0369-CFD9-4607-9238-EC483E6D58A3">beIN SPORTS MAX 4</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSportsMax5.qa@France" site_id="A4425E44-B004-4137-ACB4-458BA4D710F8">beIN SPORTS MAX 5</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSportsMax6.qa@France" site_id="BBD26D71-897D-4799-87A1-A87120130D48">beIN SPORTS MAX 6</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSportsMax7.qa@France" site_id="9B4708C5-F5F0-452A-8157-4661C30FAE6A">beIN SPORTS MAX 7</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSportsMax8.qa@France" site_id="76D2430C-8BCB-41BD-A1DE-FBA0D58C5E8A">beIN SPORTS MAX 8</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSportsMax9.qa@France" site_id="FB208953-1C70-4D1E-B918-103AB02AB181">beIN SPORTS MAX 9</channel>
<channel site="beinsports.com" lang="fr" xmltv_id="beINSportsMax10.qa@France" site_id="6F425028-14F0-4E38-B776-71A9DB3F3493">beIN SPORTS MAX 10</channel>
</channels>

View File

@@ -2,5 +2,5 @@
<channels>
<channel site="beinsports.com" lang="en" xmltv_id="" site_id="7C714598-E7ED-4B0F-8BD1-E8E80D473922">beIN SPORTS 3</channel>
<channel site="beinsports.com" lang="en" xmltv_id="" site_id="DDFC8C16-6363-4A2C-AE66-2CE357DBC28E">beIN SPORTS 2</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports1.my" site_id="0FA3DEF0-234B-4E25-934F-392DF2C3162C">beIN SPORTS</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports1.qa@Malaysia" site_id="0FA3DEF0-234B-4E25-934F-392DF2C3162C">beIN SPORTS</channel>
</channels>

View File

@@ -3,13 +3,13 @@
<channel site="beinsports.com" lang="en" xmltv_id="" site_id="5ED9E1C4-BEF4-4AC2-8F90-28B3DCA26375">BEINC</channel>
<channel site="beinsports.com" lang="en" xmltv_id="" site_id="520D107A-71D4-4CB7-B141-1C6B089A7FFC">BEINS8C</channel>
<channel site="beinsports.com" lang="en" xmltv_id="" site_id="5824C394-7211-4004-AC46-35BD58B9D1EE">BEINSSC</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports3USA.us" site_id="90E69FC7-AA8C-40F2-B35F-EBD174495F76">beIN SPORTS 3</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports4USA.us" site_id="D0546ED7-9DB2-4924-9E32-C4F077E7BFC7">beIN SPORTS 4</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports5USA.us" site_id="A5A48DB1-C00B-4DB9-9FC6-5E5F25C18830">beIN SPORTS 5</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports6USA.us" site_id="E56B0905-F99F-4DB1-931E-E6002B530867">beIN SPORTS 6</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports7USA.us" site_id="831591C8-DA65-4528-B837-0E5A147887FB">beIN SPORTS 7</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports8USA.us" site_id="9A424246-EC89-43C3-9239-AA3A40540F94">beIN SPORTS 8</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSportsenEspanol.us" site_id="4083661E-F588-4700-943C-8FDF65F1B5EB">beIN SPORTS Español</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports3.qa@USA" site_id="90E69FC7-AA8C-40F2-B35F-EBD174495F76">beIN SPORTS 3</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports4.qa@USA" site_id="D0546ED7-9DB2-4924-9E32-C4F077E7BFC7">beIN SPORTS 4</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports5.qa@USA" site_id="A5A48DB1-C00B-4DB9-9FC6-5E5F25C18830">beIN SPORTS 5</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports6.qa@USA" site_id="E56B0905-F99F-4DB1-931E-E6002B530867">beIN SPORTS 6</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports7.qa@USA" site_id="831591C8-DA65-4528-B837-0E5A147887FB">beIN SPORTS 7</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSports8.qa@USA" site_id="9A424246-EC89-43C3-9239-AA3A40540F94">beIN SPORTS 8</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSportsenEspanol.qa" site_id="4083661E-F588-4700-943C-8FDF65F1B5EB">beIN SPORTS Español</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSportsUSA.us" site_id="C244C48D-3B54-406A-94C9-D63B16318267">beIN SPORTS</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSPORTSXTRA.us" site_id="1ACADCF1-DFAC-480B-872C-53D51FE1B45D">beIN SPORTS XTRA</channel>
<channel site="beinsports.com" lang="en" xmltv_id="beINSPORTSXTRAenEspanol.us" site_id="5223E3D7-FB4E-4155-885A-9165996B22FA">beIN SPORTS XTRA ñ</channel>

View File

@@ -3,13 +3,13 @@
<channel site="beinsports.com" lang="es" xmltv_id="" site_id="5ED9E1C4-BEF4-4AC2-8F90-28B3DCA26375">BEINC</channel>
<channel site="beinsports.com" lang="es" xmltv_id="" site_id="520D107A-71D4-4CB7-B141-1C6B089A7FFC">BEINS8C</channel>
<channel site="beinsports.com" lang="es" xmltv_id="" site_id="5824C394-7211-4004-AC46-35BD58B9D1EE">BEINSSC</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSports3USA.us" site_id="90E69FC7-AA8C-40F2-B35F-EBD174495F76">beIN SPORTS 3</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSports4USA.us" site_id="D0546ED7-9DB2-4924-9E32-C4F077E7BFC7">beIN SPORTS 4</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSports5USA.us" site_id="A5A48DB1-C00B-4DB9-9FC6-5E5F25C18830">beIN SPORTS 5</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSports6USA.us" site_id="E56B0905-F99F-4DB1-931E-E6002B530867">beIN SPORTS 6</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSports7USA.us" site_id="831591C8-DA65-4528-B837-0E5A147887FB">beIN SPORTS 7</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSports8USA.us" site_id="9A424246-EC89-43C3-9239-AA3A40540F94">beIN SPORTS 8</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSportsenEspanol.us" site_id="4083661E-F588-4700-943C-8FDF65F1B5EB">beIN SPORTS Español</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSports3.qa@USA" site_id="90E69FC7-AA8C-40F2-B35F-EBD174495F76">beIN SPORTS 3</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSports4.qa@USA" site_id="D0546ED7-9DB2-4924-9E32-C4F077E7BFC7">beIN SPORTS 4</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSports5.qa@USA" site_id="A5A48DB1-C00B-4DB9-9FC6-5E5F25C18830">beIN SPORTS 5</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSports6.qa@USA" site_id="E56B0905-F99F-4DB1-931E-E6002B530867">beIN SPORTS 6</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSports7.qa@USA" site_id="831591C8-DA65-4528-B837-0E5A147887FB">beIN SPORTS 7</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSports8.qa@USA" site_id="9A424246-EC89-43C3-9239-AA3A40540F94">beIN SPORTS 8</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSportsenEspanol.qa" site_id="4083661E-F588-4700-943C-8FDF65F1B5EB">beIN SPORTS Español</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSportsUSA.us" site_id="C244C48D-3B54-406A-94C9-D63B16318267">beIN SPORTS</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSPORTSXTRA.us" site_id="1ACADCF1-DFAC-480B-872C-53D51FE1B45D">beIN SPORTS XTRA</channel>
<channel site="beinsports.com" lang="es" xmltv_id="beINSPORTSXTRAenEspanol.us" site_id="5223E3D7-FB4E-4155-885A-9165996B22FA">beIN SPORTS XTRA ñ</channel>

View File

@@ -3,7 +3,6 @@
<channel site="berrymedia.co.kr" lang="ko" xmltv_id="BallTV.kr" site_id="6">BallTV</channel>
<channel site="berrymedia.co.kr" lang="ko" xmltv_id="CookTV.kr" site_id="2">CookTV</channel>
<channel site="berrymedia.co.kr" lang="ko" xmltv_id="GMTV.kr" site_id="4">GMTV</channel>
<channel site="berrymedia.co.kr" lang="ko" xmltv_id="GTV.kr" site_id="">GTV</channel>
<channel site="berrymedia.co.kr" lang="ko" xmltv_id="LifeSportsTV.kr" site_id="3">생활체육TV</channel>
<channel site="berrymedia.co.kr" lang="ko" xmltv_id="UHDDreamTV.kr" site_id="5">UHDDreamTV</channel>
</channels>

View File

@@ -1,93 +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) {
const $ = cheerio.load(content)
return $('.sc_time dd').toArray()
}
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) {
const $ = cheerio.load(content)
return $('.sc_time dd').toArray()
}

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