diff --git a/sites/tvguide.com/__data__/content.html b/sites/tvguide.com/__data__/content.html new file mode 100644 index 00000000..c939514b --- /dev/null +++ b/sites/tvguide.com/__data__/content.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/sites/tvguide.com/__data__/content.json b/sites/tvguide.com/__data__/content.json deleted file mode 100644 index 03f5ba63..00000000 --- a/sites/tvguide.com/__data__/content.json +++ /dev/null @@ -1,159 +0,0 @@ -{ - "data": { - "duration": "1440", - "providerId": "9100001138", - "startTime": "1667088000", - "items": [ - { - "channel": { - "fullName": "CBS", - "name": "CBS", - "number": null, - "sourceId": 9200018514, - "legacySourceId": 5943, - "networkName": "CBS", - "networkId": 1, - "logo": "/provider/1/4/1-685389140.png" - }, - "programSchedules": [ - { - "airingAttrib": 524817, - "catId": 2, - "startTime": 1667088000, - "endTime": 1667097000, - "programId": 6060455538, - "title": "NWSL Soccer Playoff", - "rating": null, - "programDetails": "https://fandom-prod.apigee.net/v1/xapi/tvschedules/tvguide/programdetails/6060455538/web" - }, - { - "airingAttrib": 558098, - "catId": 5, - "startTime": 1667097000, - "endTime": 1667098800, - "programId": 6060248599, - "title": "Young Sheldon", - "rating": "TV-PG", - "programDetails": "https://fandom-prod.apigee.net/v1/xapi/tvschedules/tvguide/programdetails/6060248599/web" - }, - { - "airingAttrib": 524288, - "catId": 5, - "startTime": 1667098800, - "endTime": 1667102400, - "programId": 1030182907, - "title": "Local Programming", - "rating": "TV-G", - "programDetails": "https://fandom-prod.apigee.net/v1/xapi/tvschedules/tvguide/programdetails/1030182907/web" - }, - { - "airingAttrib": 524288, - "catId": 5, - "startTime": 1667102400, - "endTime": 1667120400, - "programId": 1030182907, - "title": "Local Programming", - "rating": "TV-G", - "programDetails": "https://fandom-prod.apigee.net/v1/xapi/tvschedules/tvguide/programdetails/1030182907/web" - }, - { - "airingAttrib": 524288, - "catId": 5, - "startTime": 1667120400, - "endTime": 1667134800, - "programId": 1030182907, - "title": "Local Programming", - "rating": "TV-G", - "programDetails": "https://fandom-prod.apigee.net/v1/xapi/tvschedules/tvguide/programdetails/1030182907/web" - }, - { - "airingAttrib": 557588, - "catId": 4, - "startTime": 1667134800, - "endTime": 1667140200, - "programId": 6060613824, - "title": "CBS Sunday Morning", - "rating": "TV-PG", - "programDetails": "https://fandom-prod.apigee.net/v1/xapi/tvschedules/tvguide/programdetails/6060613824/web" - }, - { - "airingAttrib": 557588, - "catId": 4, - "startTime": 1667140200, - "endTime": 1667143800, - "programId": 6060613861, - "title": "Face the Nation", - "rating": "TV-PG", - "programDetails": "https://fandom-prod.apigee.net/v1/xapi/tvschedules/tvguide/programdetails/6060613861/web" - }, - { - "airingAttrib": 524288, - "catId": 5, - "startTime": 1667143800, - "endTime": 1667145600, - "programId": 1030182907, - "title": "Local Programming", - "rating": "TV-G", - "programDetails": "https://fandom-prod.apigee.net/v1/xapi/tvschedules/tvguide/programdetails/1030182907/web" - }, - { - "airingAttrib": 558097, - "catId": 2, - "startTime": 1667145600, - "endTime": 1667149200, - "programId": 6003572942, - "title": "The NFL Today", - "rating": null, - "programDetails": "https://fandom-prod.apigee.net/v1/xapi/tvschedules/tvguide/programdetails/6003572942/web" - }, - { - "airingAttrib": 524817, - "catId": 2, - "startTime": 1667149200, - "endTime": 1667160000, - "programId": 6000129053, - "title": "NFL Football", - "rating": null, - "programDetails": "https://fandom-prod.apigee.net/v1/xapi/tvschedules/tvguide/programdetails/6000129053/web" - }, - { - "airingAttrib": 524817, - "catId": 2, - "startTime": 1667160000, - "endTime": 1667170800, - "programId": 6000129053, - "title": "NFL Football", - "rating": null, - "programDetails": "https://fandom-prod.apigee.net/v1/xapi/tvschedules/tvguide/programdetails/6000129053/web" - }, - { - "airingAttrib": 558100, - "catId": 4, - "startTime": 1667170800, - "endTime": 1667174400, - "programId": 6003572892, - "title": "60 Minutes", - "rating": "TV-PG", - "programDetails": "https://fandom-prod.apigee.net/v1/xapi/tvschedules/tvguide/programdetails/6003572892/web" - } - ] - } - ] - }, - "links": { - "self": { - "href": "https://fandom-prod.apigee.net/v1/xapi/tvschedules/tvguide/9100001138/web?start=1667088000&duration=1440&channelSourceIds=9200018514" - }, - "prev": { - "href": null - }, - "next": { - "href": "https://fandom-prod.apigee.net/v1/xapi/tvschedules/tvguide/9100001138/web?start=1667088000&duration=1440&channelSourceIds=9200018514&offset=1667089440&limit=1667088000" - } - }, - "meta": { - "componentName": null, - "componentDisplayName": null, - "componentType": null - } -} \ No newline at end of file diff --git a/sites/tvguide.com/__data__/content1.json b/sites/tvguide.com/__data__/content1.json new file mode 100644 index 00000000..41c0938d --- /dev/null +++ b/sites/tvguide.com/__data__/content1.json @@ -0,0 +1 @@ +{"data":{"duration":"240","providerId":"9100001138","startTime":"1736640000","items":[{"channel":{"fullName":"CBS National Schedule","name":"CBS","number":null,"sourceId":9200018514,"legacySourceId":null,"networkName":"CBS","networkId":1,"logo":"/provider/8/4/8-9200018514.png"},"programSchedules":[{"airingAttrib":524304,"catId":5,"startTime":1736643600,"endTime":1736647200,"programId":9000351140,"title":"FBI: International","rating":null,"programDetails":"https://backend.tvguide.com/tvschedules/tvguide/programdetails/9000351140/web"},{"airingAttrib":524304,"catId":5,"startTime":1736647200,"endTime":1736650800,"programId":9000317198,"title":"FBI: Most Wanted","rating":null,"programDetails":"https://backend.tvguide.com/tvschedules/tvguide/programdetails/9000317198/web"},{"airingAttrib":524308,"catId":5,"startTime":1736650800,"endTime":1736654400,"programId":9000415495,"title":"48 Hours","rating":null,"programDetails":"https://backend.tvguide.com/tvschedules/tvguide/programdetails/9000415495/web"}]}]},"links":{"self":{"href":"https://backend.tvguide.com/tvschedules/tvguide/9100001138/web?start=1736640000&duration=240&apiKey=DI9elXhZ3bU6ujsA2gXEKOANyncXGUGc"},"prev":{"href":"https://backend.tvguide.com/tvschedules/tvguide/9100001138/web?start=1736625600&duration=240&apiKey=DI9elXhZ3bU6ujsA2gXEKOANyncXGUGc"},"next":{"href":"https://backend.tvguide.com/tvschedules/tvguide/9100001138/web?start=1736654400&duration=240&apiKey=DI9elXhZ3bU6ujsA2gXEKOANyncXGUGc"}},"meta":{"componentName":null,"componentDisplayName":null,"componentType":null}} \ No newline at end of file diff --git a/sites/tvguide.com/__data__/content2.json b/sites/tvguide.com/__data__/content2.json new file mode 100644 index 00000000..19618c9b --- /dev/null +++ b/sites/tvguide.com/__data__/content2.json @@ -0,0 +1 @@ +{"data":{"duration":"240","providerId":"9100001138","startTime":"1736654400","items":[{"channel":{"fullName":"CBS National Schedule","name":"CBS","number":null,"sourceId":9200018514,"legacySourceId":null,"networkName":"CBS","networkId":1,"logo":"/provider/8/4/8-9200018514.png"},"programSchedules":[{"airingAttrib":524288,"catId":5,"startTime":1736654400,"endTime":1736661600,"programId":9000000408,"title":"Local Programs","rating":null,"programDetails":"https://backend.tvguide.com/tvschedules/tvguide/programdetails/9000000408/web"},{"airingAttrib":524288,"catId":5,"startTime":1736661600,"endTime":1736668800,"programId":9000000408,"title":"Local Programs","rating":null,"programDetails":"https://backend.tvguide.com/tvschedules/tvguide/programdetails/9000000408/web"}]}]},"links":{"self":{"href":"https://backend.tvguide.com/tvschedules/tvguide/9100001138/web?start=1736654400&duration=240&apiKey=DI9elXhZ3bU6ujsA2gXEKOANyncXGUGc"},"prev":{"href":"https://backend.tvguide.com/tvschedules/tvguide/9100001138/web?start=1736640000&duration=240&apiKey=DI9elXhZ3bU6ujsA2gXEKOANyncXGUGc"},"next":{"href":"https://backend.tvguide.com/tvschedules/tvguide/9100001138/web?start=1736668800&duration=240&apiKey=DI9elXhZ3bU6ujsA2gXEKOANyncXGUGc"}},"meta":{"componentName":null,"componentDisplayName":null,"componentType":null}} \ No newline at end of file diff --git a/sites/tvguide.com/__data__/no-content.json b/sites/tvguide.com/__data__/no-content.json index d67154ca..0637a088 100644 --- a/sites/tvguide.com/__data__/no-content.json +++ b/sites/tvguide.com/__data__/no-content.json @@ -1,20 +1 @@ -{ - "errors": [ - { - "code": 400, - "reason": "Not Found", - "message": "Bad Request" - } - ], - "links": { - "self": { - "href": "https://cmg-prod.apigee.net/v1/xapi/tvschedules/tvguide/100001138/web?start=1667088000&duration=1440&channelSourceIds=9200018514" - } - }, - "meta": { - "componentName": null, - "componentDisplayName": null, - "componentType": null - } -} - \ No newline at end of file +[] \ No newline at end of file diff --git a/sites/tvguide.com/__data__/program.json b/sites/tvguide.com/__data__/program.json deleted file mode 100644 index e0697a72..00000000 --- a/sites/tvguide.com/__data__/program.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "data": { - "item": { - "id": 6060613824, - "name": "CBS Sunday Morning", - "parentId": 1030037352, - "description": "The Backseat Lovers perform on the \"Saturday Sessions\"; and Daisy Ryan guests on \"The Dish.\" Also: comedian Fortune Feimster.", - "isSportsEvent": false, - "rating": null, - "tvRating": "TV-PG", - "episodeTitle": "10-30-2022", - "releaseYear": 2022, - "seoUrl": null, - "categoryId": 4, - "subCategoryId": 0, - "episodeAirDate": "/Date(1667088000000)/", - "episodeNumber": 248, - "seasonNumber": 40, - "mcoId": 1030037352, - "title": "CBS Sunday Morning", - "type": "show", - "slug": "cbs-sunday-morning", - "typeId": 1, - "images": [ - { - "id": "1-10744155154", - "provider": "Tivo", - "imageType": { - "typeId": 1, - "typeName": "showcard", - "providerTypeName": "Vertical Showcard (3:4)" - }, - "bucketType": "catalog", - "bucketPath": "/provider/1/1/1-10744155154.jpg", - "filename": "", - "width": 2160, - "height": 2880 - }, - { - "id": "1-10744155148", - "provider": "Tivo", - "imageType": { - "typeId": 5, - "typeName": "key art", - "providerTypeName": "Key Art" - }, - "bucketType": "catalog", - "bucketPath": "/provider/1/5/1-10744155148.jpg", - "filename": "", - "width": 3000, - "height": 1688 - } - ], - "genres": [ - { - "id": 19, - "name": "Talk & Interview", - "genres": [ - "interview", - "talk" - ] - }, - { - "id": 99, - "name": "Other", - "genres": [ - "newsmagazine", - "profile" - ] - } - ], - "duration": null, - "metacriticSummary": { - "url": null, - "score": 0, - "reviewCount": 0 - }, - "video": null - } - }, - "links": { - "self": { - "href": "https://cmg-prod.apigee.net/v1/xapi/tvschedules/tvguide/programdetails/6060613824/web" - } - }, - "meta": { - "componentName": null, - "componentDisplayName": null, - "componentType": null - } -} \ No newline at end of file diff --git a/sites/tvguide.com/__data__/program1.json b/sites/tvguide.com/__data__/program1.json new file mode 100644 index 00000000..895526f9 --- /dev/null +++ b/sites/tvguide.com/__data__/program1.json @@ -0,0 +1 @@ +{"data":{"item":{"id":9000351140,"name":"FBI: International","isSportsEvent":false,"tvRating":"TV-14","categoryId":5,"subCategoryId":0,"episodeNumber":12,"mcoId":1060026058,"title":"FBI: International","type":"show","slug":"fbi-international","typeId":1,"images":[{"id":"2-da3822c4eec5e6100c9b6ff2ac667213","provider":"2","imageType":{"typeId":1,"typeName":"showcard","providerTypeName":"showcard"},"bucketType":"catalog","bucketPath":"/provider/2/13/2-da3822c4eec5e6100c9b6ff2ac667213.jpg","filename":"","width":3840,"height":2160},{"id":"2-d7bbccddf55702be0028e4c7b37d91d2","provider":"2","imageType":{"typeId":2,"typeName":"poster art","providerTypeName":"poster art"},"bucketType":"catalog","bucketPath":"/provider/2/2/2-d7bbccddf55702be0028e4c7b37d91d2.jpg","filename":"","width":1400,"height":2100}],"genres":[{"id":3,"name":"Action & Adventure","genres":["Action","Adventure"]},{"id":5,"name":"Suspense","genres":["Crime","Mystery","Thriller"]},{"id":1,"name":"Drama","genres":["Drama"]}],"metacriticSummary":null,"video":null,"parentId":1060026058,"description":"The owner of a prominent cyber security company is murdered in Copenhagen just before a massive data leak surfaces online, leading the NSA to ask the team for assistance in catching the killer and leaker before more data is revealed.","rating":"L","episodeTitle":"Gift","releaseYear":2024,"seoUrl":null,"episodeAirDate":"/Date(1715644800000)/","seasonNumber":3,"duration":null}},"links":{"self":{"href":"https://backend.tvguide.com/tvschedules/tvguide/programdetails/9000351140/web"}},"meta":{"componentName":null,"componentDisplayName":null,"componentType":null}} \ No newline at end of file diff --git a/sites/tvguide.com/__data__/program2.json b/sites/tvguide.com/__data__/program2.json new file mode 100644 index 00000000..91e825d3 --- /dev/null +++ b/sites/tvguide.com/__data__/program2.json @@ -0,0 +1 @@ +{"data":{"item":{"id":9000000408,"name":"Local Programs","isSportsEvent":false,"tvRating":"TV-14","categoryId":5,"subCategoryId":0,"episodeNumber":null,"mcoId":null,"title":null,"type":null,"slug":null,"typeId":null,"images":[],"genres":[],"metacriticSummary":null,"video":null,"parentId":null,"description":"Local programming information.","rating":"L","episodeTitle":"Local Programs","releaseYear":null,"seoUrl":null,"episodeAirDate":null,"seasonNumber":null,"duration":null}},"links":{"self":{"href":"https://backend.tvguide.com/tvschedules/tvguide/programdetails/9000000408/web"}},"meta":{"componentName":null,"componentDisplayName":null,"componentType":null}} \ No newline at end of file diff --git a/sites/tvguide.com/tvguide.com.channels.xml b/sites/tvguide.com/tvguide.com.channels.xml index ebec711e..0d76f7d3 100644 --- a/sites/tvguide.com/tvguide.com.channels.xml +++ b/sites/tvguide.com/tvguide.com.channels.xml @@ -1,89 +1,156 @@ - Travel Channel (East) - MyNetworkTV - ABC - A&E Network (East) - AMC (East) - Animal Planet (East) - BBC America (East) - Black Entertainment Television (East) - Bravo (East) - Cartoon Network (East) - CBS - Cinemax (East) - CMT (East) - Consumer News & Business Channel - Cable News Network - Comedy Central (East) - The Discovery Channel (East) - Discovery Life Channel - The Disney Channel (East) - Disney XD (East) - E! Entertainment Television (East) - ESPN2 - ESPN - ESPNU - FanDuel TV - Flix (East) - Food Network (East) - FOX - Fox News Channel (East) - Fox Sports 1 - Freeform (East) - Fuse (East) - FX (East) - FX Movie Channel - FXX (East) - FYI - GSN (East) - The Golf Channel - Hallmark Channel (East) - HBO 2 (East) - HBO (East) - HBO Signature (East) - Home & Garden Television (East) - History (East) - IFC (East) - Investigation Discovery - ION East Cable/Dish - Lifetime Television (East) - Lifetime Movies (East) - Lifetime Real Women - Magnolia Network [East] - More Max (East) - msnbc - MTV (East) - National Geographic Channel - NBC - NewsNation SDTV - Nickelodeon (East) - The Oprah Winfrey Network (East) - Oxygen (East) - Paramount Network (East) - PBS - Pop (East) - Quality Value Convenience Network - ReelzChannel - Science - Showtime 2 (East) - Showtime (East) - Smithsonian Channel (East) - Starz (East) - STARZ ENCORE (East) - SundanceTV (East) - Syfy (East) - TBS Superstation (East) - Turner Classic Movies - Telemundo Network (East) - The CW - The Movie Channel (East) - The Learning Channel (East) - Turner Network Television (East) - truTV (East) - TV Land (East) - Univisión Network (East) - USA Network (East) - VH1 (East) - Women's Entertainment Network (East) - \ No newline at end of file + Great American Family + MyNetworkTV National + Hallmark Family + 5StarMax + ABC Network Feed + ACC Network + ActionMax + A&E + AMC + American Heroes + Animal Planet + BBC America + BBC News + BET + BET Her + Big Ten Network + Bloomberg Television + Boomerang + Bravo + Cartoon Network + CBS National + CBS Sports Network + Cinemax + CMT + CNBC + CNN + Comedy Central + Cooking + Crime & Investigation Network + C-SPAN + Destination America + Discovery + Discovery Family + Discovery Life + Disney + Disney Junior + Disney XD + E! + ESPN2 + ESPN + ESPN News + ESPNU + FanDuel TV + Flix + Food Network + Fox Business Network + FOX + Fox News + FOX Sports 1 + FOX Sports 2 + Freeform + Fuse HD + FX + FX Movie + FXX + FYI + Game Show Network + Golf + Hallmark + Hallmark Mystery + HBO 2 + HBO Comedy + HBO + HBO Family + HBO Signature + HBO Zone + HGTV + History + HLN + IFC + Investigation Discovery + ION + Lifetime + LMN + LOGO + MAGNOLIA Network + MGM+ HD + MGM+ Drive-In + MGM+ Hits HD + MGM+ Marquee HD + MLB Network + MoreMax + Motor Trend Network + MovieMax + MSNBC + MTV2 + MTV + National Geographic + National Geographic Wild + NBA TV + NBC National + NewsNation + NFL Network + NHL Network + Nickelodeon + Nick Jr. + Nicktoons + Outdoor + OuterMax + Ovation + OWN + Oxygen + Paramount Network + PBS HD + Pop Network + Reelz + Science + SEC Network + SHOWTIME 2 + Paramount+ with Showtime + SHOWTIME EXTREME + SHOWTIME FAMILY ZONE + SHOWTIME NEXT + SHOWTIME SHOWCASE + SHOWTIME WOMEN + SHOxBET + Smithsonian + STARZ Cinema + STARZ Comedy + STARZ + STARZ Edge + STARZ ENCORE Action + STARZ ENCORE Black + STARZ ENCORE Classic + STARZ ENCORE + STARZ ENCORE Family + STARZ ENCORE Suspense + STARZ ENCORE Westerns + STARZ InBlack + STARZ Kids & Family + Sundance TV + Syfy + tbs + Turner Classic Movies + TeenNick + Telemundo + The Tennis + CW Network National + The Movie + The Movie Xtra + The Weather + ThrillerMax + TLC + TNT + Travel + truTV + TV Land + Universal Kids + USA + VH1 + VICE + WE tv + Univision + diff --git a/sites/tvguide.com/tvguide.com.config.js b/sites/tvguide.com/tvguide.com.config.js index 54b08bbb..940601d8 100644 --- a/sites/tvguide.com/tvguide.com.config.js +++ b/sites/tvguide.com/tvguide.com.config.js @@ -2,97 +2,113 @@ const axios = require('axios') const dayjs = require('dayjs') const utc = require('dayjs/plugin/utc') const timezone = require('dayjs/plugin/timezone') +const doFetch = require('@ntlab/sfetch') +const debug = require('debug')('site:tvguide.com') dayjs.extend(utc) dayjs.extend(timezone) +doFetch.setDebugger(debug).setCheckResult(false) + +const providerId = '9100001138' +const maxDuration = 240 +const segments = 1440 / maxDuration + module.exports = { site: 'tvguide.com', days: 2, - url: function ({ date, channel }) { - const [providerId, channelSourceIds] = channel.site_id.split('#') - const url = `https://internal-prod.apigee.fandom.net/v1/xapi/tvschedules/tvguide/${providerId}/web?start=${date - .startOf('d') - .unix()}&duration=1440&channelSourceIds=${channelSourceIds}` - - return url + request: { + cache: { + ttl: 24 * 60 * 60 * 1000 // 1 day + } }, - async parser({ content }) { + async url({ date, segment = 1 }) { + const params = [] + if (module.exports.apiKey === undefined) { + module.exports.apiKey = await module.exports.fetchApiKey() + debug('Got api key', module.exports.apiKey) + } + if (date) { + if (segment > 1) { + date = date.add((segment - 1) * maxDuration, 'm') + } + params.push(`start=${date.unix()}`, `duration=${maxDuration}`) + } + params.push(`apiKey=${module.exports.apiKey}`) + + return date ? + `https://backend.tvguide.com/tvschedules/tvguide/${providerId}/web?${params.join('&')}` : + `https://backend.tvguide.com/tvschedules/tvguide/serviceprovider/${providerId}/sources/web?${params.join('&')}` + }, + async parser({ content, date, channel }) { const programs = [] - const items = parseItems(content) - for (let item of items) { - const details = await loadProgramDetails(item) - programs.push({ - title: item.title, - sub_title: details.episodeTitle, - description: details.description, - season: details.seasonNumber, - episode: details.episodeNumber, - rating: parseRating(item), - categories: parseCategories(details), - start: parseTime(item.startTime), - stop: parseTime(item.endTime) + const f = data => { + const result = [] + if (typeof data === 'string') { + data = JSON.parse(data) + } + if (data && Array.isArray(data?.data?.items)) { + data.data.items + .filter(i => i.channel.sourceId.toString() === channel.site_id) + .forEach(i => { + result.push(...i.programSchedules.map(p => { + return { i: p, url: p.programDetails } + })) + }) + } + + return result + } + const queues = f(content) + if (queues.length) { + const parts = [] + for (let i = 2; i <= segments; i++) { + parts.push(await module.exports.url({ date, segment: i })) + } + await doFetch(parts, (url, res) => { + queues.push(...f(res)) + }) + await doFetch(queues, (queue, res) => { + const item = res?.data?.item ? res.data.item : queue.i + programs.push({ + title: item.title ? item.title : queue.i.title, + sub_title: item.episodeNumber ? item.episodeTitle : null, + description: item.description, + season: item.seasonNumber, + episode: item.episodeNumber, + rating: item.rating ? { system: 'MPA', value: item.rating } : null, + categories: Array.isArray(item.genres) ? item.genres.map(g => g.name) : null, + start: dayjs.unix(item.startTime ? item.startTime : queue.i.startTime), + stop: dayjs.unix(item.endTime ? item.endTime : queue.i.endTime) + }) }) } return programs }, async channels() { - const providers = [9100001138] + const channels = [] + const data = await axios + .get(await this.url({})) + .then(r => r.data) + .catch(console.error) - let channels = [] - for (let providerId of providers) { - const data = await axios - .get( - `https://internal-prod.apigee.fandom.net/v1/xapi/tvschedules/tvguide/serviceprovider/${providerId}/sources/web` - ) - .then(r => r.data) - .catch(console.log) - - data.data.items.forEach(item => { - channels.push({ - lang: 'en', - site_id: `${providerId}#${item.sourceId}`, - name: item.fullName - }) + data.data.items.forEach(item => { + channels.push({ + lang: 'en', + site_id: item.sourceId, + name: item.fullName.replace(/Channel|Schedule/g, '').trim() }) - } + }) return channels + }, + async fetchApiKey() { + const data = await axios + .get('https://www.tvguide.com/listings/') + .then(r => r.data) + .catch(console.error) + + return data ? data.match(/apiKey=([a-zA-Z0-9]+)&/)[1] : null } } - -function parseRating(item) { - return item.rating ? { system: 'MPA', value: item.rating } : null -} - -function parseCategories(details) { - return Array.isArray(details.genres) ? details.genres.map(g => g.name) : [] -} - -function parseTime(timestamp) { - return dayjs.unix(timestamp) -} - -function parseItems(content) { - const data = JSON.parse(content) - if (!data.data || !Array.isArray(data.data.items) || !data.data.items.length) return [] - - return data.data.items[0].programSchedules -} - -async function loadProgramDetails(item) { - item.programDetails = item.programDetails.replace( - 'player1-backend-prod-internal.apigee.net', - 'internal-prod.apigee.fandom.net' - ) - const data = await axios - .get(item.programDetails) - .then(r => r.data) - .catch(err => { - console.log(err.message) - }) - if (!data || !data.data || !data.data.item) return {} - - return data.data.item -} diff --git a/sites/tvguide.com/tvguide.com.test.js b/sites/tvguide.com/tvguide.com.test.js index 5018ce43..938adcb8 100644 --- a/sites/tvguide.com/tvguide.com.test.js +++ b/sites/tvguide.com/tvguide.com.test.js @@ -5,59 +5,82 @@ 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') -const date = dayjs.utc('2022-10-30', 'YYYY-MM-DD').startOf('d') +const date = dayjs.utc('2025-01-12', 'YYYY-MM-DD').startOf('d') const channel = { - site_id: '9100001138#9200018514', + site_id: '9200018514', xmltv_id: 'CBSEast.us' } -it('can generate valid url', () => { - expect(url({ date, channel })).toBe( - 'https://internal-prod.apigee.fandom.net/v1/xapi/tvschedules/tvguide/9100001138/web?start=1667088000&duration=1440&channelSourceIds=9200018514' +axios.get.mockImplementation(url => { + const result = {} + const urls = { + 'https://www.tvguide.com/listings/': + 'content.html', + 'https://backend.tvguide.com/tvschedules/tvguide/9100001138/web?start=1736640000&duration=240&apiKey=DI9elXhZ3bU6ujsA2gXEKOANyncXGUGc': + 'content1.json', + 'https://backend.tvguide.com/tvschedules/tvguide/9100001138/web?start=1736654400&duration=240&apiKey=DI9elXhZ3bU6ujsA2gXEKOANyncXGUGc': + 'content2.json', + 'https://backend.tvguide.com/tvschedules/tvguide/programdetails/9000351140/web': + 'program1.json', + 'https://backend.tvguide.com/tvschedules/tvguide/programdetails/9000000408/web': + 'program2.json', + } + if (urls[url] !== undefined) { + result.data = fs.readFileSync(path.join(__dirname, '__data__', urls[url])).toString() + if (!urls[url].startsWith('content1') && !urls[url].endsWith('.html')) { + result.data = JSON.parse(result.data) + } + } + + return Promise.resolve(result) +}) + +it('can generate valid url', async () => { + expect(await url({ date })).toBe( + 'https://backend.tvguide.com/tvschedules/tvguide/9100001138/web?start=1736640000&duration=240&apiKey=DI9elXhZ3bU6ujsA2gXEKOANyncXGUGc' ) }) it('can parse response', async () => { - const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json')) - - axios.get.mockImplementation(url => { - if ( - url === - 'https://fandom-prod.apigee.net/v1/xapi/tvschedules/tvguide/programdetails/6060613824/web' - ) { - return Promise.resolve({ - data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/program.json'))) - }) - } else { - return Promise.resolve({ data: '' }) - } - }) - - let results = await parser({ content, channel, date }) - results = results.map(p => { + const content = fs.readFileSync(path.join(__dirname, '__data__', 'content1.json')).toString() + const results = (await parser({ content, channel, date })).map(p => { p.start = p.start.toJSON() p.stop = p.stop.toJSON() return p }) - expect(results[5]).toMatchObject({ - start: '2022-10-30T13:00:00.000Z', - stop: '2022-10-30T14:30:00.000Z', - title: 'CBS Sunday Morning', - sub_title: '10-30-2022', + expect(results.length).toBe(5) + expect(results[0]).toMatchObject({ + start: '2025-01-12T01:00:00.000Z', + stop: '2025-01-12T02:00:00.000Z', + title: 'FBI: International', + sub_title: 'Gift', description: - 'The Backseat Lovers perform on the "Saturday Sessions"; and Daisy Ryan guests on "The Dish." Also: comedian Fortune Feimster.', - categories: ['Talk & Interview', 'Other'], - season: 40, - episode: 248, + 'The owner of a prominent cyber security company is murdered in Copenhagen just before a massive data leak surfaces online, leading the NSA to ask the team for assistance in catching the killer and leaker before more data is revealed.', + categories: ['Action & Adventure', 'Suspense', 'Drama'], + season: 3, + episode: 12, rating: { system: 'MPA', - value: 'TV-PG' + value: 'L' + } + }) + expect(results[4]).toMatchObject({ + start: '2025-01-12T06:00:00.000Z', + stop: '2025-01-12T08:00:00.000Z', + title: 'Local Programs', + description: + 'Local programming information.', + categories: [], + rating: { + system: 'MPA', + value: 'L' } }) }) @@ -66,7 +89,7 @@ it('can handle empty guide', async () => { const results = await parser({ date, channel, - content: fs.readFileSync(path.resolve(__dirname, '__data__/no-content.json')) + content: fs.readFileSync(path.join(__dirname, '__data__', 'no-content.json')).toString() }) expect(results).toMatchObject([]) })