Make code prettier

This commit is contained in:
Aleksandr Statciuk 2022-12-29 23:50:36 +03:00
parent 268d150cc5
commit dd6d694491
31 changed files with 1079 additions and 1051 deletions

View file

@ -32,45 +32,45 @@ const xsd = `<?xml version="1.0" encoding="UTF-8"?>
program.argument('<filepath>', 'Path to file to validate').parse(process.argv) program.argument('<filepath>', 'Path to file to validate').parse(process.argv)
async function main() { async function main() {
if (!program.args.length) { if (!program.args.length) {
logger.error('required argument "filepath" not specified') logger.error('required argument "filepath" not specified')
} }
let errors = [] let errors = []
for (const filepath of program.args) { for (const filepath of program.args) {
if (!filepath.endsWith('.xml')) continue if (!filepath.endsWith('.xml')) continue
const xml = await file.read(filepath) const xml = await file.read(filepath)
let localErrors = [] let localErrors = []
try { try {
const xsdDoc = libxml.parseXml(xsd) const xsdDoc = libxml.parseXml(xsd)
const doc = libxml.parseXml(xml) const doc = libxml.parseXml(xml)
if (!doc.validate(xsdDoc)) { if (!doc.validate(xsdDoc)) {
localErrors = doc.validationErrors localErrors = doc.validationErrors
} }
} catch (error) { } catch (error) {
localErrors.push(error) localErrors.push(error)
} }
if (localErrors.length) { if (localErrors.length) {
logger.info(`\n${chalk.underline(filepath)}`) logger.info(`\n${chalk.underline(filepath)}`)
localErrors.forEach(error => { localErrors.forEach(error => {
const position = `${error.line}:${error.column}` const position = `${error.line}:${error.column}`
logger.error(` ${chalk.gray(position.padEnd(4, ' '))} ${error.message.trim()}`) logger.error(` ${chalk.gray(position.padEnd(4, ' '))} ${error.message.trim()}`)
}) })
errors = errors.concat(localErrors) errors = errors.concat(localErrors)
} }
} }
if (errors.length) { if (errors.length) {
logger.error(chalk.red(`\n${errors.length} error(s)`)) logger.error(chalk.red(`\n${errors.length} error(s)`))
process.exit(1) process.exit(1)
} }
} }
main() main()

View file

@ -5,9 +5,9 @@ dayjs.extend(utc)
const date = {} const date = {}
date.getUTC = function (d = null) { date.getUTC = function (d = null) {
if (typeof d === 'string') return dayjs.utc(d).startOf('d') if (typeof d === 'string') return dayjs.utc(d).startOf('d')
return dayjs.utc().startOf('d') return dayjs.utc().startOf('d')
} }
module.exports = date module.exports = date

View file

@ -3,11 +3,11 @@ const { gzip, ungzip } = require('node-gzip')
const zip = {} const zip = {}
zip.compress = async function (string) { zip.compress = async function (string) {
return gzip(string) return gzip(string)
} }
zip.decompress = async function (string) { zip.decompress = async function (string) {
return ungzip(string) return ungzip(string)
} }
module.exports = zip module.exports = zip

View file

@ -15,7 +15,7 @@ module.exports = {
} }
}, },
url({ date }) { url({ date }) {
return `https://epg.abctv.net.au/processed/Sydney_${date.format('YYYY-MM-DD')}.json` return `https://epg.abctv.net.au/processed/Sydney_${date.format('YYYY-MM-DD')}.json`
}, },
parser({ content, channel }) { parser({ content, channel }) {
let programs = [] let programs = []
@ -28,7 +28,7 @@ module.exports = {
description: item.description, description: item.description,
season: parseSeason(item), season: parseSeason(item),
episode: parseEpisode(item), episode: parseEpisode(item),
rating: parseRating(item), rating: parseRating(item),
icon: parseIcon(item), icon: parseIcon(item),
start: parseTime(item.start_time), start: parseTime(item.start_time),
stop: parseTime(item.end_time) stop: parseTime(item.end_time)
@ -40,35 +40,37 @@ module.exports = {
} }
function parseItems(content, channel) { function parseItems(content, channel) {
try { try {
const data = JSON.parse(content) const data = JSON.parse(content)
if (!data) return [] if (!data) return []
if (!Array.isArray(data.schedule)) return [] if (!Array.isArray(data.schedule)) return []
const channelData = data.schedule.find(i => i.channel == channel.site_id) const channelData = data.schedule.find(i => i.channel == channel.site_id)
return channelData.listing && Array.isArray(channelData.listing) ? channelData.listing : [] return channelData.listing && Array.isArray(channelData.listing) ? channelData.listing : []
} catch (err) { } catch (err) {
return [] return []
} }
} }
function parseSeason(item) { function parseSeason(item) {
return item.series_num || null return item.series_num || null
} }
function parseEpisode(item) { function parseEpisode(item) {
return item.episode_num || null return item.episode_num || null
} }
function parseTime(time) { function parseTime(time) {
return dayjs.tz(time, 'YYYY-MM-DD HH:mm', 'Australia/Sydney') return dayjs.tz(time, 'YYYY-MM-DD HH:mm', 'Australia/Sydney')
} }
function parseIcon(item) { function parseIcon(item) {
return item.image_file ? `https://www.abc.net.au/tv/common/images/publicity/${item.image_file}` : null return item.image_file
? `https://www.abc.net.au/tv/common/images/publicity/${item.image_file}`
: null
} }
function parseRating(item) { function parseRating(item) {
return item.rating return item.rating
? { ? {
system: 'ACB', system: 'ACB',
value: item.rating value: item.rating
} }
: null : null
} }

View file

@ -11,9 +11,7 @@ const channel = {
xmltv_id: 'ABCTV.au' xmltv_id: 'ABCTV.au'
} }
it('can generate valid url', () => { it('can generate valid url', () => {
expect(url({ date })).toBe( expect(url({ date })).toBe('https://epg.abctv.net.au/processed/Sydney_2022-12-22.json')
'https://epg.abctv.net.au/processed/Sydney_2022-12-22.json'
)
}) })
it('can parse response', () => { it('can parse response', () => {
@ -33,7 +31,8 @@ it('can parse response', () => {
category: ['Entertainment'], category: ['Entertainment'],
rating: { rating: {
system: 'ACB', system: 'ACB',
value: 'M'}, value: 'M'
},
season: 22, season: 22,
episode: 4, episode: 4,
icon: 'https://www.abc.net.au/tv/common/images/publicity/ZW2178A004S00_460.jpg', icon: 'https://www.abc.net.au/tv/common/images/publicity/ZW2178A004S00_460.jpg',

View file

@ -55,8 +55,8 @@ function parseItems(content, channel) {
} }
function parseSeason(item) { function parseSeason(item) {
return item.details.season || null return item.details.season || null
} }
function parseEpisode(item) { function parseEpisode(item) {
return item.details.episode || null return item.details.episode || null
} }

View file

@ -51,7 +51,8 @@ it('can parse response', () => {
start: '2022-03-03T21:30:00.000Z', start: '2022-03-03T21:30:00.000Z',
stop: '2022-03-03T23:04:00.000Z', stop: '2022-03-03T23:04:00.000Z',
title: 'الراقصه و السياسي', title: 'الراقصه و السياسي',
description: 'تقرر الراقصه سونيا انشاء دار حضانه للأطفال اليتامى و عندما تتقدم بمشورعها للمسئول يرفض فتتحداه ، تلجأ للوزير عبد الحميد رأفت تربطه بها علاقة قديمة ، يخشى على مركزه و يرفض مساعدتها فتقرر كتابة مذكراتها بمساعدة أحد الصحفيين ، يتخوف عبد الحميد و المسئولين ثم يفاجأ عبد الحميد بحصول سونيا على الموافقه للمشورع و البدء في تنفيذه و ذلك لعلاقتها بأحد كبار المسئولين .', description:
'تقرر الراقصه سونيا انشاء دار حضانه للأطفال اليتامى و عندما تتقدم بمشورعها للمسئول يرفض فتتحداه ، تلجأ للوزير عبد الحميد رأفت تربطه بها علاقة قديمة ، يخشى على مركزه و يرفض مساعدتها فتقرر كتابة مذكراتها بمساعدة أحد الصحفيين ، يتخوف عبد الحميد و المسئولين ثم يفاجأ عبد الحميد بحصول سونيا على الموافقه للمشورع و البدء في تنفيذه و ذلك لعلاقتها بأحد كبار المسئولين .',
icon: 'https://www.artonline.tv/UploadImages/Channel/ARTAFLAM1/03/AlRaqesaWaAlSeyasi.jpg' icon: 'https://www.artonline.tv/UploadImages/Channel/ARTAFLAM1/03/AlRaqesaWaAlSeyasi.jpg'
} }
]) ])

View file

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

View file

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

View file

@ -19,12 +19,12 @@ module.exports = {
if (item.title === 'Fin des programmes') return if (item.title === 'Fin des programmes') return
const detail = await loadProgramDetails(item) const detail = await loadProgramDetails(item)
programs.push({ programs.push({
title: item.title, title: item.title,
description:parseDescription(detail), description: parseDescription(detail),
category: parseCategory(detail), category: parseCategory(detail),
icon: parseIcon(item), icon: parseIcon(item),
start: parseStart(item), start: parseStart(item),
stop: parseStop(item) stop: parseStop(item)
}) })
} }
@ -52,26 +52,25 @@ module.exports = {
} }
} }
async function loadProgramDetails(item) { async function loadProgramDetails(item) {
if (!item.onClick.URLPage) return {} if (!item.onClick.URLPage) return {}
const url = item.onClick.URLPage const url = item.onClick.URLPage
const data = await axios const data = await axios
.get(url) .get(url)
.then(r => r.data) .then(r => r.data)
.catch(console.log) .catch(console.log)
return data || {} return data || {}
}
function parseDescription(detail){
return detail.detail.informations.summary || null
} }
function parseCategory(detail){ function parseDescription(detail) {
return detail.detail.informations.subGenre || null return detail.detail.informations.summary || null
} }
function parseIcon(item){
return item.URLImage || item.URLImageDefault function parseCategory(detail) {
return detail.detail.informations.subGenre || null
}
function parseIcon(item) {
return item.URLImage || item.URLImageDefault
} }
function parseStart(item) { function parseStart(item) {
@ -92,4 +91,3 @@ function parseItems(content) {
return items return items
} }

View file

@ -12,30 +12,30 @@ dayjs.extend(utc)
jest.mock('axios') jest.mock('axios')
const channel = { const channel = {
site_id: '80759', site_id: '80759',
xmltv_id: 'Animaux.fr' xmltv_id: 'Animaux.fr'
} }
it('can generate valid url for today', () => { it('can generate valid url for today', () => {
const date = dayjs.utc().startOf('d') const date = dayjs.utc().startOf('d')
expect(url({ channel, date })).toBe( expect(url({ channel, date })).toBe(
'https://service.canal-overseas.com/ott-frontend/vector/83001/channel/80759/events?filter.day=0' 'https://service.canal-overseas.com/ott-frontend/vector/83001/channel/80759/events?filter.day=0'
) )
}) })
it('can generate valid url for tomorrow', () => { it('can generate valid url for tomorrow', () => {
const date = dayjs.utc().startOf('d').add(1, 'd') const date = dayjs.utc().startOf('d').add(1, 'd')
expect(url({ channel, date })).toBe( expect(url({ channel, date })).toBe(
'https://service.canal-overseas.com/ott-frontend/vector/83001/channel/80759/events?filter.day=1' 'https://service.canal-overseas.com/ott-frontend/vector/83001/channel/80759/events?filter.day=1'
) )
}) })
it('can parse response', done => { it('can parse response', done => {
const content = `{"timeSlices":[{"contents":[{"title":"A petit pas","subtitle":"Episode 1 - La naissance","thirdTitle":"ANIMAUX","startTime":1660794900,"endTime":1660797900,"onClick":{"displayTemplate":"miniDetail","displayName":"A petit pas","URLPage":"https://service.canal-overseas.com/ott-frontend/vector/83001/event/140280189","URLVitrine":"https://service.canal-overseas.com/ott-frontend/vector/83001/program/104991257/recommendations"},"programID":104991257,"diffusionID":"140280189","URLImageDefault":"https://service.canal-overseas.com/image-api/v1/image/generic","URLImage":"https://service.canal-overseas.com/image-api/v1/image/7dedf4a579b66153a1988637e9e023f5"}],"timeSlice":"1"}]}` const content = `{"timeSlices":[{"contents":[{"title":"A petit pas","subtitle":"Episode 1 - La naissance","thirdTitle":"ANIMAUX","startTime":1660794900,"endTime":1660797900,"onClick":{"displayTemplate":"miniDetail","displayName":"A petit pas","URLPage":"https://service.canal-overseas.com/ott-frontend/vector/83001/event/140280189","URLVitrine":"https://service.canal-overseas.com/ott-frontend/vector/83001/program/104991257/recommendations"},"programID":104991257,"diffusionID":"140280189","URLImageDefault":"https://service.canal-overseas.com/image-api/v1/image/generic","URLImage":"https://service.canal-overseas.com/image-api/v1/image/7dedf4a579b66153a1988637e9e023f5"}],"timeSlice":"1"}]}`
axios.get.mockImplementation(url => { axios.get.mockImplementation(url => {
if (url === 'https://service.canal-overseas.com/ott-frontend/vector/83001/event/140280189') { if (url === 'https://service.canal-overseas.com/ott-frontend/vector/83001/event/140280189') {
return Promise.resolve({ return Promise.resolve({
data: JSON.parse(`{ data: JSON.parse(`{
"currentPage": { "currentPage": {
"displayName": "A petit pas", "displayName": "A petit pas",
"displayTemplate": "detailPage", "displayTemplate": "detailPage",
@ -109,42 +109,43 @@ it('can parse response', done => {
] ]
} }
}`) }`)
}) })
} else { } else {
return Promise.resolve({ data: '' }) return Promise.resolve({ data: '' })
}
})
parser({ content })
.then(result => {
result = result.map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2022-08-18T03:55:00.000Z',
stop: '2022-08-18T04:45:00.000Z',
title: 'A petit pas',
icon: 'https://service.canal-overseas.com/image-api/v1/image/7dedf4a579b66153a1988637e9e023f5',
category: 'Doc. Animalier',
description:
'Suivi pendant une année entière de trois bébés animaux, un border collie, un poulain et un lémurien, prédestinés par leur maître à devenir de véritables champions.'
} }
])
done()
}) })
.catch(done)
parser({ content })
.then(result => {
result = result.map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2022-08-18T03:55:00.000Z',
stop: '2022-08-18T04:45:00.000Z',
title: 'A petit pas',
icon: 'https://service.canal-overseas.com/image-api/v1/image/7dedf4a579b66153a1988637e9e023f5',
category: 'Doc. Animalier',
description: 'Suivi pendant une année entière de trois bébés animaux, un border collie, un poulain et un lémurien, prédestinés par leur maître à devenir de véritables champions.'
}
])
done()
})
.catch(done)
}) })
it('can handle empty guide', done => { it('can handle empty guide', done => {
parser({ parser({
content: `{"currentPage":{"displayTemplate":"error","BOName":"Page introuvable"},"title":"Page introuvable","text":"La page que vous demandez est introuvable. Si le problème persiste, vous pouvez contacter l'assistance de CANAL+/CANALSAT.","code":404}` content: `{"currentPage":{"displayTemplate":"error","BOName":"Page introuvable"},"title":"Page introuvable","text":"La page que vous demandez est introuvable. Si le problème persiste, vous pouvez contacter l'assistance de CANAL+/CANALSAT.","code":404}`
})
.then(result => {
expect(result).toMatchObject([])
done()
}) })
.then(result => { .catch(done)
expect(result).toMatchObject([])
done()
})
.catch(done)
}) })

