diff --git a/.github/workflows/virginmediatelevision.ie.yml b/.github/workflows/virginmediatelevision.ie.yml new file mode 100644 index 00000000..44da1cb6 --- /dev/null +++ b/.github/workflows/virginmediatelevision.ie.yml @@ -0,0 +1,17 @@ +name: virginmediatelevision.ie +on: + schedule: + - cron: '0 3 * * *' + workflow_dispatch: + workflow_run: + workflows: [_trigger] + types: + - completed +jobs: + load: + uses: ./.github/workflows/_load.yml + with: + site: ${{github.workflow}} + secrets: + APP_ID: ${{ secrets.APP_ID }} + APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} diff --git a/sites/virginmediatelevision.ie/__data__/content.html b/sites/virginmediatelevision.ie/__data__/content.html new file mode 100644 index 00000000..f8539bc5 --- /dev/null +++ b/sites/virginmediatelevision.ie/__data__/content.html @@ -0,0 +1,591 @@ + +
+
+12.00am1.00am2.00am3.00am4.00am5.00am6.00am7.00am8.00am9.00am10.00am11.00am12.00pm1.00pm2.00pm3.00pm4.00pm5.00pm6.00pm7.00pm8.00pm9.00pm10.00pm11.00pm + +
+
+ +
+
+
+
+
+One Logo +One Logo Gray +
+
+Two Logo +Two Logo Gray +
+
+Three Logo +Three Logo Gray +
+
+Four Logo +Four Logo Gray +
+
+Virgin Media More Logo +Virgin Media More Logo +
+
+
+
+
+
+

Chasing Shadows

+ 12.00am - 1.00am +
+
+
+

Vicky Phelan: The Big Interview

+ 1.00am - 2.00am +
+
+
+

Off Air

+ 2.00am - 5.25am +
+
+
+

The Tonight Show

+ 5.25am - 6.15am [S] +
+
+
+

The Six O'Clock Show

+ 6.15am - 7.00am [S] +
+
+
+

Ireland AM

+ 7.00am - 10.00am [S] +
+
+
+

This Morning

+ 10.00am - 12.30pm +
+
+
+

News at 12.30

+ 12.30pm - 1.00pm [S] +
+
+
+

The Chase

+ 1.00pm - 2.00pm [S] +
+
+
+

The Chase

+ 2.00pm - 3.00pm [S] +
+
+
+

Loose Women

+ 3.00pm - 4.00pm +
+
+
+

Heathrow: Britain's Busiest Airport

+ 4.00pm - 4.30pm +
+
+
+

Judge Judy

+ 4.30pm - 5.00pm +
+
+
+

Judge Judy

+ 5.00pm - 5.30pm +
+
+
+

News at 5.30

+ 5.30pm - 6.05pm [S] +
+
+
+

The Six O'Clock Show

+ 6.05pm - 7.00pm [S] +
+
+
+

News at 7

+ 7.00pm - 7.30pm [S] +
+
+
+

Emmerdale

+ 7.30pm - 8.00pm [S] +
+
+
+

Paul O'Grady: For the Love of Dogs

+ 8.00pm - 8.30pm [S] +
+
+
+

Call the Cleaners

+ 8.30pm - 9.00pm [S] +
+
+
+

Murder in the Family

+ 9.00pm - 10.00pm +
+
+
+

The Tonight Show

+ 10.00pm - 11.00pm [S] +
+
+
+

Who Wants to Be a Millionaire?

+ 11.00pm - 12.00am +
+
+
+
+
+

The Jonathan Ross Show

+ 11.05pm - 12.05am +
+
+
+

Love Island

+ 12.05am - 1.05am +
+
+
+

Olivia Meets Her Match

+ 1.05am - 2.05am +
+
+
+

Killing Spree

+ 2.05am - 2.55am +
+
+
+

Off Air

+ 2.55am - 7.00am +
+
+
+

Nanny 911

+ 7.00am - 8.00am +
+
+
+

Tipping Point

+ 8.00am - 9.00am [S] +
+
+
+

The Chase

+ 9.00am - 10.00am [S] +
+
+
+

The Chase

+ 10.00am - 11.00am [S] +
+
+
+

Hello Campers

+ 11.00am - 12.00pm +
+
+
+

The National Lottery: 5-Star Family Reunion

+ 12.00pm - 1.00pm +
+
+
+

Heathrow: Britain's Busiest Airport

+ 1.00pm - 2.00pm +
+
+
+

The Deal Makers

+ 2.00pm - 3.00pm +
+
+
+

The Deal Makers

+ 3.00pm - 4.00pm +
+
+
+

Tipping Point

+ 4.00pm - 5.00pm [S] +
+
+
+

Tipping Point

+ 5.00pm - 6.00pm [S] +
+
+
+

The Chase

+ 6.00pm - 7.00pm [S] +
+
+
+

The Chase

+ 7.00pm - 8.00pm [S] +
+
+
+

The Family Chase

+ 8.00pm - 9.00pm +
+
+
+

Love Island

