diff --git a/.github/workflows/tv24.co.uk.yml b/.github/workflows/tv24.co.uk.yml
new file mode 100644
index 00000000..eff5a34c
--- /dev/null
+++ b/.github/workflows/tv24.co.uk.yml
@@ -0,0 +1,17 @@
+name: tv24.co.uk
+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/tv24.co.uk/__data__/content.html b/sites/tv24.co.uk/__data__/content.html
new file mode 100644
index 00000000..ec135238
--- /dev/null
+++ b/sites/tv24.co.uk/__data__/content.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/sites/tv24.co.uk/tv24.co.uk.config.js b/sites/tv24.co.uk/tv24.co.uk.config.js
new file mode 100644
index 00000000..993ea2cf
--- /dev/null
+++ b/sites/tv24.co.uk/tv24.co.uk.config.js
@@ -0,0 +1,91 @@
+const dayjs = require('dayjs')
+const axios = require('axios')
+const cheerio = require('cheerio')
+const utc = require('dayjs/plugin/utc')
+const customParseFormat = require('dayjs/plugin/customParseFormat')
+
+dayjs.extend(utc)
+dayjs.extend(customParseFormat)
+
+module.exports = {
+ site: 'tv24.co.uk',
+ url: function ({ channel, date }) {
+ return `https://tv24.co.uk/x/channel/${channel.site_id}/0/${date.format('YYYY-MM-DD')}`
+ },
+ parser: function ({ content, date }) {
+ let 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(30, 'm')
+ programs.push({
+ title: parseTitle($item),
+ description: parseDescription($item),
+ start,
+ stop
+ })
+ })
+
+ return programs
+ },
+ async channels() {
+ let html = await axios
+ .get(`https://tv24.co.uk/x/settings/addremove`)
+ .then(r => r.data)
+ .catch(console.log)
+ let $ = cheerio.load(html)
+ const nums = $('li')
+ .toArray()
+ .map(item => $(item).data('channel'))
+ html = await axios
+ .get(`https://tv24.co.uk`, {
+ headers: {
+ Cookie: `selectedChannels=${nums.join(',')}`
+ }
+ })
+ .then(r => r.data)
+ .catch(console.log)
+ $ = cheerio.load(html)
+ const items = $('li.c').toArray()
+
+ return items.map(item => {
+ const name = $(item).find('h3').text().trim()
+ const link = $(item).find('.channel').attr('href')
+ const [_, site_id] = link.match(/\/channel\/(.*)/) || [null, null]
+
+ return {
+ site_id,
+ name
+ }
+ })
+ }
+}
+
+function parseTitle($item) {
+ return $item('h3').text()
+}
+
+function parseDescription($item) {
+ return $item('p').text()
+}
+
+function parseStart($item, date) {
+ const time = $item('.time').text()
+
+ return dayjs.utc(`${date.format('YYYY-MM-DD')} ${time}`, 'YYYY-MM-DD h:mma')
+}
+
+function parseItems(content) {
+ const $ = cheerio.load(content)
+
+ return $('.program').toArray()
+}
diff --git a/sites/tv24.co.uk/tv24.co.uk.test.js b/sites/tv24.co.uk/tv24.co.uk.test.js
new file mode 100644
index 00000000..ea934e1e
--- /dev/null
+++ b/sites/tv24.co.uk/tv24.co.uk.test.js
@@ -0,0 +1,53 @@
+// npm run channels:parse -- --config=./sites/tv24.co.uk/tv24.co.uk.config.js --output=./sites/tv24.co.uk/tv24.co.uk_uk.channels.xml
+// npx epg-grabber --config=sites/tv24.co.uk/tv24.co.uk.config.js --channels=sites/tv24.co.uk/tv24.co.uk_uk.channels.xml --output=guide.xml --days=2
+
+const { parser, url } = require('./tv24.co.uk.config.js')
+const fs = require('fs')
+const path = require('path')
+const dayjs = require('dayjs')
+const utc = require('dayjs/plugin/utc')
+const customParseFormat = require('dayjs/plugin/customParseFormat')
+dayjs.extend(customParseFormat)
+dayjs.extend(utc)
+
+const date = dayjs.utc('2022-08-28', 'YYYY-MM-DD').startOf('d')
+const channel = {
+ site_id: 'bbc-two',
+ xmltv_id: 'BBCTwo.uk'
+}
+
+it('can generate valid url', () => {
+ expect(url({ channel, date })).toBe('https://tv24.co.uk/x/channel/bbc-two/0/2022-08-28')
+})
+
+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: '2022-08-28T05:05:00.000Z',
+ stop: '2022-08-28T06:05:00.000Z',
+ title: "Gardeners' World",
+ description:
+ 'Arit Anderson discovers a paradise garden in Cambridge which has become a focal point for the local community, and Frances Tophill shares the joy of collecting and saving heirloom vegetable seeds on a visit to Pembrokeshire.'
+ })
+
+ expect(results[22]).toMatchObject({
+ start: '2022-08-29T05:30:00.000Z',
+ stop: '2022-08-29T06:00:00.000Z',
+ title: 'Animal Park',
+ description:
+ "One of the park's vultures has laid an egg. It is ten years since Longleat had a successfully reared vulture chick, so the keepers send Hamza to find out if the parents are incubating their egg."
+ })
+})
+
+it('can handle empty guide', () => {
+ const result = parser({
+ content: ''
+ })
+ expect(result).toMatchObject([])
+})
diff --git a/sites/tv24.co.uk/tv24.co.uk_uk.channels.xml b/sites/tv24.co.uk/tv24.co.uk_uk.channels.xml
new file mode 100644
index 00000000..679b4f33
--- /dev/null
+++ b/sites/tv24.co.uk/tv24.co.uk_uk.channels.xml
@@ -0,0 +1,112 @@
+
+
+
+ 4Seven
+ 5 Action
+ 5SELECT
+ 5USA
+ Al Arabiya
+ Al Jazeera English
+ ARISE
+ Babestation
+ BBC Four
+ BBC Four HD
+ BBC News
+ BBC One HD (England)
+ BBC One London
+ BBC Parliament
+ BBC Red Button 1
+ BBC Three
+ BBC Two
+ BBC Two HD
+ CBBC
+ CBeebies
+ CBS Reality
+ Challenge TV
+ Channel 4
+ Channel 4 +1
+ Channel 5
+ Channel 5+1
+ Create and Craft (Freeview)
+ Dave Ja Vu
+ Dave
+ DMAX
+ Drama
+ E4
+ Film4
+ Food Network
+ GB News
+ HGTV
+ Ideal World (Freeview)
+ ITV2
+ ITV3
+ ITV4
+ ITV BE
+ Kiss
+ London Live
+ More 4
+ Planet Knowledge
+ Pop
+ Quest Red
+ Quest Red +1
+ Quest
+ QVC Style (Freeview)
+ Really
+ Sky Arts
+ Sky News
+ Smithsonian Channel SD
+ Talking Pictures TV
+ TBN UK
+ Together
+ xxXpanded TV
+ Yesterday
+ Yesterday +1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+