From cb10f7a162e7f93e415fe3df28129b2bc9e09e24 Mon Sep 17 00:00:00 2001 From: freearhey <7253922+freearhey@users.noreply.github.com> Date: Mon, 27 Jan 2025 04:50:04 +0300 Subject: [PATCH 01/12] Create content.json --- sites/tvtv.us/__data__/content.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 sites/tvtv.us/__data__/content.json diff --git a/sites/tvtv.us/__data__/content.json b/sites/tvtv.us/__data__/content.json new file mode 100644 index 00000000..e8e95c07 --- /dev/null +++ b/sites/tvtv.us/__data__/content.json @@ -0,0 +1 @@ +[[{"type":"O","startTime":"2025-01-30T00:00Z","start":0,"duration":30,"runTime":30,"flags":["New","HD 1080p"],"programId":"SH047338460000","title":"NY Sports Nation Nightly"},{"subtitle":"The Bow Tie Asymmetry","type":"O","startTime":"2025-01-30T00:30Z","start":120,"duration":30,"runTime":30,"flags":["CC","HD 1080p","HDTV","Stereo"],"programId":"EP009311820269","title":"The Big Bang Theory"},{"subtitle":"Reborn","type":"O","startTime":"2025-01-30T01:00Z","start":240,"duration":60,"runTime":60,"flags":["New","CC","DD 5.1","HD 1080p","HDTV","Stereo"],"programId":"EP029730910107","title":"All American"},{"subtitle":"Week 21","type":"O","startTime":"2025-01-30T02:00Z","start":480,"duration":60,"runTime":60,"flags":["New","CC","DD 5.1","HD 1080p","HDTV","Stereo"],"programId":"EP000388400649","title":"Inside the NFL"},{"type":"N","startTime":"2025-01-30T03:00Z","start":720,"duration":60,"runTime":60,"flags":["New","CC","HD 1080p","HDTV","Stereo"],"programId":"SH019353980000","title":"PIX11 News at Ten"},{"subtitle":"The Label Maker","type":"O","startTime":"2025-01-30T04:00Z","start":960,"duration":30,"runTime":30,"flags":["CC","HD 1080p","HDTV","Stereo"],"programId":"EP000169160107","title":"Seinfeld"},{"subtitle":"The Sniffing Accountant","type":"O","startTime":"2025-01-30T04:30Z","start":1080,"duration":30,"runTime":30,"flags":["CC","HD 1080p","HDTV","Stereo"],"programId":"EP000169160080","title":"Seinfeld"},{"subtitle":"The One That Could Have Been","type":"O","startTime":"2025-01-30T05:00Z","start":1200,"duration":30,"runTime":30,"flags":["CC","HD 1080p","Stereo"],"programId":"EP001151270156","title":"Friends"},{"subtitle":"It's Always Nazi Week","type":"O","startTime":"2025-01-30T05:30Z","start":1320,"duration":30,"runTime":30,"flags":["CC","HD 1080p","HDTV","Stereo"],"programId":"EP005927330125","title":"Two and a Half Men"},{"subtitle":"The Wildebeest Implementation","type":"O","startTime":"2025-01-30T06:00Z","start":1440,"duration":30,"runTime":30,"flags":["CC","HD 1080p","HDTV","Stereo"],"programId":"EP009311820089","title":"The Big Bang Theory"},{"subtitle":"A Box of Treasure and the Meemaw of Science","type":"O","startTime":"2025-01-30T06:30Z","start":1560,"duration":30,"runTime":30,"flags":["CC","DVS","HD 1080p","HDTV","Stereo"],"programId":"EP026422390078","title":"Young Sheldon"},{"type":"O","startTime":"2025-01-30T07:00Z","start":1680,"duration":30,"runTime":30,"flags":["CC","HD 1080p"],"programId":"SH000000010000","title":"Paid Programming"},{"subtitle":"Twanging Your Magic Clanger","type":"O","startTime":"2025-01-30T07:30Z","start":1800,"duration":30,"runTime":30,"flags":["CC","HD 1080p","HDTV","Stereo"],"programId":"EP005927330177","title":"Two and a Half Men"},{"subtitle":"Useless Potheads","type":"O","startTime":"2025-01-30T08:00Z","start":1920,"duration":30,"runTime":30,"flags":["CC","HD 1080p","HDTV","Stereo"],"programId":"EP032302210008","title":"Bob Hearts Abishola"},{"subtitle":"Oates & Oates","type":"O","startTime":"2025-01-30T08:30Z","start":2040,"duration":30,"runTime":30,"flags":["CC","DVS","HD 1080p","HDTV","Stereo"],"programId":"EP017396170163","title":"The Goldbergs"},{"type":"N","startTime":"2025-01-30T09:00Z","start":2160,"duration":30,"runTime":30,"flags":["New","CC","HD 1080p","HDTV","Stereo"],"programId":"SH040688380000","title":"PIX11 Morning News at 4am"},{"type":"N","startTime":"2025-01-30T09:30Z","start":2280,"duration":30,"runTime":30,"flags":["New","CC","HD 1080p","HDTV","Stereo"],"programId":"SH030981260000","title":"PIX11 Morning News at 4:30am"},{"type":"N","startTime":"2025-01-30T10:00Z","start":2400,"duration":60,"runTime":60,"flags":["New","CC","HD 1080p","HDTV","Stereo"],"programId":"SH024105120000","title":"PIX11 Morning News at 5am"},{"type":"N","startTime":"2025-01-30T11:00Z","start":2640,"duration":60,"runTime":60,"flags":["New","CC","HD 1080p","HDTV","Stereo"],"programId":"SH030981290000","title":"PIX11 Morning News at 6am"},{"type":"N","startTime":"2025-01-30T12:00Z","start":2880,"duration":120,"runTime":120,"flags":["New","CC","HD 1080p","HDTV","Stereo"],"programId":"SH030981310000","title":"PIX11 Morning News at 7am"},{"type":"N","startTime":"2025-01-30T14:00Z","start":3360,"duration":60,"runTime":60,"flags":["New","CC","HD 1080p","HDTV","Stereo"],"programId":"SH033926520000","title":"PIX11 Morning News at 9am"},{"type":"O","startTime":"2025-01-30T15:00Z","start":3600,"duration":60,"runTime":60,"flags":["New","CC","HD 1080p","HDTV","Stereo"],"programId":"SH041806690000","title":"New York Living"},{"type":"R","startTime":"2025-01-30T16:00Z","start":3840,"duration":30,"runTime":30,"flags":["New","CC","HD 1080p","HDTV","Stereo"],"programId":"EP048030230139","title":"Mathis Court With Judge Mathis"},{"subtitle":"Drop Dead Dropout & I Fooled You","type":"R","startTime":"2025-01-30T16:30Z","start":3960,"duration":30,"runTime":30,"flags":["CC","HD 1080p","HDTV","Stereo"],"programId":"EP048030230103","title":"Mathis Court With Judge Mathis"},{"type":"O","startTime":"2025-01-30T17:00Z","start":4080,"duration":60,"runTime":60,"flags":["CC","HD 1080p","HDTV","Stereo"],"programId":"SH009511390000","title":"The Steve Wilkos Show"},{"subtitle":"Unlock the Truth: Did My Bestie Drug Me?; DNA: Adopted and Seeking the Truth","type":"O","startTime":"2025-01-30T18:00Z","start":4320,"duration":60,"runTime":60,"flags":["New","CC","HD 1080p","HDTV","Stereo"],"programId":"EP043399210359","title":"Karamo"},{"subtitle":"Buyer Beware","type":"R","startTime":"2025-01-30T19:00Z","start":4560,"duration":30,"runTime":30,"flags":["CC","HD 1080p","HDTV","Stereo"],"programId":"EP040033230087","title":"Judy Justice"},{"subtitle":"Bitter Break-Up; Dissatisfied Tenants","type":"R","startTime":"2025-01-30T19:30Z","start":4680,"duration":30,"runTime":30,"flags":["CC","HD 1080p","HDTV","Stereo"],"programId":"EP040033230091","title":"Judy Justice"},{"subtitle":"Dr. Phil Interrogates: Did He Lie to the Nation?","type":"O","startTime":"2025-01-30T20:00Z","start":4800,"duration":60,"runTime":60,"flags":["CC","HD 1080p","HDTV","Stereo"],"programId":"EP005178511881","title":"Dr. Phil"},{"type":"N","startTime":"2025-01-30T21:00Z","start":5040,"duration":60,"runTime":60,"flags":["New","CC","HD 1080p","HDTV","Stereo"],"programId":"SH039765200000","title":"PIX11 News at 4"},{"type":"N","startTime":"2025-01-30T22:00Z","start":5280,"duration":60,"runTime":60,"flags":["New","CC","HD 1080p","HDTV","Stereo"],"programId":"SH019353950000","title":"PIX11 News at 5"},{"type":"N","startTime":"2025-01-30T23:00Z","start":5520,"duration":30,"runTime":30,"flags":["New","CC","HD 1080p","HDTV","Stereo"],"programId":"SH021560980000","title":"PIX11 News at 6"},{"type":"N","startTime":"2025-01-30T23:30Z","start":5644,"duration":30,"runTime":30,"flags":["New","CC","HD 1080p","HDTV","Stereo"],"programId":"SH042401180000","title":"PIX11 Evening News"}]] \ No newline at end of file From c0d4c631f8ed23d768c5745f113be62234d70631 Mon Sep 17 00:00:00 2001 From: freearhey <7253922+freearhey@users.noreply.github.com> Date: Mon, 27 Jan 2025 04:50:07 +0300 Subject: [PATCH 02/12] Update tvtv.us.test.js --- sites/tvtv.us/tvtv.us.test.js | 48 ++++++++++++++++------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/sites/tvtv.us/tvtv.us.test.js b/sites/tvtv.us/tvtv.us.test.js index 66687893..a6f2714b 100644 --- a/sites/tvtv.us/tvtv.us.test.js +++ b/sites/tvtv.us/tvtv.us.test.js @@ -1,52 +1,48 @@ const { parser, url } = require('./tvtv.us.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-09-20', 'YYYY-MM-DD').startOf('d') -const channel = { - site_id: '62670', - xmltv_id: 'AMITV.ca', - logo: 'https://tvtv.us/gn/i/assets/s62670_ll_h15_ab.png?w=360&h=270' -} +const date = dayjs.utc('2025-01-30', 'YYYY-MM-DD').startOf('d') +const channel = { site_id: '20373' } it('can generate valid url', () => { expect(url({ channel, date })).toBe( - 'https://www.tvtv.us/api/v1/lineup/USA-NY71652-X/grid/2022-09-20T00:00:00.000Z/2022-09-21T00:00:00.000Z/62670' + 'https://www.tvtv.us/api/v1/lineup/USA-NY71652-X/grid/2025-01-30T00:00:00.000Z/2025-01-31T00:00:00.000Z/20373' ) }) it('can parse response', () => { - const content = - '[[{"programId":"EP039131940001","title":"Beyond the Field","subtitle":"Diversity in Sport","flags":["CC","DVS"],"type":"O","startTime":"2022-09-20T00:00Z","start":0,"duration":30,"runTime":30},{"programId":"EP032368970002","title":"IGotThis","subtitle":"Listen to Dis","flags":["CC","DVS"],"type":"O","startTime":"2022-09-20T00:30Z","start":120,"duration":30,"runTime":30}]]' + const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json')) - const result = parser({ content }).map(p => { + const results = parser({ content }).map(p => { p.start = p.start.toJSON() p.stop = p.stop.toJSON() return p }) - expect(result).toMatchObject([ - { - start: '2022-09-20T00:00:00.000Z', - stop: '2022-09-20T00:30:00.000Z', - title: 'Beyond the Field', - description: 'Diversity in Sport' - }, - { - start: '2022-09-20T00:30:00.000Z', - stop: '2022-09-20T01:00:00.000Z', - title: 'IGotThis', - description: 'Listen to Dis' - } - ]) + expect(results.length).toBe(33) + expect(results[0]).toMatchObject({ + start: '2025-01-30T00:00:00.000Z', + stop: '2025-01-30T00:30:00.000Z', + title: 'NY Sports Nation Nightly', + subtitle: null + }) + expect(results[1]).toMatchObject({ + start: '2025-01-30T00:30:00.000Z', + stop: '2025-01-30T01:00:00.000Z', + title: 'The Big Bang Theory', + subtitle: 'The Bow Tie Asymmetry' + }) }) it('can handle empty guide', () => { - const result = parser({ + const results = parser({ content: '[]' }) - expect(result).toMatchObject([]) + expect(results).toMatchObject([]) }) From 42ce11a6bab799dc5cefcbe21f8b8989856f8244 Mon Sep 17 00:00:00 2001 From: freearhey <7253922+freearhey@users.noreply.github.com> Date: Mon, 27 Jan 2025 04:50:14 +0300 Subject: [PATCH 03/12] Update tvtv.us.config.js --- sites/tvtv.us/tvtv.us.config.js | 41 +++++++++++---------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/sites/tvtv.us/tvtv.us.config.js b/sites/tvtv.us/tvtv.us.config.js index 098be11f..87823fcd 100644 --- a/sites/tvtv.us/tvtv.us.config.js +++ b/sites/tvtv.us/tvtv.us.config.js @@ -1,42 +1,24 @@ const dayjs = require('dayjs') -const utc = require('dayjs/plugin/utc') - -dayjs.extend(utc) module.exports = { site: 'tvtv.us', days: 2, - url: function ({ date, channel }) { - if (!dayjs.isDayjs(date)) { - throw new Error('Invalid date object passed to url function') - } - + url({ date, channel }) { return `https://www.tvtv.us/api/v1/lineup/USA-NY71652-X/grid/${date.toJSON()}/${date .add(1, 'day') .toJSON()}/${channel.site_id}` }, - request: { - method: 'GET', - headers: { - Accept: '*/*', - Connection: 'keep-alive', - 'User-Agent': - 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36', - 'sec-ch-ua': '"Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"', - 'sec-ch-ua-mobile': '?0', - 'sec-ch-ua-platform': '"Windows"' - } - }, - parser: function ({ content }) { + parser({ content }) { let programs = [] const items = parseItems(content) items.forEach(item => { - const start = dayjs.utc(item.startTime) - const stop = start.add(item.runTime, 'minute') + const start = dayjs(item.startTime) + const stop = start.add(item.duration, 'minute') + programs.push({ title: item.title, - description: item.subtitle, + subtitle: item.subtitle || null, start, stop }) @@ -47,7 +29,12 @@ module.exports = { } function parseItems(content) { - const json = JSON.parse(content) - if (!json.length) return [] - return json[0] + try { + const json = JSON.parse(content) + if (!json.length) return [] + + return json[0] + } catch { + return [] + } } From 378d13869421b7f5bc30b28debfb7c21e0d35aec Mon Sep 17 00:00:00 2001 From: freearhey <7253922+freearhey@users.noreply.github.com> Date: Mon, 27 Jan 2025 05:36:45 +0300 Subject: [PATCH 04/12] Create program_1.json --- sites/tvtv.us/__data__/program_1.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 sites/tvtv.us/__data__/program_1.json diff --git a/sites/tvtv.us/__data__/program_1.json b/sites/tvtv.us/__data__/program_1.json new file mode 100644 index 00000000..323a5b43 --- /dev/null +++ b/sites/tvtv.us/__data__/program_1.json @@ -0,0 +1 @@ +{"type":"E","title":"The Big Bang Theory","image":"/gn/pi/assets/p185554_b_v11_az.jpg?w=240&h=360","description":"When Amy's parents and Sheldon's family arrive, everybody is focused on making sure the wedding arrangements go according to plan -- everyone except the bride and groom.","releaseYear":2018,"mainCast":["Johnny Galecki (Leonard Hofstadter)","Jim Parsons (Sheldon Cooper)","Kaley Cuoco (Penny)"],"directors":["Mark Cendrowski"],"genres":["Sitcom"],"ratings":[{"code":"TVPG","body":"USA Parental Rating"}],"seriesEpisode":{"seriesId":"185554","episodeTitle":"The Bow Tie Asymmetry","image":"/gn/pi/assets/p15015849_e_v8_aa.jpg?w=240&h=360","seasonEpisode":"Season 11; Episode 24"},"cast":[{"personId":"33631","name":"Johnny Galecki","role":"Leonard Hofstadter"},{"personId":"314170","name":"Jim Parsons","role":"Sheldon Cooper"},{"personId":"169721","name":"Kaley Cuoco","role":"Penny"},{"personId":"220961","name":"Simon Helberg","role":"Howard Wolowitz"},{"personId":"508075","name":"Kunal Nayyar","role":"Raj Koothrappali"},{"personId":"155","name":"Mayim Bialik","role":"Amy Farrah Fowler"},{"personId":"530748","name":"Melissa Rauch","role":"Bernadette Rostenkowski"},{"personId":"308458","name":"Kevin Sussman","role":"Stuart - Guest Star"},{"personId":"38285","name":"Laurie Metcalf","role":"Mary - Guest Star"},{"personId":"260209","name":"John Ross Bowie","role":"Kripke - Guest Star"},{"personId":"65798","name":"Wil Wheaton","role":"Himself - Guest Star"},{"personId":"181887","name":"Brian Posehn","role":"Bert - Guest Star"},{"personId":"31226","name":"Jerry O'Connell","role":"George - Guest Star"},{"personId":"271536","name":"Courtney Henggeler","role":"Missy - Guest Star"},{"personId":"620417","name":"Lauren Lapkus","role":"Denise - Guest Star"},{"personId":"232486","name":"Teller","role":"Mr. Fowler - Guest Star"},{"personId":"106","name":"Kathy Bates","role":"Mrs. Fowler - Guest Star"},{"personId":"73414","name":"Mark Hamill","role":"Himself - Guest Star"}],"crew":[{"personId":"75481","name":"Chuck Lorre","role":"Executive Producer"},{"personId":"232097","name":"Bill Prady","role":"Executive Producer"},{"personId":"262338","name":"Steven Molaro","role":"Executive Producer"},{"personId":"75481","name":"Chuck Lorre","role":"Writer"},{"personId":"262338","name":"Steven Molaro","role":"Writer"},{"personId":"490163","name":"Maria Ferrari","role":"Writer"},{"personId":"278500","name":"Steve Holland","role":"Writer"},{"personId":"383184","name":"Eric Kaplan","role":"Writer"},{"personId":"643632","name":"Tara Hernandez","role":"Writer"},{"personId":"188536","name":"Mark Cendrowski","role":"Director"}]} \ No newline at end of file From cffd2a635f686c111f376c0eada12c59ab1d7d58 Mon Sep 17 00:00:00 2001 From: freearhey <7253922+freearhey@users.noreply.github.com> Date: Mon, 27 Jan 2025 05:36:51 +0300 Subject: [PATCH 05/12] Update tvtv.us.test.js --- sites/tvtv.us/tvtv.us.test.js | 133 ++++++++++++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 5 deletions(-) diff --git a/sites/tvtv.us/tvtv.us.test.js b/sites/tvtv.us/tvtv.us.test.js index a6f2714b..b01e43ba 100644 --- a/sites/tvtv.us/tvtv.us.test.js +++ b/sites/tvtv.us/tvtv.us.test.js @@ -1,12 +1,25 @@ const { parser, url } = require('./tvtv.us.config.js') const fs = require('fs') const path = require('path') +const axios = require('axios') const dayjs = require('dayjs') const utc = require('dayjs/plugin/utc') const customParseFormat = require('dayjs/plugin/customParseFormat') dayjs.extend(customParseFormat) dayjs.extend(utc) +jest.mock('axios') + +axios.get.mockImplementation(url => { + if (url === 'https://tvtv.us/api/v1/programs/EP009311820269') { + return Promise.resolve({ + data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/program_1.json'))) + }) + } else { + return Promise.resolve({ data: '' }) + } +}) + const date = dayjs.utc('2025-01-30', 'YYYY-MM-DD').startOf('d') const channel = { site_id: '20373' } @@ -16,10 +29,11 @@ it('can generate valid url', () => { ) }) -it('can parse response', () => { +it('can parse response', async () => { const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json')) - const results = parser({ content }).map(p => { + let results = await parser({ content }) + results = results.map(p => { p.start = p.start.toJSON() p.stop = p.stop.toJSON() return p @@ -36,13 +50,122 @@ it('can parse response', () => { start: '2025-01-30T00:30:00.000Z', stop: '2025-01-30T01:00:00.000Z', title: 'The Big Bang Theory', - subtitle: 'The Bow Tie Asymmetry' + subtitle: 'The Bow Tie Asymmetry', + description: + "When Amy's parents and Sheldon's family arrive, everybody is focused on making sure the wedding arrangements go according to plan -- everyone except the bride and groom.", + image: 'https://tvtv.us/gn/pi/assets/p185554_b_v11_az.jpg?w=240&h=360', + date: '2018', + season: 11, + episode: 24, + actors: [ + { + value: 'Johnny Galecki', + role: 'Leonard Hofstadter' + }, + { + value: 'Jim Parsons', + role: 'Sheldon Cooper' + }, + { + value: 'Kaley Cuoco', + role: 'Penny' + }, + { + value: 'Simon Helberg', + role: 'Howard Wolowitz' + }, + { + value: 'Kunal Nayyar', + role: 'Raj Koothrappali' + }, + { + value: 'Mayim Bialik', + role: 'Amy Farrah Fowler' + }, + { + value: 'Melissa Rauch', + role: 'Bernadette Rostenkowski' + }, + { + value: 'Kevin Sussman', + role: 'Stuart', + guest: 'yes' + }, + { + value: 'Laurie Metcalf', + role: 'Mary', + guest: 'yes' + }, + { + value: 'John Ross Bowie', + role: 'Kripke', + guest: 'yes' + }, + { + value: 'Wil Wheaton', + role: 'Himself', + guest: 'yes' + }, + { + value: 'Brian Posehn', + role: 'Bert', + guest: 'yes' + }, + { + value: "Jerry O'Connell", + role: 'George', + guest: 'yes' + }, + { + value: 'Courtney Henggeler', + role: 'Missy', + guest: 'yes' + }, + { + value: 'Lauren Lapkus', + role: 'Denise', + guest: 'yes' + }, + { + value: 'Teller', + role: 'Mr. Fowler', + guest: 'yes' + }, + { + value: 'Kathy Bates', + role: 'Mrs. Fowler', + guest: 'yes' + }, + { + value: 'Mark Hamill', + role: 'Himself', + guest: 'yes' + } + ], + directors: ['Mark Cendrowski'], + producers: ['Chuck Lorre', 'Bill Prady', 'Steven Molaro'], + writers: [ + 'Chuck Lorre', + 'Steven Molaro', + 'Maria Ferrari', + 'Steve Holland', + 'Eric Kaplan', + 'Tara Hernandez' + ], + categories: ['Sitcom'], + ratings: [ + { + value: 'TVPG', + system: 'USA Parental Rating' + } + ] }) }) -it('can handle empty guide', () => { - const results = parser({ +it('can handle empty guide', async () => { + const results = await parser({ content: '[]' }) + expect(results).toMatchObject([]) }) From 33428dd37c64293253b2065b18104e0e6d39536a Mon Sep 17 00:00:00 2001 From: freearhey <7253922+freearhey@users.noreply.github.com> Date: Mon, 27 Jan 2025 05:41:09 +0300 Subject: [PATCH 06/12] Update tvtv.us.config.js --- sites/tvtv.us/tvtv.us.config.js | 82 ++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/sites/tvtv.us/tvtv.us.config.js b/sites/tvtv.us/tvtv.us.config.js index 87823fcd..090c1171 100644 --- a/sites/tvtv.us/tvtv.us.config.js +++ b/sites/tvtv.us/tvtv.us.config.js @@ -1,4 +1,7 @@ const dayjs = require('dayjs') +const doFetch = require('@ntlab/sfetch') + +let cachedPrograms = {} module.exports = { site: 'tvtv.us', @@ -8,8 +11,9 @@ module.exports = { .add(1, 'day') .toJSON()}/${channel.site_id}` }, - parser({ content }) { + async parser({ content }) { let programs = [] + let queue = [] const items = parseItems(content) items.forEach(item => { @@ -17,17 +21,93 @@ module.exports = { const stop = start.add(item.duration, 'minute') programs.push({ + id: item.programId, title: item.title, subtitle: item.subtitle || null, start, stop }) + + if (item.programId && !cachedPrograms[item.programId]) { + queue.push({ + programId: item.programId, + url: `https://tvtv.us/api/v1/programs/${item.programId}` + }) + } + }) + + await doFetch(queue, (req, data) => { + if (!data || !data.title) return + + cachedPrograms[req.programId] = data + }) + + programs.forEach(program => { + const data = cachedPrograms[program.id] + + if (!data) return + + program.description = data.description || null + program.image = data.image ? `https://tvtv.us${data.image}` : null + program.date = data.releaseYear ? data.releaseYear.toString() : null + program.directors = data.directors + program.categories = data.genres + program.actors = parseActors(data) + program.writers = parseWriters(data) + program.producers = parseProducers(data) + program.ratings = parseRatings(data) + program.season = parseSeason(data) + program.episode = parseEpisode(data) }) return programs } } +function parseEpisode(data) { + if (!data?.seriesEpisode?.seasonEpisode) return null + + const [, episode] = data.seriesEpisode.seasonEpisode.match(/Episode (\d+)/) || [null, null] + + return episode ? parseInt(episode) : null +} + +function parseSeason(data) { + if (!data?.seriesEpisode?.seasonEpisode) return null + + const [, season] = data.seriesEpisode.seasonEpisode.match(/Season (\d+);/) || [null, null] + + return season ? parseInt(season) : null +} + +function parseRatings(data) { + return data.ratings.map(rating => ({ + value: rating.code, + system: rating.body + })) +} + +function parseWriters(data) { + return data.crew.filter(member => member.role.includes('Writer')).map(member => member.name) +} + +function parseProducers(data) { + return data.crew.filter(member => member.role.includes('Producer')).map(member => member.name) +} + +function parseActors(data) { + return data.cast.map(actor => { + const guest = actor.role.includes('Guest Star') ? 'yes' : undefined + const role = actor.role.replace(' - Guest Star', '') + + return { + value: actor.name, + role, + guest + } + }) +} + function parseItems(content) { try { const json = JSON.parse(content) From b8285b1970fbf492c43862bab272105dbcee4a15 Mon Sep 17 00:00:00 2001 From: freearhey <7253922+freearhey@users.noreply.github.com> Date: Fri, 31 Jan 2025 20:46:49 +0300 Subject: [PATCH 07/12] Update tvtv.us.test.js --- sites/tvtv.us/tvtv.us.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sites/tvtv.us/tvtv.us.test.js b/sites/tvtv.us/tvtv.us.test.js index b01e43ba..a55755a9 100644 --- a/sites/tvtv.us/tvtv.us.test.js +++ b/sites/tvtv.us/tvtv.us.test.js @@ -10,8 +10,8 @@ dayjs.extend(utc) jest.mock('axios') -axios.get.mockImplementation(url => { - if (url === 'https://tvtv.us/api/v1/programs/EP009311820269') { +axios.mockImplementation(req => { + if (req.url === 'https://tvtv.us/api/v1/programs/EP009311820269') { return Promise.resolve({ data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/program_1.json'))) }) From 51827d1bffc31b507d9cd9b948f1982ecd327c59 Mon Sep 17 00:00:00 2001 From: freearhey <7253922+freearhey@users.noreply.github.com> Date: Sat, 1 Feb 2025 00:56:43 +0300 Subject: [PATCH 08/12] Update tvtv.us.config.js --- sites/tvtv.us/tvtv.us.config.js | 52 +++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/sites/tvtv.us/tvtv.us.config.js b/sites/tvtv.us/tvtv.us.config.js index 090c1171..8cda8034 100644 --- a/sites/tvtv.us/tvtv.us.config.js +++ b/sites/tvtv.us/tvtv.us.config.js @@ -1,5 +1,4 @@ const dayjs = require('dayjs') -const doFetch = require('@ntlab/sfetch') let cachedPrograms = {} @@ -11,12 +10,23 @@ module.exports = { .add(1, 'day') .toJSON()}/${channel.site_id}` }, - async parser({ content }) { + request: { + headers: { + Accept: '*/*', + Connection: 'keep-alive', + 'User-Agent': + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36', + 'sec-ch-ua': '"Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-platform': '"Windows"' + } + }, + async parser({ content, request }) { let programs = [] let queue = [] const items = parseItems(content) - items.forEach(item => { + for (const item of items) { const start = dayjs(item.startTime) const stop = start.add(item.duration, 'minute') @@ -31,16 +41,26 @@ module.exports = { if (item.programId && !cachedPrograms[item.programId]) { queue.push({ programId: item.programId, - url: `https://tvtv.us/api/v1/programs/${item.programId}` + url: `https://tvtv.us/api/v1/programs/${item.programId}`, + httpAgent: request.agent, + httpsAgent: request.agent, + headers: module.exports.request.headers }) } - }) + } - await doFetch(queue, (req, data) => { - if (!data || !data.title) return + const axios = require('axios') + for (const req of queue) { + await wait(5000) + + const data = await axios(req) + .then(r => r.data) + .catch(console.error) + + if (!data || !data.title) continue cachedPrograms[req.programId] = data - }) + } programs.forEach(program => { const data = cachedPrograms[program.id] @@ -81,10 +101,12 @@ function parseSeason(data) { } function parseRatings(data) { - return data.ratings.map(rating => ({ - value: rating.code, - system: rating.body - })) + return Array.isArray(data.ratings) + ? data.ratings.map(rating => ({ + value: rating.code, + system: rating.body + })) + : [] } function parseWriters(data) { @@ -118,3 +140,9 @@ function parseItems(content) { return [] } } + +function wait(ms) { + return new Promise(resolve => { + setTimeout(resolve, ms) + }) +} From e275e04c672d89fb55e7e583893ebefc02447331 Mon Sep 17 00:00:00 2001 From: freearhey <7253922+freearhey@users.noreply.github.com> Date: Sat, 1 Feb 2025 01:08:16 +0300 Subject: [PATCH 09/12] Update tvtv.us.test.js --- sites/tvtv.us/tvtv.us.test.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sites/tvtv.us/tvtv.us.test.js b/sites/tvtv.us/tvtv.us.test.js index a55755a9..3e640c82 100644 --- a/sites/tvtv.us/tvtv.us.test.js +++ b/sites/tvtv.us/tvtv.us.test.js @@ -32,7 +32,7 @@ it('can generate valid url', () => { it('can parse response', async () => { const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json')) - let results = await parser({ content }) + let results = await parser({ content, request: { agent: null } }) results = results.map(p => { p.start = p.start.toJSON() p.stop = p.stop.toJSON() @@ -164,7 +164,8 @@ it('can parse response', async () => { it('can handle empty guide', async () => { const results = await parser({ - content: '[]' + content: '[]', + request: { agent: null } }) expect(results).toMatchObject([]) From abd6d0531d53ab7622998b2d77afa454c2f1ec04 Mon Sep 17 00:00:00 2001 From: freearhey <7253922+freearhey@users.noreply.github.com> Date: Sat, 1 Feb 2025 01:08:23 +0300 Subject: [PATCH 10/12] Update tvtv.us.config.js --- sites/tvtv.us/tvtv.us.config.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sites/tvtv.us/tvtv.us.config.js b/sites/tvtv.us/tvtv.us.config.js index 8cda8034..ac1f602c 100644 --- a/sites/tvtv.us/tvtv.us.config.js +++ b/sites/tvtv.us/tvtv.us.config.js @@ -142,6 +142,8 @@ function parseItems(content) { } function wait(ms) { + if (process.env.NODE_ENV === 'test') return + return new Promise(resolve => { setTimeout(resolve, ms) }) From 4bdcdf0962f0f2183cef7d8779deb4538123dd31 Mon Sep 17 00:00:00 2001 From: freearhey <7253922+freearhey@users.noreply.github.com> Date: Mon, 31 Mar 2025 09:10:44 +0300 Subject: [PATCH 11/12] Update tvtv.us.test.js --- sites/tvtv.us/tvtv.us.test.js | 218 +++++++++++++++++----------------- 1 file changed, 109 insertions(+), 109 deletions(-) diff --git a/sites/tvtv.us/tvtv.us.test.js b/sites/tvtv.us/tvtv.us.test.js index 3e640c82..2a5e6c9a 100644 --- a/sites/tvtv.us/tvtv.us.test.js +++ b/sites/tvtv.us/tvtv.us.test.js @@ -50,115 +50,115 @@ it('can parse response', async () => { start: '2025-01-30T00:30:00.000Z', stop: '2025-01-30T01:00:00.000Z', title: 'The Big Bang Theory', - subtitle: 'The Bow Tie Asymmetry', - description: - "When Amy's parents and Sheldon's family arrive, everybody is focused on making sure the wedding arrangements go according to plan -- everyone except the bride and groom.", - image: 'https://tvtv.us/gn/pi/assets/p185554_b_v11_az.jpg?w=240&h=360', - date: '2018', - season: 11, - episode: 24, - actors: [ - { - value: 'Johnny Galecki', - role: 'Leonard Hofstadter' - }, - { - value: 'Jim Parsons', - role: 'Sheldon Cooper' - }, - { - value: 'Kaley Cuoco', - role: 'Penny' - }, - { - value: 'Simon Helberg', - role: 'Howard Wolowitz' - }, - { - value: 'Kunal Nayyar', - role: 'Raj Koothrappali' - }, - { - value: 'Mayim Bialik', - role: 'Amy Farrah Fowler' - }, - { - value: 'Melissa Rauch', - role: 'Bernadette Rostenkowski' - }, - { - value: 'Kevin Sussman', - role: 'Stuart', - guest: 'yes' - }, - { - value: 'Laurie Metcalf', - role: 'Mary', - guest: 'yes' - }, - { - value: 'John Ross Bowie', - role: 'Kripke', - guest: 'yes' - }, - { - value: 'Wil Wheaton', - role: 'Himself', - guest: 'yes' - }, - { - value: 'Brian Posehn', - role: 'Bert', - guest: 'yes' - }, - { - value: "Jerry O'Connell", - role: 'George', - guest: 'yes' - }, - { - value: 'Courtney Henggeler', - role: 'Missy', - guest: 'yes' - }, - { - value: 'Lauren Lapkus', - role: 'Denise', - guest: 'yes' - }, - { - value: 'Teller', - role: 'Mr. Fowler', - guest: 'yes' - }, - { - value: 'Kathy Bates', - role: 'Mrs. Fowler', - guest: 'yes' - }, - { - value: 'Mark Hamill', - role: 'Himself', - guest: 'yes' - } - ], - directors: ['Mark Cendrowski'], - producers: ['Chuck Lorre', 'Bill Prady', 'Steven Molaro'], - writers: [ - 'Chuck Lorre', - 'Steven Molaro', - 'Maria Ferrari', - 'Steve Holland', - 'Eric Kaplan', - 'Tara Hernandez' - ], - categories: ['Sitcom'], - ratings: [ - { - value: 'TVPG', - system: 'USA Parental Rating' - } - ] + subtitle: 'The Bow Tie Asymmetry' + // description: + // "When Amy's parents and Sheldon's family arrive, everybody is focused on making sure the wedding arrangements go according to plan -- everyone except the bride and groom.", + // image: 'https://tvtv.us/gn/pi/assets/p185554_b_v11_az.jpg?w=240&h=360', + // date: '2018', + // season: 11, + // episode: 24, + // actors: [ + // { + // value: 'Johnny Galecki', + // role: 'Leonard Hofstadter' + // }, + // { + // value: 'Jim Parsons', + // role: 'Sheldon Cooper' + // }, + // { + // value: 'Kaley Cuoco', + // role: 'Penny' + // }, + // { + // value: 'Simon Helberg', + // role: 'Howard Wolowitz' + // }, + // { + // value: 'Kunal Nayyar', + // role: 'Raj Koothrappali' + // }, + // { + // value: 'Mayim Bialik', + // role: 'Amy Farrah Fowler' + // }, + // { + // value: 'Melissa Rauch', + // role: 'Bernadette Rostenkowski' + // }, + // { + // value: 'Kevin Sussman', + // role: 'Stuart', + // guest: 'yes' + // }, + // { + // value: 'Laurie Metcalf', + // role: 'Mary', + // guest: 'yes' + // }, + // { + // value: 'John Ross Bowie', + // role: 'Kripke', + // guest: 'yes' + // }, + // { + // value: 'Wil Wheaton', + // role: 'Himself', + // guest: 'yes' + // }, + // { + // value: 'Brian Posehn', + // role: 'Bert', + // guest: 'yes' + // }, + // { + // value: "Jerry O'Connell", + // role: 'George', + // guest: 'yes' + // }, + // { + // value: 'Courtney Henggeler', + // role: 'Missy', + // guest: 'yes' + // }, + // { + // value: 'Lauren Lapkus', + // role: 'Denise', + // guest: 'yes' + // }, + // { + // value: 'Teller', + // role: 'Mr. Fowler', + // guest: 'yes' + // }, + // { + // value: 'Kathy Bates', + // role: 'Mrs. Fowler', + // guest: 'yes' + // }, + // { + // value: 'Mark Hamill', + // role: 'Himself', + // guest: 'yes' + // } + // ], + // directors: ['Mark Cendrowski'], + // producers: ['Chuck Lorre', 'Bill Prady', 'Steven Molaro'], + // writers: [ + // 'Chuck Lorre', + // 'Steven Molaro', + // 'Maria Ferrari', + // 'Steve Holland', + // 'Eric Kaplan', + // 'Tara Hernandez' + // ], + // categories: ['Sitcom'], + // ratings: [ + // { + // value: 'TVPG', + // system: 'USA Parental Rating' + // } + // ] }) }) From ad2dd69287a78e9cde2529d6ae858e3129ec5a6a Mon Sep 17 00:00:00 2001 From: freearhey <7253922+freearhey@users.noreply.github.com> Date: Mon, 31 Mar 2025 09:12:29 +0300 Subject: [PATCH 12/12] Update tvtv.us.config.js --- sites/tvtv.us/tvtv.us.config.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/sites/tvtv.us/tvtv.us.config.js b/sites/tvtv.us/tvtv.us.config.js index ac1f602c..eef953fc 100644 --- a/sites/tvtv.us/tvtv.us.config.js +++ b/sites/tvtv.us/tvtv.us.config.js @@ -21,11 +21,11 @@ module.exports = { 'sec-ch-ua-platform': '"Windows"' } }, - async parser({ content, request }) { + async parser(ctx) { let programs = [] let queue = [] - const items = parseItems(content) + const items = parseItems(ctx.content) for (const item of items) { const start = dayjs(item.startTime) const stop = start.add(item.duration, 'minute') @@ -38,15 +38,16 @@ module.exports = { stop }) - if (item.programId && !cachedPrograms[item.programId]) { - queue.push({ - programId: item.programId, - url: `https://tvtv.us/api/v1/programs/${item.programId}`, - httpAgent: request.agent, - httpsAgent: request.agent, - headers: module.exports.request.headers - }) - } + // NOTE: This part of the code is commented out because loading additional data leads either to error 429 Too Many Requests or to even greater delays between requests. + // if (item.programId && !cachedPrograms[item.programId]) { + // queue.push({ + // programId: item.programId, + // url: `https://tvtv.us/api/v1/programs/${item.programId}`, + // httpAgent: ctx.request.agent, + // httpsAgent: ctx.request.agent, + // headers: module.exports.request.headers + // }) + // } } const axios = require('axios')