From f9515b3962bac868c206b7e5357c44db7a3700b8 Mon Sep 17 00:00:00 2001 From: Toha Date: Fri, 6 Dec 2024 20:58:13 +0700 Subject: [PATCH] Update programme.tvb.com guide. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: ```sh npm test -- programme.tvb.com > test > run-script-os programme.tvb.com > test:win32 > SET "TZ=Pacific/Nauru" && npx jest --runInBand programme.tvb.com PASS sites/programme.tvb.com/programme.tvb.com.test.js (5.14 s) √ can generate valid url (4 ms) √ can parse response (en) (41 ms) √ can parse response (zh) (2 ms) √ can handle empty guide (1 ms) Test Suites: 1 passed, 1 total Tests: 4 passed, 4 total Snapshots: 0 total Time: 5.391 s Ran all test suites matching /programme.tvb.com/i. ``` Grab: ```sh npm run grab -- --site=programme.tvb.com --lang=en > grab > npx tsx scripts/commands/epg/grab.ts --site=programme.tvb.com --lang=en starting... config: output: guide.xml maxConnections: 1 gzip: false site: programme.tvb.com lang: en loading channels... found 4 channel(s) run #1: [1/8] programme.tvb.com (en) - B - Dec 6, 2024 (37 programs) [2/8] programme.tvb.com (en) - B - Dec 7, 2024 (33 programs) [3/8] programme.tvb.com (en) - TVBNewsChannel.hk - Dec 7, 2024 (48 programs) [4/8] programme.tvb.com (en) - TVBNewsChannel.hk - Dec 6, 2024 (50 programs) [5/8] programme.tvb.com (en) - Pearl.hk - Dec 7, 2024 (32 programs) [6/8] programme.tvb.com (en) - Pearl.hk - Dec 6, 2024 (37 programs) [7/8] programme.tvb.com (en) - Jade.hk - Dec 7, 2024 (36 programs) [8/8] programme.tvb.com (en) - Jade.hk - Dec 6, 2024 (48 programs) saving to "guide.xml"... done in 00h 00m 03s ``` Signed-off-by: Toha --- sites/programme.tvb.com/__data__/content.html | 3 - sites/programme.tvb.com/__data__/content.json | 1 + .../__data__/no-content.html | 3 - .../programme.tvb.com.channels.xml | 12 -- .../programme.tvb.com.config.js | 120 +++++++++++------- .../programme.tvb.com.test.js | 47 +++++-- .../programme.tvb.com_en.channels.xml | 7 + .../programme.tvb.com_zh.channels.xml | 7 + sites/programme.tvb.com/readme.md | 26 +++- 9 files changed, 147 insertions(+), 79 deletions(-) delete mode 100644 sites/programme.tvb.com/__data__/content.html create mode 100644 sites/programme.tvb.com/__data__/content.json delete mode 100644 sites/programme.tvb.com/__data__/no-content.html delete mode 100644 sites/programme.tvb.com/programme.tvb.com.channels.xml create mode 100644 sites/programme.tvb.com/programme.tvb.com_en.channels.xml create mode 100644 sites/programme.tvb.com/programme.tvb.com_zh.channels.xml diff --git a/sites/programme.tvb.com/__data__/content.html b/sites/programme.tvb.com/__data__/content.html deleted file mode 100644 index 14d317fb..00000000 --- a/sites/programme.tvb.com/__data__/content.html +++ /dev/null @@ -1,3 +0,0 @@ - - diff --git a/sites/programme.tvb.com/__data__/content.json b/sites/programme.tvb.com/__data__/content.json new file mode 100644 index 00000000..055c4620 --- /dev/null +++ b/sites/programme.tvb.com/__data__/content.json @@ -0,0 +1 @@ +{"code":0,"message":"","data":{"total":1,"list":[{"network_code":"j","ref_date":20241206,"schedules":[{"box_set_id":203,"network_code":"J","video_ratio":"2","video_definition":"1","event_time":1733500200,"event_datetime":"2024-12-06 23:50:00","programme_title":"天氣報告[粵] 及 潮流生活誌[粵]","en_programme_title":"Weather Report[Can] and Pop Lifestyle Guide (Ad Mag)[Can]","synopsis":"","en_synopsis":"","programme_path":"weatherreport_203","default_language":1,"play_available":1,"mytv_super_url":"https://www.mytvsuper.com/tc/programme/weatherreport_203/天氣報告[粵] 及 潮流生活誌[粵]","on_air_code":"L2,","tag":[{"icon":"hd","title":"HD"}]},{"box_set_id":0,"network_code":"J","video_ratio":"2","video_definition":"1","event_time":1733500500,"event_datetime":"2024-12-06 23:55:00","programme_title":"使徒行者3#16[粵][PG]","en_programme_title":"Line Walker: Bull Fight#16[Can][PG]","synopsis":"文鼎從淑梅手上救走大聖爺兒子,大聖爺還恩於歡喜,答允支持九指強。崇聯社定下選舉日子,恰巧是韋傑出獄之日,頭目們顧念舊日恩義,紛紛轉投浩洋。浩洋帶亞希逛傢俬店,憧憬二人未來。亞希向家強承認愛上浩洋,要求退出臥底任務。作榮與歡喜暗中會面,將國際犯罪組織「永恆幫」情報交給他。阿火遭家強出賣,到沐足店搶錢。家強逮住阿火,惟被合星誤會而受拘捕。家強把正植遺下的頸鏈和學生證交還,合星意識到家強已知悉正植身世。","en_synopsis":"","programme_path":"","default_language":0,"play_available":0,"mytv_super_url":"","on_air_code":"S2,C2,C3,C1,A,PG11L,","tag":[{"icon":"s","title":"繁/簡中文字幕"},{"icon":"e","title":"英文字幕"},{"icon":"pg","title":"PG11L"},{"icon":"hd","title":"HD"}]},{"box_set_id":0,"network_code":"J","video_ratio":"1","video_definition":"2","event_time":1733504100,"event_datetime":"2024-12-07 00:55:00","programme_title":"宣傳易[粵]","en_programme_title":"TV Easy[Can]","synopsis":"","en_synopsis":"","programme_path":"","default_language":0,"play_available":0,"mytv_super_url":"","on_air_code":"D2,","tag":[]}]}]}} \ No newline at end of file diff --git a/sites/programme.tvb.com/__data__/no-content.html b/sites/programme.tvb.com/__data__/no-content.html deleted file mode 100644 index 6c648b03..00000000 --- a/sites/programme.tvb.com/__data__/no-content.html +++ /dev/null @@ -1,3 +0,0 @@ - - diff --git a/sites/programme.tvb.com/programme.tvb.com.channels.xml b/sites/programme.tvb.com/programme.tvb.com.channels.xml deleted file mode 100644 index e613b067..00000000 --- a/sites/programme.tvb.com/programme.tvb.com.channels.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - J2 - 翡翠台 - Pearl - 華語劇台 - TVB經典台 - 粵語片台 - 無綫財經體育資訊台 - 無綫新聞台 - TVB星河頻道 - diff --git a/sites/programme.tvb.com/programme.tvb.com.config.js b/sites/programme.tvb.com/programme.tvb.com.config.js index 16aea97a..c487257e 100644 --- a/sites/programme.tvb.com/programme.tvb.com.config.js +++ b/sites/programme.tvb.com/programme.tvb.com.config.js @@ -1,5 +1,4 @@ const dayjs = require('dayjs') -const cheerio = require('cheerio') const utc = require('dayjs/plugin/utc') const timezone = require('dayjs/plugin/timezone') const customParseFormat = require('dayjs/plugin/customParseFormat') @@ -8,57 +7,88 @@ dayjs.extend(utc) dayjs.extend(timezone) dayjs.extend(customParseFormat) +const tz = 'Asia/Hong_Kong' + module.exports = { site: 'programme.tvb.com', days: 2, - url: function ({ channel, date }) { - return `https://programme.tvb.com/ajax.php?action=channellist&code=${ - channel.site_id - }&date=${date.format('YYYY-MM-DD')}` + url({ channel, date, time = null }) { + return `https://programme.tvb.com/api/schedule?input_date=${ + date.format('YYYYMMDD') + }&network_code=${channel.site_id}&_t=${time ? time : parseInt(Date.now() / 1000)}` }, - 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') + parser({ content, channel, date }) { + const programs = [] + const data = content ? JSON.parse(content) : {} + if (Array.isArray(data.data?.list)) { + const dt = date.format('YYYY-MM-DD') + for (const d of data.data.list) { + if (Array.isArray(d.schedules)) { + const schedules = d.schedules + .filter(s => s.network_code === channel.site_id) + schedules.forEach((s, i) => { + const start = dayjs.tz(s.event_datetime, 'YYYY-MM-DD HH:mm:ss', tz) + let stop + if (i < schedules.length - 1) { + stop = dayjs.tz(schedules[i + 1].event_datetime, 'YYYY-MM-DD HH:mm:ss', tz) + } else { + stop = date.add(1, 'd') + } + programs.push({ + title: channel.lang === 'en' ? s.en_programme_title : s.programme_title, + description: channel.lang === 'en' ? s.en_synopsis : s.synopsis, + start, + stop + }) + }) } - prev.stop = start } - const stop = start.add(30, 'm') - programs.push({ - title: parseTitle($item), - description: parseDescription($item), - start, - stop - }) - }) + } return programs + }, + async channels({ lang = 'en' }) { + const channels = [] + const axios = require('axios') + const base = 'https://programme.tvb.com' + const queues = [base] + while (true) { + if (queues.length) { + const url = queues.shift() + const content = await axios + .get(url) + .then(response => response.data) + .catch(console.error) + if (content) { + const assets = content.match(/assets\/index\.([a-z0-9]+)\.js/g) + if (assets) { + queues.push(...assets.map(a => base + '/' + a)) + } else { + const metadata = content.match(/e\=(\[(.*?)\])/) + if (metadata) { + const infos = eval(metadata[1]) + if (Array.isArray(infos)) { + infos + .filter(a => a.code.length) + .map(a => { + channels.push({ + lang, + site_id: a.code, + name: lang === 'en' ? a.nameEn : a.name + }) + }) + break + } + } + } + if (queues.length) { + continue + } + } + } + break + } + + return channels } } - -function parseTitle($item) { - return $item('.ftit').text().trim() -} - -function parseDescription($item) { - return $item('.full').text().trim() -} - -function parseStart($item, date) { - const time = $item('.time').text() - - return dayjs.tz(`${date.format('YYYY-MM-DD')} ${time}`, 'YYYY-MM-DD hh:mmA', 'Asia/Hong_Kong') -} - -function parseItems(content) { - const $ = cheerio.load(content) - - return $('ul > li.item').toArray() -} diff --git a/sites/programme.tvb.com/programme.tvb.com.test.js b/sites/programme.tvb.com/programme.tvb.com.test.js index e2a3e36b..8bcf56f7 100644 --- a/sites/programme.tvb.com/programme.tvb.com.test.js +++ b/sites/programme.tvb.com/programme.tvb.com.test.js @@ -4,41 +4,60 @@ const path = require('path') const dayjs = require('dayjs') const utc = require('dayjs/plugin/utc') const customParseFormat = require('dayjs/plugin/customParseFormat') + dayjs.extend(customParseFormat) dayjs.extend(utc) -const date = dayjs.utc('2022-11-15', 'YYYY-MM-DD').startOf('d') +const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json')) +const date = dayjs.utc('2024-12-06', 'YYYY-MM-DD').startOf('d') const channel = { - site_id: 'B', - xmltv_id: 'J2.hk' + site_id: 'J', + xmltv_id: 'Jade.hk', + lang: 'en' } it('can generate valid url', () => { - expect(url({ channel, date })).toBe( - 'https://programme.tvb.com/ajax.php?action=channellist&code=B&date=2022-11-15' + const time = 1733491000 + expect(url({ channel, date, time })).toBe( + 'https://programme.tvb.com/api/schedule?input_date=20241206&network_code=J&_t=1733491000' ) }) -it('can parse response', () => { - const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html')) - const results = parser({ content, date }).map(p => { +it('can parse response (en)', () => { + const results = parser({ content, channel, date }).map(p => { p.start = p.start.toJSON() p.stop = p.stop.toJSON() return p }) - expect(results[0]).toMatchObject({ - start: '2022-11-14T22:00:00.000Z', - stop: '2022-11-14T23:00:00.000Z', - title: '想見你#3[粵/普][PG]', + expect(results.length).toBe(3) + expect(results[1]).toMatchObject({ + start: '2024-12-06T15:55:00.000Z', + stop: '2024-12-06T16:55:00.000Z', + title: 'Line Walker: Bull Fight#16[Can][PG]', + }) +}) + +it('can parse response (zh)', () => { + const results = parser({ content, channel: { ...channel, lang: 'zh' }, date }).map(p => { + p.start = p.start.toJSON() + p.stop = p.stop.toJSON() + return p + }) + + expect(results.length).toBe(3) + expect(results[1]).toMatchObject({ + start: '2024-12-06T15:55:00.000Z', + stop: '2024-12-06T16:55:00.000Z', + title: '使徒行者3#16[粵][PG]', description: - '韻如因父母離婚都不要自己而跑出家門,遇到子維,兩人互吐心事。雨萱順著照片上的唱片行線索,找到一家同名咖啡店,從文磊處得知照片中人是已經過世的韻如,從而推測那個男生也不是詮勝,但她內心反而更加痛苦。' + '文鼎從淑梅手上救走大聖爺兒子,大聖爺還恩於歡喜,答允支持九指強。崇聯社定下選舉日子,恰巧是韋傑出獄之日,頭目們顧念舊日恩義,紛紛轉投浩洋。浩洋帶亞希逛傢俬店,憧憬二人未來。亞希向家強承認愛上浩洋,要求退出臥底任務。作榮與歡喜暗中會面,將國際犯罪組織「永恆幫」情報交給他。阿火遭家強出賣,到沐足店搶錢。家強逮住阿火,惟被合星誤會而受拘捕。家強把正植遺下的頸鏈和學生證交還,合星意識到家強已知悉正植身世。', }) }) it('can handle empty guide', () => { const result = parser({ - content: fs.readFileSync(path.resolve(__dirname, '__data__/no-content.html')), + content: '', date }) expect(result).toMatchObject([]) diff --git a/sites/programme.tvb.com/programme.tvb.com_en.channels.xml b/sites/programme.tvb.com/programme.tvb.com_en.channels.xml new file mode 100644 index 00000000..29546257 --- /dev/null +++ b/sites/programme.tvb.com/programme.tvb.com_en.channels.xml @@ -0,0 +1,7 @@ + + + tvb plus + jade + pearl + tvb news channel + diff --git a/sites/programme.tvb.com/programme.tvb.com_zh.channels.xml b/sites/programme.tvb.com/programme.tvb.com_zh.channels.xml new file mode 100644 index 00000000..3411965e --- /dev/null +++ b/sites/programme.tvb.com/programme.tvb.com_zh.channels.xml @@ -0,0 +1,7 @@ + + + TVB Plus + 翡翠台 + 明珠台 + 無綫新聞台 + diff --git a/sites/programme.tvb.com/readme.md b/sites/programme.tvb.com/readme.md index 284e0234..4bc63b26 100644 --- a/sites/programme.tvb.com/readme.md +++ b/sites/programme.tvb.com/readme.md @@ -1,11 +1,33 @@ # programme.tvb.com -https://programme.tvb.com/ +https://www.programme.tvb.com/ ### Download the guide +English: + ```sh -npm run grab -- --site=programme.tvb.com +npm run grab -- --site=programme.tvb.com --lang=en +``` + +Chinese: + +```sh +npm run grab -- --site=programme.tvb.com --lang=zh +``` + +### Update channel list + +English: + +```sh +npm run channels:parse -- --config=sites/programme.tvb.com/programme.tvb.com.config.js --output=sites/programme.tvb.com/programme.tvb.com_en.channels.xml --set=lang:en +``` + +Chinese: + +```sh +npm run channels:parse -- --config=sites/programme.tvb.com/programme.tvb.com.config.js --output=sites/programme.tvb.com/programme.tvb.com_zh.channels.xml --set=lang:zh ``` ### Test