View file

@ -19,12 +19,12 @@ module.exports = {
if (item.title === 'Fin des programmes') return if (item.title === 'Fin des programmes') return
const detail = await loadProgramDetails(item) const detail = await loadProgramDetails(item)
programs.push({ programs.push({
title: item.title, title: item.title,
description:parseDescription(detail), description: parseDescription(detail),
category: parseCategory(detail), category: parseCategory(detail),
icon: parseIcon(item), icon: parseIcon(item),
start: parseStart(item), start: parseStart(item),
stop: parseStop(item) stop: parseStop(item)
}) })
} }
@ -53,24 +53,24 @@ module.exports = {
} }
async function loadProgramDetails(item) { async function loadProgramDetails(item) {
if (!item.onClick.URLPage) return {} if (!item.onClick.URLPage) return {}
const url = item.onClick.URLPage const url = item.onClick.URLPage
const data = await axios const data = await axios
.get(url) .get(url)
.then(r => r.data) .then(r => r.data)
.catch(console.log) .catch(console.log)
return data || {} return data || {}
}
function parseDescription(detail){
return detail.detail.informations.summary || null
} }
function parseCategory(detail){ function parseDescription(detail) {
return detail.detail.informations.subGenre || null return detail.detail.informations.summary || null
} }
function parseIcon(item){
return item.URLImage || item.URLImageDefault function parseCategory(detail) {
return detail.detail.informations.subGenre || null
}
function parseIcon(item) {
return item.URLImage || item.URLImageDefault
} }
function parseStart(item) { function parseStart(item) {
return dayjs.unix(item.startTime) return dayjs.unix(item.startTime)

View file

@ -19,12 +19,12 @@ module.exports = {
if (item.title === 'Fin des programmes') return if (item.title === 'Fin des programmes') return
const detail = await loadProgramDetails(item) const detail = await loadProgramDetails(item)
programs.push({ programs.push({
title: item.title, title: item.title,
description:parseDescription(detail), description: parseDescription(detail),
category: parseCategory(detail), category: parseCategory(detail),
icon: parseIcon(item), icon: parseIcon(item),
start: parseStart(item), start: parseStart(item),
stop: parseStop(item) stop: parseStop(item)
}) })
} }
@ -52,26 +52,25 @@ module.exports = {
} }
} }
async function loadProgramDetails(item) { async function loadProgramDetails(item) {
if (!item.onClick.URLPage) return {} if (!item.onClick.URLPage) return {}
const url = item.onClick.URLPage const url = item.onClick.URLPage
const data = await axios const data = await axios
.get(url) .get(url)
.then(r => r.data) .then(r => r.data)
.catch(console.log) .catch(console.log)
return data || {} return data || {}
}
function parseDescription(detail){
return detail.detail.informations.summary || null
} }
function parseCategory(detail){ function parseDescription(detail) {
return detail.detail.informations.subGenre || null return detail.detail.informations.summary || null
} }
function parseIcon(item){
return item.URLImage || item.URLImageDefault function parseCategory(detail) {
return detail.detail.informations.subGenre || null
}
function parseIcon(item) {
return item.URLImage || item.URLImageDefault
} }
function parseStart(item) { function parseStart(item) {

View file

@ -18,12 +18,12 @@ module.exports = {
if (item.title === 'Fin des programmes') return if (item.title === 'Fin des programmes') return
const detail = await loadProgramDetails(item) const detail = await loadProgramDetails(item)
programs.push({ programs.push({
title: item.title, title: item.title,
description:parseDescription(detail), description: parseDescription(detail),
category: parseCategory(detail), category: parseCategory(detail),
icon: parseIcon(item), icon: parseIcon(item),
start: parseStart(item), start: parseStart(item),
stop: parseStop(item) stop: parseStop(item)
}) })
} }
@ -32,24 +32,24 @@ module.exports = {
} }
async function loadProgramDetails(item) { async function loadProgramDetails(item) {
if (!item.onClick.URLPage) return {} if (!item.onClick.URLPage) return {}
const url = item.onClick.URLPage const url = item.onClick.URLPage
const data = await axios const data = await axios
.get(url) .get(url)
.then(r => r.data) .then(r => r.data)
.catch(console.log) .catch(console.log)
return data || {} return data || {}
}
function parseDescription(detail){
return detail.detail.informations.summary || null
} }
function parseCategory(detail){ function parseDescription(detail) {
return detail.detail.informations.subGenre || null return detail.detail.informations.summary || null
} }
function parseIcon(item){
return item.URLImage || item.URLImageDefault function parseCategory(detail) {
return detail.detail.informations.subGenre || null
}
function parseIcon(item) {
return item.URLImage || item.URLImageDefault
} }
function parseStart(item) { function parseStart(item) {
return dayjs.unix(item.startTime) return dayjs.unix(item.startTime)

View file

@ -8,7 +8,9 @@ module.exports = {
} }
}, },
url({ date }) { url({ date }) {
return `https://tvguide.foxsports.com.au/granite-api/programmes.json?from=${date.format('YYYY-MM-DD')}&to=${date.add(1, 'd').format('YYYY-MM-DD')}` return `https://tvguide.foxsports.com.au/granite-api/programmes.json?from=${date.format(
'YYYY-MM-DD'
)}&to=${date.add(1, 'd').format('YYYY-MM-DD')}`
}, },
parser({ content, channel }) { parser({ content, channel }) {
let programs = [] let programs = []

View file

@ -32,12 +32,12 @@ module.exports = {
} }
function parseCategory(item) { function parseCategory(item) {
let category = item.content.genre.name || null; let category = item.content.genre.name || null
const subcategory = item.content.subgenre.name || null; const subcategory = item.content.subgenre.name || null
if(category && subcategory){ if (category && subcategory) {
category += `/${subcategory}`; category += `/${subcategory}`
} }
return category; return category
} }
function parseStart(item) { function parseStart(item) {
@ -59,13 +59,13 @@ function parseIcon(item) {
} }
function parseSeason(item) { function parseSeason(item) {
if (!item.content.seasonNumber) return null if (!item.content.seasonNumber) return null
if (String(item.content.seasonNumber).length > 2) return null if (String(item.content.seasonNumber).length > 2) return null
return item.content.seasonNumber return item.content.seasonNumber
} }
function parseEpisode(item) { function parseEpisode(item) {
if (!item.content.episodeNumber) return null if (!item.content.episodeNumber) return null
if (String(item.content.episodeNumber).length > 3) return null if (String(item.content.episodeNumber).length > 3) return null
return item.content.episodeNumber return item.content.episodeNumber
} }

View file

@ -122,13 +122,13 @@ function parseItems(content, channel) {
} }
function parseSeason(detail) { function parseSeason(detail) {
if (!detail.seasonNumber) return null if (!detail.seasonNumber) return null
if (String(detail.seasonNumber).length > 2) return null if (String(detail.seasonNumber).length > 2) return null
return detail.seasonNumber return detail.seasonNumber
} }
function parseEpisode(detail) { function parseEpisode(detail) {
if (!detail.episodeNumber) return null if (!detail.episodeNumber) return null
if (String(detail.episodeNumber).length > 3) return null if (String(detail.episodeNumber).length > 3) return null
return detail.episodeNumber return detail.episodeNumber
} }

View file

@ -9,7 +9,6 @@ const customParseFormat = require('dayjs/plugin/customParseFormat')
dayjs.extend(customParseFormat) dayjs.extend(customParseFormat)
dayjs.extend(utc) dayjs.extend(utc)
const channel = { const channel = {
site_id: '1', site_id: '1',
xmltv_id: 'CT1.cz' xmltv_id: 'CT1.cz'
@ -17,36 +16,40 @@ const channel = {
it('can generate valid url for today', () => { it('can generate valid url for today', () => {
const date = dayjs.utc().startOf('d') const date = dayjs.utc().startOf('d')
expect(url({ channel, date })).toBe('https://services.mujtvprogram.cz/tvprogram2services/services/tvprogrammelist_mobile.php?channel_cid=1&day=0') expect(url({ channel, date })).toBe(
'https://services.mujtvprogram.cz/tvprogram2services/services/tvprogrammelist_mobile.php?channel_cid=1&day=0'
)
}) })
it('can generate valid url for tomorrow', () => { it('can generate valid url for tomorrow', () => {
const date = dayjs.utc().startOf('d').add(1, 'd') const date = dayjs.utc().startOf('d').add(1, 'd')
expect(url({ channel, date })).toBe('https://services.mujtvprogram.cz/tvprogram2services/services/tvprogrammelist_mobile.php?channel_cid=1&day=1') expect(url({ channel, date })).toBe(
'https://services.mujtvprogram.cz/tvprogram2services/services/tvprogrammelist_mobile.php?channel_cid=1&day=1'
)
}) })
it('can parse response', () => { it('can parse response', () => {
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html')) const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'))
let results = parser({ content }).map(p => { let results = parser({ content }).map(p => {
p.start = p.start.toJSON() p.start = p.start.toJSON()
p.stop = p.stop.toJSON() p.stop = p.stop.toJSON()
return p return p
}) })
expect(results[3]).toMatchObject({ expect(results[3]).toMatchObject({
title: `Čepice`, title: `Čepice`,
description: `Jarka (J. Bohdalová) vyčítá manželovi Jiřímu (F. Řehák), že jí nepomáhá při předvánočním úklidu. Vzápětí ale náhodou najde ve skříni ukrytou dámskou čepici a napadne ji, že jde o Jiřího dárek pro ni pod stromeček. Její chování se ihned změní. Jen muži naznačí, že by chtěla čepici jiné barvy. Manžel jí ovšem řekne, že čepici si u něj schoval kamarád Venca (M. Šulc). Zklamaná žena to prozradí Vencově manželce Božce (A. Tománková). Na Štědrý den však Božka najde pod stromečkem jen rtěnku...`, description: `Jarka (J. Bohdalová) vyčítá manželovi Jiřímu (F. Řehák), že jí nepomáhá při předvánočním úklidu. Vzápětí ale náhodou najde ve skříni ukrytou dámskou čepici a napadne ji, že jde o Jiřího dárek pro ni pod stromeček. Její chování se ihned změní. Jen muži naznačí, že by chtěla čepici jiné barvy. Manžel jí ovšem řekne, že čepici si u něj schoval kamarád Venca (M. Šulc). Zklamaná žena to prozradí Vencově manželce Božce (A. Tománková). Na Štědrý den však Božka najde pod stromečkem jen rtěnku...`,
category: 'film', category: 'film',
date: '1983', date: '1983',
director: ['Mudra F.'], director: ['Mudra F.'],
actor: ['Bohdalová J.', 'Řehák F.', 'Šulc M.'], actor: ['Bohdalová J.', 'Řehák F.', 'Šulc M.'],
start: '2022-12-23T08:00:00.000Z', start: '2022-12-23T08:00:00.000Z',
stop: '2022-12-23T08:20:00.000Z' stop: '2022-12-23T08:20:00.000Z'
}) })
}) })
it('can handle empty guide', () => { it('can handle empty guide', () => {
const content = fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html')) const content = fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'))
const result = parser(content, channel ) const result = parser(content, channel)
expect(result).toMatchObject([]) expect(result).toMatchObject([])
}) })