+ 9.00pm - 10.05pm +
+
+
+

10 Years Younger in 10 Days

+ 10.05pm - 11.10pm +
+
+
+

The Jonathan Ross Show

+ 11.10pm - 12.15am +
+
+
+
+

Coronation Street

+ 11.40pm - 12.10am [S] +
+
+
+

Coronation Street

+ 12.10am - 12.40am [S] +
+
+
+

Emmerdale

+ 12.40am - 1.10am [S] +
+
+
+

Cleaning Up

+ 1.10am - 2.05am [S] +
+
+
+

Off Air

+ 2.05am - 7.15am +
+
+
+

The Chase Australia

+ 7.15am - 8.00am +
+
+
+

Yes Chef

+ 8.00am - 9.00am [S] +
+
+
+

Loose Women

+ 9.00am - 10.00am +
+
+
+

Judge Judy

+ 10.00am - 10.30am +
+
+
+

Judge Judy

+ 10.30am - 11.00am +
+
+
+

The Deal Makers

+ 11.00am - 12.00pm +
+
+
+

Storage Hoarders

+ 12.00pm - 1.00pm +
+
+
+

The Good Witch

+ 1.00pm - 2.00pm +
+
+
+

Emmerdale

+ 2.00pm - 2.30pm [S] +
+
+
+

Coronation Street

+ 2.30pm - 3.00pm [S] +
+
+
+

Coronation Street

+ 3.00pm - 3.30pm [S] +
+
+
+

Keeping Canada Safe

+ 3.30pm - 4.00pm +
+
+
+

Paul O'Grady: The Sally Army and Me

+ 4.00pm - 4.35pm [S] +
+
+
+

Heartbeat

+ 4.35pm - 5.45pm [S] +
+
+
+

Agatha Christie's Poirot

+ 5.45pm - 7.55pm [S] +
+
+
+

Heartbeat

+ 7.55pm - 9.00pm [S] +
+
+
+

Vera

+ 9.00pm - 11.00pm [S] +
+
+
+

Emmerdale

+ 11.00pm - 11.30pm [S] +
+
+
+

Killing Spree

+ 11.30pm - 12.30am +
+
+
+
+

Formula E Highlights

+ 11.30pm - 12.30am +
+
+
+

Paramedics

+ 12.30am - 1.30am [S] +
+
+
+

Off Air

+ 1.30am - 7.00am +
+
+
+

5 Gold Rings

+ 7.00am - 8.00am +
+
+
+

5 Gold Rings

+ 8.00am - 9.00am +
+
+
+

Vet School

+ 9.00am - 10.00am [S] +
+
+
+

Vet School

+ 10.00am - 11.00am [S] +
+
+
+

Tipping Point: Lucky Stars

+ 11.00am - 12.00pm [S] +
+
+
+

Heathrow: Britain's Busiest Airport

+ 12.00pm - 12.30pm +
+
+
+

Heathrow: Britain's Busiest Airport

+ 12.30pm - 1.00pm +
+
+
+

Paramedics

+ 1.00pm - 2.00pm [S] +
+
+
+

The National Lottery: 5-Star Family Reunion

+ 2.00pm - 3.00pm +
+
+
+

Dog Rescue

+ 3.00pm - 3.30pm +
+
+
+

Wild China with Ray Mears

+ 3.30pm - 4.05pm +
+
+
+

The Motorway: Life in the Fast Lane

+ 4.05pm - 5.00pm +
+
+
+

The National Lottery: 5-Star Family Reunion

+ 5.00pm - 6.00pm +
+
+
+

Drive

+ 6.00pm - 7.00pm +
+
+
+

The Deal Makers

+ 7.00pm - 8.00pm +
+
+
+

Arthur & George

+ 8.00pm - 9.00pm +
+
+
+

Judge Rinder's Crime Stories

+ 9.00pm - 10.00pm +
+
+
+

Judge Rinder's Crime Stories

+ 10.00pm - 11.00pm +
+
+
+

The Jonathan Ross Show

+ 11.00pm - 11.30pm +
+
+
+

Sport Stories

+ 11.30pm - 12.30am [S] +
+
+
+
+

Vera

+ 11.30pm - 1.10am [S] +
+
+
+

Formula E Highlights

+ 1.10am - 2.05am +
+
+
+

Off Air

+ 2.05am - 1.10pm +
+
+
+

Sport Stories

+ 1.10pm - 2.00pm +
+
+
+

Sport Stories

+ 2.00pm - 2.50pm +
+
+
+

Sport Stories

+ 2.50pm - 3.40pm +
+
+
+

Niall Quinn: Bootroom to Boardroom

+ 3.40pm - 4.30pm +
+
+
+

Best of UEFA Champions League

+ 4.30pm - 5.25pm +
+
+
+

Best of UEFA Champions League

+ 5.25pm - 6.20pm +
+
+
+

Classic Six Nations

+ 6.20pm - 7.15pm +
+
+
+

Classic Six Nations

+ 7.15pm - 8.10pm +
+
+
+

Impossible Engineering

