Replace LF line endings with CRLF

This commit is contained in:
freearhey committed 2025-09-28 17:55:05 +03:00
1 parent efc74efcf8
commit b6a589c62a
1192 files changed
+445631 -445631

No files matched your search

+21 -21
View File
@@ -1,21 +1,21 @@
# tivie.id
https://tivie.id
### Download the guide
```sh
npm run grab --- --site=tivie.id
```
### Update channel list
```sh
npm run channels:parse --- --config=./sites/tivie.id/tivie.id.config.js --output=./sites/tivie.id/tivie.id.channels.xml
```
### Test
```sh
npm test --- tivie.id
```
# tivie.id
https://tivie.id
### Download the guide
```sh
npm run grab --- --site=tivie.id
```
### Update channel list
```sh
npm run channels:parse --- --config=./sites/tivie.id/tivie.id.config.js --output=./sites/tivie.id/tivie.id.channels.xml
```
### Test
```sh
npm test --- tivie.id
```
+48 -48
View File
@@ -1,48 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="tivie.id" lang="id" xmltv_id="ANTV.id" site_id="antv">ANTV</channel>
<channel site="tivie.id" lang="id" xmltv_id="AXNAsia.sg@Indonesia" site_id="axn">AXN</channel>
<channel site="tivie.id" lang="id" xmltv_id="beINSports1.qa@Indonesia" site_id="beinsports1">beIN Sports 1</channel>
<channel site="tivie.id" lang="id" xmltv_id="" site_id="beinsports2">beIN Sports 2</channel>
<channel site="tivie.id" lang="id" xmltv_id="beINSports3.qa@Indonesia" site_id="beinsports3">beIN Sports 3</channel>
<channel site="tivie.id" lang="id" xmltv_id="BTV.id" site_id="btv">BTV</channel>
<channel site="tivie.id" lang="id" xmltv_id="CinemaxAsia.sg" site_id="cinemax">Cinemax</channel>
<channel site="tivie.id" lang="id" xmltv_id="CNNIndonesia.id" site_id="cnnindonesia">CNN</channel>
<channel site="tivie.id" lang="id" xmltv_id="Galaxy.id" site_id="galaxy">Galaxy</channel>
<channel site="tivie.id" lang="id" xmltv_id="GalaxyPremium.id" site_id="galaxypremium">Galaxy Premium</channel>
<channel site="tivie.id" lang="id" xmltv_id="GarudaTV.id" site_id="garudatv">Garuda TV</channel>
<channel site="tivie.id" lang="id" xmltv_id="GTV.id" site_id="gtv">GTV</channel>
<channel site="tivie.id" lang="id" xmltv_id="HBOAsia.sg" site_id="hbo">HBO</channel>
<channel site="tivie.id" lang="id" xmltv_id="HBOFamilyAsia.sg" site_id="hbofamily">HBO Family</channel>
<channel site="tivie.id" lang="id" xmltv_id="HBOHitsAsia.sg" site_id="hbohits">HBO Hits</channel>
<channel site="tivie.id" lang="id" xmltv_id="HBOSignatureAsia.sg" site_id="hbosignature">HBO Signature</channel>
<channel site="tivie.id" lang="id" xmltv_id="HITS.sg" site_id="hits">HITS</channel>
<channel site="tivie.id" lang="id" xmltv_id="HITSMovies.sg" site_id="hitsmovies">HITS Movies</channel>
<channel site="tivie.id" lang="id" xmltv_id="HITSNowHD.sg" site_id="hitsnow">HITS Now</channel>
<channel site="tivie.id" lang="id" xmltv_id="Indosiar.id" site_id="indosiar">Indosiar</channel>
<channel site="tivie.id" lang="id" xmltv_id="iNews.id" site_id="inews">iNews</channel>
<channel site="tivie.id" lang="id" xmltv_id="KompasTV.id" site_id="kompastv">Kompas TV</channel>
<channel site="tivie.id" lang="id" xmltv_id="LifetimeAsia.us" site_id="lifetime">Lifetime</channel>
<channel site="tivie.id" lang="id" xmltv_id="NET.id" site_id="mdtv">MDTV</channel>
<channel site="tivie.id" lang="id" xmltv_id="MentariTV.id" site_id="mentaritv">Mentari TV</channel>
<channel site="tivie.id" lang="id" xmltv_id="MetroTV.id" site_id="metrotv">Metro TV</channel>
<channel site="tivie.id" lang="id" xmltv_id="MNCTV.id" site_id="mnctv">MNC TV</channel>
<channel site="tivie.id" lang="id" xmltv_id="Moji.id" site_id="moji">Moji</channel>
<channel site="tivie.id" lang="id" xmltv_id="NusantaraTV.id" site_id="nusantaratv">Nusantara TV</channel>
<channel site="tivie.id" lang="id" xmltv_id="RajawaliTV.id" site_id="rtv">RTV</channel>
<channel site="tivie.id" lang="id" xmltv_id="RCTI.id" site_id="rcti">RCTI</channel>
<channel site="tivie.id" lang="id" xmltv_id="ROCKEntertainment.sg" site_id="rockentertainment">Rock Entertainment</channel>
<channel site="tivie.id" lang="id" xmltv_id="ROCKExtreme.sg" site_id="rockaction">Rock Action</channel>
<channel site="tivie.id" lang="id" xmltv_id="SCTV.id" site_id="sctv">SCTV</channel>
<channel site="tivie.id" lang="id" xmltv_id="SEAToday.id" site_id="seatoday">SEA Today</channel>
<channel site="tivie.id" lang="id" xmltv_id="SindoNewsTV.id" site_id="sindonews">Sindonews TV</channel>
<channel site="tivie.id" lang="id" xmltv_id="SPOTV2.id" site_id="spotv2">SpoTV 2</channel>
<channel site="tivie.id" lang="id" xmltv_id="SPOTV.id" site_id="spotv">SpoTV</channel>
<channel site="tivie.id" lang="id" xmltv_id="Trans7.id" site_id="trans7">Trans7</channel>
<channel site="tivie.id" lang="id" xmltv_id="TransTV.id" site_id="transtv">Trans TV</channel>
<channel site="tivie.id" lang="id" xmltv_id="tvNAsia.hk" site_id="tvn">tvN</channel>
<channel site="tivie.id" lang="id" xmltv_id="tvNMoviesAsia.hk" site_id="tvnmovies">tvN Movies</channel>
<channel site="tivie.id" lang="id" xmltv_id="tvOne.id" site_id="tvone">TvOne</channel>
<channel site="tivie.id" lang="id" xmltv_id="TVRINasional.id" site_id="tvri">TVRI</channel>
<channel site="tivie.id" lang="id" xmltv_id="ZeeBioskop.id" site_id="zeebioskop">Zee Bioskop</channel>
</channels>
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="tivie.id" lang="id" xmltv_id="ANTV.id" site_id="antv">ANTV</channel>
<channel site="tivie.id" lang="id" xmltv_id="AXNAsia.sg@Indonesia" site_id="axn">AXN</channel>
<channel site="tivie.id" lang="id" xmltv_id="beINSports1.qa@Indonesia" site_id="beinsports1">beIN Sports 1</channel>
<channel site="tivie.id" lang="id" xmltv_id="" site_id="beinsports2">beIN Sports 2</channel>
<channel site="tivie.id" lang="id" xmltv_id="beINSports3.qa@Indonesia" site_id="beinsports3">beIN Sports 3</channel>
<channel site="tivie.id" lang="id" xmltv_id="BTV.id" site_id="btv">BTV</channel>
<channel site="tivie.id" lang="id" xmltv_id="CinemaxAsia.sg" site_id="cinemax">Cinemax</channel>
<channel site="tivie.id" lang="id" xmltv_id="CNNIndonesia.id" site_id="cnnindonesia">CNN</channel>
<channel site="tivie.id" lang="id" xmltv_id="Galaxy.id" site_id="galaxy">Galaxy</channel>
<channel site="tivie.id" lang="id" xmltv_id="GalaxyPremium.id" site_id="galaxypremium">Galaxy Premium</channel>
<channel site="tivie.id" lang="id" xmltv_id="GarudaTV.id" site_id="garudatv">Garuda TV</channel>
<channel site="tivie.id" lang="id" xmltv_id="GTV.id" site_id="gtv">GTV</channel>
<channel site="tivie.id" lang="id" xmltv_id="HBOAsia.sg" site_id="hbo">HBO</channel>
<channel site="tivie.id" lang="id" xmltv_id="HBOFamilyAsia.sg" site_id="hbofamily">HBO Family</channel>
<channel site="tivie.id" lang="id" xmltv_id="HBOHitsAsia.sg" site_id="hbohits">HBO Hits</channel>
<channel site="tivie.id" lang="id" xmltv_id="HBOSignatureAsia.sg" site_id="hbosignature">HBO Signature</channel>
<channel site="tivie.id" lang="id" xmltv_id="HITS.sg" site_id="hits">HITS</channel>
<channel site="tivie.id" lang="id" xmltv_id="HITSMovies.sg" site_id="hitsmovies">HITS Movies</channel>
<channel site="tivie.id" lang="id" xmltv_id="HITSNowHD.sg" site_id="hitsnow">HITS Now</channel>
<channel site="tivie.id" lang="id" xmltv_id="Indosiar.id" site_id="indosiar">Indosiar</channel>
<channel site="tivie.id" lang="id" xmltv_id="iNews.id" site_id="inews">iNews</channel>
<channel site="tivie.id" lang="id" xmltv_id="KompasTV.id" site_id="kompastv">Kompas TV</channel>
<channel site="tivie.id" lang="id" xmltv_id="LifetimeAsia.us" site_id="lifetime">Lifetime</channel>
<channel site="tivie.id" lang="id" xmltv_id="NET.id" site_id="mdtv">MDTV</channel>
<channel site="tivie.id" lang="id" xmltv_id="MentariTV.id" site_id="mentaritv">Mentari TV</channel>
<channel site="tivie.id" lang="id" xmltv_id="MetroTV.id" site_id="metrotv">Metro TV</channel>
<channel site="tivie.id" lang="id" xmltv_id="MNCTV.id" site_id="mnctv">MNC TV</channel>
<channel site="tivie.id" lang="id" xmltv_id="Moji.id" site_id="moji">Moji</channel>
<channel site="tivie.id" lang="id" xmltv_id="NusantaraTV.id" site_id="nusantaratv">Nusantara TV</channel>
<channel site="tivie.id" lang="id" xmltv_id="RajawaliTV.id" site_id="rtv">RTV</channel>
<channel site="tivie.id" lang="id" xmltv_id="RCTI.id" site_id="rcti">RCTI</channel>
<channel site="tivie.id" lang="id" xmltv_id="ROCKEntertainment.sg" site_id="rockentertainment">Rock Entertainment</channel>
<channel site="tivie.id" lang="id" xmltv_id="ROCKExtreme.sg" site_id="rockaction">Rock Action</channel>
<channel site="tivie.id" lang="id" xmltv_id="SCTV.id" site_id="sctv">SCTV</channel>
<channel site="tivie.id" lang="id" xmltv_id="SEAToday.id" site_id="seatoday">SEA Today</channel>
<channel site="tivie.id" lang="id" xmltv_id="SindoNewsTV.id" site_id="sindonews">Sindonews TV</channel>
<channel site="tivie.id" lang="id" xmltv_id="SPOTV2.id" site_id="spotv2">SpoTV 2</channel>
<channel site="tivie.id" lang="id" xmltv_id="SPOTV.id" site_id="spotv">SpoTV</channel>
<channel site="tivie.id" lang="id" xmltv_id="Trans7.id" site_id="trans7">Trans7</channel>
<channel site="tivie.id" lang="id" xmltv_id="TransTV.id" site_id="transtv">Trans TV</channel>
<channel site="tivie.id" lang="id" xmltv_id="tvNAsia.hk" site_id="tvn">tvN</channel>
<channel site="tivie.id" lang="id" xmltv_id="tvNMoviesAsia.hk" site_id="tvnmovies">tvN Movies</channel>
<channel site="tivie.id" lang="id" xmltv_id="tvOne.id" site_id="tvone">TvOne</channel>
<channel site="tivie.id" lang="id" xmltv_id="TVRINasional.id" site_id="tvri">TVRI</channel>
<channel site="tivie.id" lang="id" xmltv_id="ZeeBioskop.id" site_id="zeebioskop">Zee Bioskop</channel>
</channels>
+141 -141
View File
@@ -1,141 +1,141 @@
const axios = require('axios')
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')
const doFetch = require('@ntlab/sfetch')
const debug = require('debug')('site:tivie.id')
dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.extend(customParseFormat)
doFetch.setDebugger(debug)
const tz = 'Asia/Jakarta'
module.exports = {
site: 'tivie.id',
days: 2,
url({ channel, date }) {
return `https://tivie.id/channel/${channel.site_id}/${date.format('YYYYMMDD')}`
},
async parser({ content, date }) {
const programs = []
if (content) {
const $ = cheerio.load(content)
const items = $('ul[x-data] > li[id*="event-"] > div.w-full')
.toArray()
.map(item => {
const $item = $(item)
const time = $item.find('div:nth-child(1) span:nth-child(1)')
const info = $item.find('div:nth-child(2) h5')
const detail = info.find('a')
const p = {
start: dayjs.tz(`${date.format('YYYY-MM-DD')} ${time.html()}`, 'YYYY-MM-DD HH:mm', tz)
}
if (detail.length) {
const subtitle = detail.find('div')
p.title = parseText(subtitle.length ? subtitle : detail)
p.url = detail.attr('href')
} else {
p.title = parseText(info)
}
if (p.title) {
const [, , season, episode] = p.title.match(/( S(\d+))?, Ep\. (\d+)/) || [
null,
null,
null,
null
]
if (season) {
p.season = parseInt(season)
}
if (episode) {
p.episode = parseInt(episode)
}
}
return p
})
// fetch detailed guide if necessary
const queues = items
.filter(i => i.url)
.map(i => {
const url = i.url
delete i.url
return { i, url }
})
if (queues.length) {
await doFetch(queues, (queue, res) => {
const $ = cheerio.load(res)
const img = $('#main-content > div > div:nth-child(1) img')
const info = $('#main-content > div > div:nth-child(2)')
const title = parseText(info.find('h2:nth-child(2)'))
if (!queue.i.title.startsWith(title) && !queue.i.title.startsWith('LIVE ')) {
queue.i.subTitle = parseText(info.find('h2:nth-child(2)'))
}
const desc1 = parseText(info.find('div[class=""]:nth-child(3)'))
const desc2 = parseText(info.find('div[class=""]:nth-child(4)'))
if (desc2 == '') {
queue.i.description = desc1.replace('TiViE.id | ', '')
} else {
queue.i.description = desc2.replace('TiViE.id | ', '')
queue.i.date = parseText(info.find('h2:nth-child(3)'))
}
queue.i.categories = parseText(info.find('div[class=""]:nth-child(1)')).split(', ')
queue.i.image = img.length ? img.attr('src') : null
})
}
// fill start-stop
for (let i = 0; i < items.length; i++) {
if (i < items.length - 1) {
items[i].stop = items[i + 1].start
} else {
items[i].stop = dayjs.tz(
`${date.add(1, 'd').format('YYYY-MM-DD')} 00:00`,
'YYYY-MM-DD HH:mm',
tz
)
}
}
// add programs
programs.push(...items)
}
return programs
},
async channels({ lang = 'id' }) {
const result = await axios
.get('https://tivie.id/channel')
.then(response => response.data)
.catch(console.error)
const $ = cheerio.load(result)
const items = $('ul[x-data] li[x-data] div header h2 a').toArray()
const channels = items.map(item => {
const $item = $(item)
const url = $item.attr('href')
return {
lang,
site_id: url.substr(url.lastIndexOf('/') + 1),
name: $item.find('strong').text()
}
})
return channels
}
}
function parseText($item) {
let text = $item.text().replace(/\t/g, '').replace(/\n/g, ' ').trim()
while (true) {
if (text.match(/\s\s/)) {
text = text.replace(/\s\s/g, ' ')
continue
}
break
}
return text
}
const axios = require('axios')
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')
const doFetch = require('@ntlab/sfetch')
const debug = require('debug')('site:tivie.id')
dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.extend(customParseFormat)
doFetch.setDebugger(debug)
const tz = 'Asia/Jakarta'
module.exports = {
site: 'tivie.id',
days: 2,
url({ channel, date }) {
return `https://tivie.id/channel/${channel.site_id}/${date.format('YYYYMMDD')}`
},
async parser({ content, date }) {
const programs = []
if (content) {
const $ = cheerio.load(content)
const items = $('ul[x-data] > li[id*="event-"] > div.w-full')
.toArray()
.map(item => {
const $item = $(item)
const time = $item.find('div:nth-child(1) span:nth-child(1)')
const info = $item.find('div:nth-child(2) h5')
const detail = info.find('a')
const p = {
start: dayjs.tz(`${date.format('YYYY-MM-DD')} ${time.html()}`, 'YYYY-MM-DD HH:mm', tz)
}
if (detail.length) {
const subtitle = detail.find('div')
p.title = parseText(subtitle.length ? subtitle : detail)
p.url = detail.attr('href')
} else {
p.title = parseText(info)
}
if (p.title) {
const [, , season, episode] = p.title.match(/( S(\d+))?, Ep\. (\d+)/) || [
null,
null,
null,
null
]
if (season) {
p.season = parseInt(season)
}
if (episode) {
p.episode = parseInt(episode)
}
}
return p
})
// fetch detailed guide if necessary
const queues = items
.filter(i => i.url)
.map(i => {
const url = i.url
delete i.url
return { i, url }
})
if (queues.length) {
await doFetch(queues, (queue, res) => {
const $ = cheerio.load(res)
const img = $('#main-content > div > div:nth-child(1) img')
const info = $('#main-content > div > div:nth-child(2)')
const title = parseText(info.find('h2:nth-child(2)'))
if (!queue.i.title.startsWith(title) && !queue.i.title.startsWith('LIVE ')) {
queue.i.subTitle = parseText(info.find('h2:nth-child(2)'))
}
const desc1 = parseText(info.find('div[class=""]:nth-child(3)'))
const desc2 = parseText(info.find('div[class=""]:nth-child(4)'))
if (desc2 == '') {
queue.i.description = desc1.replace('TiViE.id | ', '')
} else {
queue.i.description = desc2.replace('TiViE.id | ', '')
queue.i.date = parseText(info.find('h2:nth-child(3)'))
}
queue.i.categories = parseText(info.find('div[class=""]:nth-child(1)')).split(', ')
queue.i.image = img.length ? img.attr('src') : null
})
}
// fill start-stop
for (let i = 0; i < items.length; i++) {
if (i < items.length - 1) {
items[i].stop = items[i + 1].start
} else {
items[i].stop = dayjs.tz(
`${date.add(1, 'd').format('YYYY-MM-DD')} 00:00`,
'YYYY-MM-DD HH:mm',
tz
)
}
}
// add programs
programs.push(...items)
}
return programs
},
async channels({ lang = 'id' }) {
const result = await axios
.get('https://tivie.id/channel')
.then(response => response.data)
.catch(console.error)
const $ = cheerio.load(result)
const items = $('ul[x-data] li[x-data] div header h2 a').toArray()
const channels = items.map(item => {
const $item = $(item)
const url = $item.attr('href')
return {
lang,
site_id: url.substr(url.lastIndexOf('/') + 1),
name: $item.find('strong').text()
}
})
return channels
}
}
function parseText($item) {
let text = $item.text().replace(/\t/g, '').replace(/\n/g, ' ').trim()
while (true) {
if (text.match(/\s\s/)) {
text = text.replace(/\s\s/g, ' ')
continue
}
break
}
return text
}
+75 -75
View File
@@ -1,75 +1,75 @@
const { parser, url } = require('./tivie.id.config')
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')
const date = dayjs.utc('2024-12-31').startOf('d')
const channel = {
site_id: 'axn',
xmltv_id: 'AXN.id',
lang: 'id'
}
axios.get.mockImplementation(url => {
const urls = {
'https://tivie.id/film/white-house-down-nwzDnwz9nAv6': 'program01.html',
'https://tivie.id/program/hudson-rex-s6-e14-nwzDnwvBmQr9': 'program02.html'
}
let data = ''
if (urls[url] !== undefined) {
data = fs.readFileSync(path.join(__dirname, '__data__', urls[url])).toString()
}
return Promise.resolve({ data })
})
it('can generate valid url', () => {
expect(url({ channel, date })).toBe('https://tivie.id/channel/axn/20241231')
})
it('can parse response', async () => {
const content = fs.readFileSync(path.join(__dirname, '__data__', 'content.html'))
const results = (await parser({ date, content, channel })).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(results.length).toBe(27)
expect(results[0]).toMatchObject({
start: '2024-12-30T17:00:00.000Z',
stop: '2024-12-30T17:05:00.000Z',
title: 'White House Down',
description:
'Saat melakukan tur di Gedung Putih bersama putrinya yang masih kecil, seorang perwira polisi beraksi untuk melindungi anaknya dan presiden dari sekelompok penjajah paramiliter bersenjata lengkap.',
image:
'https://i0.wp.com/is3.cloudhost.id/tivie/poster/2023/09/65116c78791c2-1695640694.jpg?resize=480,270'
})
expect(results[2]).toMatchObject({
start: '2024-12-30T18:00:00.000Z',
stop: '2024-12-30T18:55:00.000Z',
title: 'Hudson & Rex S6, Ep. 14',
description:
'Saat guru musik Jesse terbunuh di studio rekamannya, Charlie dan Rex menghubungkan kejahatan tersebut dengan pembunuhan yang tampaknya tak ada hubungannya.',
image:
'https://i0.wp.com/is3.cloudhost.id/tivie/poster/2024/07/668b7ced47b25-1720417517.jpg?resize=480,270',
season: 6,
episode: 14
})
})
it('can handle empty guide', async () => {
const results = await parser({
date,
channel,
content: ''
})
expect(results).toMatchObject([])
})
const { parser, url } = require('./tivie.id.config')
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')
const date = dayjs.utc('2024-12-31').startOf('d')
const channel = {
site_id: 'axn',
xmltv_id: 'AXN.id',
lang: 'id'
}
axios.get.mockImplementation(url => {
const urls = {
'https://tivie.id/film/white-house-down-nwzDnwz9nAv6': 'program01.html',
'https://tivie.id/program/hudson-rex-s6-e14-nwzDnwvBmQr9': 'program02.html'
}
let data = ''
if (urls[url] !== undefined) {
data = fs.readFileSync(path.join(__dirname, '__data__', urls[url])).toString()
}
return Promise.resolve({ data })
})
it('can generate valid url', () => {
expect(url({ channel, date })).toBe('https://tivie.id/channel/axn/20241231')
})
it('can parse response', async () => {
const content = fs.readFileSync(path.join(__dirname, '__data__', 'content.html'))
const results = (await parser({ date, content, channel })).map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
return p
})
expect(results.length).toBe(27)
expect(results[0]).toMatchObject({
start: '2024-12-30T17:00:00.000Z',
stop: '2024-12-30T17:05:00.000Z',
title: 'White House Down',
description:
'Saat melakukan tur di Gedung Putih bersama putrinya yang masih kecil, seorang perwira polisi beraksi untuk melindungi anaknya dan presiden dari sekelompok penjajah paramiliter bersenjata lengkap.',
image:
'https://i0.wp.com/is3.cloudhost.id/tivie/poster/2023/09/65116c78791c2-1695640694.jpg?resize=480,270'
})
expect(results[2]).toMatchObject({
start: '2024-12-30T18:00:00.000Z',
stop: '2024-12-30T18:55:00.000Z',
title: 'Hudson & Rex S6, Ep. 14',
description:
'Saat guru musik Jesse terbunuh di studio rekamannya, Charlie dan Rex menghubungkan kejahatan tersebut dengan pembunuhan yang tampaknya tak ada hubungannya.',
image:
'https://i0.wp.com/is3.cloudhost.id/tivie/poster/2024/07/668b7ced47b25-1720417517.jpg?resize=480,270',
season: 6,
episode: 14
})
})
it('can handle empty guide', async () => {
const results = await parser({
date,
channel,
content: ''
})
expect(results).toMatchObject([])
})