View file

@ -61,20 +61,19 @@ function parseContent(content) {
return data ? JSON.parse(data) : {} return data ? JSON.parse(data) : {}
} }
function parseDirector(item) { function parseDirector(item) {
return item.credits && item.credits.director ? item.credits.director : null return item.credits && item.credits.director ? item.credits.director : null
} }
function parseActor(item) { function parseActor(item) {
return item.credits && item.credits.actor ? item.credits.actor : null return item.credits && item.credits.actor ? item.credits.actor : null
} }
function parseRating(item) { function parseRating(item) {
return item.rating return item.rating
? { ? {
system: 'CNC', system: 'CNC',
value: item.rating.toUpperCase() value: item.rating.toUpperCase()
} }
: null : null
} }

View file

@ -8,39 +8,37 @@ dayjs.extend(timezone)
dayjs.extend(customParseFormat) dayjs.extend(customParseFormat)
module.exports = { module.exports = {
site: 'rtmklik.rtm.gov.my', site: 'rtmklik.rtm.gov.my',
url: function ({ date, channel }) { url: function ({ date, channel }) {
return `https://rtm.glueapi.io/v3/epg/${channel.site_id}/ChannelSchedule?dateStart=${date.format( return `https://rtm.glueapi.io/v3/epg/${
'YYYY-MM-DD' channel.site_id
)}&dateEnd=${date.format( }/ChannelSchedule?dateStart=${date.format('YYYY-MM-DD')}&dateEnd=${date.format(
'YYYY-MM-DD' 'YYYY-MM-DD'
)}&timezone=0` )}&timezone=0`
// return `https://rtm.glueapi.io/v3/epg/99/ChannelSchedule?dateStart=${date.format('YYYY-MM-DD')}&dateEnd=${date.format('YYYY-MM-DD')}&timezone=0` // return `https://rtm.glueapi.io/v3/epg/99/ChannelSchedule?dateStart=${date.format('YYYY-MM-DD')}&dateEnd=${date.format('YYYY-MM-DD')}&timezone=0`
}, },
parser: function ({ content }) { parser: function ({ content }) {
const programs = [] const programs = []
const items = parseItems(content) const items = parseItems(content)
if (!items.length) return programs if (!items.length) return programs
items.forEach(item => { items.forEach(item => {
programs.push({ programs.push({
title: item.programTitle, title: item.programTitle,
description: item.description, description: item.description,
start: parseTime(item.dateTimeStart), start: parseTime(item.dateTimeStart),
stop: parseTime(item.dateTimeEnd) stop: parseTime(item.dateTimeEnd)
})
}) })
})
return programs return programs
}
} }
}
function parseItems(content) { function parseItems(content) {
const data = JSON.parse(content) const data = JSON.parse(content)
return data.schedule ? data.schedule : [] return data.schedule ? data.schedule : []
} }
function parseTime(time) { function parseTime(time) {
return dayjs.utc(time, 'YYYY-MM-DDTHH:mm:ss') return dayjs.utc(time, 'YYYY-MM-DDTHH:mm:ss')
} }