+ 8.10pm - 9.00pm +
+
+
+

Our House

+ 9.00pm - 9.50pm [S] +
+
+
+

Bancroft

+ 9.50pm - 10.40pm [S] +
+
+
+

Intruder

+ 10.40pm - 11.30pm [S] +
+
+
+

Redemption

+ 11.30pm - 12.20am +
+
+ +
+
+
diff --git a/sites/virginmediatelevision.ie/virginmediatelevision.ie.channels.xml b/sites/virginmediatelevision.ie/virginmediatelevision.ie.channels.xml new file mode 100644 index 00000000..990dc604 --- /dev/null +++ b/sites/virginmediatelevision.ie/virginmediatelevision.ie.channels.xml @@ -0,0 +1,10 @@ + + + + One + Two + Three + Four + More + + diff --git a/sites/virginmediatelevision.ie/virginmediatelevision.ie.config.js b/sites/virginmediatelevision.ie/virginmediatelevision.ie.config.js new file mode 100644 index 00000000..b1fa6144 --- /dev/null +++ b/sites/virginmediatelevision.ie/virginmediatelevision.ie.config.js @@ -0,0 +1,82 @@ +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: 'virginmediatelevision.ie', + days: 2, + url({ date }) { + return `https://www.virginmediatelevision.ie/includes/ajax/tv_guide.php?date=${date.format( + 'YYYY-MM-DD' + )}` + }, + request: { + cache: { + ttl: 60 * 60 * 1000 // 1h + } + }, + parser({ content, channel, date }) { + const programs = [] + const items = parseItems(content, channel) + items.forEach(item => { + const $item = cheerio.load(item) + let start = parseStart($item, date) + let duration = parseDuration($item) + let stop = start.add(duration, 'm') + programs.push({ + title: parseTitle($item), + description: parseDescription($item), + sub_title: parseSubTitle($item), + icon: parseIcon($item), + start, + stop + }) + }) + + return programs + } +} + +function parseTitle($item) { + return $item('.info > h2').text().trim() +} + +function parseDescription($item) { + return $item('.info').data('description') +} + +function parseSubTitle($item) { + return $item('.info').data('subtitle') +} + +function parseIcon($item) { + return $item('.info').data('image') +} + +function parseStart($item, date) { + const [time] = $item('.info') + .data('time') + .match(/^\d{1,2}\.\d{2}(am|pm)/) || [null] + + if (!time) return null + + return dayjs.tz(`${date.format('YYYY-MM-DD')} ${time}`, 'YYYY-MM-DD h.mma', 'Europe/London') +} + +function parseDuration($item) { + const duration = $item('.info > .time').data('minutes') + + return duration ? parseInt(duration) : 30 +} + +function parseItems(content, channel) { + const $ = cheerio.load(content) + + return $(`.programs_parent > .programs[data-channel='${channel.site_id}'] > .program`).toArray() +} diff --git a/sites/virginmediatelevision.ie/virginmediatelevision.ie.test.js b/sites/virginmediatelevision.ie/virginmediatelevision.ie.test.js new file mode 100644 index 00000000..e104bad8 --- /dev/null +++ b/sites/virginmediatelevision.ie/virginmediatelevision.ie.test.js @@ -0,0 +1,52 @@ +// npx epg-grabber --config=sites/virginmediatelevision.ie/virginmediatelevision.ie.config.js --channels=sites/virginmediatelevision.ie/virginmediatelevision.ie.channels.xml --output=guide.xml --days=2 + +const { parser, url } = require('./virginmediatelevision.ie.config.js') +const fs = require('fs') +const path = require('path') +const dayjs = require('dayjs') +const utc = require('dayjs/plugin/utc') +const customParseFormat = require('dayjs/plugin/customParseFormat') +dayjs.extend(customParseFormat) +dayjs.extend(utc) + +const date = dayjs.utc('2023-01-31', 'YYYY-MM-DD').startOf('d') +const channel = { + site_id: 'one', + xmltv_id: 'VirginMediaOne.ie' +} + +it('can generate valid url', () => { + expect(url({ date })).toBe( + 'https://www.virginmediatelevision.ie/includes/ajax/tv_guide.php?date=2023-01-31' + ) +}) + +it('can parse response', () => { + const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8') + let results = parser({ content, channel, date }) + results = results.map(p => { + p.start = p.start.toJSON() + p.stop = p.stop.toJSON() + return p + }) + + expect(results.length).toBe(23) + expect(results[0]).toMatchObject({ + start: '2023-01-31T00:00:00.000Z', + stop: '2023-01-31T01:00:00.000Z', + title: `Chasing Shadows`, + sub_title: '', + description: `A detective sergeant and expert in the field of serial killers working for the Missing Persons Bureau tries to protect the general public from evil.`, + icon: 'https://bcboltvirgin.akamaized.net/player/shows/1498_517x291_1528141264.jpg' + }) +}) + +it('can handle empty guide', () => { + const results = parser({ + date, + channel, + content: `` + }) + + expect(results).toMatchObject([]) +})