View file

@ -119,13 +119,13 @@ function parseItems(content, channel) {
} }
function parseSeason(detail) { function parseSeason(detail) {
if (!detail.seasonNumber) return null if (!detail.seasonNumber) return null
if (String(detail.seasonNumber).length > 2) return null if (String(detail.seasonNumber).length > 2) return null
return detail.seasonNumber return detail.seasonNumber
} }
function parseEpisode(detail) { function parseEpisode(detail) {
if (!detail.episodeNumber) return null if (!detail.episodeNumber) return null
if (String(detail.episodeNumber).length > 3) return null if (String(detail.episodeNumber).length > 3) return null
return detail.episodeNumber return detail.episodeNumber
} }

View file

@ -35,8 +35,8 @@ it('can parse response', () => {
description: description:
'Hellseherin Sedona Wiley wird tot aufgefunden. Die Ermittlungen führen zu einem alten Mord. Gordon Wallace wurde vor 15 Jahren beschuldigt, seine Frau getötet zu haben, jedoch wurde nie eine Leiche gefunden.', 'Hellseherin Sedona Wiley wird tot aufgefunden. Die Ermittlungen führen zu einem alten Mord. Gordon Wallace wurde vor 15 Jahren beschuldigt, seine Frau getötet zu haben, jedoch wurde nie eine Leiche gefunden.',
icon: 'https://new.static.tv.nu/13119997', icon: 'https://new.static.tv.nu/13119997',
category: ['Action', 'Kriminaldrama', 'Mysterium', 'Spänning','Thriller'], category: ['Action', 'Kriminaldrama', 'Mysterium', 'Spänning', 'Thriller'],
season : 6, season: 6,
episode: 19 episode: 19
} }
]) ])

View file

@ -29,16 +29,16 @@ module.exports = {
.catch(console.error) .catch(console.error)
// items.forEach(item => { // items.forEach(item => {
for (let item of items) { for (let item of items) {
const detail = await loadProgramDetails(item) const detail = await loadProgramDetails(item)
programs.push({ programs.push({
title: item.t, title: item.t,
description: parseDescription(detail), description: parseDescription(detail),
category: parseCategory(detail), category: parseCategory(detail),
season: parseSeason(detail), season: parseSeason(detail),
episode: parseEpisode(detail), episode: parseEpisode(detail),
start: parseStart(item), start: parseStart(item),
stop: parseStop(item) stop: parseStop(item)
}) })
} }
//) //)
@ -61,14 +61,14 @@ module.exports = {
} }
async function loadProgramDetails(item) { async function loadProgramDetails(item) {
if (!item.i) return {} if (!item.i) return {}
const url = `${API_ENDPOINT}/listings/${item.i}` const url = `${API_ENDPOINT}/listings/${item.i}`
const data = await axios const data = await axios
.get(url) .get(url)
.then(r => r.data) .then(r => r.data)
.catch(console.log) .catch(console.log)
return data || {} return data || {}
} }
function parseStart(item) { function parseStart(item) {
return dayjs(item.s) return dayjs(item.s)
@ -86,27 +86,26 @@ function parseItems(content, channel) {
return entity ? entity.l : [] return entity ? entity.l : []
} }
function parseDescription(detail){ function parseDescription(detail) {
return detail.program.longDescription || null return detail.program.longDescription || null
} }
function parseCategory(detail) { function parseCategory(detail) {
let categories = [] let categories = []
detail.program.categories.forEach(category => { detail.program.categories.forEach(category => {
categories.push(category.title) categories.push(category.title)
}); })
return categories return categories
} }
function parseSeason(detail) { function parseSeason(detail) {
if (!detail.program.seriesNumber) return null if (!detail.program.seriesNumber) return null
if (String(detail.program.seriesNumber).length > 2) return null if (String(detail.program.seriesNumber).length > 2) return null
return detail.program.seriesNumber return detail.program.seriesNumber
} }
function parseEpisode(detail) { function parseEpisode(detail) {
if (!detail.program.seriesEpisodeNumber) return null if (!detail.program.seriesEpisodeNumber) return null
if (String(detail.program.seriesEpisodeNumber).length > 3) return null if (String(detail.program.seriesEpisodeNumber).length > 3) return null
return detail.program.seriesEpisodeNumber return detail.program.seriesEpisodeNumber
} }

View file

@ -13,121 +13,143 @@ jest.mock('axios')
const date = dayjs.utc('2022-03-17', 'YYYY-MM-DD').startOf('d') const date = dayjs.utc('2022-03-17', 'YYYY-MM-DD').startOf('d')
const channel = { const channel = {
site_id: '1761', site_id: '1761',
xmltv_id: 'ViaplaySports1.uk' xmltv_id: 'ViaplaySports1.uk'
} }
it('can generate valid url', () => { it('can generate valid url', () => {
expect(url({ date })).toBe( expect(url({ date })).toBe(
'https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/programschedules/20220317/1' 'https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/programschedules/20220317/1'
) )
}) })
it('can parse response', done => { it('can parse response', done => {
const content = `{"entryCount":410,"totalResults":410,"updated":1647459686755,"expires":1647460298218,"title":"EPG","periods":4,"periodStartTime":1647475200000,"periodEndTime":1647496800000,"entries":[{"o":"lgi-gb-prodobo-master:1761","l":[{"i":"crid:~~2F~~2Fgn.tv~~2F21763419~~2FEP013520125005,imi:de610af9a9b049c8a0245173f273136d36458f6f","t":"Live: NHL Hockey","s":1647473400000,"e":1647484200000,"c":"lgi-gb-prodobo-master:genre-27","a":false,"r":true,"rm":true,"rs":0,"re":2592000,"rst":"cloud","ra":false,"ad":[],"sl":[]}]}]}` const content = `{"entryCount":410,"totalResults":410,"updated":1647459686755,"expires":1647460298218,"title":"EPG","periods":4,"periodStartTime":1647475200000,"periodEndTime":1647496800000,"entries":[{"o":"lgi-gb-prodobo-master:1761","l":[{"i":"crid:~~2F~~2Fgn.tv~~2F21763419~~2FEP013520125005,imi:de610af9a9b049c8a0245173f273136d36458f6f","t":"Live: NHL Hockey","s":1647473400000,"e":1647484200000,"c":"lgi-gb-prodobo-master:genre-27","a":false,"r":true,"rm":true,"rs":0,"re":2592000,"rst":"cloud","ra":false,"ad":[],"sl":[]}]}]}`
axios.get.mockImplementation(url => { axios.get.mockImplementation(url => {
if (url === 'https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/programschedules/20220317/2') { if (
return Promise.resolve({ url === 'https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/programschedules/20220317/2'
data: JSON.parse( ) {
`{"entryCount":410,"totalResults":410,"updated":1647460887411,"expires":1647461895572,"title":"EPG","periods":4,"periodStartTime":1647496800000,"periodEndTime":1647518400000,"entries":[{"o":"lgi-gb-prodobo-master:1761","l":[{"i":"crid:~~2F~~2Fgn.tv~~2F21720572~~2FEP021779870005,imi:d4324f579ad36992f0c3f6e6d35a9b93e98cb78a","t":"Challenge Cup Ice Hockey","s":1647484200000,"e":1647496800000,"c":"lgi-gb-prodobo-master:genre-123","a":false,"r":true,"rm":true,"rs":0,"re":2592000,"rst":"cloud","ra":false,"ad":[],"sl":[]}]}]}` return Promise.resolve({
) data: JSON.parse(
}) `{"entryCount":410,"totalResults":410,"updated":1647460887411,"expires":1647461895572,"title":"EPG","periods":4,"periodStartTime":1647496800000,"periodEndTime":1647518400000,"entries":[{"o":"lgi-gb-prodobo-master:1761","l":[{"i":"crid:~~2F~~2Fgn.tv~~2F21720572~~2FEP021779870005,imi:d4324f579ad36992f0c3f6e6d35a9b93e98cb78a","t":"Challenge Cup Ice Hockey","s":1647484200000,"e":1647496800000,"c":"lgi-gb-prodobo-master:genre-123","a":false,"r":true,"rm":true,"rs":0,"re":2592000,"rst":"cloud","ra":false,"ad":[],"sl":[]}]}]}`
} else if (url === 'https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/programschedules/20220317/3') { )
return Promise.resolve({ })
data: JSON.parse( } else if (
`{"entryCount":410,"totalResults":410,"updated":1647460871713,"expires":1647461910282,"title":"EPG","periods":4,"periodStartTime":1647518400000,"periodEndTime":1647540000000,"entries":[{"o":"lgi-gb-prodobo-master:1761","l":[{"i":"crid:~~2F~~2Fgn.tv~~2F21763550~~2FEP012830215435,imi:9692f5ceb0b63354262339e8529e3a9cb57add9c","t":"NHL Hockey","s":1647511200000,"e":1647518400000,"c":"lgi-gb-prodobo-master:genre-27","a":false,"r":true,"rm":true,"rs":0,"re":2592000,"rst":"cloud","ra":false,"ad":[],"sl":[]}]}]}` url === 'https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/programschedules/20220317/3'
) ) {
}) return Promise.resolve({
} else if (url === 'https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/programschedules/20220317/4') { data: JSON.parse(
return Promise.resolve({ `{"entryCount":410,"totalResults":410,"updated":1647460871713,"expires":1647461910282,"title":"EPG","periods":4,"periodStartTime":1647518400000,"periodEndTime":1647540000000,"entries":[{"o":"lgi-gb-prodobo-master:1761","l":[{"i":"crid:~~2F~~2Fgn.tv~~2F21763550~~2FEP012830215435,imi:9692f5ceb0b63354262339e8529e3a9cb57add9c","t":"NHL Hockey","s":1647511200000,"e":1647518400000,"c":"lgi-gb-prodobo-master:genre-27","a":false,"r":true,"rm":true,"rs":0,"re":2592000,"rst":"cloud","ra":false,"ad":[],"sl":[]}]}]}`
data: JSON.parse( )
`{"entryCount":410,"totalResults":410,"updated":1647460871713,"expires":1647461920720,"title":"EPG","periods":4,"periodStartTime":1647540000000,"periodEndTime":1647561600000,"entries":[{"o":"lgi-gb-prodobo-master:1761","l":[{"i":"crid:~~2F~~2Fgn.tv~~2F21764379~~2FEP025886890145,imi:c02da14358110cec07d14dc154717ce62ba2f489","t":"Boxing World Weekly","s":1647539100000,"e":1647540900000,"c":"lgi-gb-prodobo-master:genre-27","a":false,"r":true,"rm":true,"rs":0,"re":2592000,"rst":"cloud","ra":false,"ad":[],"sl":[]}]}]}` })
) } else if (
}) url === 'https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/programschedules/20220317/4'
} else if (url === 'https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/listings/crid:~~2F~~2Fgn.tv~~2F21763419~~2FEP013520125005,imi:de610af9a9b049c8a0245173f273136d36458f6f') { ) {
return Promise.resolve({ return Promise.resolve({
data: JSON.parse( data: JSON.parse(
`{"id":"crid:~~2F~~2Fgn.tv~~2F21763419~~2FEP013520125005,imi:de610af9a9b049c8a0245173f273136d36458f6f","startTime":1647473400000,"endTime":1647484200000,"actualStartTime":1647473400000,"actualEndTime":1647484200000,"expirationDate":1648078200000,"stationId":"lgi-gb-prodobo-master:1761","imi":"imi:de610af9a9b049c8a0245173f273136d36458f6f","scCridImi":"crid:~~2F~~2Fgn.tv~~2F21763419~~2FEP013520125005,imi:de610af9a9b049c8a0245173f273136d36458f6f","mediaGroupId":"crid:~~2F~~2Fgn.tv~~2F8396306~~2FSH013520120000","program":{"id":"crid:~~2F~~2Fgn.tv~~2F21763419~~2FEP013520125005","title":"Live: NHL Hockey","description":"The Boston Bruins make the trip to Xcel Energy Center for an NHL clash with the Minnesota Wild.","longDescription":"The Boston Bruins make the trip to Xcel Energy Center for an NHL clash with the Minnesota Wild.","medium":"TV","categories":[{"id":"lgi-gb-prodobo-master:genre-27","title":"Sport","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"},{"id":"lgi-gb-prodobo-master:genre-123","title":"Ice Hockey","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"}],"isAdult":false,"cast":[],"directors":[],"images":[{"assetType":"HighResLandscapeProductionStill","assetTypes":["HighResLandscapeProductionStill"],"url":"https://staticqbr-gb-prod.prod.cdn.dmdsdp.com/image-service/ImagesEPG/EventImages/p21763419_tb2_h8_aa.jpg"},{"assetType":"HighResPortrait","assetTypes":["HighResPortrait"],"url":"https://staticqbr-gb-prod.prod.cdn.dmdsdp.com/image-service/ImagesEPG/EventImages/p21763419_tb2_v12_aa.jpg"}],"parentId":"crid:~~2F~~2Fgn.tv~~2F123456789~~2FSH013520120000","rootId":"crid:~~2F~~2Fgn.tv~~2F8396306~~2FSH013520120000","parentalRatingDescription":[],"resolutions":[],"mediaGroupId":"crid:~~2F~~2Fgn.tv~~2F8396306~~2FSH013520120000","shortDescription":"The Boston Bruins make the trip to Xcel Energy Center for an NHL clash with the Minnesota Wild.","mediaType":"Episode","year":"2022","seriesEpisodeNumber":"2022031605","seriesNumber":"20120000","videos":[],"videoStreams":[],"entitlements":["VIP","_OPEN_"],"currentProductIds":[],"currentTvodProductIds":[],"secondaryTitle":"Boston Bruins at Minnesota Wild"},"parentId":"crid:~~2F~~2Fgn.tv~~2F123456789~~2FSH013520120000","rootId":"crid:~~2F~~2Fgn.tv~~2F8396306~~2FSH013520120000","replayTvAvailable":true,"audioTracks":[{"lang":"en","audioPurpose":"main"}],"ratings":[],"offersLatestExpirationDate":1647484200000,"replayTvStartOffset":0,"replayTvEndOffset":2592000,"replayEnabledOnMobileClients":true,"replaySource":"cloud","isGoReplayableViaExternalApp":false,"mergedId":"21763419|en-GB"}` `{"entryCount":410,"totalResults":410,"updated":1647460871713,"expires":1647461920720,"title":"EPG","periods":4,"periodStartTime":1647540000000,"periodEndTime":1647561600000,"entries":[{"o":"lgi-gb-prodobo-master:1761","l":[{"i":"crid:~~2F~~2Fgn.tv~~2F21764379~~2FEP025886890145,imi:c02da14358110cec07d14dc154717ce62ba2f489","t":"Boxing World Weekly","s":1647539100000,"e":1647540900000,"c":"lgi-gb-prodobo-master:genre-27","a":false,"r":true,"rm":true,"rs":0,"re":2592000,"rst":"cloud","ra":false,"ad":[],"sl":[]}]}]}`
) )
}) })
} else if (url === 'https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/listings/crid:~~2F~~2Fgn.tv~~2F21720572~~2FEP021779870005,imi:d4324f579ad36992f0c3f6e6d35a9b93e98cb78a') { } else if (
return Promise.resolve({ url ===
data: JSON.parse( 'https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/listings/crid:~~2F~~2Fgn.tv~~2F21763419~~2FEP013520125005,imi:de610af9a9b049c8a0245173f273136d36458f6f'
`{"id":"crid:~~2F~~2Fgn.tv~~2F21720572~~2FEP021779870005,imi:d4324f579ad36992f0c3f6e6d35a9b93e98cb78a","startTime":1647484200000,"endTime":1647496800000,"actualStartTime":1647484200000,"actualEndTime":1647496800000,"expirationDate":1648089000000,"stationId":"lgi-gb-prodobo-master:1761","imi":"imi:d4324f579ad36992f0c3f6e6d35a9b93e98cb78a","scCridImi":"crid:~~2F~~2Fgn.tv~~2F21720572~~2FEP021779870005,imi:d4324f579ad36992f0c3f6e6d35a9b93e98cb78a","mediaGroupId":"crid:~~2F~~2Fgn.tv~~2F11743980~~2FSH021779870000","program":{"id":"crid:~~2F~~2Fgn.tv~~2F21720572~~2FEP021779870005","title":"Challenge Cup Ice Hockey","description":"Exclusive coverage from SSE Arena of the Premier Sports Challenge Final between Belfast Giants and Cardiff Devils.","longDescription":"Exclusive coverage from SSE Arena of the Premier Sports Challenge Final between Belfast Giants and Cardiff Devils.","medium":"TV","categories":[{"id":"lgi-gb-prodobo-master:genre-123","title":"Ice Hockey","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"}],"isAdult":false,"cast":[],"directors":[],"images":[{"assetType":"HighResPortrait","assetTypes":["HighResPortrait"],"url":"https://staticqbr-gb-prod.prod.cdn.dmdsdp.com/image-service/ImagesEPG/EventImages/p11743980_b_v12_aa.jpg"}],"parentId":"crid:~~2F~~2Fgn.tv~~2F123456789~~2FSH021779870000","rootId":"crid:~~2F~~2Fgn.tv~~2F11743980~~2FSH021779870000","parentalRatingDescription":[],"resolutions":[],"mediaGroupId":"crid:~~2F~~2Fgn.tv~~2F11743980~~2FSH021779870000","shortDescription":"Exclusive coverage from SSE Arena of the Premier Sports Challenge Final between Belfast Giants and Cardiff Devils.","mediaType":"Episode","year":"2022","seriesEpisodeNumber":"2022031605","seriesNumber":"79870000","videos":[],"videoStreams":[],"entitlements":["VIP","_OPEN_"],"currentProductIds":[],"currentTvodProductIds":[],"secondaryTitle":"Final: Belfast Giants v Cardiff Devils"},"parentId":"crid:~~2F~~2Fgn.tv~~2F123456789~~2FSH021779870000","rootId":"crid:~~2F~~2Fgn.tv~~2F11743980~~2FSH021779870000","replayTvAvailable":true,"audioTracks":[{"lang":"en","audioPurpose":"main"}],"ratings":[],"offersLatestExpirationDate":1647928800000,"replayTvStartOffset":0,"replayTvEndOffset":2592000,"replayEnabledOnMobileClients":true,"replaySource":"cloud","isGoReplayableViaExternalApp":false,"mergedId":"21720572|en-GB"}` ) {
) return Promise.resolve({
}) data: JSON.parse(
} else if (url === 'https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/listings/crid:~~2F~~2Fgn.tv~~2F21763550~~2FEP012830215435,imi:9692f5ceb0b63354262339e8529e3a9cb57add9c') { `{"id":"crid:~~2F~~2Fgn.tv~~2F21763419~~2FEP013520125005,imi:de610af9a9b049c8a0245173f273136d36458f6f","startTime":1647473400000,"endTime":1647484200000,"actualStartTime":1647473400000,"actualEndTime":1647484200000,"expirationDate":1648078200000,"stationId":"lgi-gb-prodobo-master:1761","imi":"imi:de610af9a9b049c8a0245173f273136d36458f6f","scCridImi":"crid:~~2F~~2Fgn.tv~~2F21763419~~2FEP013520125005,imi:de610af9a9b049c8a0245173f273136d36458f6f","mediaGroupId":"crid:~~2F~~2Fgn.tv~~2F8396306~~2FSH013520120000","program":{"id":"crid:~~2F~~2Fgn.tv~~2F21763419~~2FEP013520125005","title":"Live: NHL Hockey","description":"The Boston Bruins make the trip to Xcel Energy Center for an NHL clash with the Minnesota Wild.","longDescription":"The Boston Bruins make the trip to Xcel Energy Center for an NHL clash with the Minnesota Wild.","medium":"TV","categories":[{"id":"lgi-gb-prodobo-master:genre-27","title":"Sport","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"},{"id":"lgi-gb-prodobo-master:genre-123","title":"Ice Hockey","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"}],"isAdult":false,"cast":[],"directors":[],"images":[{"assetType":"HighResLandscapeProductionStill","assetTypes":["HighResLandscapeProductionStill"],"url":"https://staticqbr-gb-prod.prod.cdn.dmdsdp.com/image-service/ImagesEPG/EventImages/p21763419_tb2_h8_aa.jpg"},{"assetType":"HighResPortrait","assetTypes":["HighResPortrait"],"url":"https://staticqbr-gb-prod.prod.cdn.dmdsdp.com/image-service/ImagesEPG/EventImages/p21763419_tb2_v12_aa.jpg"}],"parentId":"crid:~~2F~~2Fgn.tv~~2F123456789~~2FSH013520120000","rootId":"crid:~~2F~~2Fgn.tv~~2F8396306~~2FSH013520120000","parentalRatingDescription":[],"resolutions":[],"mediaGroupId":"crid:~~2F~~2Fgn.tv~~2F8396306~~2FSH013520120000","shortDescription":"The Boston Bruins make the trip to Xcel Energy Center for an NHL clash with the Minnesota Wild.","mediaType":"Episode","year":"2022","seriesEpisodeNumber":"2022031605","seriesNumber":"20120000","videos":[],"videoStreams":[],"entitlements":["VIP","_OPEN_"],"currentProductIds":[],"currentTvodProductIds":[],"secondaryTitle":"Boston Bruins at Minnesota Wild"},"parentId":"crid:~~2F~~2Fgn.tv~~2F123456789~~2FSH013520120000","rootId":"crid:~~2F~~2Fgn.tv~~2F8396306~~2FSH013520120000","replayTvAvailable":true,"audioTracks":[{"lang":"en","audioPurpose":"main"}],"ratings":[],"offersLatestExpirationDate":1647484200000,"replayTvStartOffset":0,"replayTvEndOffset":2592000,"replayEnabledOnMobileClients":true,"replaySource":"cloud","isGoReplayableViaExternalApp":false,"mergedId":"21763419|en-GB"}`
return Promise.resolve({ )
data: JSON.parse( })
`{"id":"crid:~~2F~~2Fgn.tv~~2F21763550~~2FEP012830215435,imi:9692f5ceb0b63354262339e8529e3a9cb57add9c","startTime":1647511200000,"endTime":1647518400000,"actualStartTime":1647511200000,"actualEndTime":1647518400000,"expirationDate":1648116000000,"stationId":"lgi-gb-prodobo-master:1761","imi":"imi:9692f5ceb0b63354262339e8529e3a9cb57add9c","scCridImi":"crid:~~2F~~2Fgn.tv~~2F21763550~~2FEP012830215435,imi:9692f5ceb0b63354262339e8529e3a9cb57add9c","mediaGroupId":"crid:~~2F~~2Fgn.tv~~2F448880~~2FSH012830210000","program":{"id":"crid:~~2F~~2Fgn.tv~~2F21763550~~2FEP012830215435","title":"NHL Hockey","description":"The Calgary Flames play host to the New Jersey Devils in this NHL encounter from Scotiabank Saddledome.","longDescription":"The Calgary Flames play host to the New Jersey Devils in this NHL encounter from Scotiabank Saddledome.","medium":"TV","categories":[{"id":"lgi-gb-prodobo-master:genre-27","title":"Sport","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"},{"id":"lgi-gb-prodobo-master:genre-123","title":"Ice Hockey","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"}],"isAdult":false,"cast":[],"directors":[],"images":[{"assetType":"HighResLandscapeProductionStill","assetTypes":["HighResLandscapeProductionStill"],"url":"https://staticqbr-gb-prod.prod.cdn.dmdsdp.com/image-service/ImagesEPG/EventImages/p448880_b_h8_ak.jpg"},{"assetType":"HighResPortrait","assetTypes":["HighResPortrait"],"url":"https://staticqbr-gb-prod.prod.cdn.dmdsdp.com/image-service/ImagesEPG/EventImages/p448880_b_v12_ak.jpg"}],"parentId":"crid:~~2F~~2Fgn.tv~~2F21275201~~2FSH012830210000","rootId":"crid:~~2F~~2Fgn.tv~~2F448880~~2FSH012830210000","parentalRatingDescription":[],"resolutions":[],"mediaGroupId":"crid:~~2F~~2Fgn.tv~~2F448880~~2FSH012830210000","shortDescription":"The Calgary Flames play host to the New Jersey Devils in this NHL encounter from Scotiabank Saddledome.","mediaType":"Episode","year":"2022","seriesEpisodeNumber":"194","seriesNumber":"102022","videos":[],"videoStreams":[],"entitlements":["VIP","_OPEN_"],"currentProductIds":[],"currentTvodProductIds":[],"secondaryTitle":"New Jersey Devils at Calgary Flames"},"parentId":"crid:~~2F~~2Fgn.tv~~2F21275201~~2FSH012830210000","rootId":"crid:~~2F~~2Fgn.tv~~2F448880~~2FSH012830210000","replayTvAvailable":true,"audioTracks":[{"lang":"en","audioPurpose":"main"}],"ratings":[],"offersLatestExpirationDate":1647583200000,"replayTvStartOffset":0,"replayTvEndOffset":2592000,"replayEnabledOnMobileClients":true,"replaySource":"cloud","isGoReplayableViaExternalApp":false,"mergedId":"21763550|en-GB"}` } else if (
) url ===
}) 'https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/listings/crid:~~2F~~2Fgn.tv~~2F21720572~~2FEP021779870005,imi:d4324f579ad36992f0c3f6e6d35a9b93e98cb78a'
} else if (url === 'https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/listings/crid:~~2F~~2Fgn.tv~~2F21764379~~2FEP025886890145,imi:c02da14358110cec07d14dc154717ce62ba2f489') { ) {
return Promise.resolve({ return Promise.resolve({
data: JSON.parse( data: JSON.parse(
`{"id":"crid:~~2F~~2Fgn.tv~~2F21764379~~2FEP025886890145,imi:c02da14358110cec07d14dc154717ce62ba2f489","startTime":1647539100000,"endTime":1647540900000,"actualStartTime":1647539100000,"actualEndTime":1647540900000,"expirationDate":1648143900000,"stationId":"lgi-gb-prodobo-master:1761","imi":"imi:c02da14358110cec07d14dc154717ce62ba2f489","scCridImi":"crid:~~2F~~2Fgn.tv~~2F21764379~~2FEP025886890145,imi:c02da14358110cec07d14dc154717ce62ba2f489","mediaGroupId":"crid:~~2F~~2Fgn.tv~~2F13641079~~2FSH025886890000","program":{"id":"crid:~~2F~~2Fgn.tv~~2F21764379~~2FEP025886890145","title":"Boxing World Weekly","description":"A weekly series designed to showcase the best of our sport. Boxing World features news, highlights, previews and profiles from the world of pro boxing.","longDescription":"A weekly series designed to showcase the best of our sport. Boxing World features news, highlights, previews and profiles from the world of pro boxing.","medium":"TV","categories":[{"id":"lgi-gb-prodobo-master:genre-27","title":"Sport","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"},{"id":"lgi-gb-prodobo-master:genre-83","title":"Boxing","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"}],"isAdult":false,"cast":[],"directors":[],"images":[{"assetType":"HighResPortrait","assetTypes":["HighResPortrait"],"url":"https://staticqbr-gb-prod.prod.cdn.dmdsdp.com/image-service/ImagesEPG/EventImages/p19340143_b_v8_aa.jpg"},{"assetType":"TitleTreatment","assetTypes":["TitleTreatment"],"url":"https://staticqbr-gb-prod.prod.cdn.dmdsdp.com/image-service/ImagesEPG/EventImages/p13641079_ttl_h95_aa.png"}],"parentId":"crid:~~2F~~2Fgn.tv~~2F19340143~~2FSH025886890000","rootId":"crid:~~2F~~2Fgn.tv~~2F13641079~~2FSH025886890000","parentalRatingDescription":[],"resolutions":[],"mediaGroupId":"crid:~~2F~~2Fgn.tv~~2F13641079~~2FSH025886890000","shortDescription":"A weekly series designed to showcase the best of our sport. Boxing World features news, highlights, previews and profiles from the world of pro boxing.","mediaType":"Episode","year":"2022","seriesEpisodeNumber":"60","seriesNumber":"4","videos":[],"videoStreams":[],"entitlements":["VIP","_OPEN_"],"currentProductIds":[],"currentTvodProductIds":[]},"parentId":"crid:~~2F~~2Fgn.tv~~2F19340143~~2FSH025886890000","rootId":"crid:~~2F~~2Fgn.tv~~2F13641079~~2FSH025886890000","replayTvAvailable":true,"audioTracks":[{"lang":"en","audioPurpose":"main"}],"ratings":[],"offersLatestExpirationDate":1648142400000,"replayTvStartOffset":0,"replayTvEndOffset":2592000,"replayEnabledOnMobileClients":true,"replaySource":"cloud","isGoReplayableViaExternalApp":false,"mergedId":"21764379|en-GB"}` `{"id":"crid:~~2F~~2Fgn.tv~~2F21720572~~2FEP021779870005,imi:d4324f579ad36992f0c3f6e6d35a9b93e98cb78a","startTime":1647484200000,"endTime":1647496800000,"actualStartTime":1647484200000,"actualEndTime":1647496800000,"expirationDate":1648089000000,"stationId":"lgi-gb-prodobo-master:1761","imi":"imi:d4324f579ad36992f0c3f6e6d35a9b93e98cb78a","scCridImi":"crid:~~2F~~2Fgn.tv~~2F21720572~~2FEP021779870005,imi:d4324f579ad36992f0c3f6e6d35a9b93e98cb78a","mediaGroupId":"crid:~~2F~~2Fgn.tv~~2F11743980~~2FSH021779870000","program":{"id":"crid:~~2F~~2Fgn.tv~~2F21720572~~2FEP021779870005","title":"Challenge Cup Ice Hockey","description":"Exclusive coverage from SSE Arena of the Premier Sports Challenge Final between Belfast Giants and Cardiff Devils.","longDescription":"Exclusive coverage from SSE Arena of the Premier Sports Challenge Final between Belfast Giants and Cardiff Devils.","medium":"TV","categories":[{"id":"lgi-gb-prodobo-master:genre-123","title":"Ice Hockey","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"}],"isAdult":false,"cast":[],"directors":[],"images":[{"assetType":"HighResPortrait","assetTypes":["HighResPortrait"],"url":"https://staticqbr-gb-prod.prod.cdn.dmdsdp.com/image-service/ImagesEPG/EventImages/p11743980_b_v12_aa.jpg"}],"parentId":"crid:~~2F~~2Fgn.tv~~2F123456789~~2FSH021779870000","rootId":"crid:~~2F~~2Fgn.tv~~2F11743980~~2FSH021779870000","parentalRatingDescription":[],"resolutions":[],"mediaGroupId":"crid:~~2F~~2Fgn.tv~~2F11743980~~2FSH021779870000","shortDescription":"Exclusive coverage from SSE Arena of the Premier Sports Challenge Final between Belfast Giants and Cardiff Devils.","mediaType":"Episode","year":"2022","seriesEpisodeNumber":"2022031605","seriesNumber":"79870000","videos":[],"videoStreams":[],"entitlements":["VIP","_OPEN_"],"currentProductIds":[],"currentTvodProductIds":[],"secondaryTitle":"Final: Belfast Giants v Cardiff Devils"},"parentId":"crid:~~2F~~2Fgn.tv~~2F123456789~~2FSH021779870000","rootId":"crid:~~2F~~2Fgn.tv~~2F11743980~~2FSH021779870000","replayTvAvailable":true,"audioTracks":[{"lang":"en","audioPurpose":"main"}],"ratings":[],"offersLatestExpirationDate":1647928800000,"replayTvStartOffset":0,"replayTvEndOffset":2592000,"replayEnabledOnMobileClients":true,"replaySource":"cloud","isGoReplayableViaExternalApp":false,"mergedId":"21720572|en-GB"}`
) )
}) })
} else { } else if (
return Promise.resolve({ data: '' }) url ===
'https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/listings/crid:~~2F~~2Fgn.tv~~2F21763550~~2FEP012830215435,imi:9692f5ceb0b63354262339e8529e3a9cb57add9c'
) {
return Promise.resolve({
data: JSON.parse(
`{"id":"crid:~~2F~~2Fgn.tv~~2F21763550~~2FEP012830215435,imi:9692f5ceb0b63354262339e8529e3a9cb57add9c","startTime":1647511200000,"endTime":1647518400000,"actualStartTime":1647511200000,"actualEndTime":1647518400000,"expirationDate":1648116000000,"stationId":"lgi-gb-prodobo-master:1761","imi":"imi:9692f5ceb0b63354262339e8529e3a9cb57add9c","scCridImi":"crid:~~2F~~2Fgn.tv~~2F21763550~~2FEP012830215435,imi:9692f5ceb0b63354262339e8529e3a9cb57add9c","mediaGroupId":"crid:~~2F~~2Fgn.tv~~2F448880~~2FSH012830210000","program":{"id":"crid:~~2F~~2Fgn.tv~~2F21763550~~2FEP012830215435","title":"NHL Hockey","description":"The Calgary Flames play host to the New Jersey Devils in this NHL encounter from Scotiabank Saddledome.","longDescription":"The Calgary Flames play host to the New Jersey Devils in this NHL encounter from Scotiabank Saddledome.","medium":"TV","categories":[{"id":"lgi-gb-prodobo-master:genre-27","title":"Sport","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"},{"id":"lgi-gb-prodobo-master:genre-123","title":"Ice Hockey","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"}],"isAdult":false,"cast":[],"directors":[],"images":[{"assetType":"HighResLandscapeProductionStill","assetTypes":["HighResLandscapeProductionStill"],"url":"https://staticqbr-gb-prod.prod.cdn.dmdsdp.com/image-service/ImagesEPG/EventImages/p448880_b_h8_ak.jpg"},{"assetType":"HighResPortrait","assetTypes":["HighResPortrait"],"url":"https://staticqbr-gb-prod.prod.cdn.dmdsdp.com/image-service/ImagesEPG/EventImages/p448880_b_v12_ak.jpg"}],"parentId":"crid:~~2F~~2Fgn.tv~~2F21275201~~2FSH012830210000","rootId":"crid:~~2F~~2Fgn.tv~~2F448880~~2FSH012830210000","parentalRatingDescription":[],"resolutions":[],"mediaGroupId":"crid:~~2F~~2Fgn.tv~~2F448880~~2FSH012830210000","shortDescription":"The Calgary Flames play host to the New Jersey Devils in this NHL encounter from Scotiabank Saddledome.","mediaType":"Episode","year":"2022","seriesEpisodeNumber":"194","seriesNumber":"102022","videos":[],"videoStreams":[],"entitlements":["VIP","_OPEN_"],"currentProductIds":[],"currentTvodProductIds":[],"secondaryTitle":"New Jersey Devils at Calgary Flames"},"parentId":"crid:~~2F~~2Fgn.tv~~2F21275201~~2FSH012830210000","rootId":"crid:~~2F~~2Fgn.tv~~2F448880~~2FSH012830210000","replayTvAvailable":true,"audioTracks":[{"lang":"en","audioPurpose":"main"}],"ratings":[],"offersLatestExpirationDate":1647583200000,"replayTvStartOffset":0,"replayTvEndOffset":2592000,"replayEnabledOnMobileClients":true,"replaySource":"cloud","isGoReplayableViaExternalApp":false,"mergedId":"21763550|en-GB"}`
)
})
} else if (
url ===
'https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web/listings/crid:~~2F~~2Fgn.tv~~2F21764379~~2FEP025886890145,imi:c02da14358110cec07d14dc154717ce62ba2f489'
) {
return Promise.resolve({
data: JSON.parse(
`{"id":"crid:~~2F~~2Fgn.tv~~2F21764379~~2FEP025886890145,imi:c02da14358110cec07d14dc154717ce62ba2f489","startTime":1647539100000,"endTime":1647540900000,"actualStartTime":1647539100000,"actualEndTime":1647540900000,"expirationDate":1648143900000,"stationId":"lgi-gb-prodobo-master:1761","imi":"imi:c02da14358110cec07d14dc154717ce62ba2f489","scCridImi":"crid:~~2F~~2Fgn.tv~~2F21764379~~2FEP025886890145,imi:c02da14358110cec07d14dc154717ce62ba2f489","mediaGroupId":"crid:~~2F~~2Fgn.tv~~2F13641079~~2FSH025886890000","program":{"id":"crid:~~2F~~2Fgn.tv~~2F21764379~~2FEP025886890145","title":"Boxing World Weekly","description":"A weekly series designed to showcase the best of our sport. Boxing World features news, highlights, previews and profiles from the world of pro boxing.","longDescription":"A weekly series designed to showcase the best of our sport. Boxing World features news, highlights, previews and profiles from the world of pro boxing.","medium":"TV","categories":[{"id":"lgi-gb-prodobo-master:genre-27","title":"Sport","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"},{"id":"lgi-gb-prodobo-master:genre-83","title":"Boxing","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"}],"isAdult":false,"cast":[],"directors":[],"images":[{"assetType":"HighResPortrait","assetTypes":["HighResPortrait"],"url":"https://staticqbr-gb-prod.prod.cdn.dmdsdp.com/image-service/ImagesEPG/EventImages/p19340143_b_v8_aa.jpg"},{"assetType":"TitleTreatment","assetTypes":["TitleTreatment"],"url":"https://staticqbr-gb-prod.prod.cdn.dmdsdp.com/image-service/ImagesEPG/EventImages/p13641079_ttl_h95_aa.png"}],"parentId":"crid:~~2F~~2Fgn.tv~~2F19340143~~2FSH025886890000","rootId":"crid:~~2F~~2Fgn.tv~~2F13641079~~2FSH025886890000","parentalRatingDescription":[],"resolutions":[],"mediaGroupId":"crid:~~2F~~2Fgn.tv~~2F13641079~~2FSH025886890000","shortDescription":"A weekly series designed to showcase the best of our sport. Boxing World features news, highlights, previews and profiles from the world of pro boxing.","mediaType":"Episode","year":"2022","seriesEpisodeNumber":"60","seriesNumber":"4","videos":[],"videoStreams":[],"entitlements":["VIP","_OPEN_"],"currentProductIds":[],"currentTvodProductIds":[]},"parentId":"crid:~~2F~~2Fgn.tv~~2F19340143~~2FSH025886890000","rootId":"crid:~~2F~~2Fgn.tv~~2F13641079~~2FSH025886890000","replayTvAvailable":true,"audioTracks":[{"lang":"en","audioPurpose":"main"}],"ratings":[],"offersLatestExpirationDate":1648142400000,"replayTvStartOffset":0,"replayTvEndOffset":2592000,"replayEnabledOnMobileClients":true,"replaySource":"cloud","isGoReplayableViaExternalApp":false,"mergedId":"21764379|en-GB"}`
)
})
} else {
return Promise.resolve({ data: '' })
}
})
parser({ content, channel, date })
.then(result => {
result = result.map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2022-03-16T23:30:00.000Z',
stop: '2022-03-17T02:30:00.000Z',
title: 'Live: NHL Hockey',
description:
'The Boston Bruins make the trip to Xcel Energy Center for an NHL clash with the Minnesota Wild.',
category: ['Sport', 'Ice Hockey']
},
{
start: '2022-03-17T02:30:00.000Z',
stop: '2022-03-17T06:00:00.000Z',
title: 'Challenge Cup Ice Hockey',
description:
'Exclusive coverage from SSE Arena of the Premier Sports Challenge Final between Belfast Giants and Cardiff Devils.',
category: ['Ice Hockey']
},
{
start: '2022-03-17T10:00:00.000Z',
stop: '2022-03-17T12:00:00.000Z',
title: 'NHL Hockey',
description:
'The Calgary Flames play host to the New Jersey Devils in this NHL encounter from Scotiabank Saddledome.',
category: ['Sport', 'Ice Hockey']
},
{
start: '2022-03-17T17:45:00.000Z',
stop: '2022-03-17T18:15:00.000Z',
title: 'Boxing World Weekly',
description:
'A weekly series designed to showcase the best of our sport. Boxing World features news, highlights, previews and profiles from the world of pro boxing.',
category: ['Sport', 'Boxing'],
season: '4',
episode: '60'
} }
])
done()
}) })
.catch(done)
parser({ content, channel, date })
.then(result => {
result = result.map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(result).toMatchObject([
{
start: '2022-03-16T23:30:00.000Z',
stop: '2022-03-17T02:30:00.000Z',
title: 'Live: NHL Hockey',
description: 'The Boston Bruins make the trip to Xcel Energy Center for an NHL clash with the Minnesota Wild.',
category: ['Sport', 'Ice Hockey']
},
{
start: '2022-03-17T02:30:00.000Z',
stop: '2022-03-17T06:00:00.000Z',
title: 'Challenge Cup Ice Hockey',
description: 'Exclusive coverage from SSE Arena of the Premier Sports Challenge Final between Belfast Giants and Cardiff Devils.',
category: ['Ice Hockey']
},
{
start: '2022-03-17T10:00:00.000Z',
stop: '2022-03-17T12:00:00.000Z',
title: 'NHL Hockey',
description: 'The Calgary Flames play host to the New Jersey Devils in this NHL encounter from Scotiabank Saddledome.',
category: ['Sport', 'Ice Hockey']
},
{
start: '2022-03-17T17:45:00.000Z',
stop: '2022-03-17T18:15:00.000Z',
title: 'Boxing World Weekly',
description: 'A weekly series designed to showcase the best of our sport. Boxing World features news, highlights, previews and profiles from the world of pro boxing.',
category: ['Sport', 'Boxing'],
season: '4',
episode: '60'
}
])
done()
})
.catch(done)
}) })
it('can handle empty guide', done => { it('can handle empty guide', done => {
parser({ parser({
content: `[{"type":"PATH_PARAM","code":"period","reason":"INVALID"}]`, content: `[{"type":"PATH_PARAM","code":"period","reason":"INVALID"}]`,
channel, channel,
date date
})
.then(result => {
expect(result).toMatchObject([])
done()
}) })
.then(result => { .catch(done)
expect(result).toMatchObject([])
done()
})
.catch(done)
}) })

View file

@ -120,13 +120,13 @@ function parseItems(content, channel) {
} }
function parseSeason(detail) { function parseSeason(detail) {
if (!detail.seasonNumber) return null if (!detail.seasonNumber) return null
if (String(detail.seasonNumber).length > 2) return null if (String(detail.seasonNumber).length > 2) return null
return detail.seasonNumber return detail.seasonNumber
} }
function parseEpisode(detail) { function parseEpisode(detail) {
if (!detail.episodeNumber) return null if (!detail.episodeNumber) return null
if (String(detail.episodeNumber).length > 3) return null if (String(detail.episodeNumber).length > 3) return null
return detail.episodeNumber return detail.episodeNumber
} }