mirror of
https://github.com/iptv-org/epg
synced 2026-05-09 02:47:00 -04:00
Replaced LF endings with CRLF
This commit is contained in:
@@ -1,32 +1,32 @@
|
|||||||
import { SiteConfig } from 'epg-grabber'
|
import { SiteConfig } from 'epg-grabber'
|
||||||
import { pathToFileURL } from 'url'
|
import { pathToFileURL } from 'url'
|
||||||
|
|
||||||
export class ConfigLoader {
|
export class ConfigLoader {
|
||||||
async load(filepath: string): Promise<SiteConfig> {
|
async load(filepath: string): Promise<SiteConfig> {
|
||||||
const fileUrl = pathToFileURL(filepath).toString()
|
const fileUrl = pathToFileURL(filepath).toString()
|
||||||
const config = (await import(fileUrl)).default
|
const config = (await import(fileUrl)).default
|
||||||
const defaultConfig = {
|
const defaultConfig = {
|
||||||
days: 1,
|
days: 1,
|
||||||
delay: 0,
|
delay: 0,
|
||||||
output: 'guide.xml',
|
output: 'guide.xml',
|
||||||
request: {
|
request: {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
maxContentLength: 5242880,
|
maxContentLength: 5242880,
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
jar: null,
|
jar: null,
|
||||||
responseType: 'arraybuffer',
|
responseType: 'arraybuffer',
|
||||||
cache: false,
|
cache: false,
|
||||||
headers: null,
|
headers: null,
|
||||||
data: null
|
data: null
|
||||||
},
|
},
|
||||||
maxConnections: 1,
|
maxConnections: 1,
|
||||||
site: undefined,
|
site: undefined,
|
||||||
url: undefined,
|
url: undefined,
|
||||||
parser: undefined,
|
parser: undefined,
|
||||||
channels: undefined
|
channels: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
return { ...defaultConfig, ...config } as SiteConfig
|
return { ...defaultConfig, ...config } as SiteConfig
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +1,56 @@
|
|||||||
const { parser, url } = require('./9tv.co.il.config.js')
|
const { parser, url } = require('./9tv.co.il.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-03-06', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-03-06', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '#',
|
site_id: '#',
|
||||||
xmltv_id: 'Channel9.il'
|
xmltv_id: 'Channel9.il'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date })).toBe(
|
expect(url({ date })).toBe(
|
||||||
'https://www.9tv.co.il/BroadcastSchedule/getBrodcastSchedule?date=06/03/2022 00:00:00'
|
'https://www.9tv.co.il/BroadcastSchedule/getBrodcastSchedule?date=06/03/2022 00:00:00'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
||||||
const result = parser({ content, date }).map(p => {
|
const result = parser({ content, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-03-06T04:30:00.000Z',
|
start: '2022-03-06T04:30:00.000Z',
|
||||||
stop: '2022-03-06T07:10:00.000Z',
|
stop: '2022-03-06T07:10:00.000Z',
|
||||||
title: 'Слепая',
|
title: 'Слепая',
|
||||||
image: 'https://www.9tv.co.il/download/pictures/img_id=8484.jpg',
|
image: 'https://www.9tv.co.il/download/pictures/img_id=8484.jpg',
|
||||||
description:
|
description:
|
||||||
'Она не очень любит говорить о себе или о том, кто и зачем к ней обращается. Живет уединенно, в глуши. Но тех, кто приходит -принимает. Она видит судьбы.'
|
'Она не очень любит говорить о себе или о том, кто и зачем к ней обращается. Живет уединенно, в глуши. Но тех, кто приходит -принимает. Она видит судьбы.'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2022-03-06T07:10:00.000Z',
|
start: '2022-03-06T07:10:00.000Z',
|
||||||
stop: '2022-03-06T08:10:00.000Z',
|
stop: '2022-03-06T08:10:00.000Z',
|
||||||
image: 'https://www.9tv.co.il/download/pictures/img_id=23694.jpg',
|
image: 'https://www.9tv.co.il/download/pictures/img_id=23694.jpg',
|
||||||
title: 'Орел и решка. Морской сезон',
|
title: 'Орел и решка. Морской сезон',
|
||||||
description: 'Орел и решка. Морской сезон. Ведущие -Алина Астровская и Коля Серга.'
|
description: 'Орел и решка. Морской сезон. Ведущие -Алина Астровская и Коля Серга.'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,50 +1,50 @@
|
|||||||
const { parser, url } = require('./allente.dk.config.js')
|
const { parser, url } = require('./allente.dk.config.js')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-17', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-17', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '0148',
|
site_id: '0148',
|
||||||
xmltv_id: 'SVT1.se'
|
xmltv_id: 'SVT1.se'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date, channel })).toBe('https://cs-vcb.allente.dk/epg/events?date=2021-11-17')
|
expect(url({ date, channel })).toBe('https://cs-vcb.allente.dk/epg/events?date=2021-11-17')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content =
|
const content =
|
||||||
''
|
''
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-08-22T07:10:00.000Z',
|
start: '2022-08-22T07:10:00.000Z',
|
||||||
stop: '2022-08-22T07:30:00.000Z',
|
stop: '2022-08-22T07:30:00.000Z',
|
||||||
title: 'Hemmagympa med Sofia',
|
title: 'Hemmagympa med Sofia',
|
||||||
category: ['other'],
|
category: ['other'],
|
||||||
description:
|
description:
|
||||||
'Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.',
|
'Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.',
|
||||||
image:
|
image:
|
||||||
'https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440',
|
'https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440',
|
||||||
season: 4,
|
season: 4,
|
||||||
episode: 1
|
episode: 1
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: '{"date":"2001-11-17","categories":[],"channels":[]}'
|
content: '{"date":"2001-11-17","categories":[],"channels":[]}'
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
const { parser, url } = require('./allente.fi.config.js')
|
const { parser, url } = require('./allente.fi.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-17', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-17', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '0148',
|
site_id: '0148',
|
||||||
xmltv_id: 'SVT1.se'
|
xmltv_id: 'SVT1.se'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date, channel })).toBe('https://cs-vcb.allente.fi/epg/events?date=2021-11-17')
|
expect(url({ date, channel })).toBe('https://cs-vcb.allente.fi/epg/events?date=2021-11-17')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-08-22T07:10:00.000Z',
|
start: '2022-08-22T07:10:00.000Z',
|
||||||
stop: '2022-08-22T07:30:00.000Z',
|
stop: '2022-08-22T07:30:00.000Z',
|
||||||
title: 'Hemmagympa med Sofia',
|
title: 'Hemmagympa med Sofia',
|
||||||
category: ['other'],
|
category: ['other'],
|
||||||
description:
|
description:
|
||||||
'Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.',
|
'Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.',
|
||||||
image:
|
image:
|
||||||
'https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440',
|
'https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440',
|
||||||
season: 4,
|
season: 4,
|
||||||
episode: 1
|
episode: 1
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
const { parser, url } = require('./allente.no.config.js')
|
const { parser, url } = require('./allente.no.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-17', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-17', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '0148',
|
site_id: '0148',
|
||||||
xmltv_id: 'SVT1.se'
|
xmltv_id: 'SVT1.se'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date, channel })).toBe('https://cs-vcb.allente.no/epg/events?date=2021-11-17')
|
expect(url({ date, channel })).toBe('https://cs-vcb.allente.no/epg/events?date=2021-11-17')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-08-22T07:10:00.000Z',
|
start: '2022-08-22T07:10:00.000Z',
|
||||||
stop: '2022-08-22T07:30:00.000Z',
|
stop: '2022-08-22T07:30:00.000Z',
|
||||||
title: 'Hemmagympa med Sofia',
|
title: 'Hemmagympa med Sofia',
|
||||||
category: ['other'],
|
category: ['other'],
|
||||||
description:
|
description:
|
||||||
'Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.',
|
'Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.',
|
||||||
image:
|
image:
|
||||||
'https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440',
|
'https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440',
|
||||||
season: 4,
|
season: 4,
|
||||||
episode: 1
|
episode: 1
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
const { parser, url } = require('./allente.se.config.js')
|
const { parser, url } = require('./allente.se.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-17', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-17', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '0148',
|
site_id: '0148',
|
||||||
xmltv_id: 'SVT1.se'
|
xmltv_id: 'SVT1.se'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date, channel })).toBe('https://cs-vcb.allente.se/epg/events?date=2021-11-17')
|
expect(url({ date, channel })).toBe('https://cs-vcb.allente.se/epg/events?date=2021-11-17')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-08-22T07:10:00.000Z',
|
start: '2022-08-22T07:10:00.000Z',
|
||||||
stop: '2022-08-22T07:30:00.000Z',
|
stop: '2022-08-22T07:30:00.000Z',
|
||||||
title: 'Hemmagympa med Sofia',
|
title: 'Hemmagympa med Sofia',
|
||||||
category: ['other'],
|
category: ['other'],
|
||||||
description:
|
description:
|
||||||
'Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.',
|
'Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.',
|
||||||
image:
|
image:
|
||||||
'https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440',
|
'https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440',
|
||||||
season: 4,
|
season: 4,
|
||||||
episode: 1
|
episode: 1
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,59 +1,59 @@
|
|||||||
const { parser, url } = require('./arianatelevision.com.config.js')
|
const { parser, url } = require('./arianatelevision.com.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-27', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-27', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '#',
|
site_id: '#',
|
||||||
xmltv_id: 'ArianaTVNational.af'
|
xmltv_id: 'ArianaTVNational.af'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url).toBe('https://www.arianatelevision.com/program-schedule/')
|
expect(url).toBe('https://www.arianatelevision.com/program-schedule/')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
||||||
const result = parser({ content, date }).map(p => {
|
const result = parser({ content, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-27T02:30:00.000Z',
|
start: '2021-11-27T02:30:00.000Z',
|
||||||
stop: '2021-11-27T03:00:00.000Z',
|
stop: '2021-11-27T03:00:00.000Z',
|
||||||
title: 'City Report'
|
title: 'City Report'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2021-11-27T03:00:00.000Z',
|
start: '2021-11-27T03:00:00.000Z',
|
||||||
stop: '2021-11-27T10:30:00.000Z',
|
stop: '2021-11-27T10:30:00.000Z',
|
||||||
title: 'ICC T20 Highlights'
|
title: 'ICC T20 Highlights'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2021-11-27T10:30:00.000Z',
|
start: '2021-11-27T10:30:00.000Z',
|
||||||
stop: '2021-11-28T02:00:00.000Z',
|
stop: '2021-11-28T02:00:00.000Z',
|
||||||
title: 'ICC T20 World Cup'
|
title: 'ICC T20 World Cup'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2021-11-28T02:00:00.000Z',
|
start: '2021-11-28T02:00:00.000Z',
|
||||||
stop: '2021-11-28T02:30:00.000Z',
|
stop: '2021-11-28T02:30:00.000Z',
|
||||||
title: 'Quran and Hadis'
|
title: 'Quran and Hadis'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,66 +1,66 @@
|
|||||||
const { parser, url, request } = require('./artonline.tv.config.js')
|
const { parser, url, request } = require('./artonline.tv.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '#Aflam2',
|
site_id: '#Aflam2',
|
||||||
xmltv_id: 'ARTAflam2.sa'
|
xmltv_id: 'ARTAflam2.sa'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel })).toBe('https://www.artonline.tv/Home/TvlistAflam2')
|
expect(url({ channel })).toBe('https://www.artonline.tv/Home/TvlistAflam2')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request method', () => {
|
it('can generate valid request method', () => {
|
||||||
expect(request.method).toBe('POST')
|
expect(request.method).toBe('POST')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request headers', () => {
|
it('can generate valid request headers', () => {
|
||||||
expect(request.headers).toMatchObject({
|
expect(request.headers).toMatchObject({
|
||||||
'content-type': 'application/x-www-form-urlencoded'
|
'content-type': 'application/x-www-form-urlencoded'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request data for today', () => {
|
it('can generate valid request data for today', () => {
|
||||||
const date = dayjs.utc().startOf('d')
|
const date = dayjs.utc().startOf('d')
|
||||||
const data = request.data({ date })
|
const data = request.data({ date })
|
||||||
expect(data.get('objId')).toBe('0')
|
expect(data.get('objId')).toBe('0')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request data for tomorrow', () => {
|
it('can generate valid request data for tomorrow', () => {
|
||||||
const date = dayjs.utc().startOf('d').add(1, 'd')
|
const date = dayjs.utc().startOf('d').add(1, 'd')
|
||||||
const data = request.data({ date })
|
const data = request.data({ date })
|
||||||
expect(data.get('objId')).toBe('1')
|
expect(data.get('objId')).toBe('1')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-03-03T21:30:00.000Z',
|
start: '2022-03-03T21:30:00.000Z',
|
||||||
stop: '2022-03-03T23:04:00.000Z',
|
stop: '2022-03-03T23:04:00.000Z',
|
||||||
title: 'الراقصه و السياسي',
|
title: 'الراقصه و السياسي',
|
||||||
description:
|
description:
|
||||||
'تقرر الراقصه سونيا انشاء دار حضانه للأطفال اليتامى و عندما تتقدم بمشورعها للمسئول يرفض فتتحداه ، تلجأ للوزير عبد الحميد رأفت تربطه بها علاقة قديمة ، يخشى على مركزه و يرفض مساعدتها فتقرر كتابة مذكراتها بمساعدة أحد الصحفيين ، يتخوف عبد الحميد و المسئولين ثم يفاجأ عبد الحميد بحصول سونيا على الموافقه للمشورع و البدء في تنفيذه و ذلك لعلاقتها بأحد كبار المسئولين .',
|
'تقرر الراقصه سونيا انشاء دار حضانه للأطفال اليتامى و عندما تتقدم بمشورعها للمسئول يرفض فتتحداه ، تلجأ للوزير عبد الحميد رأفت تربطه بها علاقة قديمة ، يخشى على مركزه و يرفض مساعدتها فتقرر كتابة مذكراتها بمساعدة أحد الصحفيين ، يتخوف عبد الحميد و المسئولين ثم يفاجأ عبد الحميد بحصول سونيا على الموافقه للمشورع و البدء في تنفيذه و ذلك لعلاقتها بأحد كبار المسئولين .',
|
||||||
image: 'https://www.artonline.tv/UploadImages/Channel/ARTAFLAM1/03/AlRaqesaWaAlSeyasi.jpg'
|
image: 'https://www.artonline.tv/UploadImages/Channel/ARTAFLAM1/03/AlRaqesaWaAlSeyasi.jpg'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: ''
|
content: ''
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
const { parser, url } = require('./chada.ma.config.js')
|
const { parser, url } = require('./chada.ma.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
|
|
||||||
jest.mock('axios')
|
jest.mock('axios')
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url()).toBe('https://chada.ma/fr/chada-tv/grille-tv/')
|
expect(url()).toBe('https://chada.ma/fr/chada-tv/grille-tv/')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = dayjs(p.start).tz('Africa/Casablanca').format('YYYY-MM-DDTHH:mm:ssZ')
|
p.start = dayjs(p.start).tz('Africa/Casablanca').format('YYYY-MM-DDTHH:mm:ssZ')
|
||||||
p.stop = dayjs(p.stop).tz('Africa/Casablanca').format('YYYY-MM-DDTHH:mm:ssZ')
|
p.stop = dayjs(p.stop).tz('Africa/Casablanca').format('YYYY-MM-DDTHH:mm:ssZ')
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
title: 'Bloc Prime + Clips',
|
title: 'Bloc Prime + Clips',
|
||||||
description: 'No description available',
|
description: 'No description available',
|
||||||
start: dayjs.tz('00:00', 'HH:mm', 'Africa/Casablanca').format('YYYY-MM-DDTHH:mm:ssZ'),
|
start: dayjs.tz('00:00', 'HH:mm', 'Africa/Casablanca').format('YYYY-MM-DDTHH:mm:ssZ'),
|
||||||
stop: dayjs.tz('09:00', 'HH:mm', 'Africa/Casablanca').format('YYYY-MM-DDTHH:mm:ssZ')
|
stop: dayjs.tz('09:00', 'HH:mm', 'Africa/Casablanca').format('YYYY-MM-DDTHH:mm:ssZ')
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,49 +1,49 @@
|
|||||||
const { parser, url } = require('./chaines-tv.orange.fr.config.js')
|
const { parser, url } = require('./chaines-tv.orange.fr.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-08', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-08', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '192',
|
site_id: '192',
|
||||||
xmltv_id: 'TF1.fr'
|
xmltv_id: 'TF1.fr'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
const result = url({ channel, date })
|
const result = url({ channel, date })
|
||||||
expect(result).toBe(
|
expect(result).toBe(
|
||||||
'https://rp-ott-mediation-tv.woopic.com/api-gw/live/v3/applications/STB4PC/programs?groupBy=channel&includeEmptyChannels=false&period=1636329600000,1636416000000&after=192&limit=1'
|
'https://rp-ott-mediation-tv.woopic.com/api-gw/live/v3/applications/STB4PC/programs?groupBy=channel&includeEmptyChannels=false&period=1636329600000,1636416000000&after=192&limit=1'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ date, channel, content })
|
const result = parser({ date, channel, content })
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-07T23:35:00.000Z',
|
start: '2021-11-07T23:35:00.000Z',
|
||||||
stop: '2021-11-08T00:20:00.000Z',
|
stop: '2021-11-08T00:20:00.000Z',
|
||||||
title: 'Tête de liste',
|
title: 'Tête de liste',
|
||||||
subTitle: 'Esprits criminels',
|
subTitle: 'Esprits criminels',
|
||||||
season: 10,
|
season: 10,
|
||||||
episode: 12,
|
episode: 12,
|
||||||
description:
|
description:
|
||||||
"Un tueur en série prend un plaisir pervers à prévenir les autorités de Tallahassee avant chaque nouveau meurtre. Rossi apprend le décès d'un de ses vieux amis.",
|
"Un tueur en série prend un plaisir pervers à prévenir les autorités de Tallahassee avant chaque nouveau meurtre. Rossi apprend le décès d'un de ses vieux amis.",
|
||||||
category: 'Série Suspense',
|
category: 'Série Suspense',
|
||||||
image: 'https://proxymedia.woopic.com/340/p/169_EMI_9697669.jpg'
|
image: 'https://proxymedia.woopic.com/340/p/169_EMI_9697669.jpg'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,55 +1,55 @@
|
|||||||
const { parser, url } = require('./cosmotetv.gr.config.js')
|
const { parser, url } = require('./cosmotetv.gr.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
|
|
||||||
jest.mock('axios')
|
jest.mock('axios')
|
||||||
|
|
||||||
const date = dayjs.utc('2024-12-26', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2024-12-26', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = { site_id: 'vouli', xmltv_id: 'HellenicParliamentTV.gr' }
|
const channel = { site_id: 'vouli', xmltv_id: 'HellenicParliamentTV.gr' }
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
const startOfDay = dayjs(date).startOf('day').utc().unix()
|
const startOfDay = dayjs(date).startOf('day').utc().unix()
|
||||||
const endOfDay = dayjs(date).endOf('day').utc().unix()
|
const endOfDay = dayjs(date).endOf('day').utc().unix()
|
||||||
expect(url({ date, channel })).toBe(
|
expect(url({ date, channel })).toBe(
|
||||||
`https://mwapi-prod.cosmotetvott.gr/api/v3.4/epg/listings/el?from=${startOfDay}&to=${endOfDay}&callSigns=${channel.site_id}&endingIncludedInRange=false`
|
`https://mwapi-prod.cosmotetvott.gr/api/v3.4/epg/listings/el?from=${startOfDay}&to=${endOfDay}&callSigns=${channel.site_id}&endingIncludedInRange=false`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'), 'utf8')
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'), 'utf8')
|
||||||
const result = parser({ date, content }).map(p => {
|
const result = parser({ date, content }).map(p => {
|
||||||
p.start = dayjs(p.start).toISOString()
|
p.start = dayjs(p.start).toISOString()
|
||||||
p.stop = dayjs(p.stop).toISOString()
|
p.stop = dayjs(p.stop).toISOString()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
title: 'Τι Λέει ο Νόμος',
|
title: 'Τι Λέει ο Νόμος',
|
||||||
description:
|
description:
|
||||||
'νημερωτική εκπομπή. Συζήτηση με τους εισηγητές των κομμάτων για το νομοθετικό έργο.',
|
'νημερωτική εκπομπή. Συζήτηση με τους εισηγητές των κομμάτων για το νομοθετικό έργο.',
|
||||||
category: 'Special',
|
category: 'Special',
|
||||||
image:
|
image:
|
||||||
'https://gr-ermou-prod-cache05.static.cdn.cosmotetvott.gr/ote-prod/70/280/040029714812000800_1734415727199.jpg',
|
'https://gr-ermou-prod-cache05.static.cdn.cosmotetvott.gr/ote-prod/70/280/040029714812000800_1734415727199.jpg',
|
||||||
start: '2024-12-26T23:00:00.000Z',
|
start: '2024-12-26T23:00:00.000Z',
|
||||||
stop: '2024-12-27T00:00:00.000Z'
|
stop: '2024-12-27T00:00:00.000Z'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'), 'utf8')
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'), 'utf8')
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,47 +1,47 @@
|
|||||||
const { url, parser } = require('./cubmu.com.config.js')
|
const { url, parser } = require('./cubmu.com.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2023-11-05', 'DD/MM/YYYY').startOf('d')
|
const date = dayjs.utc('2023-11-05', 'DD/MM/YYYY').startOf('d')
|
||||||
const channel = { site_id: '4028c68574537fcd0174be43042758d8', xmltv_id: 'TransTV.id', lang: 'id' }
|
const channel = { site_id: '4028c68574537fcd0174be43042758d8', xmltv_id: 'TransTV.id', lang: 'id' }
|
||||||
const channelEn = Object.assign({}, channel, { lang: 'en' })
|
const channelEn = Object.assign({}, channel, { lang: 'en' })
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://servicebuss.transvision.co.id/v2/cms/getEPGData?app_id=cubmu&tvs_platform_id=standalone&schedule_date=2023-11-05&channel_id=4028c68574537fcd0174be43042758d8'
|
'https://servicebuss.transvision.co.id/v2/cms/getEPGData?app_id=cubmu&tvs_platform_id=standalone&schedule_date=2023-11-05&channel_id=4028c68574537fcd0174be43042758d8'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'), 'utf8')
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'), 'utf8')
|
||||||
const idResults = parser({ content, channel })
|
const idResults = parser({ content, channel })
|
||||||
expect(idResults).toMatchObject([
|
expect(idResults).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2023-11-04T18:30:00.000Z',
|
start: '2023-11-04T18:30:00.000Z',
|
||||||
stop: '2023-11-04T19:00:00.000Z',
|
stop: '2023-11-04T19:00:00.000Z',
|
||||||
title: 'CNN Tech News',
|
title: 'CNN Tech News',
|
||||||
description:
|
description:
|
||||||
'CNN Indonesia Tech News adalah berita teknologi yang membawa pemirsa ke dunia teknologi yang penuh dengan informasi, pendidikan, hiburan sampai informasi kesehatan terkini.'
|
'CNN Indonesia Tech News adalah berita teknologi yang membawa pemirsa ke dunia teknologi yang penuh dengan informasi, pendidikan, hiburan sampai informasi kesehatan terkini.'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
const enResults = parser({ content, channel: channelEn })
|
const enResults = parser({ content, channel: channelEn })
|
||||||
expect(enResults).toMatchObject([
|
expect(enResults).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2023-11-04T18:30:00.000Z',
|
start: '2023-11-04T18:30:00.000Z',
|
||||||
stop: '2023-11-04T19:00:00.000Z',
|
stop: '2023-11-04T19:00:00.000Z',
|
||||||
title: 'CNN Tech News',
|
title: 'CNN Tech News',
|
||||||
description:
|
description:
|
||||||
'CNN Indonesia Tech News is tech news brings viewers into the world of technology that provides information, education, entertainment to the latest health information.'
|
'CNN Indonesia Tech News is tech news brings viewers into the world of technology that provides information, education, entertainment to the latest health information.'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const results = parser({ content: '' })
|
const results = parser({ content: '' })
|
||||||
|
|
||||||
expect(results).toMatchObject([])
|
expect(results).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,48 +1,48 @@
|
|||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
const parseDuration = require('parse-duration').default
|
const parseDuration = require('parse-duration').default
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
const { sortBy } = require('../../scripts/functions')
|
const { sortBy } = require('../../scripts/functions')
|
||||||
|
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'derana.lk',
|
site: 'derana.lk',
|
||||||
url({ date }) {
|
url({ date }) {
|
||||||
return `https://derana.lk/api/schedules/${date.format('DD-MM-YYYY')}`
|
return `https://derana.lk/api/schedules/${date.format('DD-MM-YYYY')}`
|
||||||
},
|
},
|
||||||
parser({ content }) {
|
parser({ content }) {
|
||||||
const programs = parseItems(content).map(item => {
|
const programs = parseItems(content).map(item => {
|
||||||
const start = parseStart(item)
|
const start = parseStart(item)
|
||||||
const duration = parseDuration(item.duration)
|
const duration = parseDuration(item.duration)
|
||||||
const stop = start.add(duration, 'ms')
|
const stop = start.add(duration, 'ms')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: item.dramaName,
|
title: item.dramaName,
|
||||||
image: item.imageUrl,
|
image: item.imageUrl,
|
||||||
start,
|
start,
|
||||||
stop
|
stop
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return sortBy(programs, p => p.start.valueOf())
|
return sortBy(programs, p => p.start.valueOf())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStart(item) {
|
function parseStart(item) {
|
||||||
return dayjs.tz(`${item.date} ${item.time}`, 'DD-MM-YYYY H:mm A', 'Asia/Colombo')
|
return dayjs.tz(`${item.date} ${item.time}`, 'DD-MM-YYYY H:mm A', 'Asia/Colombo')
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(content) {
|
function parseItems(content) {
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(content)
|
const data = JSON.parse(content)
|
||||||
if (!data || !Array.isArray(data.all_schedules)) return []
|
if (!data || !Array.isArray(data.all_schedules)) return []
|
||||||
|
|
||||||
return data.all_schedules
|
return data.all_schedules
|
||||||
} catch {
|
} catch {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,78 +1,78 @@
|
|||||||
const { parser, url, request } = require('./directv.com.ar.config.js')
|
const { parser, url, request } = require('./directv.com.ar.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-06-19', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-06-19', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '207#A&EHD',
|
site_id: '207#A&EHD',
|
||||||
xmltv_id: 'AEHDSouth.us'
|
xmltv_id: 'AEHDSouth.us'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url).toBe('https://www.directv.com.ar/guia/ChannelDetail.aspx/GetProgramming')
|
expect(url).toBe('https://www.directv.com.ar/guia/ChannelDetail.aspx/GetProgramming')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request method', () => {
|
it('can generate valid request method', () => {
|
||||||
expect(request.method).toBe('POST')
|
expect(request.method).toBe('POST')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request headers', () => {
|
it('can generate valid request headers', () => {
|
||||||
expect(request.headers).toMatchObject({
|
expect(request.headers).toMatchObject({
|
||||||
'Content-Type': 'application/json; charset=UTF-8',
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
Cookie: 'PGCSS=16; PGLang=S; PGCulture=es-AR;'
|
Cookie: 'PGCSS=16; PGLang=S; PGCulture=es-AR;'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request data', () => {
|
it('can generate valid request data', () => {
|
||||||
expect(request.data({ channel, date })).toMatchObject({
|
expect(request.data({ channel, date })).toMatchObject({
|
||||||
filterParameters: {
|
filterParameters: {
|
||||||
day: 19,
|
day: 19,
|
||||||
time: 0,
|
time: 0,
|
||||||
minute: 0,
|
minute: 0,
|
||||||
month: 6,
|
month: 6,
|
||||||
year: 2022,
|
year: 2022,
|
||||||
offSetValue: 0,
|
offSetValue: 0,
|
||||||
filtersScreenFilters: [''],
|
filtersScreenFilters: [''],
|
||||||
isHd: '',
|
isHd: '',
|
||||||
isChannelDetails: 'Y',
|
isChannelDetails: 'Y',
|
||||||
channelNum: '207',
|
channelNum: '207',
|
||||||
channelName: 'A&EHD'
|
channelName: 'A&EHD'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-06-19T03:00:00.000Z',
|
start: '2022-06-19T03:00:00.000Z',
|
||||||
stop: '2022-06-19T03:15:00.000Z',
|
stop: '2022-06-19T03:15:00.000Z',
|
||||||
title: 'Chicas guapas',
|
title: 'Chicas guapas',
|
||||||
description:
|
description:
|
||||||
'Un espacio destinado a la belleza y los distintos estilos de vida, que muestra el trabajo inspiracional de la moda latinoamericana.',
|
'Un espacio destinado a la belleza y los distintos estilos de vida, que muestra el trabajo inspiracional de la moda latinoamericana.',
|
||||||
rating: {
|
rating: {
|
||||||
system: 'MPA',
|
system: 'MPA',
|
||||||
value: 'NR'
|
value: 'NR'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: '',
|
content: '',
|
||||||
channel
|
channel
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,206 +1,206 @@
|
|||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
const { uniqBy } = require('../../scripts/functions')
|
const { uniqBy } = require('../../scripts/functions')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
|
|
||||||
const API_ENDPOINT = 'https://www.dstv.com/umbraco/api/TvGuide'
|
const API_ENDPOINT = 'https://www.dstv.com/umbraco/api/TvGuide'
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'dstv.com',
|
site: 'dstv.com',
|
||||||
days: 2,
|
days: 2,
|
||||||
request: {
|
request: {
|
||||||
cache: {
|
cache: {
|
||||||
ttl: 3 * 60 * 60 * 1000, // 3h
|
ttl: 3 * 60 * 60 * 1000, // 3h
|
||||||
interpretHeader: false
|
interpretHeader: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
url: function ({ channel, date }) {
|
url: function ({ channel, date }) {
|
||||||
const [region] = channel.site_id.split('#')
|
const [region] = channel.site_id.split('#')
|
||||||
const packageName = region === 'nga' ? '&package=DStv%20Premium' : ''
|
const packageName = region === 'nga' ? '&package=DStv%20Premium' : ''
|
||||||
|
|
||||||
return `${API_ENDPOINT}/GetProgrammes?d=${date.format(
|
return `${API_ENDPOINT}/GetProgrammes?d=${date.format(
|
||||||
'YYYY-MM-DD'
|
'YYYY-MM-DD'
|
||||||
)}${packageName}&country=${region}`
|
)}${packageName}&country=${region}`
|
||||||
},
|
},
|
||||||
async parser({ content, channel }) {
|
async parser({ content, channel }) {
|
||||||
let programs = []
|
let programs = []
|
||||||
const items = parseItems(content, channel)
|
const items = parseItems(content, channel)
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
const details = await loadProgramDetails(item)
|
const details = await loadProgramDetails(item)
|
||||||
programs.push({
|
programs.push({
|
||||||
title: item.Title,
|
title: item.Title,
|
||||||
description: parseDescription(details),
|
description: parseDescription(details),
|
||||||
image: parseImage(details),
|
image: parseImage(details),
|
||||||
category: parseCategory(details),
|
category: parseCategory(details),
|
||||||
start: parseTime(item.StartTime, channel),
|
start: parseTime(item.StartTime, channel),
|
||||||
stop: parseTime(item.EndTime, channel)
|
stop: parseTime(item.EndTime, channel)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels({ country }) {
|
async channels({ country }) {
|
||||||
|
|
||||||
const countries = {
|
const countries = {
|
||||||
ao: 'ago',
|
ao: 'ago',
|
||||||
bj: 'ben',
|
bj: 'ben',
|
||||||
bw: 'bwa',
|
bw: 'bwa',
|
||||||
bf: 'bfa',
|
bf: 'bfa',
|
||||||
bi: 'bdi',
|
bi: 'bdi',
|
||||||
cm: 'cmr',
|
cm: 'cmr',
|
||||||
cv: 'cpv',
|
cv: 'cpv',
|
||||||
td: 'tcd',
|
td: 'tcd',
|
||||||
cf: 'caf',
|
cf: 'caf',
|
||||||
km: 'com',
|
km: 'com',
|
||||||
cd: 'cod',
|
cd: 'cod',
|
||||||
dj: 'dji',
|
dj: 'dji',
|
||||||
gq: 'gnq',
|
gq: 'gnq',
|
||||||
er: 'eri',
|
er: 'eri',
|
||||||
sz: 'swz',
|
sz: 'swz',
|
||||||
et: 'eth',
|
et: 'eth',
|
||||||
ga: 'gab',
|
ga: 'gab',
|
||||||
gm: 'gmb',
|
gm: 'gmb',
|
||||||
gh: 'gha',
|
gh: 'gha',
|
||||||
gn: 'gin',
|
gn: 'gin',
|
||||||
gw: 'gnb',
|
gw: 'gnb',
|
||||||
ci: 'civ',
|
ci: 'civ',
|
||||||
ke: 'ken',
|
ke: 'ken',
|
||||||
lr: 'lbr',
|
lr: 'lbr',
|
||||||
mg: 'mdg',
|
mg: 'mdg',
|
||||||
mw: 'mwi',
|
mw: 'mwi',
|
||||||
ml: 'mli',
|
ml: 'mli',
|
||||||
mr: 'mrt',
|
mr: 'mrt',
|
||||||
mu: 'mus',
|
mu: 'mus',
|
||||||
mz: 'moz',
|
mz: 'moz',
|
||||||
na: 'nam',
|
na: 'nam',
|
||||||
ne: 'ner',
|
ne: 'ner',
|
||||||
ng: 'nga',
|
ng: 'nga',
|
||||||
cg: 'cog',
|
cg: 'cog',
|
||||||
rw: 'rwa',
|
rw: 'rwa',
|
||||||
st: 'stp',
|
st: 'stp',
|
||||||
sn: 'sen',
|
sn: 'sen',
|
||||||
sc: 'syc',
|
sc: 'syc',
|
||||||
sl: 'sle',
|
sl: 'sle',
|
||||||
so: 'som',
|
so: 'som',
|
||||||
za: 'zaf',
|
za: 'zaf',
|
||||||
ss: 'ssd',
|
ss: 'ssd',
|
||||||
sd: 'sdn',
|
sd: 'sdn',
|
||||||
tz: 'tza',
|
tz: 'tza',
|
||||||
tg: 'tgo',
|
tg: 'tgo',
|
||||||
ug: 'uga',
|
ug: 'uga',
|
||||||
zm: 'zmb',
|
zm: 'zmb',
|
||||||
zw: 'zwe'
|
zw: 'zwe'
|
||||||
}
|
}
|
||||||
|
|
||||||
const code = countries[country]
|
const code = countries[country]
|
||||||
|
|
||||||
const data = await axios
|
const data = await axios
|
||||||
.get(`${API_ENDPOINT}/GetProgrammes?d=${dayjs().format('YYYY-MM-DD')}&country=${code}`)
|
.get(`${API_ENDPOINT}/GetProgrammes?d=${dayjs().format('YYYY-MM-DD')}&country=${code}`)
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
|
|
||||||
let channels = []
|
let channels = []
|
||||||
data.Channels.forEach(item => {
|
data.Channels.forEach(item => {
|
||||||
channels.push({
|
channels.push({
|
||||||
lang: 'en',
|
lang: 'en',
|
||||||
site_id: `${code}#${item.Number}`,
|
site_id: `${code}#${item.Number}`,
|
||||||
name: item.Name
|
name: item.Name
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return uniqBy(channels, 'site_id')
|
return uniqBy(channels, 'site_id')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTime(time, channel) {
|
function parseTime(time, channel) {
|
||||||
const tz = {
|
const tz = {
|
||||||
ago: 'Africa/Luanda',
|
ago: 'Africa/Luanda',
|
||||||
ben: 'Africa/Porto-Novo',
|
ben: 'Africa/Porto-Novo',
|
||||||
bwa: 'Africa/Gaborone',
|
bwa: 'Africa/Gaborone',
|
||||||
bfa: 'Africa/Ouagadougou',
|
bfa: 'Africa/Ouagadougou',
|
||||||
bdi: 'Africa/Bujumbura',
|
bdi: 'Africa/Bujumbura',
|
||||||
cmr: 'Africa/Douala',
|
cmr: 'Africa/Douala',
|
||||||
cpv: 'CVT',
|
cpv: 'CVT',
|
||||||
tcd: 'Africa/Ndjamena',
|
tcd: 'Africa/Ndjamena',
|
||||||
caf: 'Africa/Bangui',
|
caf: 'Africa/Bangui',
|
||||||
com: 'Indian/Comoro',
|
com: 'Indian/Comoro',
|
||||||
cod: 'Africa/Kinshasa',
|
cod: 'Africa/Kinshasa',
|
||||||
dji: 'Africa/Djibouti',
|
dji: 'Africa/Djibouti',
|
||||||
gnq: 'Africa/Malabo',
|
gnq: 'Africa/Malabo',
|
||||||
eri: 'Africa/Asmara',
|
eri: 'Africa/Asmara',
|
||||||
swz: 'SAST',
|
swz: 'SAST',
|
||||||
eth: 'Africa/Addis_Ababa',
|
eth: 'Africa/Addis_Ababa',
|
||||||
gap: 'Africa/Libreville',
|
gap: 'Africa/Libreville',
|
||||||
gmb: 'Africa/Banjul',
|
gmb: 'Africa/Banjul',
|
||||||
gha: 'Africa/Accra',
|
gha: 'Africa/Accra',
|
||||||
gin: 'Africa/Conakry',
|
gin: 'Africa/Conakry',
|
||||||
gnb: 'Africa/Bissau',
|
gnb: 'Africa/Bissau',
|
||||||
civ: 'Africa/Abidjan',
|
civ: 'Africa/Abidjan',
|
||||||
ken: 'Africa/Nairobi',
|
ken: 'Africa/Nairobi',
|
||||||
lbr: 'Africa/Monrovia',
|
lbr: 'Africa/Monrovia',
|
||||||
mdg: 'Indian/Antananarivo',
|
mdg: 'Indian/Antananarivo',
|
||||||
mwi: 'Africa/Blantyre',
|
mwi: 'Africa/Blantyre',
|
||||||
mli: 'Africa/Bamako',
|
mli: 'Africa/Bamako',
|
||||||
mrt: 'Africa/Nouakchott',
|
mrt: 'Africa/Nouakchott',
|
||||||
mus: 'Indian/Mauritius',
|
mus: 'Indian/Mauritius',
|
||||||
moz: 'Africa/Maputo',
|
moz: 'Africa/Maputo',
|
||||||
nam: 'Africa/Windhoek',
|
nam: 'Africa/Windhoek',
|
||||||
ner: 'Africa/Niamey',
|
ner: 'Africa/Niamey',
|
||||||
nga: 'Africa/Lagos',
|
nga: 'Africa/Lagos',
|
||||||
cog: 'Africa/Brazzaville',
|
cog: 'Africa/Brazzaville',
|
||||||
rwa: 'Africa/Kigali',
|
rwa: 'Africa/Kigali',
|
||||||
stp: 'Africa/Sao_Tome',
|
stp: 'Africa/Sao_Tome',
|
||||||
sen: 'Africa/Dakar',
|
sen: 'Africa/Dakar',
|
||||||
syc: 'Indian/Mahe',
|
syc: 'Indian/Mahe',
|
||||||
sle: 'Africa/Freetown',
|
sle: 'Africa/Freetown',
|
||||||
som: 'Africa/Mogadishu',
|
som: 'Africa/Mogadishu',
|
||||||
zaf: 'Africa/Johannesburg',
|
zaf: 'Africa/Johannesburg',
|
||||||
ssd: 'Africa/Juba',
|
ssd: 'Africa/Juba',
|
||||||
sdn: 'Africa/Khartoum',
|
sdn: 'Africa/Khartoum',
|
||||||
tza: 'Africa/Dar_es_Salaam',
|
tza: 'Africa/Dar_es_Salaam',
|
||||||
tgo: 'Africa/Lome',
|
tgo: 'Africa/Lome',
|
||||||
uga: 'Africa/Kampala',
|
uga: 'Africa/Kampala',
|
||||||
zmb: 'Africa/Lusaka',
|
zmb: 'Africa/Lusaka',
|
||||||
zwe: 'Africa/Harare'
|
zwe: 'Africa/Harare'
|
||||||
}
|
}
|
||||||
const [region] = channel.site_id.split('#')
|
const [region] = channel.site_id.split('#')
|
||||||
|
|
||||||
return dayjs.tz(time, 'YYYY-MM-DDTHH:mm:ss', tz[region])
|
return dayjs.tz(time, 'YYYY-MM-DDTHH:mm:ss', tz[region])
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDescription(details) {
|
function parseDescription(details) {
|
||||||
return details ? details.Synopsis : null
|
return details ? details.Synopsis : null
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseImage(details) {
|
function parseImage(details) {
|
||||||
return details ? details.ThumbnailUri : null
|
return details ? details.ThumbnailUri : null
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseCategory(details) {
|
function parseCategory(details) {
|
||||||
return details ? details.SubGenres : null
|
return details ? details.SubGenres : null
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadProgramDetails(item) {
|
async function loadProgramDetails(item) {
|
||||||
const url = `${API_ENDPOINT}/GetProgramme?id=${item.Id}`
|
const url = `${API_ENDPOINT}/GetProgramme?id=${item.Id}`
|
||||||
|
|
||||||
return axios
|
return axios
|
||||||
.get(url)
|
.get(url)
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(content, channel) {
|
function parseItems(content, channel) {
|
||||||
const [, channelId] = channel.site_id.split('#')
|
const [, channelId] = channel.site_id.split('#')
|
||||||
const data = JSON.parse(content)
|
const data = JSON.parse(content)
|
||||||
if (!data || !Array.isArray(data.Channels)) return []
|
if (!data || !Array.isArray(data.Channels)) return []
|
||||||
const channelData = data.Channels.find(c => c.Number === channelId)
|
const channelData = data.Channels.find(c => c.Number === channelId)
|
||||||
if (!channelData || !Array.isArray(channelData.Programmes)) return []
|
if (!channelData || !Array.isArray(channelData.Programmes)) return []
|
||||||
|
|
||||||
return channelData.Programmes
|
return channelData.Programmes
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +1,38 @@
|
|||||||
const { url, parser } = require('./firstmedia.com.config.js')
|
const { url, parser } = require('./firstmedia.com.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2023-11-08').startOf('d')
|
const date = dayjs.utc('2023-11-08').startOf('d')
|
||||||
const channel = { site_id: '243', xmltv_id: 'AlJazeeraEnglish.qa', lang: 'id' }
|
const channel = { site_id: '243', xmltv_id: 'AlJazeeraEnglish.qa', lang: 'id' }
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://api.firstmedia.com/api/content/tv-guide/list?date=08/11/2023&channel=243&startTime=1&endTime=24'
|
'https://api.firstmedia.com/api/content/tv-guide/list?date=08/11/2023&channel=243&startTime=1&endTime=24'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'), 'utf8')
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'), 'utf8')
|
||||||
const results = parser({ content, channel, date })
|
const results = parser({ content, channel, date })
|
||||||
|
|
||||||
// All time in Asia/Jakarta
|
// All time in Asia/Jakarta
|
||||||
// 2023-11-08 17:00:00 -> 2023-11-08 20:00:00 = 2023-11-08 03:00:00
|
// 2023-11-08 17:00:00 -> 2023-11-08 20:00:00 = 2023-11-08 03:00:00
|
||||||
// 2023-11-08 17:00:00 -> 2023-11-08 20:30:00 = 2023-11-08 03:30:00
|
// 2023-11-08 17:00:00 -> 2023-11-08 20:30:00 = 2023-11-08 03:30:00
|
||||||
expect(results).toMatchObject([
|
expect(results).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2023-11-07T20:00:00.000Z',
|
start: '2023-11-07T20:00:00.000Z',
|
||||||
stop: '2023-11-07T20:30:00.000Z',
|
stop: '2023-11-07T20:30:00.000Z',
|
||||||
title: 'News Live',
|
title: 'News Live',
|
||||||
description: 'Up to date news and analysis from around the world.'
|
description: 'Up to date news and analysis from around the world.'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const results = parser({ content: '' })
|
const results = parser({ content: '' })
|
||||||
|
|
||||||
expect(results).toMatchObject([])
|
expect(results).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,43 +1,43 @@
|
|||||||
const { parser, url } = require('./foxsports.com.au.config.js')
|
const { parser, url } = require('./foxsports.com.au.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-12-14', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-12-14', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '2',
|
site_id: '2',
|
||||||
xmltv_id: 'FoxLeague.au'
|
xmltv_id: 'FoxLeague.au'
|
||||||
}
|
}
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date })).toBe(
|
expect(url({ date })).toBe(
|
||||||
'https://tvguide.foxsports.com.au/granite-api/programmes.json?from=2022-12-14&to=2022-12-15'
|
'https://tvguide.foxsports.com.au/granite-api/programmes.json?from=2022-12-14&to=2022-12-15'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
title: 'NRL',
|
title: 'NRL',
|
||||||
sub_title: 'Eels v Titans',
|
sub_title: 'Eels v Titans',
|
||||||
description:
|
description:
|
||||||
'The Eels and Titans have plenty of motivation this season after heartbreaking Finals losses in 2021. Parramatta has won their past five against Gold Coast.',
|
'The Eels and Titans have plenty of motivation this season after heartbreaking Finals losses in 2021. Parramatta has won their past five against Gold Coast.',
|
||||||
category: 'Rugby League',
|
category: 'Rugby League',
|
||||||
start: '2022-12-13T13:00:00.000Z',
|
start: '2022-12-13T13:00:00.000Z',
|
||||||
stop: '2022-12-13T14:00:00.000Z'
|
stop: '2022-12-13T14:00:00.000Z'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({content: ''}, channel)
|
const result = parser({content: ''}, channel)
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
const { parser, url } = require('./freetv.tv.config.js')
|
const { parser, url } = require('./freetv.tv.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2025-03-28', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2025-03-28', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '3370462',
|
site_id: '3370462',
|
||||||
xmltv_id: 'Kan11.il'
|
xmltv_id: 'Kan11.il'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe('https://web.freetv.tv/api/products/lives/programmes?liveId[]=3370462&since=2025-03-28T00%3A00%2B0200&till=2025-03-29T00%3A00%2B0300&lang=HEB&platform=BROWSER')
|
expect(url({ channel, date })).toBe('https://web.freetv.tv/api/products/lives/programmes?liveId[]=3370462&since=2025-03-28T00%3A00%2B0200&till=2025-03-29T00%3A00%2B0300&lang=HEB&platform=BROWSER')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const results = parser({ content }).map(p => {
|
const results = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(results.length).toBe(2)
|
expect(results.length).toBe(2)
|
||||||
expect(results[0]).toMatchObject({
|
expect(results[0]).toMatchObject({
|
||||||
title: 'בוש 4 - פרק 3',
|
title: 'בוש 4 - פרק 3',
|
||||||
description: 'עונה 4 חדשה לדרמה הבלשית. 3. השטן בתוך הבית: הכוח המיוחד מנסה לחקור, ומגלה אליבי שקרי עם השלכות מרעישות. הבלש סנטיאגו רוברטסון צריך לשים את קשריו האישיים בצד למען החקירה. בוש זוכה לביקור פתע לילי.כ עב',
|
description: 'עונה 4 חדשה לדרמה הבלשית. 3. השטן בתוך הבית: הכוח המיוחד מנסה לחקור, ומגלה אליבי שקרי עם השלכות מרעישות. הבלש סנטיאגו רוברטסון צריך לשים את קשריו האישיים בצד למען החקירה. בוש זוכה לביקור פתע לילי.כ עב',
|
||||||
image: 'https://d1zqtf09wb8nt5.cloudfront.net/scale/oil/freetv/upload/programme/1361162/COVER/images/1361162_1736767668746.jpg?dsth=177&dstw=315&srcmode=0&srcx=0&srcy=0&quality=65&type=1&srcw=1/1&srch=1/1',
|
image: 'https://d1zqtf09wb8nt5.cloudfront.net/scale/oil/freetv/upload/programme/1361162/COVER/images/1361162_1736767668746.jpg?dsth=177&dstw=315&srcmode=0&srcx=0&srcy=0&quality=65&type=1&srcw=1/1&srch=1/1',
|
||||||
icon: 'https://d1zqtf09wb8nt5.cloudfront.net/scale/oil/freetv/upload/programme/1361162/COVER/images/1361162_1736767668746.jpg?dsth=177&dstw=315&srcmode=0&srcx=0&srcy=0&quality=65&type=1&srcw=1/1&srch=1/1',
|
icon: 'https://d1zqtf09wb8nt5.cloudfront.net/scale/oil/freetv/upload/programme/1361162/COVER/images/1361162_1736767668746.jpg?dsth=177&dstw=315&srcmode=0&srcx=0&srcy=0&quality=65&type=1&srcw=1/1&srch=1/1',
|
||||||
start: '2025-03-27T21:26:00.000Z',
|
start: '2025-03-27T21:26:00.000Z',
|
||||||
stop: '2025-03-27T22:17:00.000Z'
|
stop: '2025-03-27T22:17:00.000Z'
|
||||||
})
|
})
|
||||||
expect(results[1]).toMatchObject({
|
expect(results[1]).toMatchObject({
|
||||||
title: 'אבא משתדל - 5. חבר',
|
title: 'אבא משתדל - 5. חבר',
|
||||||
description: 'סדרה קומית. יוסי מכיר אב לילד עם צרכים מיוחדים ובין השניים מתפתח קשר בסגנון חיזור גורלי שמערער את יוסי. כ עב.',
|
description: 'סדרה קומית. יוסי מכיר אב לילד עם צרכים מיוחדים ובין השניים מתפתח קשר בסגנון חיזור גורלי שמערער את יוסי. כ עב.',
|
||||||
image: 'https://d1zqtf09wb8nt5.cloudfront.net/scale/oil/freetv/upload/programme/1070668/COVER/images/1070668_1742202219830.jpg?dsth=177&dstw=315&srcmode=0&srcx=0&srcy=0&quality=65&type=1&srcw=1/1&srch=1/1',
|
image: 'https://d1zqtf09wb8nt5.cloudfront.net/scale/oil/freetv/upload/programme/1070668/COVER/images/1070668_1742202219830.jpg?dsth=177&dstw=315&srcmode=0&srcx=0&srcy=0&quality=65&type=1&srcw=1/1&srch=1/1',
|
||||||
icon: 'https://d1zqtf09wb8nt5.cloudfront.net/scale/oil/freetv/upload/programme/1070668/COVER/images/1070668_1742202219830.jpg?dsth=177&dstw=315&srcmode=0&srcx=0&srcy=0&quality=65&type=1&srcw=1/1&srch=1/1',
|
icon: 'https://d1zqtf09wb8nt5.cloudfront.net/scale/oil/freetv/upload/programme/1070668/COVER/images/1070668_1742202219830.jpg?dsth=177&dstw=315&srcmode=0&srcx=0&srcy=0&quality=65&type=1&srcw=1/1&srch=1/1',
|
||||||
start: '2025-03-27T22:17:00.000Z',
|
start: '2025-03-27T22:17:00.000Z',
|
||||||
stop: '2025-03-27T22:43:00.000Z'
|
stop: '2025-03-27T22:43:00.000Z'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const results = parser({ content: '' })
|
const results = parser({ content: '' })
|
||||||
|
|
||||||
expect(results).toMatchObject([])
|
expect(results).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,48 +1,48 @@
|
|||||||
const { parser, url } = require('./frikanalen.no.config.js')
|
const { parser, url } = require('./frikanalen.no.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-01-19', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-01-19', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '#',
|
site_id: '#',
|
||||||
xmltv_id: 'Frikanalen.no'
|
xmltv_id: 'Frikanalen.no'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date })).toBe(
|
expect(url({ date })).toBe(
|
||||||
'https://frikanalen.no/api/scheduleitems/?date=2022-01-19&format=json&limit=100'
|
'https://frikanalen.no/api/scheduleitems/?date=2022-01-19&format=json&limit=100'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-01-18T23:47:00.000Z',
|
start: '2022-01-18T23:47:00.000Z',
|
||||||
stop: '2022-01-19T00:44:55.640Z',
|
stop: '2022-01-19T00:44:55.640Z',
|
||||||
title: 'FSCONS 2017 - Keynote: TBA - Linda Sandvik',
|
title: 'FSCONS 2017 - Keynote: TBA - Linda Sandvik',
|
||||||
category: ['Samfunn'],
|
category: ['Samfunn'],
|
||||||
description: "Linda Sandvik's keynote at FSCONS 2017\r\n\r\nRecorded by NUUG for FSCONS."
|
description: "Linda Sandvik's keynote at FSCONS 2017\r\n\r\nRecorded by NUUG for FSCONS."
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,52 +1,52 @@
|
|||||||
const { parser, url } = require('./galamtv.kz.config.js')
|
const { parser, url } = require('./galamtv.kz.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
|
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2025-01-10', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2025-01-10', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '636e54cf8a8f73bae8244f41',
|
site_id: '636e54cf8a8f73bae8244f41',
|
||||||
xmltv_id: 'Qazaqstan.kz'
|
xmltv_id: 'Qazaqstan.kz'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date, channel })).toBe(
|
expect(url({ date, channel })).toBe(
|
||||||
`https://galam.server-api.lfstrm.tv/channels/${
|
`https://galam.server-api.lfstrm.tv/channels/${
|
||||||
channel.site_id
|
channel.site_id
|
||||||
}/programs?period=${date.unix()}:${date.add(1, 'day').unix()}`
|
}/programs?period=${date.unix()}:${date.add(1, 'day').unix()}`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2025-01-10T01:00:00.000Z',
|
start: '2025-01-10T01:00:00.000Z',
|
||||||
stop: '2025-01-10T01:05:00.000Z',
|
stop: '2025-01-10T01:05:00.000Z',
|
||||||
title: 'Гимн',
|
title: 'Гимн',
|
||||||
description: 'Государственный гимн Республики Казахстан',
|
description: 'Государственный гимн Республики Казахстан',
|
||||||
image:
|
image:
|
||||||
'http://galam.server-img.lfstrm.tv:80/image/aHR0cDovL2dhbGFtLmltZy1vcmlnaW5hbHMubGZzdHJtLnR2OjgwL3R2aW1hZ2VzL3RodW1iL2YyNWFmYWY2ZDkzYjU5YjdkMjBiZDNiODhiZjg4NWI0X29yaWcuanBn'
|
'http://galam.server-img.lfstrm.tv:80/image/aHR0cDovL2dhbGFtLmltZy1vcmlnaW5hbHMubGZzdHJtLnR2OjgwL3R2aW1hZ2VzL3RodW1iL2YyNWFmYWY2ZDkzYjU5YjdkMjBiZDNiODhiZjg4NWI0X29yaWcuanBn'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,98 +1,98 @@
|
|||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const cheerio = require('cheerio')
|
const cheerio = require('cheerio')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
const { uniqBy } = require('../../scripts/functions')
|
const { uniqBy } = require('../../scripts/functions')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'guida.tv',
|
site: 'guida.tv',
|
||||||
days: 2,
|
days: 2,
|
||||||
url: function ({ date, channel }) {
|
url: function ({ date, channel }) {
|
||||||
return `https://www.guida.tv/programmi-tv/palinsesto/canale/${
|
return `https://www.guida.tv/programmi-tv/palinsesto/canale/${
|
||||||
channel.site_id
|
channel.site_id
|
||||||
}.html?dt=${date.format('YYYY-MM-DD')}`
|
}.html?dt=${date.format('YYYY-MM-DD')}`
|
||||||
},
|
},
|
||||||
parser: function ({ content, date, channel }) {
|
parser: function ({ content, date, channel }) {
|
||||||
const programs = []
|
const programs = []
|
||||||
const items = parseItems(content)
|
const items = parseItems(content)
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
const prev = programs[programs.length - 1]
|
const prev = programs[programs.length - 1]
|
||||||
const $item = cheerio.load(item)
|
const $item = cheerio.load(item)
|
||||||
let start = parseStart($item, date, channel)
|
let start = parseStart($item, date, channel)
|
||||||
if (prev) {
|
if (prev) {
|
||||||
if (start.isBefore(prev.start)) {
|
if (start.isBefore(prev.start)) {
|
||||||
start = start.add(1, 'd')
|
start = start.add(1, 'd')
|
||||||
date = date.add(1, 'd')
|
date = date.add(1, 'd')
|
||||||
}
|
}
|
||||||
prev.stop = start
|
prev.stop = start
|
||||||
}
|
}
|
||||||
const stop = start.add(30, 'm')
|
const stop = start.add(30, 'm')
|
||||||
programs.push({
|
programs.push({
|
||||||
title: parseTitle($item),
|
title: parseTitle($item),
|
||||||
start,
|
start,
|
||||||
stop
|
stop
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels() {
|
async channels() {
|
||||||
const providers = ['-1', '-2', '-3']
|
const providers = ['-1', '-2', '-3']
|
||||||
|
|
||||||
const channels = []
|
const channels = []
|
||||||
for (let provider of providers) {
|
for (let provider of providers) {
|
||||||
const data = await axios
|
const data = await axios
|
||||||
.post('https://www.guida.tv/guide/schedule', null, {
|
.post('https://www.guida.tv/guide/schedule', null, {
|
||||||
params: {
|
params: {
|
||||||
provider,
|
provider,
|
||||||
region: 'Italy',
|
region: 'Italy',
|
||||||
TVperiod: 'Night',
|
TVperiod: 'Night',
|
||||||
date: dayjs().format('YYYY-MM-DD'),
|
date: dayjs().format('YYYY-MM-DD'),
|
||||||
st: 0,
|
st: 0,
|
||||||
u_time: 1429,
|
u_time: 1429,
|
||||||
is_mobile: 1
|
is_mobile: 1
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
|
|
||||||
const $ = cheerio.load(data)
|
const $ = cheerio.load(data)
|
||||||
$('.channelname').each((i, el) => {
|
$('.channelname').each((i, el) => {
|
||||||
const name = $(el).find('center > a:eq(1)').text()
|
const name = $(el).find('center > a:eq(1)').text()
|
||||||
const url = $(el).find('center > a:eq(1)').attr('href')
|
const url = $(el).find('center > a:eq(1)').attr('href')
|
||||||
const [, number, slug] = url.match(/\/(\d+)\/(.*)\.html$/)
|
const [, number, slug] = url.match(/\/(\d+)\/(.*)\.html$/)
|
||||||
|
|
||||||
channels.push({
|
channels.push({
|
||||||
lang: 'it',
|
lang: 'it',
|
||||||
name,
|
name,
|
||||||
site_id: `${number}/${slug}`
|
site_id: `${number}/${slug}`
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return uniqBy(channels, 'site_id')
|
return uniqBy(channels, 'site_id')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStart($item, date) {
|
function parseStart($item, date) {
|
||||||
const timeString = $item('td:eq(0)').text().trim()
|
const timeString = $item('td:eq(0)').text().trim()
|
||||||
const dateString = `${date.format('YYYY-MM-DD')} ${timeString}`
|
const dateString = `${date.format('YYYY-MM-DD')} ${timeString}`
|
||||||
|
|
||||||
return dayjs.tz(dateString, 'YYYY-MM-DD HH:mm', 'Europe/Rome')
|
return dayjs.tz(dateString, 'YYYY-MM-DD HH:mm', 'Europe/Rome')
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTitle($item) {
|
function parseTitle($item) {
|
||||||
return $item('td:eq(1)').text().trim()
|
return $item('td:eq(1)').text().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(content) {
|
function parseItems(content) {
|
||||||
const $ = cheerio.load(content)
|
const $ = cheerio.load(content)
|
||||||
|
|
||||||
return $('table.table > tbody > tr').toArray()
|
return $('table.table > tbody > tr').toArray()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +1,52 @@
|
|||||||
const { parser, url } = require('./guidatv.sky.it.config.js')
|
const { parser, url } = require('./guidatv.sky.it.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-05-06', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-05-06', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: 'DTH#10458',
|
site_id: 'DTH#10458',
|
||||||
xmltv_id: '20Mediaset.it'
|
xmltv_id: '20Mediaset.it'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://apid.sky.it/gtv/v1/events?from=2022-05-06T00:00:00Z&to=2022-05-07T00:00:00Z&pageSize=999&pageNum=0&env=DTH&channels=10458'
|
'https://apid.sky.it/gtv/v1/events?from=2022-05-06T00:00:00Z&to=2022-05-07T00:00:00Z&pageSize=999&pageNum=0&env=DTH&channels=10458'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-05-06T00:35:40.000Z',
|
start: '2022-05-06T00:35:40.000Z',
|
||||||
stop: '2022-05-06T01:15:40.000Z',
|
stop: '2022-05-06T01:15:40.000Z',
|
||||||
title: 'Distretto di Polizia',
|
title: 'Distretto di Polizia',
|
||||||
description:
|
description:
|
||||||
"S6 Ep26 La resa dei conti - Fino all'ultimo la sfida tra Ardenzi e Carrano, nemici di vecchia data, riserva clamorosi colpi di scena. E si scopre che non e' tutto come sembrava.",
|
"S6 Ep26 La resa dei conti - Fino all'ultimo la sfida tra Ardenzi e Carrano, nemici di vecchia data, riserva clamorosi colpi di scena. E si scopre che non e' tutto come sembrava.",
|
||||||
season: 6,
|
season: 6,
|
||||||
episode: 26,
|
episode: 26,
|
||||||
image:
|
image:
|
||||||
'https://guidatv.sky.it/uuid/77c630aa-4744-44cb-a88e-3e871c6b73d9/cover?md5ChecksumParam=61135b999a63e3d3f4a933b9edeb0c1b',
|
'https://guidatv.sky.it/uuid/77c630aa-4744-44cb-a88e-3e871c6b73d9/cover?md5ChecksumParam=61135b999a63e3d3f4a933b9edeb0c1b',
|
||||||
category: 'Intrattenimento/Fiction',
|
category: 'Intrattenimento/Fiction',
|
||||||
url: 'https://guidatv.sky.it/serie-tv/distretto-di-polizia/stagione-6/episodio-26/77c630aa-4744-44cb-a88e-3e871c6b73d9'
|
url: 'https://guidatv.sky.it/serie-tv/distretto-di-polizia/stagione-6/episodio-26/77c630aa-4744-44cb-a88e-3e871c6b73d9'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,338 +1,338 @@
|
|||||||
const cheerio = require('cheerio')
|
const cheerio = require('cheerio')
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
require('dayjs/locale/fr')
|
require('dayjs/locale/fr')
|
||||||
|
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
|
|
||||||
const PARIS_TZ = 'Europe/Paris'
|
const PARIS_TZ = 'Europe/Paris'
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'guidetnt.com',
|
site: 'guidetnt.com',
|
||||||
days: 2,
|
days: 2,
|
||||||
url({ channel, date }) {
|
url({ channel, date }) {
|
||||||
const now = dayjs()
|
const now = dayjs()
|
||||||
const demain = now.add(1, 'd')
|
const demain = now.add(1, 'd')
|
||||||
if (date && date.isSame(demain, 'day')) {
|
if (date && date.isSame(demain, 'day')) {
|
||||||
return `https://www.guidetnt.com/tv-demain/programme-${channel.site_id}`
|
return `https://www.guidetnt.com/tv-demain/programme-${channel.site_id}`
|
||||||
} else if (!date || date.isSame(now, 'day')) {
|
} else if (!date || date.isSame(now, 'day')) {
|
||||||
return `https://www.guidetnt.com/tv/programme-${channel.site_id}`
|
return `https://www.guidetnt.com/tv/programme-${channel.site_id}`
|
||||||
} else {
|
} else {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async parser({ content, date }) {
|
async parser({ content, date }) {
|
||||||
const programs = []
|
const programs = []
|
||||||
const allItems = parseItems(content)
|
const allItems = parseItems(content)
|
||||||
const items = allItems?.rows
|
const items = allItems?.rows
|
||||||
const itemDate = allItems?.formattedDate
|
const itemDate = allItems?.formattedDate
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
const prev = programs[programs.length - 1]
|
const prev = programs[programs.length - 1]
|
||||||
const $item = cheerio.load(item)
|
const $item = cheerio.load(item)
|
||||||
const title = parseTitle($item)
|
const title = parseTitle($item)
|
||||||
let start = parseStart($item, itemDate)
|
let start = parseStart($item, itemDate)
|
||||||
|
|
||||||
if (!start || !title) return
|
if (!start || !title) return
|
||||||
if (prev) {
|
if (prev) {
|
||||||
if (start.isBefore(prev.start)) {
|
if (start.isBefore(prev.start)) {
|
||||||
start = start.add(1, 'd')
|
start = start.add(1, 'd')
|
||||||
date = date.add(1, 'd')
|
date = date.add(1, 'd')
|
||||||
}
|
}
|
||||||
prev.stop = start
|
prev.stop = start
|
||||||
}
|
}
|
||||||
let stop = start.add(30, 'm')
|
let stop = start.add(30, 'm')
|
||||||
|
|
||||||
let itemDetails = null
|
let itemDetails = null
|
||||||
let subTitle = null
|
let subTitle = null
|
||||||
//let duration = null
|
//let duration = null
|
||||||
let country = null
|
let country = null
|
||||||
let productionDate = null
|
let productionDate = null
|
||||||
let episode = null
|
let episode = null
|
||||||
let season = null
|
let season = null
|
||||||
let category = parseCategory($item)
|
let category = parseCategory($item)
|
||||||
let description = parseDescription($item)
|
let description = parseDescription($item)
|
||||||
const itemDetailsURL = parseDescriptionURL($item)
|
const itemDetailsURL = parseDescriptionURL($item)
|
||||||
if (itemDetailsURL) {
|
if (itemDetailsURL) {
|
||||||
const url = 'https://www.guidetnt.com' + itemDetailsURL
|
const url = 'https://www.guidetnt.com' + itemDetailsURL
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(url)
|
const response = await axios.get(url)
|
||||||
itemDetails = parseItemDetails(response.data)
|
itemDetails = parseItemDetails(response.data)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`Erreur lors du fetch des détails pour l'item: ${url}`, err)
|
console.error(`Erreur lors du fetch des détails pour l'item: ${url}`, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeRange = parseTimeRange(itemDetails?.programHour, date.format('YYYY-MM-DD'))
|
const timeRange = parseTimeRange(itemDetails?.programHour, date.format('YYYY-MM-DD'))
|
||||||
start = timeRange?.start
|
start = timeRange?.start
|
||||||
stop = timeRange?.stop
|
stop = timeRange?.stop
|
||||||
|
|
||||||
subTitle = itemDetails?.subTitle
|
subTitle = itemDetails?.subTitle
|
||||||
if (title == subTitle) subTitle = null
|
if (title == subTitle) subTitle = null
|
||||||
description = itemDetails?.description
|
description = itemDetails?.description
|
||||||
|
|
||||||
const categoryDetails = parseCategoryText(itemDetails?.category)
|
const categoryDetails = parseCategoryText(itemDetails?.category)
|
||||||
//duration = categoryDetails?.duration
|
//duration = categoryDetails?.duration
|
||||||
country = categoryDetails?.country
|
country = categoryDetails?.country
|
||||||
productionDate = categoryDetails?.productionDate
|
productionDate = categoryDetails?.productionDate
|
||||||
season = categoryDetails?.season
|
season = categoryDetails?.season
|
||||||
episode = categoryDetails?.episode
|
episode = categoryDetails?.episode
|
||||||
}
|
}
|
||||||
// See https://www.npmjs.com/package/epg-parser for parameters
|
// See https://www.npmjs.com/package/epg-parser for parameters
|
||||||
programs.push({
|
programs.push({
|
||||||
title,
|
title,
|
||||||
subTitle: subTitle,
|
subTitle: subTitle,
|
||||||
description: description,
|
description: description,
|
||||||
image: itemDetails?.image,
|
image: itemDetails?.image,
|
||||||
category: category,
|
category: category,
|
||||||
directors: itemDetails?.directorActors?.Réalisateur,
|
directors: itemDetails?.directorActors?.Réalisateur,
|
||||||
actors: itemDetails?.directorActors?.Acteur,
|
actors: itemDetails?.directorActors?.Acteur,
|
||||||
country: country,
|
country: country,
|
||||||
date: productionDate,
|
date: productionDate,
|
||||||
//duration: duration, // Tried with length: too, but does not work ! (stop-start is not accurate because of Ads)
|
//duration: duration, // Tried with length: too, but does not work ! (stop-start is not accurate because of Ads)
|
||||||
season: season,
|
season: season,
|
||||||
episode: episode,
|
episode: episode,
|
||||||
start,
|
start,
|
||||||
stop
|
stop
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels() {
|
async channels() {
|
||||||
const response = await axios.get('https://www.guidetnt.com')
|
const response = await axios.get('https://www.guidetnt.com')
|
||||||
const channels = []
|
const channels = []
|
||||||
const $ = cheerio.load(response.data)
|
const $ = cheerio.load(response.data)
|
||||||
|
|
||||||
// Look inside each .tvlogo container
|
// Look inside each .tvlogo container
|
||||||
$('.tvlogo').each((i, el) => {
|
$('.tvlogo').each((i, el) => {
|
||||||
// Find all descendants that have an alt attribute
|
// Find all descendants that have an alt attribute
|
||||||
$(el)
|
$(el)
|
||||||
.find('[alt]')
|
.find('[alt]')
|
||||||
.each((j, subEl) => {
|
.each((j, subEl) => {
|
||||||
const alt = $(subEl).attr('alt')
|
const alt = $(subEl).attr('alt')
|
||||||
const href = $(subEl).attr('href')
|
const href = $(subEl).attr('href')
|
||||||
if (href && alt && alt.trim() !== '') {
|
if (href && alt && alt.trim() !== '') {
|
||||||
const name = alt.trim()
|
const name = alt.trim()
|
||||||
const site_id = href.replace(/^\/tv\/programme-/, '')
|
const site_id = href.replace(/^\/tv\/programme-/, '')
|
||||||
channels.push({
|
channels.push({
|
||||||
lang: 'fr',
|
lang: 'fr',
|
||||||
name,
|
name,
|
||||||
site_id
|
site_id
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
return channels
|
return channels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTimeRange(timeRange, baseDate) {
|
function parseTimeRange(timeRange, baseDate) {
|
||||||
// Split times
|
// Split times
|
||||||
const [startStr, endStr] = timeRange.split(' - ').map(s => s.trim())
|
const [startStr, endStr] = timeRange.split(' - ').map(s => s.trim())
|
||||||
|
|
||||||
// Parse with base date
|
// Parse with base date
|
||||||
const start = dayjs(`${baseDate} ${startStr}`, 'YYYY-MM-DD HH:mm')
|
const start = dayjs(`${baseDate} ${startStr}`, 'YYYY-MM-DD HH:mm')
|
||||||
let end = dayjs(`${baseDate} ${endStr}`, 'YYYY-MM-DD HH:mm')
|
let end = dayjs(`${baseDate} ${endStr}`, 'YYYY-MM-DD HH:mm')
|
||||||
|
|
||||||
// Handle possible day wrap (e.g., 23:30 - 00:15)
|
// Handle possible day wrap (e.g., 23:30 - 00:15)
|
||||||
if (end.isBefore(start)) {
|
if (end.isBefore(start)) {
|
||||||
end = end.add(1, 'day')
|
end = end.add(1, 'day')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate duration in minutes
|
// Calculate duration in minutes
|
||||||
const diffMinutes = end.diff(start, 'minute')
|
const diffMinutes = end.diff(start, 'minute')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
start: start.format(),
|
start: start.format(),
|
||||||
stop: end.format(),
|
stop: end.format(),
|
||||||
duration: diffMinutes
|
duration: diffMinutes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItemDetails(itemDetails) {
|
function parseItemDetails(itemDetails) {
|
||||||
const $ = cheerio.load(itemDetails)
|
const $ = cheerio.load(itemDetails)
|
||||||
|
|
||||||
const program = $('.program-wrapper').first()
|
const program = $('.program-wrapper').first()
|
||||||
|
|
||||||
const programHour = program.find('.program-hour').text().trim()
|
const programHour = program.find('.program-hour').text().trim()
|
||||||
const programTitle = program.find('.program-title').text().trim()
|
const programTitle = program.find('.program-title').text().trim()
|
||||||
const programElementBold = program.find('.program-element-bold').text().trim()
|
const programElementBold = program.find('.program-element-bold').text().trim()
|
||||||
const programArea1 = program.find('.program-element.program-area-1').text().trim()
|
const programArea1 = program.find('.program-element.program-area-1').text().trim()
|
||||||
|
|
||||||
let description = ''
|
let description = ''
|
||||||
const programElements = $('.program-element').filter((i, el) => {
|
const programElements = $('.program-element').filter((i, el) => {
|
||||||
const classAttr = $(el).attr('class')
|
const classAttr = $(el).attr('class')
|
||||||
// Return true only if it is exactly "program-element" (no extra classes)
|
// Return true only if it is exactly "program-element" (no extra classes)
|
||||||
return classAttr.trim() === 'program-element'
|
return classAttr.trim() === 'program-element'
|
||||||
})
|
})
|
||||||
|
|
||||||
programElements.each((i, el) => {
|
programElements.each((i, el) => {
|
||||||
description += $(el).text().trim()
|
description += $(el).text().trim()
|
||||||
})
|
})
|
||||||
|
|
||||||
const area2Node = $('.program-area-2').first()
|
const area2Node = $('.program-area-2').first()
|
||||||
const area2 = $(area2Node)
|
const area2 = $(area2Node)
|
||||||
const data = {}
|
const data = {}
|
||||||
let currentLabel = null
|
let currentLabel = null
|
||||||
let texts = []
|
let texts = []
|
||||||
|
|
||||||
area2.contents().each((i, node) => {
|
area2.contents().each((i, node) => {
|
||||||
if (node.type === 'tag' && node.name === 'strong') {
|
if (node.type === 'tag' && node.name === 'strong') {
|
||||||
// If we had collected some text for the previous label, save it
|
// If we had collected some text for the previous label, save it
|
||||||
if (currentLabel && texts.length) {
|
if (currentLabel && texts.length) {
|
||||||
data[currentLabel] = texts.join('').trim().replace(/,\s*$/, '') // Remove trailing comma
|
data[currentLabel] = texts.join('').trim().replace(/,\s*$/, '') // Remove trailing comma
|
||||||
}
|
}
|
||||||
// New label - get text without colon
|
// New label - get text without colon
|
||||||
currentLabel = $(node).text().replace(/:$/, '').trim()
|
currentLabel = $(node).text().replace(/:$/, '').trim()
|
||||||
texts = []
|
texts = []
|
||||||
} else if (currentLabel) {
|
} else if (currentLabel) {
|
||||||
// Append the text content (text node or others)
|
// Append the text content (text node or others)
|
||||||
if (node.type === 'text') {
|
if (node.type === 'text') {
|
||||||
texts.push(node.data)
|
texts.push(node.data)
|
||||||
} else if (node.type === 'tag' && node.name !== 'strong' && node.name !== 'br') {
|
} else if (node.type === 'tag' && node.name !== 'strong' && node.name !== 'br') {
|
||||||
texts.push($(node).text())
|
texts.push($(node).text())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Save last label text
|
// Save last label text
|
||||||
if (currentLabel && texts.length) {
|
if (currentLabel && texts.length) {
|
||||||
data[currentLabel] = texts.join('').trim().replace(/,\s*$/, '')
|
data[currentLabel] = texts.join('').trim().replace(/,\s*$/, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
const imgSrc = program.find('div[style*="float:left"]')?.find('img')?.attr('src') || null
|
const imgSrc = program.find('div[style*="float:left"]')?.find('img')?.attr('src') || null
|
||||||
|
|
||||||
return {
|
return {
|
||||||
programHour,
|
programHour,
|
||||||
title: programTitle,
|
title: programTitle,
|
||||||
subTitle: programElementBold,
|
subTitle: programElementBold,
|
||||||
category: programArea1,
|
category: programArea1,
|
||||||
description: description,
|
description: description,
|
||||||
directorActors: data,
|
directorActors: data,
|
||||||
image: imgSrc
|
image: imgSrc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseCategoryText(text) {
|
function parseCategoryText(text) {
|
||||||
if (!text) return null
|
if (!text) return null
|
||||||
|
|
||||||
const parts = text
|
const parts = text
|
||||||
.split(',')
|
.split(',')
|
||||||
.map(s => s.trim())
|
.map(s => s.trim())
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
const len = parts.length
|
const len = parts.length
|
||||||
|
|
||||||
const category = parts[0] || null
|
const category = parts[0] || null
|
||||||
|
|
||||||
if (len < 3) {
|
if (len < 3) {
|
||||||
return {
|
return {
|
||||||
category: category,
|
category: category,
|
||||||
duration: null,
|
duration: null,
|
||||||
country: null,
|
country: null,
|
||||||
productionDate: null,
|
productionDate: null,
|
||||||
season: null,
|
season: null,
|
||||||
episode: null
|
episode: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check last part: date if numeric
|
// Check last part: date if numeric
|
||||||
const dateCandidate = parts[len - 1]
|
const dateCandidate = parts[len - 1]
|
||||||
const productionDate = /^\d{4}$/.test(dateCandidate) ? dateCandidate : null
|
const productionDate = /^\d{4}$/.test(dateCandidate) ? dateCandidate : null
|
||||||
|
|
||||||
// Check for duration (first part containing "minutes")
|
// Check for duration (first part containing "minutes")
|
||||||
let durationMinute = null
|
let durationMinute = null
|
||||||
//let duration = null
|
//let duration = null
|
||||||
let episode = null
|
let episode = null
|
||||||
let season = null
|
let season = null
|
||||||
let durationIndex = -1
|
let durationIndex = -1
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
if (parts[i].toLowerCase().includes('minute')) {
|
if (parts[i].toLowerCase().includes('minute')) {
|
||||||
durationMinute = parts[i].trim()
|
durationMinute = parts[i].trim()
|
||||||
durationMinute = durationMinute.replace('minutes', '')
|
durationMinute = durationMinute.replace('minutes', '')
|
||||||
durationMinute = durationMinute.replace('minute', '')
|
durationMinute = durationMinute.replace('minute', '')
|
||||||
//duration = [{ units: 'minutes', value: durationMinute }],
|
//duration = [{ units: 'minutes', value: durationMinute }],
|
||||||
durationIndex = i
|
durationIndex = i
|
||||||
} else if (parts[i].toLowerCase().includes('épisode')) {
|
} else if (parts[i].toLowerCase().includes('épisode')) {
|
||||||
const match = text.match(/épisode\s+(\d+)(?:\/(\d+))?/i)
|
const match = text.match(/épisode\s+(\d+)(?:\/(\d+))?/i)
|
||||||
if (match) {
|
if (match) {
|
||||||
episode = parseInt(match[1], 10)
|
episode = parseInt(match[1], 10)
|
||||||
}
|
}
|
||||||
} else if (parts[i].toLowerCase().includes('saison')) {
|
} else if (parts[i].toLowerCase().includes('saison')) {
|
||||||
season = parts[i].replace('saison', '').trim()
|
season = parts[i].replace('saison', '').trim()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Country: second to last
|
// Country: second to last
|
||||||
const countryIndex = len - 2
|
const countryIndex = len - 2
|
||||||
let country = durationIndex === countryIndex ? null : parts[countryIndex]
|
let country = durationIndex === countryIndex ? null : parts[countryIndex]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
category,
|
category,
|
||||||
durationMinute,
|
durationMinute,
|
||||||
country,
|
country,
|
||||||
productionDate,
|
productionDate,
|
||||||
season,
|
season,
|
||||||
episode
|
episode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTitle($item) {
|
function parseTitle($item) {
|
||||||
return $item('.channel-programs-title a').text().trim()
|
return $item('.channel-programs-title a').text().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDescription($item) {
|
function parseDescription($item) {
|
||||||
return $item('#descr').text().trim() || null
|
return $item('#descr').text().trim() || null
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDescriptionURL($item) {
|
function parseDescriptionURL($item) {
|
||||||
const descrLink = $item('#descr a')
|
const descrLink = $item('#descr a')
|
||||||
return descrLink.attr('href') || null
|
return descrLink.attr('href') || null
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseCategory($item) {
|
function parseCategory($item) {
|
||||||
let type = null
|
let type = null
|
||||||
$item('.channel-programs-title span').each((i, span) => {
|
$item('.channel-programs-title span').each((i, span) => {
|
||||||
const className = $item(span).attr('class')
|
const className = $item(span).attr('class')
|
||||||
if (className && className.startsWith('text_bg')) {
|
if (className && className.startsWith('text_bg')) {
|
||||||
type = $item(span).text().trim()
|
type = $item(span).text().trim()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return type
|
return type
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStart($item, itemDate) {
|
function parseStart($item, itemDate) {
|
||||||
const dt = $item('.channel-programs-time a').text().trim()
|
const dt = $item('.channel-programs-time a').text().trim()
|
||||||
if (!dt) return null
|
if (!dt) return null
|
||||||
|
|
||||||
const datetimeStr = `${itemDate} ${dt}`
|
const datetimeStr = `${itemDate} ${dt}`
|
||||||
return dayjs.tz(datetimeStr, 'YYYY-MM-DD HH:mm', PARIS_TZ)
|
return dayjs.tz(datetimeStr, 'YYYY-MM-DD HH:mm', PARIS_TZ)
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(content) {
|
function parseItems(content) {
|
||||||
const $ = cheerio.load(content)
|
const $ = cheerio.load(content)
|
||||||
|
|
||||||
// Extract header information
|
// Extract header information
|
||||||
const logoSrc = $('#logo img').attr('src')
|
const logoSrc = $('#logo img').attr('src')
|
||||||
const title = $('#title h1').text().trim()
|
const title = $('#title h1').text().trim()
|
||||||
const subtitle = $('#subtitle').text().trim()
|
const subtitle = $('#subtitle').text().trim()
|
||||||
const dateMatch = subtitle.match(/(\d{1,2} \w+ \d{4})/)
|
const dateMatch = subtitle.match(/(\d{1,2} \w+ \d{4})/)
|
||||||
const dateStr = dateMatch ? dateMatch[1].toLowerCase() : null
|
const dateStr = dateMatch ? dateMatch[1].toLowerCase() : null
|
||||||
|
|
||||||
// Parse the French date string
|
// Parse the French date string
|
||||||
const parsedDate = dayjs(dateStr, 'D MMMM YYYY', 'fr')
|
const parsedDate = dayjs(dateStr, 'D MMMM YYYY', 'fr')
|
||||||
// Format it as YYYY-MM-DD
|
// Format it as YYYY-MM-DD
|
||||||
const formattedDate = parsedDate.format('YYYY-MM-DD')
|
const formattedDate = parsedDate.format('YYYY-MM-DD')
|
||||||
|
|
||||||
const rows = $('.channel-row').toArray()
|
const rows = $('.channel-row').toArray()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
rows,
|
rows,
|
||||||
logoSrc,
|
logoSrc,
|
||||||
title,
|
title,
|
||||||
formattedDate
|
formattedDate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,85 +1,85 @@
|
|||||||
const { parser, url } = require('./guidetnt.com.config.js')
|
const { parser, url } = require('./guidetnt.com.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
require('dayjs/locale/fr')
|
require('dayjs/locale/fr')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
|
|
||||||
const date = dayjs.utc('2025-07-01', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2025-07-01', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: 'tf1',
|
site_id: 'tf1',
|
||||||
xmltv_id: 'TF1.fr'
|
xmltv_id: 'TF1.fr'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel })).toBe('https://www.guidetnt.com/tv/programme-tf1')
|
expect(url({ channel })).toBe('https://www.guidetnt.com/tv/programme-tf1')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', async () => {
|
it('can parse response', async () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'))
|
||||||
let results = await parser({ content, date })
|
let results = await parser({ content, date })
|
||||||
results = results.map(p => {
|
results = results.map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(results.length).toBe(29)
|
expect(results.length).toBe(29)
|
||||||
expect(results[0]).toMatchObject({
|
expect(results[0]).toMatchObject({
|
||||||
category: 'Série',
|
category: 'Série',
|
||||||
description:
|
description:
|
||||||
"Grande effervescence pour toute l'équipe du Camping Paradis, qui prépare les Olympiades. Côté arrivants, Hélène et sa fille Eva viennent passer quelques jours dans le but d'optimiser les révisions d'E...",
|
"Grande effervescence pour toute l'équipe du Camping Paradis, qui prépare les Olympiades. Côté arrivants, Hélène et sa fille Eva viennent passer quelques jours dans le but d'optimiser les révisions d'E...",
|
||||||
start: '2025-06-30T22:55:00.000Z',
|
start: '2025-06-30T22:55:00.000Z',
|
||||||
stop: '2025-06-30T23:45:00.000Z',
|
stop: '2025-06-30T23:45:00.000Z',
|
||||||
title: 'Camping Paradis'
|
title: 'Camping Paradis'
|
||||||
})
|
})
|
||||||
expect(results[2]).toMatchObject({
|
expect(results[2]).toMatchObject({
|
||||||
category: 'Magazine',
|
category: 'Magazine',
|
||||||
description: 'Retrouvez tous vos programmes de nuit.',
|
description: 'Retrouvez tous vos programmes de nuit.',
|
||||||
start: '2025-07-01T00:55:00.000Z',
|
start: '2025-07-01T00:55:00.000Z',
|
||||||
stop: '2025-07-01T04:00:00.000Z',
|
stop: '2025-07-01T04:00:00.000Z',
|
||||||
title: 'Programmes de la nuit'
|
title: 'Programmes de la nuit'
|
||||||
})
|
})
|
||||||
expect(results[15]).toMatchObject({
|
expect(results[15]).toMatchObject({
|
||||||
category: 'Téléfilm',
|
category: 'Téléfilm',
|
||||||
description:
|
description:
|
||||||
"La vie quasi parfaite de Riley bascule brutalement lorsqu'un accident de voiture lui coûte la vie, laissant derrière elle sa famille. Alors que l'enquête débute, l'affaire prend une tournure étrange l...",
|
"La vie quasi parfaite de Riley bascule brutalement lorsqu'un accident de voiture lui coûte la vie, laissant derrière elle sa famille. Alors que l'enquête débute, l'affaire prend une tournure étrange l...",
|
||||||
start: '2025-07-01T12:25:00.000Z',
|
start: '2025-07-01T12:25:00.000Z',
|
||||||
stop: '2025-07-01T14:00:00.000Z',
|
stop: '2025-07-01T14:00:00.000Z',
|
||||||
title: "Trahie par l'amour"
|
title: "Trahie par l'amour"
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response for current day', async () => {
|
it('can parse response for current day', async () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'))
|
||||||
let results = await parser({ content, date: dayjs.utc('2025-07-01', 'YYYY-MM-DD').startOf('d') })
|
let results = await parser({ content, date: dayjs.utc('2025-07-01', 'YYYY-MM-DD').startOf('d') })
|
||||||
results = results.map(p => {
|
results = results.map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(results.length).toBe(29)
|
expect(results.length).toBe(29)
|
||||||
expect(results[0]).toMatchObject({
|
expect(results[0]).toMatchObject({
|
||||||
category: 'Série',
|
category: 'Série',
|
||||||
description:
|
description:
|
||||||
"Grande effervescence pour toute l'équipe du Camping Paradis, qui prépare les Olympiades. Côté arrivants, Hélène et sa fille Eva viennent passer quelques jours dans le but d'optimiser les révisions d'E...",
|
"Grande effervescence pour toute l'équipe du Camping Paradis, qui prépare les Olympiades. Côté arrivants, Hélène et sa fille Eva viennent passer quelques jours dans le but d'optimiser les révisions d'E...",
|
||||||
start: '2025-06-30T22:55:00.000Z',
|
start: '2025-06-30T22:55:00.000Z',
|
||||||
stop: '2025-06-30T23:45:00.000Z',
|
stop: '2025-06-30T23:45:00.000Z',
|
||||||
title: 'Camping Paradis'
|
title: 'Camping Paradis'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', async () => {
|
it('can handle empty guide', async () => {
|
||||||
const results = await parser({
|
const results = await parser({
|
||||||
date,
|
date,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'))
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(results).toEqual([])
|
expect(results).toEqual([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,246 +1,246 @@
|
|||||||
const { parser, url } = require('./horizon.tv.config.js')
|
const { parser, url } = require('./horizon.tv.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
jest.mock('axios')
|
jest.mock('axios')
|
||||||
|
|
||||||
const date = dayjs.utc('2023-02-07', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2023-02-07', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '10024',
|
site_id: '10024',
|
||||||
xmltv_id: 'AMCCzechRepublic.cz'
|
xmltv_id: 'AMCCzechRepublic.cz'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date, channel })).toBe(
|
expect(url({ date, channel })).toBe(
|
||||||
'https://legacy-static.oesp.horizon.tv/oesp/v4/SK/slk/web/programschedules/20230207/1'
|
'https://legacy-static.oesp.horizon.tv/oesp/v4/SK/slk/web/programschedules/20230207/1'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', done => {
|
it('can parse response', done => {
|
||||||
const content = JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content.json'), 'utf8'))
|
const content = JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content.json'), 'utf8'))
|
||||||
|
|
||||||
axios.get.mockImplementation(url => {
|
axios.get.mockImplementation(url => {
|
||||||
if (
|
if (
|
||||||
url === 'https://legacy-static.oesp.horizon.tv/oesp/v4/SK/slk/web/programschedules/20230207/2'
|
url === 'https://legacy-static.oesp.horizon.tv/oesp/v4/SK/slk/web/programschedules/20230207/2'
|
||||||
) {
|
) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content_1.json'), 'utf8'))
|
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content_1.json'), 'utf8'))
|
||||||
})
|
})
|
||||||
} else if (
|
} else if (
|
||||||
url === 'https://legacy-static.oesp.horizon.tv/oesp/v4/SK/slk/web/programschedules/20230207/3'
|
url === 'https://legacy-static.oesp.horizon.tv/oesp/v4/SK/slk/web/programschedules/20230207/3'
|
||||||
) {
|
) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content_2.json'), 'utf8'))
|
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content_2.json'), 'utf8'))
|
||||||
})
|
})
|
||||||
} else if (
|
} else if (
|
||||||
url === 'https://legacy-static.oesp.horizon.tv/oesp/v4/SK/slk/web/programschedules/20230207/4'
|
url === 'https://legacy-static.oesp.horizon.tv/oesp/v4/SK/slk/web/programschedules/20230207/4'
|
||||||
) {
|
) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content_3.json'), 'utf8'))
|
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content_3.json'), 'utf8'))
|
||||||
})
|
})
|
||||||
} else if (
|
} else if (
|
||||||
url === 'https://legacy-static.oesp.horizon.tv/oesp/v4/SK/slk/web/listings/crid:~~2F~~2Fport.cs~~2F122941980,imi:7ca159c917344e0dd3fbe1cd8db5ff8043d96a78'
|
url === 'https://legacy-static.oesp.horizon.tv/oesp/v4/SK/slk/web/listings/crid:~~2F~~2Fport.cs~~2F122941980,imi:7ca159c917344e0dd3fbe1cd8db5ff8043d96a78'
|
||||||
) {
|
) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content_listings_1.json'), 'utf8'))
|
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content_listings_1.json'), 'utf8'))
|
||||||
})
|
})
|
||||||
} else if (
|
} else if (
|
||||||
url === 'https://legacy-static.oesp.horizon.tv/oesp/v4/SK/slk/web/listings/crid:~~2F~~2Fport.cs~~2F248281986,imi:e85129f9d1e211406a521df7a36f22237c22651b'
|
url === 'https://legacy-static.oesp.horizon.tv/oesp/v4/SK/slk/web/listings/crid:~~2F~~2Fport.cs~~2F248281986,imi:e85129f9d1e211406a521df7a36f22237c22651b'
|
||||||
) {
|
) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content_listings_2.json'), 'utf8'))
|
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content_listings_2.json'), 'utf8'))
|
||||||
})
|
})
|
||||||
} else if (
|
} else if (
|
||||||
url === 'https://legacy-static.oesp.horizon.tv/oesp/v4/SK/slk/web/listings/crid:~~2F~~2Fport.cs~~2F1379541,imi:5f806a2a0bc13e9745e14907a27116c60ea2c6ad'
|
url === 'https://legacy-static.oesp.horizon.tv/oesp/v4/SK/slk/web/listings/crid:~~2F~~2Fport.cs~~2F1379541,imi:5f806a2a0bc13e9745e14907a27116c60ea2c6ad'
|
||||||
) {
|
) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content_listings_3.json'), 'utf8'))
|
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content_listings_3.json'), 'utf8'))
|
||||||
})
|
})
|
||||||
} else if (
|
} else if (
|
||||||
url === 'https://legacy-static.oesp.horizon.tv/oesp/v4/SK/slk/web/listings/crid:~~2F~~2Fport.cs~~2F71927954,imi:f1b4b0285b72cf44cba74e1c62322a4c682385c7'
|
url === 'https://legacy-static.oesp.horizon.tv/oesp/v4/SK/slk/web/listings/crid:~~2F~~2Fport.cs~~2F71927954,imi:f1b4b0285b72cf44cba74e1c62322a4c682385c7'
|
||||||
) {
|
) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content_listings_4.json'), 'utf8'))
|
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content_listings_4.json'), 'utf8'))
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
return Promise.resolve({ data: '' })
|
return Promise.resolve({ data: '' })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
parser({ content, channel, date })
|
parser({ content, channel, date })
|
||||||
.then(result => {
|
.then(result => {
|
||||||
result = result.map(p => {
|
result = result.map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2023-02-06T21:35:00.000Z',
|
start: '2023-02-06T21:35:00.000Z',
|
||||||
stop: '2023-02-06T23:05:00.000Z',
|
stop: '2023-02-06T23:05:00.000Z',
|
||||||
title: 'Avengement',
|
title: 'Avengement',
|
||||||
description:
|
description:
|
||||||
'Během propustky z vězení za účelem návštěvy umírající matky v nemocnici zločinec Cain Burgess (Scott Adkins) unikne svým dozorcům a mizí v ulicích Londýna. Jde o epickou cestu krve a bolesti za dosažením vytoužené pomsty na těch, kteří z něj udělali chladnokrevného vraha.',
|
'Během propustky z vězení za účelem návštěvy umírající matky v nemocnici zločinec Cain Burgess (Scott Adkins) unikne svým dozorcům a mizí v ulicích Londýna. Jde o epickou cestu krve a bolesti za dosažením vytoužené pomsty na těch, kteří z něj udělali chladnokrevného vraha.',
|
||||||
category: ['Drama', 'Akcia'],
|
category: ['Drama', 'Akcia'],
|
||||||
directors: ['Jesse V. Johnson'],
|
directors: ['Jesse V. Johnson'],
|
||||||
actors: [
|
actors: [
|
||||||
'Scott Adkins',
|
'Scott Adkins',
|
||||||
'Craig Fairbrass',
|
'Craig Fairbrass',
|
||||||
'Thomas Turgoose',
|
'Thomas Turgoose',
|
||||||
'Nick Moran',
|
'Nick Moran',
|
||||||
'Kierston Wareing',
|
'Kierston Wareing',
|
||||||
'Leo Gregory',
|
'Leo Gregory',
|
||||||
'Mark Strange',
|
'Mark Strange',
|
||||||
'Luke LaFontaine',
|
'Luke LaFontaine',
|
||||||
'Beau Fowler',
|
'Beau Fowler',
|
||||||
'Dan Styles',
|
'Dan Styles',
|
||||||
'Christopher Sciueref',
|
'Christopher Sciueref',
|
||||||
'Matt Routledge',
|
'Matt Routledge',
|
||||||
'Jane Thorne',
|
'Jane Thorne',
|
||||||
'Louis Mandylor',
|
'Louis Mandylor',
|
||||||
'Terence Maynard',
|
'Terence Maynard',
|
||||||
'Greg Burridge',
|
'Greg Burridge',
|
||||||
'Michael Higgs',
|
'Michael Higgs',
|
||||||
'Damian Gallagher',
|
'Damian Gallagher',
|
||||||
'Daniel Adegboyega',
|
'Daniel Adegboyega',
|
||||||
'John Ioannou',
|
'John Ioannou',
|
||||||
'Sofie Golding-Spittle',
|
'Sofie Golding-Spittle',
|
||||||
'Joe Egan',
|
'Joe Egan',
|
||||||
'Darren Swain',
|
'Darren Swain',
|
||||||
'Lee Charles',
|
'Lee Charles',
|
||||||
'Dominic Kinnaird',
|
'Dominic Kinnaird',
|
||||||
"Ross O'Hennessy",
|
"Ross O'Hennessy",
|
||||||
'Teresa Mahoney',
|
'Teresa Mahoney',
|
||||||
'Andrew Dunkelberger',
|
'Andrew Dunkelberger',
|
||||||
'Sam Hardy',
|
'Sam Hardy',
|
||||||
'Ivan Moy',
|
'Ivan Moy',
|
||||||
'Mark Sears',
|
'Mark Sears',
|
||||||
'Phillip Ray Tommy'
|
'Phillip Ray Tommy'
|
||||||
],
|
],
|
||||||
date: '2019'
|
date: '2019'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2023-02-07T04:35:00.000Z',
|
start: '2023-02-07T04:35:00.000Z',
|
||||||
stop: '2023-02-07T05:00:00.000Z',
|
stop: '2023-02-07T05:00:00.000Z',
|
||||||
title: 'Zoom In',
|
title: 'Zoom In',
|
||||||
description: 'Film/Kino',
|
description: 'Film/Kino',
|
||||||
category: ['Hudba a umenie', 'Film'],
|
category: ['Hudba a umenie', 'Film'],
|
||||||
date: '2010'
|
date: '2010'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2023-02-07T09:10:00.000Z',
|
start: '2023-02-07T09:10:00.000Z',
|
||||||
stop: '2023-02-07T11:00:00.000Z',
|
stop: '2023-02-07T11:00:00.000Z',
|
||||||
title: 'Studentka',
|
title: 'Studentka',
|
||||||
description:
|
description:
|
||||||
'Ambiciózní vysokoškolačka Valentina (Sophie Marceau) studuje literaturu na pařížské Sorbonně a právě se připravuje k závěrečným zkouškám. Žádný odpočinek, žádné volno, žádné večírky, téměř žádný spánek a především a hlavně ... žádná láska! Věří, že jedině tak obstojí před zkušební komisí. Jednoho dne se však odehraje něco, s čím nepočítala. Potká charismatického hudebníka Neda - a bláznivě se zamiluje. V tuto chvíli stojí před osudovým rozhodnutím: zahodí roky obrovského studijního nasazení, nebo odmítne lásku? Nebo se snad dá obojí skloubit dohromady?',
|
'Ambiciózní vysokoškolačka Valentina (Sophie Marceau) studuje literaturu na pařížské Sorbonně a právě se připravuje k závěrečným zkouškám. Žádný odpočinek, žádné volno, žádné večírky, téměř žádný spánek a především a hlavně ... žádná láska! Věří, že jedině tak obstojí před zkušební komisí. Jednoho dne se však odehraje něco, s čím nepočítala. Potká charismatického hudebníka Neda - a bláznivě se zamiluje. V tuto chvíli stojí před osudovým rozhodnutím: zahodí roky obrovského studijního nasazení, nebo odmítne lásku? Nebo se snad dá obojí skloubit dohromady?',
|
||||||
category: ['Film', 'Komédia'],
|
category: ['Film', 'Komédia'],
|
||||||
actors: [
|
actors: [
|
||||||
'Sophie Marceauová',
|
'Sophie Marceauová',
|
||||||
'Vincent Lindon',
|
'Vincent Lindon',
|
||||||
'Elisabeth Vitali',
|
'Elisabeth Vitali',
|
||||||
'Elena Pompei',
|
'Elena Pompei',
|
||||||
'Jean-Claude Leguay',
|
'Jean-Claude Leguay',
|
||||||
'Brigitte Chamarande',
|
'Brigitte Chamarande',
|
||||||
'Christian Pereira',
|
'Christian Pereira',
|
||||||
'Gérard Dacier',
|
'Gérard Dacier',
|
||||||
'Roberto Attias',
|
'Roberto Attias',
|
||||||
'Beppe Chierici',
|
'Beppe Chierici',
|
||||||
'Nathalie Mann',
|
'Nathalie Mann',
|
||||||
'Anne Macina',
|
'Anne Macina',
|
||||||
'Janine Souchon',
|
'Janine Souchon',
|
||||||
'Virginie Demians',
|
'Virginie Demians',
|
||||||
'Hugues Leforestier',
|
'Hugues Leforestier',
|
||||||
'Jacqueline Noëlle',
|
'Jacqueline Noëlle',
|
||||||
'Marc-André Brunet',
|
'Marc-André Brunet',
|
||||||
'Isabelle Caubère',
|
'Isabelle Caubère',
|
||||||
'André Chazel',
|
'André Chazel',
|
||||||
'Med Salah Cheurfi',
|
'Med Salah Cheurfi',
|
||||||
'Guillaume Corea',
|
'Guillaume Corea',
|
||||||
'Eric Denize',
|
'Eric Denize',
|
||||||
'Gilles Gaston-Dreyfuss',
|
'Gilles Gaston-Dreyfuss',
|
||||||
'Benoît Gourley',
|
'Benoît Gourley',
|
||||||
'Marc Innocenti',
|
'Marc Innocenti',
|
||||||
'Najim Laouriga',
|
'Najim Laouriga',
|
||||||
'Laurent Ledermann',
|
'Laurent Ledermann',
|
||||||
'Philippe Maygal',
|
'Philippe Maygal',
|
||||||
'Dominique Pifarely',
|
'Dominique Pifarely',
|
||||||
'Ysé Tran'
|
'Ysé Tran'
|
||||||
],
|
],
|
||||||
directors: ['Francis De Gueltz', 'Dominique Talmon', 'Claude Pinoteau'],
|
directors: ['Francis De Gueltz', 'Dominique Talmon', 'Claude Pinoteau'],
|
||||||
date: '1988'
|
date: '1988'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2023-02-07T16:05:00.000Z',
|
start: '2023-02-07T16:05:00.000Z',
|
||||||
stop: '2023-02-07T17:45:00.000Z',
|
stop: '2023-02-07T17:45:00.000Z',
|
||||||
title: 'Zilionáři',
|
title: 'Zilionáři',
|
||||||
description:
|
description:
|
||||||
'David (Zach Galifianakis) je nekomplikovaný muž, který uvízl v monotónním životě. Den co den usedá za volant svého obrněného automobilu, aby odvážel obrovské sumy peněz jiných lidí. Jediným vzrušujícím momentem v jeho životě je flirtování s kolegyní Kelly (Kristen Wiig), která ho však brzy zatáhne do těžko uvěřitelného dobrodružství. Skupinka nepříliš inteligentních loserů, pod vedením Steva (Owen Wilson), plánuje vyloupit banku a David jim v tom má samozřejmě pomoci. Navzdory absolutně amatérskému plánu se ale stane nemožné a oni mají najednou v kapse 17 miliónů dolarů. A protože tato partička je opravdu bláznivá, začne je hned ve velkém roztáčet. Peníze létají vzduchem za luxusní a kolikrát i zbytečné věci, ale nedochází jim, že pro policii tak zanechávají jasné stopy...',
|
'David (Zach Galifianakis) je nekomplikovaný muž, který uvízl v monotónním životě. Den co den usedá za volant svého obrněného automobilu, aby odvážel obrovské sumy peněz jiných lidí. Jediným vzrušujícím momentem v jeho životě je flirtování s kolegyní Kelly (Kristen Wiig), která ho však brzy zatáhne do těžko uvěřitelného dobrodružství. Skupinka nepříliš inteligentních loserů, pod vedením Steva (Owen Wilson), plánuje vyloupit banku a David jim v tom má samozřejmě pomoci. Navzdory absolutně amatérskému plánu se ale stane nemožné a oni mají najednou v kapse 17 miliónů dolarů. A protože tato partička je opravdu bláznivá, začne je hned ve velkém roztáčet. Peníze létají vzduchem za luxusní a kolikrát i zbytečné věci, ale nedochází jim, že pro policii tak zanechávají jasné stopy...',
|
||||||
category: ['Drama', 'Akcia'],
|
category: ['Drama', 'Akcia'],
|
||||||
actors: [
|
actors: [
|
||||||
'Zach Galifianakis',
|
'Zach Galifianakis',
|
||||||
'Kristen Wiigová',
|
'Kristen Wiigová',
|
||||||
'Owen Wilson',
|
'Owen Wilson',
|
||||||
'Kate McKinnon',
|
'Kate McKinnon',
|
||||||
'Leslie Jones',
|
'Leslie Jones',
|
||||||
'Jason Sudeikis',
|
'Jason Sudeikis',
|
||||||
'Ross Kimball',
|
'Ross Kimball',
|
||||||
'Devin Ratray',
|
'Devin Ratray',
|
||||||
'Mary Elizabeth Ellisová',
|
'Mary Elizabeth Ellisová',
|
||||||
'Jon Daly',
|
'Jon Daly',
|
||||||
'Ken Marino',
|
'Ken Marino',
|
||||||
'Daniel Zacapa',
|
'Daniel Zacapa',
|
||||||
'Tom Werme',
|
'Tom Werme',
|
||||||
'Njema Williams',
|
'Njema Williams',
|
||||||
'Nils Cruz',
|
'Nils Cruz',
|
||||||
'Michael Fraguada',
|
'Michael Fraguada',
|
||||||
'Christian Gonzalez',
|
'Christian Gonzalez',
|
||||||
'Candace Blanchard',
|
'Candace Blanchard',
|
||||||
'Karsten Friske',
|
'Karsten Friske',
|
||||||
'Dallas Edwards',
|
'Dallas Edwards',
|
||||||
'Barry Ratcliffe',
|
'Barry Ratcliffe',
|
||||||
'Shelton Grant',
|
'Shelton Grant',
|
||||||
'Laura Palka',
|
'Laura Palka',
|
||||||
'Reegus Flenory',
|
'Reegus Flenory',
|
||||||
'Wynn Reichert',
|
'Wynn Reichert',
|
||||||
'Jill Jane Clements',
|
'Jill Jane Clements',
|
||||||
'Joseph S. Wilson',
|
'Joseph S. Wilson',
|
||||||
'Jee An',
|
'Jee An',
|
||||||
'Rhoda Griffisová',
|
'Rhoda Griffisová',
|
||||||
'Nicole Dupre Sobchack'
|
'Nicole Dupre Sobchack'
|
||||||
],
|
],
|
||||||
directors: [
|
directors: [
|
||||||
'Scott August',
|
'Scott August',
|
||||||
'Richard L. Fox',
|
'Richard L. Fox',
|
||||||
'Michelle Malley-Campos',
|
'Michelle Malley-Campos',
|
||||||
'Sebastian Mazzola',
|
'Sebastian Mazzola',
|
||||||
'Steven Ritzi',
|
'Steven Ritzi',
|
||||||
'Pete Waterman',
|
'Pete Waterman',
|
||||||
'Jared Hess'
|
'Jared Hess'
|
||||||
],
|
],
|
||||||
date: '2016'
|
date: '2016'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
.catch(done)
|
.catch(done)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', done => {
|
it('can handle empty guide', done => {
|
||||||
parser({
|
parser({
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json')),
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json')),
|
||||||
channel,
|
channel,
|
||||||
date
|
date
|
||||||
})
|
})
|
||||||
.then(result => {
|
.then(result => {
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
.catch(done)
|
.catch(done)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,46 +1,46 @@
|
|||||||
const { parser, url } = require('./hoy.tv.config.js')
|
const { parser, url } = require('./hoy.tv.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
jest.mock('axios')
|
jest.mock('axios')
|
||||||
|
|
||||||
const date = dayjs.utc('2024-09-13', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2024-09-13', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '76',
|
site_id: '76',
|
||||||
xmltv_id: 'HOYIBC.hk',
|
xmltv_id: 'HOYIBC.hk',
|
||||||
lang: 'zh'
|
lang: 'zh'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe('https://epg-file.hoy.tv/hoy/OTT7620240913.xml')
|
expect(url({ channel, date })).toBe('https://epg-file.hoy.tv/hoy/OTT7620240913.xml')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.xml'), 'utf8')
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.xml'), 'utf8')
|
||||||
|
|
||||||
const result = parser({ content, channel, date }).map(p => {
|
const result = parser({ content, channel, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2024-09-13T03:30:00.000Z',
|
start: '2024-09-13T03:30:00.000Z',
|
||||||
stop: '2024-09-13T04:30:00.000Z',
|
stop: '2024-09-13T04:30:00.000Z',
|
||||||
title: '點講都係一家人[PG]',
|
title: '點講都係一家人[PG]',
|
||||||
sub_title: '第46集'
|
sub_title: '第46集'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2024-09-13T04:30:00.000Z',
|
start: '2024-09-13T04:30:00.000Z',
|
||||||
stop: '2024-09-13T05:30:00.000Z',
|
stop: '2024-09-13T05:30:00.000Z',
|
||||||
title: '麝香之路',
|
title: '麝香之路',
|
||||||
description:
|
description:
|
||||||
'Ep. 2 .The Secret of disappeared kingdom.shows the mysterious disappearance of the ancient Tibetan kingdom which gained world'
|
'Ep. 2 .The Secret of disappeared kingdom.shows the mysterious disappearance of the ancient Tibetan kingdom which gained world'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,46 +1,46 @@
|
|||||||
const { parser, url } = require('./i24news.tv.config.js')
|
const { parser, url } = require('./i24news.tv.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-03-06', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-03-06', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: 'ar',
|
site_id: 'ar',
|
||||||
xmltv_id: 'I24NewsArabic.il'
|
xmltv_id: 'I24NewsArabic.il'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel })).toBe('https://api.i24news.tv/v2/ar/schedules')
|
expect(url({ channel })).toBe('https://api.i24news.tv/v2/ar/schedules')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, date }).map(p => {
|
const result = parser({ content, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-03-06T13:00:00.000Z',
|
start: '2022-03-06T13:00:00.000Z',
|
||||||
stop: '2022-03-06T13:28:00.000Z',
|
stop: '2022-03-06T13:28:00.000Z',
|
||||||
title: 'تغطية خاصة',
|
title: 'تغطية خاصة',
|
||||||
description: 'Special Edition',
|
description: 'Special Edition',
|
||||||
image:
|
image:
|
||||||
'https://cdn.i24news.tv/uploads/a1/be/85/20/69/6f/32/1c/ed/b0/f8/5c/f6/1c/40/f9/a1be8520696f321cedb0f85cf61c40f9.png'
|
'https://cdn.i24news.tv/uploads/a1/be/85/20/69/6f/32/1c/ed/b0/f8/5c/f6/1c/40/f9/a1be8520696f321cedb0f85cf61c40f9.png'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: '[]',
|
content: '[]',
|
||||||
date
|
date
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,57 +1,57 @@
|
|||||||
const { parser, url } = require('./indihometv.com.config.js')
|
const { parser, url } = require('./indihometv.com.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-08-08').startOf('d')
|
const date = dayjs.utc('2022-08-08').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: 'metrotv',
|
site_id: 'metrotv',
|
||||||
xmltv_id: 'MetroTV.id'
|
xmltv_id: 'MetroTV.id'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel })).toBe('https://www.indihometv.com/livetv/metrotv')
|
expect(url({ channel })).toBe('https://www.indihometv.com/livetv/metrotv')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
||||||
const result = parser({ content, channel, date }).map(p => {
|
const result = parser({ content, channel, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
title: 'Headline News',
|
title: 'Headline News',
|
||||||
start: '2022-08-08T00:00:00.000Z',
|
start: '2022-08-08T00:00:00.000Z',
|
||||||
stop: '2022-08-08T00:05:00.000Z'
|
stop: '2022-08-08T00:05:00.000Z'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Editorial Media Indonesia',
|
title: 'Editorial Media Indonesia',
|
||||||
start: '2022-08-08T00:05:00.000Z',
|
start: '2022-08-08T00:05:00.000Z',
|
||||||
stop: '2022-08-08T00:30:00.000Z'
|
stop: '2022-08-08T00:30:00.000Z'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Editorial Media Indonesia',
|
title: 'Editorial Media Indonesia',
|
||||||
start: '2022-08-08T00:30:00.000Z',
|
start: '2022-08-08T00:30:00.000Z',
|
||||||
stop: '2022-08-08T00:45:00.000Z'
|
stop: '2022-08-08T00:45:00.000Z'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Editorial Media Indonesia',
|
title: 'Editorial Media Indonesia',
|
||||||
start: '2022-08-08T00:45:00.000Z',
|
start: '2022-08-08T00:45:00.000Z',
|
||||||
stop: '2022-08-08T01:00:00.000Z'
|
stop: '2022-08-08T01:00:00.000Z'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,54 +1,54 @@
|
|||||||
const { parser, url } = require('./ipko.tv.config.js')
|
const { parser, url } = require('./ipko.tv.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2024-12-24', 'YYYY-MM-DD').startOf('day')
|
const date = dayjs.utc('2024-12-24', 'YYYY-MM-DD').startOf('day')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: 'ipko-promo',
|
site_id: 'ipko-promo',
|
||||||
xmltv_id: 'IPKOPROMO'
|
xmltv_id: 'IPKOPROMO'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date, channel })).toBe('https://stargate.ipko.tv/api/titan.tv.WebEpg/GetWebEpgData')
|
expect(url({ date, channel })).toBe('https://stargate.ipko.tv/api/titan.tv.WebEpg/GetWebEpgData')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, channel })
|
const result = parser({ content, channel })
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
title: 'IPKO Promo',
|
title: 'IPKO Promo',
|
||||||
description: 'No description available',
|
description: 'No description available',
|
||||||
start: '2024-12-24T04:00:00.000Z',
|
start: '2024-12-24T04:00:00.000Z',
|
||||||
stop: '2024-12-24T06:00:00.000Z',
|
stop: '2024-12-24T06:00:00.000Z',
|
||||||
thumbnail: 'https://vimg.ipko.tv/mtcms/18/2/1/1821cc68-a9bf-4733-b1af-9a5d80163b78.jpg'
|
thumbnail: 'https://vimg.ipko.tv/mtcms/18/2/1/1821cc68-a9bf-4733-b1af-9a5d80163b78.jpg'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'IPKO Promo',
|
title: 'IPKO Promo',
|
||||||
description: 'No description available',
|
description: 'No description available',
|
||||||
start: '2024-12-24T06:00:00.000Z',
|
start: '2024-12-24T06:00:00.000Z',
|
||||||
stop: '2024-12-24T08:00:00.000Z',
|
stop: '2024-12-24T08:00:00.000Z',
|
||||||
thumbnail: 'https://vimg.ipko.tv/mtcms/18/2/1/1821cc68-a9bf-4733-b1af-9a5d80163b78.jpg'
|
thumbnail: 'https://vimg.ipko.tv/mtcms/18/2/1/1821cc68-a9bf-4733-b1af-9a5d80163b78.jpg'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'IPKO Promo',
|
title: 'IPKO Promo',
|
||||||
description: 'No description available',
|
description: 'No description available',
|
||||||
start: '2024-12-24T08:00:00.000Z',
|
start: '2024-12-24T08:00:00.000Z',
|
||||||
stop: '2024-12-24T10:00:00.000Z',
|
stop: '2024-12-24T10:00:00.000Z',
|
||||||
thumbnail: 'https://vimg.ipko.tv/mtcms/18/2/1/1821cc68-a9bf-4733-b1af-9a5d80163b78.jpg'
|
thumbnail: 'https://vimg.ipko.tv/mtcms/18/2/1/1821cc68-a9bf-4733-b1af-9a5d80163b78.jpg'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,47 +1,47 @@
|
|||||||
const { parser, url } = require('./kan.org.il.config.js')
|
const { parser, url } = require('./kan.org.il.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-03-06', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-03-06', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '19',
|
site_id: '19',
|
||||||
xmltv_id: 'KANEducational.il'
|
xmltv_id: 'KANEducational.il'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://www.kan.org.il/tv-guide/tv_guidePrograms.ashx?stationID=19&day=06/03/2022'
|
'https://www.kan.org.il/tv-guide/tv_guidePrograms.ashx?stationID=19&day=06/03/2022'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-03-05T22:05:37.000Z',
|
start: '2022-03-05T22:05:37.000Z',
|
||||||
stop: '2022-03-05T22:27:12.000Z',
|
stop: '2022-03-05T22:27:12.000Z',
|
||||||
title: 'ארץ מולדת - בין תורכיה לבריטניה',
|
title: 'ארץ מולדת - בין תורכיה לבריטניה',
|
||||||
description:
|
description:
|
||||||
"קבוצת תלמידים מתארגנת בפרוץ מלחמת העולם הראשונה להגיש עזרה לישוב. באמצעות התלמידים לומד הצופה על בעיותיו של הישוב בתקופת המלחמה, והתלבטותו בין נאמנות לשלטון העות'מאני לבין תקוותיו מהבריטים הכובשים.",
|
"קבוצת תלמידים מתארגנת בפרוץ מלחמת העולם הראשונה להגיש עזרה לישוב. באמצעות התלמידים לומד הצופה על בעיותיו של הישוב בתקופת המלחמה, והתלבטותו בין נאמנות לשלטון העות'מאני לבין תקוותיו מהבריטים הכובשים.",
|
||||||
image: 'https://kanweb.blob.core.windows.net/download/pictures/2021/1/20/imgid=45847_Z.jpeg'
|
image: 'https://kanweb.blob.core.windows.net/download/pictures/2021/1/20/imgid=45847_Z.jpeg'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: '[]'
|
content: '[]'
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,64 +1,64 @@
|
|||||||
const { parser, url, request } = require('./magticom.ge.config.js')
|
const { parser, url, request } = require('./magticom.ge.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-22', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-22', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '260',
|
site_id: '260',
|
||||||
xmltv_id: 'BollywoodHDRussia.ru'
|
xmltv_id: 'BollywoodHDRussia.ru'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url).toBe('https://www.magticom.ge/request/channel-program.php')
|
expect(url).toBe('https://www.magticom.ge/request/channel-program.php')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request method', () => {
|
it('can generate valid request method', () => {
|
||||||
expect(request.method).toBe('POST')
|
expect(request.method).toBe('POST')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request headers', () => {
|
it('can generate valid request headers', () => {
|
||||||
expect(request.headers).toMatchObject({
|
expect(request.headers).toMatchObject({
|
||||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||||
Referer: 'https://www.magticom.ge/en/tv/tv-services/tv-guide'
|
Referer: 'https://www.magticom.ge/en/tv/tv-services/tv-guide'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request data', () => {
|
it('can generate valid request data', () => {
|
||||||
const result = request.data({ channel, date })
|
const result = request.data({ channel, date })
|
||||||
expect(result.has('channelId')).toBe(true)
|
expect(result.has('channelId')).toBe(true)
|
||||||
expect(result.has('start')).toBe(true)
|
expect(result.has('start')).toBe(true)
|
||||||
expect(result.has('end')).toBe(true)
|
expect(result.has('end')).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-22T03:00:00.000Z',
|
start: '2021-11-22T03:00:00.000Z',
|
||||||
stop: '2021-11-22T05:00:00.000Z',
|
stop: '2021-11-22T05:00:00.000Z',
|
||||||
title: 'Х/ф "Неравный брак".',
|
title: 'Х/ф "Неравный брак".',
|
||||||
description:
|
description:
|
||||||
'Гуджаратец Хасмукх Пател поссорился с новым соседом Гугги Тандоном. Но им приходится помириться, когда их дети влюбляются друг в друга. Режиссер: Санджай Чхел. Актеры: Риши Капур, Пареш Равал, Вир Дас. 2017 год.'
|
'Гуджаратец Хасмукх Пател поссорился с новым соседом Гугги Тандоном. Но им приходится помириться, когда их дети влюбляются друг в друга. Режиссер: Санджай Чхел. Актеры: Риши Капур, Пареш Равал, Вир Дас. 2017 год.'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: '[]'
|
content: '[]'
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
const { parser, url } = require('./mako.co.il.config.js')
|
const { parser, url } = require('./mako.co.il.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-03-07', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-03-07', 'YYYY-MM-DD').startOf('d')
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url).toBe('https://www.mako.co.il/AjaxPage?jspName=EPGResponse.jsp')
|
expect(url).toBe('https://www.mako.co.il/AjaxPage?jspName=EPGResponse.jsp')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, date }).map(p => {
|
const result = parser({ content, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-03-07T00:38:00.000Z',
|
start: '2022-03-07T00:38:00.000Z',
|
||||||
stop: '2022-03-07T00:39:00.000Z',
|
stop: '2022-03-07T00:39:00.000Z',
|
||||||
title: 'רוקדים עם כוכבים - בר זומר',
|
title: 'רוקדים עם כוכבים - בר זומר',
|
||||||
description: 'מהדורת החדשות המרכזית של הבוקר, האנשים הפרשנויות והכותרות שיעשו את היום.',
|
description: 'מהדורת החדשות המרכזית של הבוקר, האנשים הפרשנויות והכותרות שיעשו את היום.',
|
||||||
image: 'https://img.mako.co.il/2022/02/13/DancingWithStars2022_EPG.jpg'
|
image: 'https://img.mako.co.il/2022/02/13/DancingWithStars2022_EPG.jpg'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: '[]',
|
content: '[]',
|
||||||
date
|
date
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,72 +1,72 @@
|
|||||||
const { parser, url } = require('./maxtvgo.mk.config.js')
|
const { parser, url } = require('./maxtvgo.mk.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-17', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-17', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '105',
|
site_id: '105',
|
||||||
xmltv_id: 'MRT1.mk'
|
xmltv_id: 'MRT1.mk'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://prd-static-mkt.spectar.tv/rev-1636968171/client_api.php/epg/list/instance_id/1/language/mk/channel_id/105/start/20211117000000/stop/20211118000000/include_current/true/format/json'
|
'https://prd-static-mkt.spectar.tv/rev-1636968171/client_api.php/epg/list/instance_id/1/language/mk/channel_id/105/start/20211117000000/stop/20211118000000/include_current/true/format/json'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-16T22:10:00.000Z',
|
start: '2021-11-16T22:10:00.000Z',
|
||||||
stop: '2021-11-17T00:00:00.000Z',
|
stop: '2021-11-17T00:00:00.000Z',
|
||||||
title: 'Палмето - игран филм',
|
title: 'Палмето - игран филм',
|
||||||
category: 'Останато',
|
category: 'Останато',
|
||||||
description:
|
description:
|
||||||
'Екстремниот рибар, Џереми Вејд, е во потрага по слатководни риби кои јадат човечко месо. Со форензички методи, Џереми им илустрира на гледачите како овие нови чудовишта се создадени да убиваат.',
|
'Екстремниот рибар, Џереми Вејд, е во потрага по слатководни риби кои јадат човечко месо. Со форензички методи, Џереми им илустрира на гледачите како овие нови чудовишта се создадени да убиваат.',
|
||||||
image:
|
image:
|
||||||
'https://prd-static-mkt.spectar.tv/rev-1636968170/image_transform.php/transform/1/epg_program_id/21949063/instance_id/1'
|
'https://prd-static-mkt.spectar.tv/rev-1636968170/image_transform.php/transform/1/epg_program_id/21949063/instance_id/1'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response with no description', () => {
|
it('can parse response with no description', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content_no_description.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content_no_description.json'))
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-16T22:10:00.000Z',
|
start: '2021-11-16T22:10:00.000Z',
|
||||||
stop: '2021-11-17T00:00:00.000Z',
|
stop: '2021-11-17T00:00:00.000Z',
|
||||||
title: 'Палмето - игран филм',
|
title: 'Палмето - игран филм',
|
||||||
category: 'Останато',
|
category: 'Останато',
|
||||||
description: null,
|
description: null,
|
||||||
image:
|
image:
|
||||||
'https://prd-static-mkt.spectar.tv/rev-1636968170/image_transform.php/transform/1/epg_program_id/21949063/instance_id/1'
|
'https://prd-static-mkt.spectar.tv/rev-1636968170/image_transform.php/transform/1/epg_program_id/21949063/instance_id/1'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
const { parser, url } = require('./melita.com.config.js')
|
const { parser, url } = require('./melita.com.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-04-20', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-04-20', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '4d40a9f9-12fd-4f03-8072-61c637ff6995',
|
site_id: '4d40a9f9-12fd-4f03-8072-61c637ff6995',
|
||||||
xmltv_id: 'TVM.mt'
|
xmltv_id: 'TVM.mt'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://androme.melitacable.com/api/epg/v1/schedule/channel/4d40a9f9-12fd-4f03-8072-61c637ff6995/from/2022-04-20T00:00+00:00/until/2022-04-21T00:00+00:00'
|
'https://androme.melitacable.com/api/epg/v1/schedule/channel/4d40a9f9-12fd-4f03-8072-61c637ff6995/from/2022-04-20T00:00+00:00/until/2022-04-21T00:00+00:00'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-04-20T06:25:00.000Z',
|
start: '2022-04-20T06:25:00.000Z',
|
||||||
stop: '2022-04-20T06:45:00.000Z',
|
stop: '2022-04-20T06:45:00.000Z',
|
||||||
title: 'How I Met Your Mother',
|
title: 'How I Met Your Mother',
|
||||||
description:
|
description:
|
||||||
'Symphony of Illumination - Robin gets some bad news and decides to keep it to herself. Marshall decorates the house.',
|
'Symphony of Illumination - Robin gets some bad news and decides to keep it to herself. Marshall decorates the house.',
|
||||||
season: 7,
|
season: 7,
|
||||||
episode: 12,
|
episode: 12,
|
||||||
image:
|
image:
|
||||||
'https://androme.melitacable.com/media/images/epg/bc/07/p8953134_e_h10_ad.jpg?form=epg-card-6',
|
'https://androme.melitacable.com/media/images/epg/bc/07/p8953134_e_h10_ad.jpg?form=epg-card-6',
|
||||||
category: ['comedy']
|
category: ['comedy']
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: '{}'
|
content: '{}'
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,56 +1,56 @@
|
|||||||
const { parser, url } = require('./mewatch.sg.config.js')
|
const { parser, url } = require('./mewatch.sg.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-06-11', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-06-11', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '97098',
|
site_id: '97098',
|
||||||
xmltv_id: 'Channel5Singapore.sg'
|
xmltv_id: 'Channel5Singapore.sg'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://cdn.mewatch.sg/api/schedules?channels=97098&date=2022-06-10&duration=24&ff=idp,ldp,rpt,cd&hour=12&intersect=true&lang=en&segments=all'
|
'https://cdn.mewatch.sg/api/schedules?channels=97098&date=2022-06-10&duration=24&ff=idp,ldp,rpt,cd&hour=12&intersect=true&lang=en&segments=all'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-06-11T21:00:00.000Z',
|
start: '2022-06-11T21:00:00.000Z',
|
||||||
stop: '2022-06-11T21:30:00.000Z',
|
stop: '2022-06-11T21:30:00.000Z',
|
||||||
title: 'Open Homes S3 - EP 2',
|
title: 'Open Homes S3 - EP 2',
|
||||||
description:
|
description:
|
||||||
'Mike heads down to the Sydney beaches to visit a beachside renovation with all the bells and whistles, we see a kitchen tip and recipe anyone can do at home. We finish up in the prestigious Byron bay to visit a multi million dollar award winning home.',
|
'Mike heads down to the Sydney beaches to visit a beachside renovation with all the bells and whistles, we see a kitchen tip and recipe anyone can do at home. We finish up in the prestigious Byron bay to visit a multi million dollar award winning home.',
|
||||||
image:
|
image:
|
||||||
"https://production.togglestatic.com/shain/v1/dataservice/ResizeImage/$value?Format='jpg'&Quality=85&ImageId='4853697'&EntityType='LinearSchedule'&EntityId='788a7dd9-9b12-446f-91b4-c8ac9fec95e5'&Width=1280&Height=720&device=web_browser&subscriptions=Anonymous&segmentationTags=all",
|
"https://production.togglestatic.com/shain/v1/dataservice/ResizeImage/$value?Format='jpg'&Quality=85&ImageId='4853697'&EntityType='LinearSchedule'&EntityId='788a7dd9-9b12-446f-91b4-c8ac9fec95e5'&Width=1280&Height=720&device=web_browser&subscriptions=Anonymous&segmentationTags=all",
|
||||||
episode: 2,
|
episode: 2,
|
||||||
season: 3,
|
season: 3,
|
||||||
rating: {
|
rating: {
|
||||||
system: 'IMDA',
|
system: 'IMDA',
|
||||||
value: 'G'
|
value: 'G'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content:
|
content:
|
||||||
fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json')),
|
fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json')),
|
||||||
channel
|
channel
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,144 +1,144 @@
|
|||||||
const cheerio = require('cheerio')
|
const cheerio = require('cheerio')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
||||||
'accept-language': 'en',
|
'accept-language': 'en',
|
||||||
'sec-fetch-site': 'same-origin',
|
'sec-fetch-site': 'same-origin',
|
||||||
'sec-fetch-user': '?1',
|
'sec-fetch-user': '?1',
|
||||||
'upgrade-insecure-requests': '1',
|
'upgrade-insecure-requests': '1',
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'mi.tv',
|
site: 'mi.tv',
|
||||||
days: 2,
|
days: 2,
|
||||||
request: { headers },
|
request: { headers },
|
||||||
url({ date, channel }) {
|
url({ date, channel }) {
|
||||||
const [country, id] = channel.site_id.split('#')
|
const [country, id] = channel.site_id.split('#')
|
||||||
return `https://mi.tv/${country}/async/channel/${id}/${date.format('YYYY-MM-DD')}/0`
|
return `https://mi.tv/${country}/async/channel/${id}/${date.format('YYYY-MM-DD')}/0`
|
||||||
},
|
},
|
||||||
parser({ content, date }) {
|
parser({ content, date }) {
|
||||||
const programs = []
|
const programs = []
|
||||||
const items = parseItems(content)
|
const items = parseItems(content)
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
const prev = programs[programs.length - 1]
|
const prev = programs[programs.length - 1]
|
||||||
const $item = cheerio.load(item)
|
const $item = cheerio.load(item)
|
||||||
let start = parseStart($item, date)
|
let start = parseStart($item, date)
|
||||||
if (!start) return
|
if (!start) return
|
||||||
if (prev) {
|
if (prev) {
|
||||||
if (start.isBefore(prev.start)) {
|
if (start.isBefore(prev.start)) {
|
||||||
start = start.add(1, 'd')
|
start = start.add(1, 'd')
|
||||||
date = date.add(1, 'd')
|
date = date.add(1, 'd')
|
||||||
}
|
}
|
||||||
prev.stop = start
|
prev.stop = start
|
||||||
}
|
}
|
||||||
const stop = start.add(1, 'h')
|
const stop = start.add(1, 'h')
|
||||||
programs.push({
|
programs.push({
|
||||||
title: parseTitle($item),
|
title: parseTitle($item),
|
||||||
category: parseCategory($item),
|
category: parseCategory($item),
|
||||||
description: parseDescription($item),
|
description: parseDescription($item),
|
||||||
image: parseImage($item),
|
image: parseImage($item),
|
||||||
start,
|
start,
|
||||||
stop
|
stop
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels({ country }) {
|
async channels({ country }) {
|
||||||
let lang = 'es'
|
let lang = 'es'
|
||||||
if (country === 'br') lang = 'pt'
|
if (country === 'br') lang = 'pt'
|
||||||
|
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const data = await axios
|
const data = await axios
|
||||||
.get(`https://mi.tv/${country}/sitemap`)
|
.get(`https://mi.tv/${country}/sitemap`)
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
|
|
||||||
const $ = cheerio.load(data)
|
const $ = cheerio.load(data)
|
||||||
|
|
||||||
let channels = []
|
let channels = []
|
||||||
$(`#page-contents a[href*="${country}/canales"], a[href*="${country}/canais"]`).each(
|
$(`#page-contents a[href*="${country}/canales"], a[href*="${country}/canais"]`).each(
|
||||||
(i, el) => {
|
(i, el) => {
|
||||||
const name = $(el).text()
|
const name = $(el).text()
|
||||||
const url = $(el).attr('href')
|
const url = $(el).attr('href')
|
||||||
const [, , , channelId] = url.split('/')
|
const [, , , channelId] = url.split('/')
|
||||||
|
|
||||||
channels.push({
|
channels.push({
|
||||||
lang,
|
lang,
|
||||||
name,
|
name,
|
||||||
site_id: `${country}#${channelId}`
|
site_id: `${country}#${channelId}`
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
return channels
|
return channels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStart($item, date) {
|
function parseStart($item, date) {
|
||||||
const timeString = $item('a > div.content > span.time').text()
|
const timeString = $item('a > div.content > span.time').text()
|
||||||
if (!timeString) return null
|
if (!timeString) return null
|
||||||
const dateString = `${date.format('MM/DD/YYYY')} ${timeString}`
|
const dateString = `${date.format('MM/DD/YYYY')} ${timeString}`
|
||||||
|
|
||||||
return dayjs.utc(dateString, 'MM/DD/YYYY HH:mm')
|
return dayjs.utc(dateString, 'MM/DD/YYYY HH:mm')
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTitle($item) {
|
function parseTitle($item) {
|
||||||
return $item('a > div.content > h2').text().trim()
|
return $item('a > div.content > h2').text().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseCategory($item) {
|
function parseCategory($item) {
|
||||||
return $item('a > div.content > span.sub-title').text().trim()
|
return $item('a > div.content > span.sub-title').text().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDescription($item) {
|
function parseDescription($item) {
|
||||||
return $item('a > div.content > p.synopsis').text().trim()
|
return $item('a > div.content > p.synopsis').text().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function parseImage($item) {
|
function parseImage($item) {
|
||||||
const styleAttr = $item('a > div.image-parent > div.image').attr('style')
|
const styleAttr = $item('a > div.image-parent > div.image').attr('style')
|
||||||
|
|
||||||
if (styleAttr) {
|
if (styleAttr) {
|
||||||
const match = styleAttr.match(/background-image:\s*url\(['"]?(.*?)['"]?\)/)
|
const match = styleAttr.match(/background-image:\s*url\(['"]?(.*?)['"]?\)/)
|
||||||
if (match) {
|
if (match) {
|
||||||
return cleanUrl(match[1])
|
return cleanUrl(match[1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const backgroundImage = $item('a > div.image-parent > div.image').css('background-image')
|
const backgroundImage = $item('a > div.image-parent > div.image').css('background-image')
|
||||||
|
|
||||||
if (backgroundImage && backgroundImage !== 'none') {
|
if (backgroundImage && backgroundImage !== 'none') {
|
||||||
const match = backgroundImage.match(/url\(['"]?(.*?)['"]?\)/)
|
const match = backgroundImage.match(/url\(['"]?(.*?)['"]?\)/)
|
||||||
if (match) {
|
if (match) {
|
||||||
return cleanUrl(match[1])
|
return cleanUrl(match[1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanUrl(url) {
|
function cleanUrl(url) {
|
||||||
if (!url) return null
|
if (!url) return null
|
||||||
|
|
||||||
return url
|
return url
|
||||||
.replace(/^['"`\\]+/, '')
|
.replace(/^['"`\\]+/, '')
|
||||||
.replace(/['"`\\]+$/, '')
|
.replace(/['"`\\]+$/, '')
|
||||||
.replace(/\\'/g, "'")
|
.replace(/\\'/g, "'")
|
||||||
.replace(/\\"/g, '"')
|
.replace(/\\"/g, '"')
|
||||||
.replace(/\\\\/g, '\\')
|
.replace(/\\\\/g, '\\')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function parseItems(content) {
|
function parseItems(content) {
|
||||||
const $ = cheerio.load(content)
|
const $ = cheerio.load(content)
|
||||||
|
|
||||||
return $('#listings > ul > li').toArray()
|
return $('#listings > ul > li').toArray()
|
||||||
}
|
}
|
||||||
@@ -1,67 +1,67 @@
|
|||||||
const { parser, url } = require('./mi.tv.config.js')
|
const { parser, url } = require('./mi.tv.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-24', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-24', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: 'ar#24-7-canal-de-noticias',
|
site_id: 'ar#24-7-canal-de-noticias',
|
||||||
xmltv_id: '247CanaldeNoticias.ar'
|
xmltv_id: '247CanaldeNoticias.ar'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://mi.tv/ar/async/channel/24-7-canal-de-noticias/2021-11-24/0'
|
'https://mi.tv/ar/async/channel/24-7-canal-de-noticias/2021-11-24/0'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
||||||
const result = parser({ content, date }).map(p => {
|
const result = parser({ content, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-24T03:00:00.000Z',
|
start: '2021-11-24T03:00:00.000Z',
|
||||||
stop: '2021-11-24T23:00:00.000Z',
|
stop: '2021-11-24T23:00:00.000Z',
|
||||||
title: 'Trasnoche de 24/7',
|
title: 'Trasnoche de 24/7',
|
||||||
category: 'Interés general',
|
category: 'Interés general',
|
||||||
description: 'Lo más visto de la semana en nuestra pantalla.',
|
description: 'Lo más visto de la semana en nuestra pantalla.',
|
||||||
image: 'https://cdn.mitvstatic.com/programs/fallback_other_l_m.jpg'
|
image: 'https://cdn.mitvstatic.com/programs/fallback_other_l_m.jpg'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2021-11-24T23:00:00.000Z',
|
start: '2021-11-24T23:00:00.000Z',
|
||||||
stop: '2021-11-25T01:00:00.000Z',
|
stop: '2021-11-25T01:00:00.000Z',
|
||||||
title: 'Noticiero central - Segunda edición',
|
title: 'Noticiero central - Segunda edición',
|
||||||
category: 'Noticiero',
|
category: 'Noticiero',
|
||||||
description:
|
description:
|
||||||
'Cerramos el día con un completo resumen de los temas más relevantes con columnistas y análisis especiales para terminar el día.',
|
'Cerramos el día con un completo resumen de los temas más relevantes con columnistas y análisis especiales para terminar el día.',
|
||||||
image: 'https://cdn.mitvstatic.com/programs/fallback_other_l_m.jpg'
|
image: 'https://cdn.mitvstatic.com/programs/fallback_other_l_m.jpg'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2021-11-25T01:00:00.000Z',
|
start: '2021-11-25T01:00:00.000Z',
|
||||||
stop: '2021-11-25T02:00:00.000Z',
|
stop: '2021-11-25T02:00:00.000Z',
|
||||||
title: 'Plus energético',
|
title: 'Plus energético',
|
||||||
category: 'Cultural',
|
category: 'Cultural',
|
||||||
description:
|
description:
|
||||||
'La energía tiene mucho para mostrar. Este programa reúne a las principales empresas y protagonistas de la actividad que esta revolucionando la región.',
|
'La energía tiene mucho para mostrar. Este programa reúne a las principales empresas y protagonistas de la actividad que esta revolucionando la región.',
|
||||||
image: 'https://cdn.mitvstatic.com/programs/fallback_other_l_m.jpg'
|
image: 'https://cdn.mitvstatic.com/programs/fallback_other_l_m.jpg'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: ''
|
content: ''
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
const { parser } = require('./moji.id.config.js')
|
const { parser } = require('./moji.id.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2023-08-18', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2023-08-18', 'YYYY-MM-DD').startOf('d')
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const results = parser({ content: '' })
|
const results = parser({ content: '' })
|
||||||
expect(results).toMatchObject([])
|
expect(results).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
||||||
const results = parser({ content, date }).map(p => {
|
const results = parser({ content, date }).map(p => {
|
||||||
p.start = p.start.year(2023).toJSON()
|
p.start = p.start.year(2023).toJSON()
|
||||||
p.stop = p.stop.year(2023).toJSON()
|
p.stop = p.stop.year(2023).toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(results[0]).toMatchObject({
|
expect(results[0]).toMatchObject({
|
||||||
title: 'TRUST',
|
title: 'TRUST',
|
||||||
start: '2023-08-17T17:00:00.000Z',
|
start: '2023-08-17T17:00:00.000Z',
|
||||||
stop: '2023-08-17T17:30:00.000Z',
|
stop: '2023-08-17T17:30:00.000Z',
|
||||||
description: 'Informasi seputar menjaga vitalitas pria'
|
description: 'Informasi seputar menjaga vitalitas pria'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,192 +1,192 @@
|
|||||||
const doFetch = require('@ntlab/sfetch')
|
const doFetch = require('@ntlab/sfetch')
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
const { sortBy } = require('../../scripts/functions')
|
const { sortBy } = require('../../scripts/functions')
|
||||||
|
|
||||||
// API Configuration Constants
|
// API Configuration Constants
|
||||||
const NATCO_CODE = 'hr'
|
const NATCO_CODE = 'hr'
|
||||||
const APP_LANGUAGE = 'hr'
|
const APP_LANGUAGE = 'hr'
|
||||||
const APP_KEY = 'GWaBW4RTloLwpUgYVzOiW5zUxFLmoMj5'
|
const APP_KEY = 'GWaBW4RTloLwpUgYVzOiW5zUxFLmoMj5'
|
||||||
const APP_VERSION = '02.0.1080'
|
const APP_VERSION = '02.0.1080'
|
||||||
const NATCO_KEY = 'l2lyvGVbUm2EKJE96ImQgcc8PKMZWtbE'
|
const NATCO_KEY = 'l2lyvGVbUm2EKJE96ImQgcc8PKMZWtbE'
|
||||||
const SITE_URL = 'mojmaxtv.hrvatskitelekom.hr'
|
const SITE_URL = 'mojmaxtv.hrvatskitelekom.hr'
|
||||||
|
|
||||||
// Role Types
|
// Role Types
|
||||||
const ROLE_TYPES = {
|
const ROLE_TYPES = {
|
||||||
ACTOR: 'GLUMI', // Croatian for "ACTS"
|
ACTOR: 'GLUMI', // Croatian for "ACTS"
|
||||||
DIRECTOR: 'REŽIJA', // Croatian for "DIRECTOR"
|
DIRECTOR: 'REŽIJA', // Croatian for "DIRECTOR"
|
||||||
PRODUCER: 'PRODUKCIJA', // Croatian for "PRODUCER"
|
PRODUCER: 'PRODUKCIJA', // Croatian for "PRODUCER"
|
||||||
WRITER: 'AUTOR',
|
WRITER: 'AUTOR',
|
||||||
SCENARIO: 'SCENARIJ'
|
SCENARIO: 'SCENARIJ'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dynamic API Endpoint based on NATCO_CODE
|
// Dynamic API Endpoint based on NATCO_CODE
|
||||||
const API_ENDPOINT = `https://tv-${NATCO_CODE}-prod.yo-digital.com/${NATCO_CODE}-bifrost`
|
const API_ENDPOINT = `https://tv-${NATCO_CODE}-prod.yo-digital.com/${NATCO_CODE}-bifrost`
|
||||||
|
|
||||||
// Session/Device IDs
|
// Session/Device IDs
|
||||||
const DEVICE_ID = crypto.randomUUID()
|
const DEVICE_ID = crypto.randomUUID()
|
||||||
const SESSION_ID = crypto.randomUUID()
|
const SESSION_ID = crypto.randomUUID()
|
||||||
|
|
||||||
const cached = {}
|
const cached = {}
|
||||||
|
|
||||||
const getHeaders = () => ({
|
const getHeaders = () => ({
|
||||||
'app_key': APP_KEY,
|
'app_key': APP_KEY,
|
||||||
'app_version': APP_VERSION,
|
'app_version': APP_VERSION,
|
||||||
'device-id': DEVICE_ID,
|
'device-id': DEVICE_ID,
|
||||||
'tenant': 'tv',
|
'tenant': 'tv',
|
||||||
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
|
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
|
||||||
'origin': `https://${SITE_URL}`,
|
'origin': `https://${SITE_URL}`,
|
||||||
'x-request-session-id': SESSION_ID,
|
'x-request-session-id': SESSION_ID,
|
||||||
'x-request-tracking-id': crypto.randomUUID(),
|
'x-request-tracking-id': crypto.randomUUID(),
|
||||||
'x-tv-step': 'EPG_SCHEDULES',
|
'x-tv-step': 'EPG_SCHEDULES',
|
||||||
'x-tv-flow': 'EPG',
|
'x-tv-flow': 'EPG',
|
||||||
'x-call-type': 'GUEST_USER',
|
'x-call-type': 'GUEST_USER',
|
||||||
'x-user-agent': `web|web|Chrome-133|${APP_VERSION}|1`
|
'x-user-agent': `web|web|Chrome-133|${APP_VERSION}|1`
|
||||||
})
|
})
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: SITE_URL,
|
site: SITE_URL,
|
||||||
url({ date }) {
|
url({ date }) {
|
||||||
return `${API_ENDPOINT}/epg/channel/schedules?date=${date.format(
|
return `${API_ENDPOINT}/epg/channel/schedules?date=${date.format(
|
||||||
'YYYY-MM-DD'
|
'YYYY-MM-DD'
|
||||||
)}&hour_offset=0&hour_range=3&channelMap_id&filler=true&app_language=${APP_LANGUAGE}&natco_code=${NATCO_CODE}`
|
)}&hour_offset=0&hour_range=3&channelMap_id&filler=true&app_language=${APP_LANGUAGE}&natco_code=${NATCO_CODE}`
|
||||||
},
|
},
|
||||||
request: {
|
request: {
|
||||||
headers: getHeaders(),
|
headers: getHeaders(),
|
||||||
cache: {
|
cache: {
|
||||||
ttl: 24 * 60 * 60 * 1000 // 1 day
|
ttl: 24 * 60 * 60 * 1000 // 1 day
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async parser({ content, channel, date }) {
|
async parser({ content, channel, date }) {
|
||||||
const data = parseData(content)
|
const data = parseData(content)
|
||||||
if (!data) return []
|
if (!data) return []
|
||||||
|
|
||||||
let items = parseItems(data, channel)
|
let items = parseItems(data, channel)
|
||||||
if (!items.length) return []
|
if (!items.length) return []
|
||||||
|
|
||||||
const queue = [3, 6, 9, 12, 15, 18, 21]
|
const queue = [3, 6, 9, 12, 15, 18, 21]
|
||||||
.map(offset => {
|
.map(offset => {
|
||||||
const url = module.exports.url({ date }).replace('hour_offset=0', `hour_offset=${offset}`)
|
const url = module.exports.url({ date }).replace('hour_offset=0', `hour_offset=${offset}`)
|
||||||
const params = { ...module.exports.request, headers: getHeaders() }
|
const params = { ...module.exports.request, headers: getHeaders() }
|
||||||
|
|
||||||
if (cached[url]) {
|
if (cached[url]) {
|
||||||
items = items.concat(parseItems(cached[url], channel))
|
items = items.concat(parseItems(cached[url], channel))
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return { url, params }
|
return { url, params }
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
|
|
||||||
await doFetch(queue, (_req, _data) => {
|
await doFetch(queue, (_req, _data) => {
|
||||||
if (_data) {
|
if (_data) {
|
||||||
cached[_req.url] = _data
|
cached[_req.url] = _data
|
||||||
items = items.concat(parseItems(_data, channel))
|
items = items.concat(parseItems(_data, channel))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
items = sortBy(items, i => dayjs(i.start_time).valueOf())
|
items = sortBy(items, i => dayjs(i.start_time).valueOf())
|
||||||
|
|
||||||
// Fetch program details for each item
|
// Fetch program details for each item
|
||||||
const programs = []
|
const programs = []
|
||||||
for (let item of items) {
|
for (let item of items) {
|
||||||
const detail = await loadProgramDetails(item)
|
const detail = await loadProgramDetails(item)
|
||||||
|
|
||||||
// detectUnknownRoles(detail)
|
// detectUnknownRoles(detail)
|
||||||
|
|
||||||
programs.push({
|
programs.push({
|
||||||
title: item.description,
|
title: item.description,
|
||||||
sub_title: item.episode_name,
|
sub_title: item.episode_name,
|
||||||
description: parseDescription(detail),
|
description: parseDescription(detail),
|
||||||
categories: Array.isArray(item.genres) ? item.genres.map(g => g.name) : [],
|
categories: Array.isArray(item.genres) ? item.genres.map(g => g.name) : [],
|
||||||
date: parseDate(item),
|
date: parseDate(item),
|
||||||
image: detail.poster_image_url,
|
image: detail.poster_image_url,
|
||||||
actors: parseRoles(detail, ROLE_TYPES.ACTOR),
|
actors: parseRoles(detail, ROLE_TYPES.ACTOR),
|
||||||
directors: parseRoles(detail, ROLE_TYPES.DIRECTOR),
|
directors: parseRoles(detail, ROLE_TYPES.DIRECTOR),
|
||||||
producers: parseRoles(detail, ROLE_TYPES.PRODUCER),
|
producers: parseRoles(detail, ROLE_TYPES.PRODUCER),
|
||||||
season: parseSeason(item),
|
season: parseSeason(item),
|
||||||
episode: parseEpisode(item),
|
episode: parseEpisode(item),
|
||||||
rating: parseRating(item),
|
rating: parseRating(item),
|
||||||
start: item.start_time,
|
start: item.start_time,
|
||||||
stop: item.end_time
|
stop: item.end_time
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels() {
|
async channels() {
|
||||||
const data = await axios
|
const data = await axios
|
||||||
.get(
|
.get(
|
||||||
`${API_ENDPOINT}/epg/channel?channelMap_id=&includeVirtualChannels=false&natco_key=${NATCO_KEY}&app_language=${APP_LANGUAGE}&natco_code=${NATCO_CODE}`,
|
`${API_ENDPOINT}/epg/channel?channelMap_id=&includeVirtualChannels=false&natco_key=${NATCO_KEY}&app_language=${APP_LANGUAGE}&natco_code=${NATCO_CODE}`,
|
||||||
{ ...module.exports.request, headers: getHeaders() }
|
{ ...module.exports.request, headers: getHeaders() }
|
||||||
)
|
)
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
|
|
||||||
return data.channels.map(channel => ({
|
return data.channels.map(channel => ({
|
||||||
lang: NATCO_CODE,
|
lang: NATCO_CODE,
|
||||||
name: channel.title,
|
name: channel.title,
|
||||||
site_id: channel.station_id
|
site_id: channel.station_id
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadProgramDetails(item) {
|
async function loadProgramDetails(item) {
|
||||||
if (!item.program_id) return {}
|
if (!item.program_id) return {}
|
||||||
const url = `${API_ENDPOINT}/details/series/${item.program_id}?natco_code=${NATCO_CODE}`
|
const url = `${API_ENDPOINT}/details/series/${item.program_id}?natco_code=${NATCO_CODE}`
|
||||||
const data = await axios
|
const data = await axios
|
||||||
.get(url, { headers: getHeaders() })
|
.get(url, { headers: getHeaders() })
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
|
|
||||||
return data || {}
|
return data || {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseData(content) {
|
function parseData(content) {
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(content)
|
const data = JSON.parse(content)
|
||||||
return data || null
|
return data || null
|
||||||
} catch {
|
} catch {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(data, channel) {
|
function parseItems(data, channel) {
|
||||||
if (!data.channels || !Array.isArray(data.channels[channel.site_id])) return []
|
if (!data.channels || !Array.isArray(data.channels[channel.site_id])) return []
|
||||||
return data.channels[channel.site_id]
|
return data.channels[channel.site_id]
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDate(item) {
|
function parseDate(item) {
|
||||||
return item && item.release_year ? item.release_year.toString() : null
|
return item && item.release_year ? item.release_year.toString() : null
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseRating(item) {
|
function parseRating(item) {
|
||||||
return item.ratings
|
return item.ratings
|
||||||
? {
|
? {
|
||||||
system: 'MPA',
|
system: 'MPA',
|
||||||
value: item.ratings
|
value: item.ratings
|
||||||
}
|
}
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseSeason(item) {
|
function parseSeason(item) {
|
||||||
if (item.season_display_number === 'Epizode') return null // 'Epizode' is 'Episodes' in Croatian
|
if (item.season_display_number === 'Epizode') return null // 'Epizode' is 'Episodes' in Croatian
|
||||||
return item.season_number
|
return item.season_number
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseEpisode(item) {
|
function parseEpisode(item) {
|
||||||
if (item.episode_number) return parseInt(item.episode_number)
|
if (item.episode_number) return parseInt(item.episode_number)
|
||||||
if (item.season_display_number === 'Epizode') return item.season_number
|
if (item.season_display_number === 'Epizode') return item.season_number
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDescription(item) {
|
function parseDescription(item) {
|
||||||
if (!item.details) return null
|
if (!item.details) return null
|
||||||
return item.details.description
|
return item.details.description
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseRoles(item, role_name) {
|
function parseRoles(item, role_name) {
|
||||||
if (!item.roles) return null
|
if (!item.roles) return null
|
||||||
return item.roles.filter(role => role.role_name === role_name).map(role => role.person_name)
|
return item.roles.filter(role => role.role_name === role_name).map(role => role.person_name)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,110 +1,110 @@
|
|||||||
const doFetch = require('@ntlab/sfetch')
|
const doFetch = require('@ntlab/sfetch')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
const { sortBy } = require('../../scripts/functions')
|
const { sortBy } = require('../../scripts/functions')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'mtel.ba',
|
site: 'mtel.ba',
|
||||||
days: 2,
|
days: 2,
|
||||||
url({ channel, date }) {
|
url({ channel, date }) {
|
||||||
const [platform] = channel.site_id.split('#')
|
const [platform] = channel.site_id.split('#')
|
||||||
|
|
||||||
return `https://mtel.ba/hybris/ecommerce/b2c/v1/products/channels/epg?platform=tv-${platform}&pageSize=999&date=${date.format(
|
return `https://mtel.ba/hybris/ecommerce/b2c/v1/products/channels/epg?platform=tv-${platform}&pageSize=999&date=${date.format(
|
||||||
'YYYY-MM-DD'
|
'YYYY-MM-DD'
|
||||||
)}`
|
)}`
|
||||||
},
|
},
|
||||||
request: {
|
request: {
|
||||||
timeout: 20000, // 20 seconds
|
timeout: 20000, // 20 seconds
|
||||||
maxContentLength: 10000000, // 10 Mb
|
maxContentLength: 10000000, // 10 Mb
|
||||||
cache: {
|
cache: {
|
||||||
interpretHeader: false,
|
interpretHeader: false,
|
||||||
ttl: 24 * 60 * 60 * 1000 // 1 day
|
ttl: 24 * 60 * 60 * 1000 // 1 day
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
parser({ content, channel }) {
|
parser({ content, channel }) {
|
||||||
let programs = []
|
let programs = []
|
||||||
const items = parseItems(content, channel)
|
const items = parseItems(content, channel)
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
programs.push({
|
programs.push({
|
||||||
title: item.title,
|
title: item.title,
|
||||||
description: item.description,
|
description: item.description,
|
||||||
categories: parseCategories(item),
|
categories: parseCategories(item),
|
||||||
image: parseImage(item),
|
image: parseImage(item),
|
||||||
start: parseStart(item),
|
start: parseStart(item),
|
||||||
stop: parseStop(item)
|
stop: parseStop(item)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels({ platform = 'msat' }) {
|
async channels({ platform = 'msat' }) {
|
||||||
const platforms = {
|
const platforms = {
|
||||||
msat: 'https://mtel.ba/hybris/ecommerce/b2c/v1/products/channels/search?pageSize=999&query=:relevantno:tv-kategorija:tv-msat',
|
msat: 'https://mtel.ba/hybris/ecommerce/b2c/v1/products/channels/search?pageSize=999&query=:relevantno:tv-kategorija:tv-msat',
|
||||||
iptv: 'https://mtel.ba/hybris/ecommerce/b2c/v1/products/channels/search?pageSize=999&query=:relevantno:tv-kategorija:tv-iptv'
|
iptv: 'https://mtel.ba/hybris/ecommerce/b2c/v1/products/channels/search?pageSize=999&query=:relevantno:tv-kategorija:tv-iptv'
|
||||||
}
|
}
|
||||||
|
|
||||||
const queue = [
|
const queue = [
|
||||||
{
|
{
|
||||||
platform,
|
platform,
|
||||||
url: platforms[platform]
|
url: platforms[platform]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
let channels = []
|
let channels = []
|
||||||
await doFetch(queue, (req, data) => {
|
await doFetch(queue, (req, data) => {
|
||||||
if (data && data.pagination.currentPage < data.pagination.totalPages) {
|
if (data && data.pagination.currentPage < data.pagination.totalPages) {
|
||||||
queue.push({
|
queue.push({
|
||||||
platform: req.platform,
|
platform: req.platform,
|
||||||
url: platforms[req.platform]
|
url: platforms[req.platform]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
data.products.forEach(channel => {
|
data.products.forEach(channel => {
|
||||||
channels.push({
|
channels.push({
|
||||||
lang: 'bs',
|
lang: 'bs',
|
||||||
name: channel.name,
|
name: channel.name,
|
||||||
site_id: `${req.platform}#${channel.code}`
|
site_id: `${req.platform}#${channel.code}`
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return channels
|
return channels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStart(item) {
|
function parseStart(item) {
|
||||||
return dayjs.tz(item.start, 'YYYY-MM-DD HH:mm', 'Europe/Sarajevo')
|
return dayjs.tz(item.start, 'YYYY-MM-DD HH:mm', 'Europe/Sarajevo')
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStop(item) {
|
function parseStop(item) {
|
||||||
return dayjs.tz(item.end, 'YYYY-MM-DD HH:mm', 'Europe/Sarajevo')
|
return dayjs.tz(item.end, 'YYYY-MM-DD HH:mm', 'Europe/Sarajevo')
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseCategories(item) {
|
function parseCategories(item) {
|
||||||
return item.category ? item.category.split(' / ') : []
|
return item.category ? item.category.split(' / ') : []
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseImage(item) {
|
function parseImage(item) {
|
||||||
return item?.picture?.url ? item.picture.url : null
|
return item?.picture?.url ? item.picture.url : null
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(content, channel) {
|
function parseItems(content, channel) {
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(content)
|
const data = JSON.parse(content)
|
||||||
if (!data || !Array.isArray(data.products)) return []
|
if (!data || !Array.isArray(data.products)) return []
|
||||||
const [, channelId] = channel.site_id.split('#')
|
const [, channelId] = channel.site_id.split('#')
|
||||||
const channelData = data.products.find(channel => channel.code === channelId)
|
const channelData = data.products.find(channel => channel.code === channelId)
|
||||||
if (!channelData || !Array.isArray(channelData.programs)) return []
|
if (!channelData || !Array.isArray(channelData.programs)) return []
|
||||||
// filter out programs that have the sentence "no program information available"
|
// filter out programs that have the sentence "no program information available"
|
||||||
channelData.programs = channelData.programs.filter(p => !p.title.includes('Nema informacija o programu'))
|
channelData.programs = channelData.programs.filter(p => !p.title.includes('Nema informacija o programu'))
|
||||||
return sortBy(channelData.programs, p => parseStart(p).valueOf())
|
return sortBy(channelData.programs, p => parseStart(p).valueOf())
|
||||||
} catch {
|
} catch {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +1,58 @@
|
|||||||
const { parser, url } = require('./mtel.ba.config.js')
|
const { parser, url } = require('./mtel.ba.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2025-02-04', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2025-02-04', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = { site_id: 'msat#ch-11-rtrs' }
|
const channel = { site_id: 'msat#ch-11-rtrs' }
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date, channel })).toBe(
|
expect(url({ date, channel })).toBe(
|
||||||
'https://mtel.ba/hybris/ecommerce/b2c/v1/products/channels/epg?platform=tv-msat&pageSize=999&date=2025-02-04'
|
'https://mtel.ba/hybris/ecommerce/b2c/v1/products/channels/epg?platform=tv-msat&pageSize=999&date=2025-02-04'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
let results = parser({ channel, content })
|
let results = parser({ channel, content })
|
||||||
results = results.map(p => {
|
results = results.map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
|
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(results.length).toBe(38)
|
expect(results.length).toBe(38)
|
||||||
expect(results[0]).toMatchObject({
|
expect(results[0]).toMatchObject({
|
||||||
start: '2025-02-03T22:38:00.000Z',
|
start: '2025-02-03T22:38:00.000Z',
|
||||||
stop: '2025-02-03T23:38:00.000Z',
|
stop: '2025-02-03T23:38:00.000Z',
|
||||||
title: 'Neka pesma kaže',
|
title: 'Neka pesma kaže',
|
||||||
image:
|
image:
|
||||||
'https://medias.services.mtel.ba/medias/407368591.jpg?context=bWFzdGVyfHJvb3R8MTM2MTZ8aW1hZ2UvanBlZ3xhR1F5TDJnell5ODBOekExTmpFMk1qRTJNRFkzTUM4ME1EY3pOamcxT1RFdWFuQm58ZWM3Zjc4MDNlZTY5OWU1ZGJiZDI5N2UzMDg4ODA3NzQ1NWM0OThlMjdhYmU4MjI4NGJhOWE2YzYwMTc5ODM3NQ',
|
'https://medias.services.mtel.ba/medias/407368591.jpg?context=bWFzdGVyfHJvb3R8MTM2MTZ8aW1hZ2UvanBlZ3xhR1F5TDJnell5ODBOekExTmpFMk1qRTJNRFkzTUM4ME1EY3pOamcxT1RFdWFuQm58ZWM3Zjc4MDNlZTY5OWU1ZGJiZDI5N2UzMDg4ODA3NzQ1NWM0OThlMjdhYmU4MjI4NGJhOWE2YzYwMTc5ODM3NQ',
|
||||||
description:
|
description:
|
||||||
'Zabavni-muzički program donosi nam divne zvukove prave, narodne muzike, u kojoj se izvođači oslanjaju na kvalitet i tradiciju.',
|
'Zabavni-muzički program donosi nam divne zvukove prave, narodne muzike, u kojoj se izvođači oslanjaju na kvalitet i tradiciju.',
|
||||||
categories: ['Music', 'Ballet', 'Dance']
|
categories: ['Music', 'Ballet', 'Dance']
|
||||||
})
|
})
|
||||||
expect(results[37]).toMatchObject({
|
expect(results[37]).toMatchObject({
|
||||||
start: '2025-02-04T22:27:00.000Z',
|
start: '2025-02-04T22:27:00.000Z',
|
||||||
stop: '2025-02-04T23:58:00.000Z',
|
stop: '2025-02-04T23:58:00.000Z',
|
||||||
title: 'Bitanga s plaže',
|
title: 'Bitanga s plaže',
|
||||||
image:
|
image:
|
||||||
'https://medias.services.mtel.ba/medias/117604203.jpg?context=bWFzdGVyfHJvb3R8MTY1MTZ8aW1hZ2UvanBlZ3xhRGd6TDJnek1DODBOekExTmpFMk16STNORGM0TWk4eE1UYzJNRFF5TURNdWFuQm58YmU5MjdkOTljMGE4YjIyNjg3ZmI1YWJjYWQ0ZDY5YjA0YWJiY2RlN2E0ZGVjOTdlYzM4MzI4MzYyMzFiODBlMg',
|
'https://medias.services.mtel.ba/medias/117604203.jpg?context=bWFzdGVyfHJvb3R8MTY1MTZ8aW1hZ2UvanBlZ3xhRGd6TDJnek1DODBOekExTmpFMk16STNORGM0TWk4eE1UYzJNRFF5TURNdWFuQm58YmU5MjdkOTljMGE4YjIyNjg3ZmI1YWJjYWQ0ZDY5YjA0YWJiY2RlN2E0ZGVjOTdlYzM4MzI4MzYyMzFiODBlMg',
|
||||||
description:
|
description:
|
||||||
'Film prati urnebesne avanture Moondoga, buntovnika i skitnicu koji svoj život živi isključivo prema vlastitim pravilima. Uz glumačke nastupe Snoop Dogga, Zaca Efrona i Isle Fisher, Bitanga s plaže osvježavajuće je originalna i subverzivna nova komedija scenarista i redatelja Harmonyja Korinea.',
|
'Film prati urnebesne avanture Moondoga, buntovnika i skitnicu koji svoj život živi isključivo prema vlastitim pravilima. Uz glumačke nastupe Snoop Dogga, Zaca Efrona i Isle Fisher, Bitanga s plaže osvježavajuće je originalna i subverzivna nova komedija scenarista i redatelja Harmonyja Korinea.',
|
||||||
categories: ['Movie', 'Drama']
|
categories: ['Movie', 'Drama']
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const results = parser({
|
const results = parser({
|
||||||
channel,
|
channel,
|
||||||
content: '{}'
|
content: '{}'
|
||||||
})
|
})
|
||||||
expect(results).toMatchObject([])
|
expect(results).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,45 +1,45 @@
|
|||||||
const { parser, url } = require('./mysky.com.ph.config.js')
|
const { parser, url } = require('./mysky.com.ph.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-10-04', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-10-04', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '8',
|
site_id: '8',
|
||||||
xmltv_id: 'KapamilyaChannel.ph'
|
xmltv_id: 'KapamilyaChannel.ph'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url).toBe('https://skyepg.mysky.com.ph/Main/getEventsbyType')
|
expect(url).toBe('https://skyepg.mysky.com.ph/Main/getEventsbyType')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, channel, date }).map(p => {
|
const result = parser({ content, channel, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-10-04T11:00:00.000Z',
|
start: '2022-10-04T11:00:00.000Z',
|
||||||
stop: '2022-10-04T12:00:00.000Z',
|
stop: '2022-10-04T12:00:00.000Z',
|
||||||
title: 'TV PATROL',
|
title: 'TV PATROL',
|
||||||
description: 'Description example'
|
description: 'Description example'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: '',
|
content: '',
|
||||||
channel,
|
channel,
|
||||||
date
|
date
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,61 +1,61 @@
|
|||||||
const { parser, url } = require('./neo.io.config.js')
|
const { parser, url } = require('./neo.io.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2024-12-26', 'YYYY-MM-DD').startOf('day')
|
const date = dayjs.utc('2024-12-26', 'YYYY-MM-DD').startOf('day')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: 'tv-slo-1',
|
site_id: 'tv-slo-1',
|
||||||
xmltv_id: 'TVSLO1.si'
|
xmltv_id: 'TVSLO1.si'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date, channel })).toBe(
|
expect(url({ date, channel })).toBe(
|
||||||
'https://stargate.telekom.si/api/titan.tv.WebEpg/GetWebEpgData'
|
'https://stargate.telekom.si/api/titan.tv.WebEpg/GetWebEpgData'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, channel })
|
const result = parser({ content, channel })
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
title: 'Napovedujemo',
|
title: 'Napovedujemo',
|
||||||
description: 'Vabilo k ogledu naših oddaj.',
|
description: 'Vabilo k ogledu naših oddaj.',
|
||||||
start: '2024-12-26T04:05:00.000Z',
|
start: '2024-12-26T04:05:00.000Z',
|
||||||
stop: '2024-12-26T05:50:00.000Z',
|
stop: '2024-12-26T05:50:00.000Z',
|
||||||
thumbnail:
|
thumbnail:
|
||||||
'https://ngimg.siol.tv/sioltv/mtcmsprod/52/0/0/5200d01a-fe5f-487e-835a-274e77227a6b.jpg'
|
'https://ngimg.siol.tv/sioltv/mtcmsprod/52/0/0/5200d01a-fe5f-487e-835a-274e77227a6b.jpg'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'S0E0 - Hrabri zajčki: Prvi sneg',
|
title: 'S0E0 - Hrabri zajčki: Prvi sneg',
|
||||||
description:
|
description:
|
||||||
'Hrabri zajčki so prispeli v borov gozd in izkusili prvi sneg. Bob in Bu še nikoli nista videla snega. Mami kuha korenčkov kakav, Bu in Bob pa kmalu spoznata novega prijatelja, losa Danija.',
|
'Hrabri zajčki so prispeli v borov gozd in izkusili prvi sneg. Bob in Bu še nikoli nista videla snega. Mami kuha korenčkov kakav, Bu in Bob pa kmalu spoznata novega prijatelja, losa Danija.',
|
||||||
start: '2024-12-26T05:50:00.000Z',
|
start: '2024-12-26T05:50:00.000Z',
|
||||||
stop: '2024-12-26T06:00:00.000Z',
|
stop: '2024-12-26T06:00:00.000Z',
|
||||||
thumbnail:
|
thumbnail:
|
||||||
'https://ngimg.siol.tv/sioltv/mtcmsprod/d6/4/5/d6456f4a-4f0a-4825-90c1-1749abd59688.jpg'
|
'https://ngimg.siol.tv/sioltv/mtcmsprod/d6/4/5/d6456f4a-4f0a-4825-90c1-1749abd59688.jpg'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Dobro jutro',
|
title: 'Dobro jutro',
|
||||||
description:
|
description:
|
||||||
'Oddaja Dobro jutro poleg informativnih in zabavnih vsebin podaja koristne nasvete o najrazličnejših tematikah iz vsakdanjega življenja.',
|
'Oddaja Dobro jutro poleg informativnih in zabavnih vsebin podaja koristne nasvete o najrazličnejših tematikah iz vsakdanjega življenja.',
|
||||||
start: '2024-12-26T06:00:00.000Z',
|
start: '2024-12-26T06:00:00.000Z',
|
||||||
stop: '2024-12-26T09:05:00.000Z',
|
stop: '2024-12-26T09:05:00.000Z',
|
||||||
thumbnail:
|
thumbnail:
|
||||||
'https://ngimg.siol.tv/sioltv/mtcmsprod/e1/2/d/e12d8eb4-693a-43d3-89d4-fd96dade9f0f.jpg'
|
'https://ngimg.siol.tv/sioltv/mtcmsprod/e1/2/d/e12d8eb4-693a-43d3-89d4-fd96dade9f0f.jpg'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,49 +1,49 @@
|
|||||||
const { parser, url } = require('./novacyprus.com.config.js')
|
const { parser, url } = require('./novacyprus.com.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-17', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-17', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '614',
|
site_id: '614',
|
||||||
xmltv_id: 'NovaCinema1.gr'
|
xmltv_id: 'NovaCinema1.gr'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date })).toBe(
|
expect(url({ date })).toBe(
|
||||||
'https://www.novacyprus.com/api/v1/tvprogram/from/20211117/to/20211118'
|
'https://www.novacyprus.com/api/v1/tvprogram/from/20211117/to/20211118'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-17T04:20:00.000Z',
|
start: '2021-11-17T04:20:00.000Z',
|
||||||
stop: '2021-11-17T06:10:00.000Z',
|
stop: '2021-11-17T06:10:00.000Z',
|
||||||
title: 'Δεσμοί Αίματος',
|
title: 'Δεσμοί Αίματος',
|
||||||
description: 'Θρίλερ Μυστηρίου',
|
description: 'Θρίλερ Μυστηρίου',
|
||||||
image:
|
image:
|
||||||
'http://cache-forthnet.secure.footprint.net/linear/3/0/305608_COMMOBLOOX_GUIDE_STILL.jpg'
|
'http://cache-forthnet.secure.footprint.net/linear/3/0/305608_COMMOBLOOX_GUIDE_STILL.jpg'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,58 +1,58 @@
|
|||||||
const { parser, url, request } = require('./nowplayer.now.com.config.js')
|
const { parser, url, request } = require('./nowplayer.now.com.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const channel = {
|
const channel = {
|
||||||
lang: 'zh',
|
lang: 'zh',
|
||||||
site_id: '096',
|
site_id: '096',
|
||||||
xmltv_id: 'ViuTVsix.hk'
|
xmltv_id: 'ViuTVsix.hk'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url for today', () => {
|
it('can generate valid url for today', () => {
|
||||||
const date = dayjs.utc().startOf('d')
|
const date = dayjs.utc().startOf('d')
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://nowplayer.now.com/tvguide/epglist?channelIdList[]=096&day=1'
|
'https://nowplayer.now.com/tvguide/epglist?channelIdList[]=096&day=1'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid url for tomorrow', () => {
|
it('can generate valid url for tomorrow', () => {
|
||||||
const date = dayjs.utc().startOf('d').add(1, 'd')
|
const date = dayjs.utc().startOf('d').add(1, 'd')
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://nowplayer.now.com/tvguide/epglist?channelIdList[]=096&day=2'
|
'https://nowplayer.now.com/tvguide/epglist?channelIdList[]=096&day=2'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request headers', () => {
|
it('can generate valid request headers', () => {
|
||||||
expect(request.headers({ channel })).toMatchObject({
|
expect(request.headers({ channel })).toMatchObject({
|
||||||
Cookie: 'LANG=zh; Expires=null; Path=/; Domain=nowplayer.now.com'
|
Cookie: 'LANG=zh; Expires=null; Path=/; Domain=nowplayer.now.com'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-23T18:00:00.000Z',
|
start: '2021-11-23T18:00:00.000Z',
|
||||||
stop: '2021-11-24T01:00:00.000Z',
|
stop: '2021-11-24T01:00:00.000Z',
|
||||||
title: 'ViuTVsix Station Closing'
|
title: 'ViuTVsix Station Closing'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: '[[]]'
|
content: '[[]]'
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,178 +1,178 @@
|
|||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const cheerio = require('cheerio')
|
const cheerio = require('cheerio')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
const { uniqBy } = require('../../scripts/functions')
|
const { uniqBy } = require('../../scripts/functions')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'ontvtonight.com',
|
site: 'ontvtonight.com',
|
||||||
days: 2,
|
days: 2,
|
||||||
url: function ({ date, channel }) {
|
url: function ({ date, channel }) {
|
||||||
const [region, id] = channel.site_id.split('#')
|
const [region, id] = channel.site_id.split('#')
|
||||||
let url = 'https://www.ontvtonight.com'
|
let url = 'https://www.ontvtonight.com'
|
||||||
if (region && region !== 'us') url += `/${region}`
|
if (region && region !== 'us') url += `/${region}`
|
||||||
url += `/guide/listings/channel/${id}.html?dt=${date.format('YYYY-MM-DD')}`
|
url += `/guide/listings/channel/${id}.html?dt=${date.format('YYYY-MM-DD')}`
|
||||||
|
|
||||||
return url
|
return url
|
||||||
},
|
},
|
||||||
parser: function ({ content, date, channel }) {
|
parser: function ({ content, date, channel }) {
|
||||||
const programs = []
|
const programs = []
|
||||||
const items = parseItems(content)
|
const items = parseItems(content)
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
const prev = programs[programs.length - 1]
|
const prev = programs[programs.length - 1]
|
||||||
const $item = cheerio.load(item)
|
const $item = cheerio.load(item)
|
||||||
let start = parseStart($item, date, channel)
|
let start = parseStart($item, date, channel)
|
||||||
if (prev) {
|
if (prev) {
|
||||||
if (start.isBefore(prev.start)) {
|
if (start.isBefore(prev.start)) {
|
||||||
start = start.add(1, 'd')
|
start = start.add(1, 'd')
|
||||||
date = date.add(1, 'd')
|
date = date.add(1, 'd')
|
||||||
}
|
}
|
||||||
prev.stop = start
|
prev.stop = start
|
||||||
}
|
}
|
||||||
const stop = start.add(1, 'h')
|
const stop = start.add(1, 'h')
|
||||||
programs.push({
|
programs.push({
|
||||||
title: parseTitle($item),
|
title: parseTitle($item),
|
||||||
description: parseDescription($item),
|
description: parseDescription($item),
|
||||||
start,
|
start,
|
||||||
stop
|
stop
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels({ country }) {
|
async channels({ country }) {
|
||||||
const providers = {
|
const providers = {
|
||||||
au: ['o', 'a'],
|
au: ['o', 'a'],
|
||||||
ca: [
|
ca: [
|
||||||
'Y464014423',
|
'Y464014423',
|
||||||
'-464014503',
|
'-464014503',
|
||||||
'-464014594',
|
'-464014594',
|
||||||
'-464014738',
|
'-464014738',
|
||||||
'X3153330286',
|
'X3153330286',
|
||||||
'X464014503',
|
'X464014503',
|
||||||
'X464013696',
|
'X464013696',
|
||||||
'X464014594',
|
'X464014594',
|
||||||
'X464014738',
|
'X464014738',
|
||||||
'X464014470',
|
'X464014470',
|
||||||
'X464013514',
|
'X464013514',
|
||||||
'X1210684931',
|
'X1210684931',
|
||||||
'T3153330286',
|
'T3153330286',
|
||||||
'T464014503',
|
'T464014503',
|
||||||
'T1810267316',
|
'T1810267316',
|
||||||
'T1210684931'
|
'T1210684931'
|
||||||
],
|
],
|
||||||
us: [
|
us: [
|
||||||
'Y341768590',
|
'Y341768590',
|
||||||
'Y1693286984',
|
'Y1693286984',
|
||||||
'Y8833268284',
|
'Y8833268284',
|
||||||
'-341767428',
|
'-341767428',
|
||||||
'-341769166',
|
'-341769166',
|
||||||
'-341769884',
|
'-341769884',
|
||||||
'-3679985536',
|
'-3679985536',
|
||||||
'-341766967',
|
'-341766967',
|
||||||
'X4100694897',
|
'X4100694897',
|
||||||
'X341767428',
|
'X341767428',
|
||||||
'X341768182',
|
'X341768182',
|
||||||
'X341767434',
|
'X341767434',
|
||||||
'X341768272',
|
'X341768272',
|
||||||
'X341769884',
|
'X341769884',
|
||||||
'X3679985536',
|
'X3679985536',
|
||||||
'X3679984937',
|
'X3679984937',
|
||||||
'X341764975',
|
'X341764975',
|
||||||
'X3679985052',
|
'X3679985052',
|
||||||
'X341766967',
|
'X341766967',
|
||||||
'K4805071612',
|
'K4805071612',
|
||||||
'K5039655414'
|
'K5039655414'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
const regions = {
|
const regions = {
|
||||||
au: [
|
au: [
|
||||||
1, 2, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 17, 18, 29, 28, 27, 26, 25, 23, 22,
|
1, 2, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 17, 18, 29, 28, 27, 26, 25, 23, 22,
|
||||||
21, 20, 19, 24, 30, 31, 32, 33, 34, 35, 36, 39, 38, 37, 40, 41, 42, 43, 44, 45, 46, 47, 48,
|
21, 20, 19, 24, 30, 31, 32, 33, 34, 35, 36, 39, 38, 37, 40, 41, 42, 43, 44, 45, 46, 47, 48,
|
||||||
49, 50, 51, 52, 53
|
49, 50, 51, 52, 53
|
||||||
],
|
],
|
||||||
ca: [null],
|
ca: [null],
|
||||||
us: [null]
|
us: [null]
|
||||||
}
|
}
|
||||||
const zipcodes = {
|
const zipcodes = {
|
||||||
au: [null],
|
au: [null],
|
||||||
ca: ['M5G1P5', 'H3B1X8', 'V6Z2H7', 'T2P3E6', 'T5J2Z2', 'K1P1B1'],
|
ca: ['M5G1P5', 'H3B1X8', 'V6Z2H7', 'T2P3E6', 'T5J2Z2', 'K1P1B1'],
|
||||||
us: [10199, 90052, 60607, 77201, 85026, 19104, 78284, 92199, 75260]
|
us: [10199, 90052, 60607, 77201, 85026, 19104, 78284, 92199, 75260]
|
||||||
}
|
}
|
||||||
|
|
||||||
const channels = []
|
const channels = []
|
||||||
for (let provider of providers[country]) {
|
for (let provider of providers[country]) {
|
||||||
for (let zipcode of zipcodes[country]) {
|
for (let zipcode of zipcodes[country]) {
|
||||||
for (let region of regions[country]) {
|
for (let region of regions[country]) {
|
||||||
let url = 'https://www.ontvtonight.com'
|
let url = 'https://www.ontvtonight.com'
|
||||||
if (country === 'us') url += '/guide/schedule'
|
if (country === 'us') url += '/guide/schedule'
|
||||||
else url += `/${country}/guide/schedule`
|
else url += `/${country}/guide/schedule`
|
||||||
const data = await axios
|
const data = await axios
|
||||||
.post(url, null, {
|
.post(url, null, {
|
||||||
params: {
|
params: {
|
||||||
provider,
|
provider,
|
||||||
region,
|
region,
|
||||||
zipcode,
|
zipcode,
|
||||||
TVperiod: 'Night',
|
TVperiod: 'Night',
|
||||||
date: dayjs().format('YYYY-MM-DD'),
|
date: dayjs().format('YYYY-MM-DD'),
|
||||||
st: 0,
|
st: 0,
|
||||||
is_mobile: 1
|
is_mobile: 1
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
|
|
||||||
const $ = cheerio.load(data)
|
const $ = cheerio.load(data)
|
||||||
$('.channelname').each((i, el) => {
|
$('.channelname').each((i, el) => {
|
||||||
let name = $(el).find('center > a:eq(1)').text()
|
let name = $(el).find('center > a:eq(1)').text()
|
||||||
name = name.replace(/--/gi, '-')
|
name = name.replace(/--/gi, '-')
|
||||||
const url = $(el).find('center > a:eq(1)').attr('href')
|
const url = $(el).find('center > a:eq(1)').attr('href')
|
||||||
if (!url) return
|
if (!url) return
|
||||||
const [, number, slug] = url.match(/\/(\d+)\/(.*)\.html$/)
|
const [, number, slug] = url.match(/\/(\d+)\/(.*)\.html$/)
|
||||||
|
|
||||||
channels.push({
|
channels.push({
|
||||||
lang: 'en',
|
lang: 'en',
|
||||||
name,
|
name,
|
||||||
site_id: `${country}#${number}/${slug}`
|
site_id: `${country}#${number}/${slug}`
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return uniqBy(channels, 'site_id')
|
return uniqBy(channels, 'site_id')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStart($item, date, channel) {
|
function parseStart($item, date, channel) {
|
||||||
const timezones = {
|
const timezones = {
|
||||||
au: 'Australia/Sydney',
|
au: 'Australia/Sydney',
|
||||||
ca: 'America/Toronto',
|
ca: 'America/Toronto',
|
||||||
us: 'America/New_York'
|
us: 'America/New_York'
|
||||||
}
|
}
|
||||||
const [region] = channel.site_id.split('#')
|
const [region] = channel.site_id.split('#')
|
||||||
const timeString = $item('td:nth-child(1) > h5').text().trim()
|
const timeString = $item('td:nth-child(1) > h5').text().trim()
|
||||||
const dateString = `${date.format('YYYY-MM-DD')} ${timeString}`
|
const dateString = `${date.format('YYYY-MM-DD')} ${timeString}`
|
||||||
|
|
||||||
return dayjs.tz(dateString, 'YYYY-MM-DD H:mm a', timezones[region])
|
return dayjs.tz(dateString, 'YYYY-MM-DD H:mm a', timezones[region])
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTitle($item) {
|
function parseTitle($item) {
|
||||||
return $item('td:nth-child(2) > h5').text().trim()
|
return $item('td:nth-child(2) > h5').text().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDescription($item) {
|
function parseDescription($item) {
|
||||||
return $item('td:nth-child(2) > h6').text().trim()
|
return $item('td:nth-child(2) > h6').text().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(content) {
|
function parseItems(content) {
|
||||||
const $ = cheerio.load(content)
|
const $ = cheerio.load(content)
|
||||||
|
|
||||||
return $('#content > div > div > div > table > tbody > tr').toArray()
|
return $('#content > div > div > div > table > tbody > tr').toArray()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,57 +1,57 @@
|
|||||||
const { parser, url } = require('./ontvtonight.com.config.js')
|
const { parser, url } = require('./ontvtonight.com.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-25', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-25', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: 'au#1692/7two',
|
site_id: 'au#1692/7two',
|
||||||
xmltv_id: '7two.au'
|
xmltv_id: '7two.au'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://www.ontvtonight.com/au/guide/listings/channel/1692/7two.html?dt=2021-11-25'
|
'https://www.ontvtonight.com/au/guide/listings/channel/1692/7two.html?dt=2021-11-25'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
||||||
const result = parser({ content, channel, date }).map(p => {
|
const result = parser({ content, channel, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-24T13:10:00.000Z',
|
start: '2021-11-24T13:10:00.000Z',
|
||||||
stop: '2021-11-24T13:50:00.000Z',
|
stop: '2021-11-24T13:50:00.000Z',
|
||||||
title: 'What A Carry On'
|
title: 'What A Carry On'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2021-11-24T13:50:00.000Z',
|
start: '2021-11-24T13:50:00.000Z',
|
||||||
stop: '2021-11-25T11:50:00.000Z',
|
stop: '2021-11-25T11:50:00.000Z',
|
||||||
title: 'Bones',
|
title: 'Bones',
|
||||||
description: 'The Devil In The Details'
|
description: 'The Devil In The Details'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2021-11-25T11:50:00.000Z',
|
start: '2021-11-25T11:50:00.000Z',
|
||||||
stop: '2021-11-25T12:50:00.000Z',
|
stop: '2021-11-25T12:50:00.000Z',
|
||||||
title: 'Inspector Morse: The Remorseful Day'
|
title: 'Inspector Morse: The Remorseful Day'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,44 +1,44 @@
|
|||||||
const { parser, url } = require('./pbsguam.org.config.js')
|
const { parser, url } = require('./pbsguam.org.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-25', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-25', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '#',
|
site_id: '#',
|
||||||
xmltv_id: 'KGTF.us'
|
xmltv_id: 'KGTF.us'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url).toBe('https://pbsguam.org/calendar/')
|
expect(url).toBe('https://pbsguam.org/calendar/')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
||||||
const result = parser({ date, content }).map(p => {
|
const result = parser({ date, content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-25T08:30:00.000Z',
|
start: '2021-11-25T08:30:00.000Z',
|
||||||
stop: '2021-11-25T09:00:00.000Z',
|
stop: '2021-11-25T09:00:00.000Z',
|
||||||
title: 'Xavier Riddle and the Secret Museum'
|
title: 'Xavier Riddle and the Secret Museum'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,95 +1,95 @@
|
|||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'programetv.ro',
|
site: 'programetv.ro',
|
||||||
days: 2,
|
days: 2,
|
||||||
url: function ({ date, channel }) {
|
url: function ({ date, channel }) {
|
||||||
const daysOfWeek = {
|
const daysOfWeek = {
|
||||||
0: 'duminica',
|
0: 'duminica',
|
||||||
1: 'luni',
|
1: 'luni',
|
||||||
2: 'marti',
|
2: 'marti',
|
||||||
3: 'miercuri',
|
3: 'miercuri',
|
||||||
4: 'joi',
|
4: 'joi',
|
||||||
5: 'vineri',
|
5: 'vineri',
|
||||||
6: 'sambata'
|
6: 'sambata'
|
||||||
}
|
}
|
||||||
const day = date.day()
|
const day = date.day()
|
||||||
|
|
||||||
return `https://www.programetv.ro/program-tv/${channel.site_id}/${daysOfWeek[day]}/`
|
return `https://www.programetv.ro/program-tv/${channel.site_id}/${daysOfWeek[day]}/`
|
||||||
},
|
},
|
||||||
parser: function ({ content }) {
|
parser: function ({ content }) {
|
||||||
let programs = []
|
let programs = []
|
||||||
const data = parseContent(content)
|
const data = parseContent(content)
|
||||||
if (!data || !data.shows) return programs
|
if (!data || !data.shows) return programs
|
||||||
const items = data.shows
|
const items = data.shows
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
programs.push({
|
programs.push({
|
||||||
title: item.title,
|
title: item.title,
|
||||||
sub_title: item.titleOriginal,
|
sub_title: item.titleOriginal,
|
||||||
description: item.desc || item.obs,
|
description: item.desc || item.obs,
|
||||||
category: item.categories,
|
category: item.categories,
|
||||||
season: item.season || null,
|
season: item.season || null,
|
||||||
episode: item.episode || null,
|
episode: item.episode || null,
|
||||||
start: parseStart(item),
|
start: parseStart(item),
|
||||||
stop: parseStop(item),
|
stop: parseStop(item),
|
||||||
url: item.url || null,
|
url: item.url || null,
|
||||||
date: item.date,
|
date: item.date,
|
||||||
rating: parseRating(item),
|
rating: parseRating(item),
|
||||||
directors: parseDirector(item),
|
directors: parseDirector(item),
|
||||||
actors: parseActor(item),
|
actors: parseActor(item),
|
||||||
icon: item.icon
|
icon: item.icon
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels() {
|
async channels() {
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const data = await axios
|
const data = await axios
|
||||||
.get('https://www.programetv.ro/api/station/index/')
|
.get('https://www.programetv.ro/api/station/index/')
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
|
|
||||||
return data.map(item => {
|
return data.map(item => {
|
||||||
return {
|
return {
|
||||||
lang: 'ro',
|
lang: 'ro',
|
||||||
site_id: item.slug,
|
site_id: item.slug,
|
||||||
name: item.displayName
|
name: item.displayName
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStart(item) {
|
function parseStart(item) {
|
||||||
return dayjs(item.start).toJSON()
|
return dayjs(item.start).toJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStop(item) {
|
function parseStop(item) {
|
||||||
return dayjs(item.stop).toJSON()
|
return dayjs(item.stop).toJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseContent(content) {
|
function parseContent(content) {
|
||||||
const [, data] = content.match(/var pageData = ({.+?});/) || [null, null]
|
const [, data] = content.match(/var pageData = ({.+?});/) || [null, null]
|
||||||
|
|
||||||
return data ? JSON.parse(data) : {}
|
return data ? JSON.parse(data) : {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDirector(item) {
|
function parseDirector(item) {
|
||||||
return item.credits && item.credits.director ? item.credits.director : null
|
return item.credits && item.credits.director ? item.credits.director : null
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseActor(item) {
|
function parseActor(item) {
|
||||||
return item.credits && item.credits.actor ? item.credits.actor : null
|
return item.credits && item.credits.actor ? item.credits.actor : null
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseRating(item) {
|
function parseRating(item) {
|
||||||
return item.rating
|
return item.rating
|
||||||
? {
|
? {
|
||||||
system: 'CNC',
|
system: 'CNC',
|
||||||
value: item.rating.toUpperCase()
|
value: item.rating.toUpperCase()
|
||||||
}
|
}
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
const { parser, url } = require('./programetv.ro.config.js')
|
const { parser, url } = require('./programetv.ro.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-10-24', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-10-24', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = { site_id: 'pro-tv', xmltv_id: 'ProTV.ro' }
|
const channel = { site_id: 'pro-tv', xmltv_id: 'ProTV.ro' }
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
const result = url({ date, channel })
|
const result = url({ date, channel })
|
||||||
expect(result).toBe('https://www.programetv.ro/program-tv/pro-tv/duminica/')
|
expect(result).toBe('https://www.programetv.ro/program-tv/pro-tv/duminica/')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
||||||
const result = parser({ date, channel, content })
|
const result = parser({ date, channel, content })
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-07T05:00:00.000Z',
|
start: '2021-11-07T05:00:00.000Z',
|
||||||
stop: '2021-11-07T07:59:59.000Z',
|
stop: '2021-11-07T07:59:59.000Z',
|
||||||
title: 'Ştirile Pro Tv',
|
title: 'Ştirile Pro Tv',
|
||||||
description:
|
description:
|
||||||
'În fiecare zi, cele mai importante evenimente, transmisiuni LIVE, analize, anchete şi reportaje sunt la Ştirile ProTV.',
|
'În fiecare zi, cele mai importante evenimente, transmisiuni LIVE, analize, anchete şi reportaje sunt la Ştirile ProTV.',
|
||||||
category: ['Ştiri'],
|
category: ['Ştiri'],
|
||||||
icon: 'https://www.programetv.ro/img/shows/84/54/stirile-pro-tv.png?key=Z2lfZnVial90cmFyZXZwLzAwLzAwLzA1LzE4MzgxMnktMTIwazE3MC1hLW40NTk4MW9zLmNhdA=='
|
icon: 'https://www.programetv.ro/img/shows/84/54/stirile-pro-tv.png?key=Z2lfZnVial90cmFyZXZwLzAwLzAwLzA1LzE4MzgxMnktMTIwazE3MC1hLW40NTk4MW9zLmNhdA=='
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
||||||
|
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,107 +1,107 @@
|
|||||||
const { parser, url, request } = require('./programme-tv.vini.pf.config.js')
|
const { parser, url, request } = require('./programme-tv.vini.pf.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
|
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
jest.mock('axios')
|
jest.mock('axios')
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-21', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-21', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: 'tf1',
|
site_id: 'tf1',
|
||||||
xmltv_id: 'TF1.fr'
|
xmltv_id: 'TF1.fr'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url).toBe('https://programme-tv.vini.pf/programmesJSON')
|
expect(url).toBe('https://programme-tv.vini.pf/programmesJSON')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request method', () => {
|
it('can generate valid request method', () => {
|
||||||
expect(request.method).toBe('POST')
|
expect(request.method).toBe('POST')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request data', () => {
|
it('can generate valid request data', () => {
|
||||||
expect(request.data({ date })).toMatchObject({ dateDebut: '2021-11-20T14:00:00-10:00' })
|
expect(request.data({ date })).toMatchObject({ dateDebut: '2021-11-20T14:00:00-10:00' })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', done => {
|
it('can parse response', done => {
|
||||||
axios.post.mockImplementation((url, data) => {
|
axios.post.mockImplementation((url, data) => {
|
||||||
if (data.dateDebut === '2021-11-20T16:00:00-10:00') {
|
if (data.dateDebut === '2021-11-20T16:00:00-10:00') {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
data: Buffer.from(fs.readFileSync(path.resolve(__dirname, '__data__/content_1.json')))
|
data: Buffer.from(fs.readFileSync(path.resolve(__dirname, '__data__/content_1.json')))
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
data: Buffer.from(fs.readFileSync(path.resolve(__dirname, '__data__/content_2.json')))
|
data: Buffer.from(fs.readFileSync(path.resolve(__dirname, '__data__/content_2.json')))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
|
|
||||||
parser({ content, channel, date })
|
parser({ content, channel, date })
|
||||||
.then(result => {
|
.then(result => {
|
||||||
result = result.map(p => {
|
result = result.map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-20T23:50:00.000Z',
|
start: '2021-11-20T23:50:00.000Z',
|
||||||
stop: '2021-11-21T01:10:00.000Z',
|
stop: '2021-11-21T01:10:00.000Z',
|
||||||
title: 'Reportages découverte',
|
title: 'Reportages découverte',
|
||||||
category: 'Magazine',
|
category: 'Magazine',
|
||||||
description:
|
description:
|
||||||
"Pour faire face à la crise du logement, aux loyers toujours plus élevés, à la solitude ou pour les gardes d'enfants, les colocations ont le vent en poupe, Pour mieux comprendre ce nouveau phénomène, une équipe a partagé le quotidien de quatre foyers : une retraitée qui héberge des étudiants, des mamans solos, enceintes, qui partagent un appartement associatif, trois générations de la même famille sur un domaine viticole et une étudiante qui intègre une colocation XXL.",
|
"Pour faire face à la crise du logement, aux loyers toujours plus élevés, à la solitude ou pour les gardes d'enfants, les colocations ont le vent en poupe, Pour mieux comprendre ce nouveau phénomène, une équipe a partagé le quotidien de quatre foyers : une retraitée qui héberge des étudiants, des mamans solos, enceintes, qui partagent un appartement associatif, trois générations de la même famille sur un domaine viticole et une étudiante qui intègre une colocation XXL.",
|
||||||
image:
|
image:
|
||||||
'https://programme-tv.vini.pf/sites/default/files/img-icones/52ada51ed86b7e7bc11eaee83ff2192785989d77.jpg'
|
'https://programme-tv.vini.pf/sites/default/files/img-icones/52ada51ed86b7e7bc11eaee83ff2192785989d77.jpg'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2021-11-21T01:10:00.000Z',
|
start: '2021-11-21T01:10:00.000Z',
|
||||||
stop: '2021-11-21T02:30:00.000Z',
|
stop: '2021-11-21T02:30:00.000Z',
|
||||||
title: 'Les docs du week-end',
|
title: 'Les docs du week-end',
|
||||||
category: 'Magazine',
|
category: 'Magazine',
|
||||||
description:
|
description:
|
||||||
'Un documentaire français réalisé en 2019, Cindy Sander, Myriam Abel, Mario, Michal ou encore Magali Vaé ont fait les grandes heures des premières émissions de télécrochet modernes, dans les années 2000, Des années après leur passage, que reste-t-il de leur notoriété ? Comment ces candidats ont-ils vécu leur soudaine médiatisation ? Quels rapports entretenaient-ils avec les autres participants et les membres du jury, souvent intransigeants ?',
|
'Un documentaire français réalisé en 2019, Cindy Sander, Myriam Abel, Mario, Michal ou encore Magali Vaé ont fait les grandes heures des premières émissions de télécrochet modernes, dans les années 2000, Des années après leur passage, que reste-t-il de leur notoriété ? Comment ces candidats ont-ils vécu leur soudaine médiatisation ? Quels rapports entretenaient-ils avec les autres participants et les membres du jury, souvent intransigeants ?',
|
||||||
image:
|
image:
|
||||||
'https://programme-tv.vini.pf/sites/default/files/img-icones/6e64cfbc55c1f4cbd11e3011401403d4dc08c6d2.jpg'
|
'https://programme-tv.vini.pf/sites/default/files/img-icones/6e64cfbc55c1f4cbd11e3011401403d4dc08c6d2.jpg'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2021-11-21T02:30:00.000Z',
|
start: '2021-11-21T02:30:00.000Z',
|
||||||
stop: '2021-11-21T03:45:00.000Z',
|
stop: '2021-11-21T03:45:00.000Z',
|
||||||
title: '50mn Inside',
|
title: '50mn Inside',
|
||||||
category: 'Magazine',
|
category: 'Magazine',
|
||||||
description:
|
description:
|
||||||
"50'INSIDE, c'est toute l'actualité des stars résumée, chaque samedi, Le rendez-vous glamour pour retrouver toujours,,",
|
"50'INSIDE, c'est toute l'actualité des stars résumée, chaque samedi, Le rendez-vous glamour pour retrouver toujours,,",
|
||||||
image:
|
image:
|
||||||
'https://programme-tv.vini.pf/sites/default/files/img-icones/3d7e252312dacb5fb7a1a786fa0022ca1be15499.jpg'
|
'https://programme-tv.vini.pf/sites/default/files/img-icones/3d7e252312dacb5fb7a1a786fa0022ca1be15499.jpg'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
done(err)
|
done(err)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', done => {
|
it('can handle empty guide', done => {
|
||||||
parser({
|
parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content:
|
content:
|
||||||
''
|
''
|
||||||
})
|
})
|
||||||
.then(result => {
|
.then(result => {
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
done(err)
|
done(err)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,76 +1,76 @@
|
|||||||
const MockDate = require('mockdate')
|
const MockDate = require('mockdate')
|
||||||
const { parser, url } = require('./programtv.onet.pl.config.js')
|
const { parser, url } = require('./programtv.onet.pl.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-24', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-24', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '13th-street-250',
|
site_id: '13th-street-250',
|
||||||
xmltv_id: '13thStreet.de'
|
xmltv_id: '13thStreet.de'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
MockDate.set(dayjs.utc('2021-11-24', 'YYYY-MM-DD').startOf('d'))
|
MockDate.set(dayjs.utc('2021-11-24', 'YYYY-MM-DD').startOf('d'))
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://programtv.onet.pl/program-tv/13th-street-250?dzien=0'
|
'https://programtv.onet.pl/program-tv/13th-street-250?dzien=0'
|
||||||
)
|
)
|
||||||
MockDate.reset()
|
MockDate.reset()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid url for next day', () => {
|
it('can generate valid url for next day', () => {
|
||||||
MockDate.set(dayjs.utc('2021-11-23', 'YYYY-MM-DD').startOf('d'))
|
MockDate.set(dayjs.utc('2021-11-23', 'YYYY-MM-DD').startOf('d'))
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://programtv.onet.pl/program-tv/13th-street-250?dzien=1'
|
'https://programtv.onet.pl/program-tv/13th-street-250?dzien=1'
|
||||||
)
|
)
|
||||||
MockDate.reset()
|
MockDate.reset()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'))
|
||||||
const result = parser({ content, date }).map(p => {
|
const result = parser({ content, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-24T02:20:00.000Z',
|
start: '2021-11-24T02:20:00.000Z',
|
||||||
stop: '2021-11-24T22:30:00.000Z',
|
stop: '2021-11-24T22:30:00.000Z',
|
||||||
title: 'Law & Order, odc. 15: Letzte Worte',
|
title: 'Law & Order, odc. 15: Letzte Worte',
|
||||||
category: 'Krimiserie',
|
category: 'Krimiserie',
|
||||||
description:
|
description:
|
||||||
'Bei einer Reality-TV-Show stirbt einer der Teilnehmer. Zunächst tappen Briscoe (Jerry Orbach) und Green (Jesse L....'
|
'Bei einer Reality-TV-Show stirbt einer der Teilnehmer. Zunächst tappen Briscoe (Jerry Orbach) und Green (Jesse L....'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2021-11-24T22:30:00.000Z',
|
start: '2021-11-24T22:30:00.000Z',
|
||||||
stop: '2021-11-25T00:00:00.000Z',
|
stop: '2021-11-25T00:00:00.000Z',
|
||||||
title: 'Navy CIS, odc. 1: New Orleans',
|
title: 'Navy CIS, odc. 1: New Orleans',
|
||||||
category: 'Krimiserie',
|
category: 'Krimiserie',
|
||||||
description:
|
description:
|
||||||
'Der Abgeordnete Dan McLane, ein ehemaliger Vorgesetzter von Gibbs, wird in New Orleans ermordet. In den 90er Jahren...'
|
'Der Abgeordnete Dan McLane, ein ehemaliger Vorgesetzter von Gibbs, wird in New Orleans ermordet. In den 90er Jahren...'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2021-11-25T00:00:00.000Z',
|
start: '2021-11-25T00:00:00.000Z',
|
||||||
stop: '2021-11-25T01:00:00.000Z',
|
stop: '2021-11-25T01:00:00.000Z',
|
||||||
title: 'Navy CIS: L.A, odc. 13: High Society',
|
title: 'Navy CIS: L.A, odc. 13: High Society',
|
||||||
category: 'Krimiserie',
|
category: 'Krimiserie',
|
||||||
description:
|
description:
|
||||||
'Die Zahl der Drogentoten ist gestiegen. Das Team des NCIS glaubt, dass sich Terroristen durch den zunehmenden...'
|
'Die Zahl der Drogentoten ist gestiegen. Das Team des NCIS glaubt, dass sich Terroristen durch den zunehmenden...'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,50 +1,50 @@
|
|||||||
const { parser, url } = require('./raiplay.it.config.js')
|
const { parser, url } = require('./raiplay.it.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-05-03', 'YYYY-MM-DD')
|
const date = dayjs.utc('2022-05-03', 'YYYY-MM-DD')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: 'rai-2',
|
site_id: 'rai-2',
|
||||||
xmltv_id: 'Rai2.it'
|
xmltv_id: 'Rai2.it'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe('https://www.raiplay.it/palinsesto/app/rai-2/03-05-2022.json')
|
expect(url({ channel, date })).toBe('https://www.raiplay.it/palinsesto/app/rai-2/03-05-2022.json')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, date }).map(p => {
|
const result = parser({ content, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
|
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-05-03T17:40:00.000Z',
|
start: '2022-05-03T17:40:00.000Z',
|
||||||
stop: '2022-05-03T18:30:00.000Z',
|
stop: '2022-05-03T18:30:00.000Z',
|
||||||
title: 'The Good Doctor S3E5 - La prima volta',
|
title: 'The Good Doctor S3E5 - La prima volta',
|
||||||
description:
|
description:
|
||||||
"Shaun affronta il suo primo intervento. Il caso si rivela complicato e, nonostante Shaun abbia un'idea geniale, sarà Andrews a portare a termine l'operazione.",
|
"Shaun affronta il suo primo intervento. Il caso si rivela complicato e, nonostante Shaun abbia un'idea geniale, sarà Andrews a portare a termine l'operazione.",
|
||||||
season: '3',
|
season: '3',
|
||||||
episode: '5',
|
episode: '5',
|
||||||
sub_title: 'La prima volta',
|
sub_title: 'La prima volta',
|
||||||
image: 'https://www.raiplay.it/dl/img/2020/03/09/1583748471860_dddddd.jpg',
|
image: 'https://www.raiplay.it/dl/img/2020/03/09/1583748471860_dddddd.jpg',
|
||||||
url: 'https://www.raiplay.it/dirette/rai2/The-Good-Doctor-S3E5---La-prima-volta-2f81030d-803b-456a-9ea5-40233234fd9d.html'
|
url: 'https://www.raiplay.it/dirette/rai2/The-Good-Doctor-S3E5---La-prima-volta-2f81030d-803b-456a-9ea5-40233234fd9d.html'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,170 +1,170 @@
|
|||||||
require('dayjs/locale/es')
|
require('dayjs/locale/es')
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const cheerio = require('cheerio')
|
const cheerio = require('cheerio')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
const { startCase } = require('../../scripts/functions')
|
const { startCase } = require('../../scripts/functions')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'reportv.com.ar',
|
site: 'reportv.com.ar',
|
||||||
days: 2,
|
days: 2,
|
||||||
request: {
|
request: {
|
||||||
cache: {
|
cache: {
|
||||||
ttl: 60 * 60 * 1000 // 1 hour
|
ttl: 60 * 60 * 1000 // 1 hour
|
||||||
},
|
},
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded'
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
},
|
},
|
||||||
data({ channel, date }) {
|
data({ channel, date }) {
|
||||||
const formData = new URLSearchParams()
|
const formData = new URLSearchParams()
|
||||||
formData.append('idSenial', channel.site_id)
|
formData.append('idSenial', channel.site_id)
|
||||||
formData.append('Alineacion', '2694')
|
formData.append('Alineacion', '2694')
|
||||||
formData.append('DiaDesde', date.format('YYYY/MM/DD'))
|
formData.append('DiaDesde', date.format('YYYY/MM/DD'))
|
||||||
formData.append('HoraDesde', '00:00:00')
|
formData.append('HoraDesde', '00:00:00')
|
||||||
|
|
||||||
return formData
|
return formData
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
url: 'https://www.reportv.com.ar/buscador/ProgXSenial.php',
|
url: 'https://www.reportv.com.ar/buscador/ProgXSenial.php',
|
||||||
parser: async function ({ content, date }) {
|
parser: async function ({ content, date }) {
|
||||||
let programs = []
|
let programs = []
|
||||||
const items = parseItems(content, date)
|
const items = parseItems(content, date)
|
||||||
for (let item of items) {
|
for (let item of items) {
|
||||||
const $item = cheerio.load(item)
|
const $item = cheerio.load(item)
|
||||||
const start = parseStart($item, date)
|
const start = parseStart($item, date)
|
||||||
const duration = parseDuration($item)
|
const duration = parseDuration($item)
|
||||||
const stop = start.add(duration, 's')
|
const stop = start.add(duration, 's')
|
||||||
const details = await loadProgramDetails($item)
|
const details = await loadProgramDetails($item)
|
||||||
programs.push({
|
programs.push({
|
||||||
title: parseTitle($item),
|
title: parseTitle($item),
|
||||||
category: parseCategory($item),
|
category: parseCategory($item),
|
||||||
image: details.image,
|
image: details.image,
|
||||||
description: details.description,
|
description: details.description,
|
||||||
directors: details.directors,
|
directors: details.directors,
|
||||||
actors: details.actors,
|
actors: details.actors,
|
||||||
start,
|
start,
|
||||||
stop
|
stop
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels() {
|
async channels() {
|
||||||
const content = await axios
|
const content = await axios
|
||||||
.get('https://www.reportv.com.ar/buscador/Buscador.php?aid=2694')
|
.get('https://www.reportv.com.ar/buscador/Buscador.php?aid=2694')
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
const $ = cheerio.load(content)
|
const $ = cheerio.load(content)
|
||||||
const items = $('#tr_home_2 > td:nth-child(1) > select > option').toArray()
|
const items = $('#tr_home_2 > td:nth-child(1) > select > option').toArray()
|
||||||
|
|
||||||
return items.map(item => {
|
return items.map(item => {
|
||||||
return {
|
return {
|
||||||
lang: 'es',
|
lang: 'es',
|
||||||
site_id: $(item).attr('value'),
|
site_id: $(item).attr('value'),
|
||||||
name: $(item).text()
|
name: $(item).text()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadProgramDetails($item) {
|
async function loadProgramDetails($item) {
|
||||||
const onclick = $item('*').attr('onclick')
|
const onclick = $item('*').attr('onclick')
|
||||||
const regexp = /detallePrograma\((\d+),(\d+),(\d+),(\d+),'([^']+)'\);/g
|
const regexp = /detallePrograma\((\d+),(\d+),(\d+),(\d+),'([^']+)'\);/g
|
||||||
const match = [...onclick.matchAll(regexp)]
|
const match = [...onclick.matchAll(regexp)]
|
||||||
const [, id, idc, id_alineacion, idp, title] = match[0]
|
const [, id, idc, id_alineacion, idp, title] = match[0]
|
||||||
if (!id || !idc || !id_alineacion || !idp || !title) return Promise.resolve({})
|
if (!id || !idc || !id_alineacion || !idp || !title) return Promise.resolve({})
|
||||||
const formData = new URLSearchParams()
|
const formData = new URLSearchParams()
|
||||||
formData.append('id', id)
|
formData.append('id', id)
|
||||||
formData.append('idc', idc)
|
formData.append('idc', idc)
|
||||||
formData.append('id_alineacion', id_alineacion)
|
formData.append('id_alineacion', id_alineacion)
|
||||||
formData.append('idp', idp)
|
formData.append('idp', idp)
|
||||||
formData.append('title', title)
|
formData.append('title', title)
|
||||||
const content = await axios
|
const content = await axios
|
||||||
.post('https://www.reportv.com.ar/buscador/DetallePrograma.php', formData)
|
.post('https://www.reportv.com.ar/buscador/DetallePrograma.php', formData)
|
||||||
.then(r => r.data.toString())
|
.then(r => r.data.toString())
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
if (!content) return Promise.resolve({})
|
if (!content) return Promise.resolve({})
|
||||||
|
|
||||||
const $ = cheerio.load(content)
|
const $ = cheerio.load(content)
|
||||||
|
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
image: parseImage($),
|
image: parseImage($),
|
||||||
actors: parseActors($),
|
actors: parseActors($),
|
||||||
directors: parseDirectors($),
|
directors: parseDirectors($),
|
||||||
description: parseDescription($)
|
description: parseDescription($)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseActors($) {
|
function parseActors($) {
|
||||||
const section = $('#Ficha > div')
|
const section = $('#Ficha > div')
|
||||||
.html()
|
.html()
|
||||||
.split('<br>')
|
.split('<br>')
|
||||||
.find(str => str.includes('Actores:'))
|
.find(str => str.includes('Actores:'))
|
||||||
if (!section) return null
|
if (!section) return null
|
||||||
const $section = cheerio.load(section)
|
const $section = cheerio.load(section)
|
||||||
|
|
||||||
return $section('span')
|
return $section('span')
|
||||||
.map((i, el) => $(el).text().trim())
|
.map((i, el) => $(el).text().trim())
|
||||||
.get()
|
.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDirectors($) {
|
function parseDirectors($) {
|
||||||
const section = $('#Ficha > div')
|
const section = $('#Ficha > div')
|
||||||
.html()
|
.html()
|
||||||
.split('<br>')
|
.split('<br>')
|
||||||
.find(str => str.includes('Directores:'))
|
.find(str => str.includes('Directores:'))
|
||||||
if (!section) return null
|
if (!section) return null
|
||||||
const $section = cheerio.load(section)
|
const $section = cheerio.load(section)
|
||||||
|
|
||||||
return $section('span')
|
return $section('span')
|
||||||
.map((i, el) => $(el).text().trim())
|
.map((i, el) => $(el).text().trim())
|
||||||
.get()
|
.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDescription($) {
|
function parseDescription($) {
|
||||||
return $('#Sinopsis > div').text().trim()
|
return $('#Sinopsis > div').text().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseImage($) {
|
function parseImage($) {
|
||||||
const src = $('#ImgProg').attr('src')
|
const src = $('#ImgProg').attr('src')
|
||||||
const url = new URL(src, 'https://www.reportv.com.ar/buscador/')
|
const url = new URL(src, 'https://www.reportv.com.ar/buscador/')
|
||||||
|
|
||||||
return url.href
|
return url.href
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTitle($item) {
|
function parseTitle($item) {
|
||||||
const [, title] = $item('div:nth-child(1) > span').text().split(' - ')
|
const [, title] = $item('div:nth-child(1) > span').text().split(' - ')
|
||||||
|
|
||||||
return title
|
return title
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseCategory($item) {
|
function parseCategory($item) {
|
||||||
return $item('div:nth-child(3) > span').text()
|
return $item('div:nth-child(3) > span').text()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStart($item, date) {
|
function parseStart($item, date) {
|
||||||
const [time] = $item('div:nth-child(1) > span').text().split(' - ')
|
const [time] = $item('div:nth-child(1) > span').text().split(' - ')
|
||||||
|
|
||||||
return dayjs.tz(`${date.format('YYYY-MM-DD')} ${time}`, 'YYYY-MM-DD HH:mm', 'America/Caracas')
|
return dayjs.tz(`${date.format('YYYY-MM-DD')} ${time}`, 'YYYY-MM-DD HH:mm', 'America/Caracas')
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDuration($item) {
|
function parseDuration($item) {
|
||||||
const [hh, mm, ss] = $item('div:nth-child(4) > span').text().split(':')
|
const [hh, mm, ss] = $item('div:nth-child(4) > span').text().split(':')
|
||||||
|
|
||||||
return parseInt(hh) * 3600 + parseInt(mm) * 60 + parseInt(ss)
|
return parseInt(hh) * 3600 + parseInt(mm) * 60 + parseInt(ss)
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(content, date) {
|
function parseItems(content, date) {
|
||||||
if (!content) return []
|
if (!content) return []
|
||||||
const $ = cheerio.load(content)
|
const $ = cheerio.load(content)
|
||||||
const d = startCase(date.locale('es').format('DD MMMM YYYY'))
|
const d = startCase(date.locale('es').format('DD MMMM YYYY'))
|
||||||
|
|
||||||
return $(`.trProg[title*="${d}"]`).toArray()
|
return $(`.trProg[title*="${d}"]`).toArray()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +1,58 @@
|
|||||||
const { parser, url } = require('./rikstv.no.config.js')
|
const { parser, url } = require('./rikstv.no.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
|
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2025-01-14', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2025-01-14', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '47',
|
site_id: '47',
|
||||||
xmltv_id: 'NRK1.no'
|
xmltv_id: 'NRK1.no'
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('rikstv.no Module Tests', () => {
|
describe('rikstv.no Module Tests', () => {
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date, channel })).toBe(
|
expect(url({ date, channel })).toBe(
|
||||||
`https://play.rikstv.no/api/content-search/1/channel/${channel.site_id}/epg/${date.format(
|
`https://play.rikstv.no/api/content-search/1/channel/${channel.site_id}/epg/${date.format(
|
||||||
'YYYY-MM-DD'
|
'YYYY-MM-DD'
|
||||||
)}`
|
)}`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = dayjs(p.start).toISOString()
|
p.start = dayjs(p.start).toISOString()
|
||||||
p.stop = dayjs(p.stop).toISOString()
|
p.stop = dayjs(p.stop).toISOString()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
title: 'Vakre og ville Oman',
|
title: 'Vakre og ville Oman',
|
||||||
sub_title: 'Vakre og ville Oman',
|
sub_title: 'Vakre og ville Oman',
|
||||||
description:
|
description:
|
||||||
'Oman er eit arabisk skattkammer av unike habitat og variert dyreliv. Rev, kvalhai, reptil og skjelpadder er blant skapningane du finn her.',
|
'Oman er eit arabisk skattkammer av unike habitat og variert dyreliv. Rev, kvalhai, reptil og skjelpadder er blant skapningane du finn her.',
|
||||||
season: 1,
|
season: 1,
|
||||||
episode: 1,
|
episode: 1,
|
||||||
category: ['Dokumentar', 'Fakta', 'Natur'],
|
category: ['Dokumentar', 'Fakta', 'Natur'],
|
||||||
actors: ['Gergana Muskalla'],
|
actors: ['Gergana Muskalla'],
|
||||||
directors: 'Stefania Muller',
|
directors: 'Stefania Muller',
|
||||||
icon: 'https://imageservice.rikstv.no/hash/EC206C374F42287C0BDF850A7D3CB4D3.jpg',
|
icon: 'https://imageservice.rikstv.no/hash/EC206C374F42287C0BDF850A7D3CB4D3.jpg',
|
||||||
start: '2025-01-13T23:00:00.000Z',
|
start: '2025-01-13T23:00:00.000Z',
|
||||||
stop: '2025-01-13T23:55:00.000Z'
|
stop: '2025-01-13T23:55:00.000Z'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: '[]'
|
content: '[]'
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,48 +1,48 @@
|
|||||||
const { parser, url } = require('./rtmklik.rtm.gov.my.config.js')
|
const { parser, url } = require('./rtmklik.rtm.gov.my.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-09-04', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-09-04', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '2',
|
site_id: '2',
|
||||||
xmltv_id: 'TV2.my'
|
xmltv_id: 'TV2.my'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date, channel })).toBe(
|
expect(url({ date, channel })).toBe(
|
||||||
'https://rtm.glueapi.io/v3/epg/2/ChannelSchedule?dateStart=2022-09-04&dateEnd=2022-09-04&timezone=0'
|
'https://rtm.glueapi.io/v3/epg/2/ChannelSchedule?dateStart=2022-09-04&dateEnd=2022-09-04&timezone=0'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, channel, date }).map(p => {
|
const result = parser({ content, channel, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-09-04T19:00:00.000Z',
|
start: '2022-09-04T19:00:00.000Z',
|
||||||
stop: '2022-09-04T20:00:00.000Z',
|
stop: '2022-09-04T20:00:00.000Z',
|
||||||
title: 'Hope Of Life',
|
title: 'Hope Of Life',
|
||||||
description:
|
description:
|
||||||
'Kisah kehidupan 3 pakar bedah yang berbeza status dan latar belakang, namun mereka komited dengan kerjaya mereka sebagai doktor. Lakonan : Johnson Low, Elvis Chin, Mayjune Tan, Kelvin Liew, Jacky Kam dan Katrina Ho.'
|
'Kisah kehidupan 3 pakar bedah yang berbeza status dan latar belakang, namun mereka komited dengan kerjaya mereka sebagai doktor. Lakonan : Johnson Low, Elvis Chin, Mayjune Tan, Kelvin Liew, Jacky Kam dan Katrina Ho.'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,65 +1,65 @@
|
|||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
|
|
||||||
const tz = {
|
const tz = {
|
||||||
lis: 'Europe/Lisbon',
|
lis: 'Europe/Lisbon',
|
||||||
per: 'Asia/Macau',
|
per: 'Asia/Macau',
|
||||||
rja: 'America/Sao_Paulo'
|
rja: 'America/Sao_Paulo'
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'rtp.pt',
|
site: 'rtp.pt',
|
||||||
days: 2,
|
days: 2,
|
||||||
url({ channel, date }) {
|
url({ channel, date }) {
|
||||||
let [region, channelCode] = channel.site_id.split('#')
|
let [region, channelCode] = channel.site_id.split('#')
|
||||||
return `https://www.rtp.pt/EPG/json/rtp-channels-page/list-grid/tv/${channelCode}/${date.format(
|
return `https://www.rtp.pt/EPG/json/rtp-channels-page/list-grid/tv/${channelCode}/${date.format(
|
||||||
'D-M-YYYY'
|
'D-M-YYYY'
|
||||||
)}/${region}`
|
)}/${region}`
|
||||||
},
|
},
|
||||||
parser({ content, channel }) {
|
parser({ content, channel }) {
|
||||||
let programs = []
|
let programs = []
|
||||||
const items = parseItems(content)
|
const items = parseItems(content)
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
const prev = programs[programs.length - 1]
|
const prev = programs[programs.length - 1]
|
||||||
let start = parseStart(item, channel)
|
let start = parseStart(item, channel)
|
||||||
if (!start) return
|
if (!start) return
|
||||||
if (prev) {
|
if (prev) {
|
||||||
prev.stop = start
|
prev.stop = start
|
||||||
}
|
}
|
||||||
const stop = start.add(30, 'm')
|
const stop = start.add(30, 'm')
|
||||||
programs.push({
|
programs.push({
|
||||||
title: item.name,
|
title: item.name,
|
||||||
description: item.description,
|
description: item.description,
|
||||||
image: parseImage(item),
|
image: parseImage(item),
|
||||||
start,
|
start,
|
||||||
stop
|
stop
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseImage(item) {
|
function parseImage(item) {
|
||||||
const last = item.image.pop()
|
const last = item.image.pop()
|
||||||
if (!last) return null
|
if (!last) return null
|
||||||
return last.src
|
return last.src
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStart(item, channel) {
|
function parseStart(item, channel) {
|
||||||
let [region] = channel.site_id.split('#')
|
let [region] = channel.site_id.split('#')
|
||||||
return dayjs.tz(item.date, 'YYYY-MM-DD HH:mm:ss', tz[region])
|
return dayjs.tz(item.date, 'YYYY-MM-DD HH:mm:ss', tz[region])
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(content) {
|
function parseItems(content) {
|
||||||
if (!content) return []
|
if (!content) return []
|
||||||
const data = JSON.parse(content)
|
const data = JSON.parse(content)
|
||||||
|
|
||||||
return Object.values(data.result).flat()
|
return Object.values(data.result).flat()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,49 +1,49 @@
|
|||||||
const { parser, url } = require('./s.mxtv.jp.config.js')
|
const { parser, url } = require('./s.mxtv.jp.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2024-08-01', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2024-08-01', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '2',
|
site_id: '2',
|
||||||
name: 'Tokyo MX2',
|
name: 'Tokyo MX2',
|
||||||
xmltv_id: 'TokyoMX2.jp'
|
xmltv_id: 'TokyoMX2.jp'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
const result = url({ date, channel })
|
const result = url({ date, channel })
|
||||||
expect(result).toBe('https://s.mxtv.jp/bangumi_file/json01/SV2EPG20240801.json')
|
expect(result).toBe('https://s.mxtv.jp/bangumi_file/json01/SV2EPG20240801.json')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ date, channel, content }).map(p => {
|
const result = parser({ date, channel, content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2024-07-26T20:00:00.000Z', // UTC time
|
start: '2024-07-26T20:00:00.000Z', // UTC time
|
||||||
stop: '2024-07-26T21:00:00.000Z', // UTC
|
stop: '2024-07-26T21:00:00.000Z', // UTC
|
||||||
title: 'ヒーリングタイム&ヘッドラインニュース',
|
title: 'ヒーリングタイム&ヘッドラインニュース',
|
||||||
description: 'ねこの足跡',
|
description: 'ねこの足跡',
|
||||||
image: null,
|
image: null,
|
||||||
category: null
|
category: null
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: '[]'
|
content: '[]'
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
const { url, parser } = require('./shahid.mbc.net.config.js')
|
const { url, parser } = require('./shahid.mbc.net.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2023-11-11').startOf('d')
|
const date = dayjs.utc('2023-11-11').startOf('d')
|
||||||
const channel = { site_id: '996520', xmltv_id: 'AlAanTV.ae', lang: 'en' }
|
const channel = { site_id: '996520', xmltv_id: 'AlAanTV.ae', lang: 'en' }
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
`https://api2.shahid.net/proxy/v2.1/shahid-epg-api/?csvChannelIds=${
|
`https://api2.shahid.net/proxy/v2.1/shahid-epg-api/?csvChannelIds=${
|
||||||
channel.site_id
|
channel.site_id
|
||||||
}&from=${date.format('YYYY-MM-DD')}T00:00:00.000Z&to=${date.format(
|
}&from=${date.format('YYYY-MM-DD')}T00:00:00.000Z&to=${date.format(
|
||||||
'YYYY-MM-DD'
|
'YYYY-MM-DD'
|
||||||
)}T23:59:59.999Z&country=SA&language=${channel.lang}&Accept-Language=${channel.lang}`
|
)}T23:59:59.999Z&country=SA&language=${channel.lang}&Accept-Language=${channel.lang}`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, channel, date })
|
const result = parser({ content, channel, date })
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2023-11-10T21:00:00.000Z',
|
start: '2023-11-10T21:00:00.000Z',
|
||||||
stop: '2023-11-10T21:30:00.000Z',
|
stop: '2023-11-10T21:30:00.000Z',
|
||||||
title: "Menassaatona Fi Osboo'",
|
title: "Menassaatona Fi Osboo'",
|
||||||
description:
|
description:
|
||||||
"The presenter reviews the most prominent episodes of news programs produced by the channel's team on a weekly basis, which include the most important global updates and developments at all levels."
|
"The presenter reviews the most prominent episodes of news programs produced by the channel's team on a weekly basis, which include the most important global updates and developments at all levels."
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({ content: '' })
|
const result = parser({ content: '' })
|
||||||
|
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,54 +1,54 @@
|
|||||||
const { parser, url, request } = require('./siba.com.co.config.js')
|
const { parser, url, request } = require('./siba.com.co.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-11', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-11', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '395',
|
site_id: '395',
|
||||||
xmltv_id: 'CanalClaro.cl'
|
xmltv_id: 'CanalClaro.cl'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url).toBe('http://devportal.siba.com.co/index.php?action=grilla')
|
expect(url).toBe('http://devportal.siba.com.co/index.php?action=grilla')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request headers', () => {
|
it('can generate valid request headers', () => {
|
||||||
expect(request.headers).toMatchObject({
|
expect(request.headers).toMatchObject({
|
||||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
|
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request data', () => {
|
it('can generate valid request data', () => {
|
||||||
const result = request.data({ channel, date })
|
const result = request.data({ channel, date })
|
||||||
expect(result.has('servicio')).toBe(true)
|
expect(result.has('servicio')).toBe(true)
|
||||||
expect(result.has('ini')).toBe(true)
|
expect(result.has('ini')).toBe(true)
|
||||||
expect(result.has('end')).toBe(true)
|
expect(result.has('end')).toBe(true)
|
||||||
expect(result.has('chn')).toBe(true)
|
expect(result.has('chn')).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ date, channel, content })
|
const result = parser({ date, channel, content })
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-11T00:00:00.000Z',
|
start: '2021-11-11T00:00:00.000Z',
|
||||||
stop: '2021-11-11T01:00:00.000Z',
|
stop: '2021-11-11T01:00:00.000Z',
|
||||||
title: 'Worst Cooks In America'
|
title: 'Worst Cooks In America'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
|
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,85 +1,85 @@
|
|||||||
const cheerio = require('cheerio')
|
const cheerio = require('cheerio')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const doFetch = require('@ntlab/sfetch')
|
const doFetch = require('@ntlab/sfetch')
|
||||||
const debug = require('debug')('site:sky.com')
|
const debug = require('debug')('site:sky.com')
|
||||||
const { sortBy } = require('../../scripts/functions')
|
const { sortBy } = require('../../scripts/functions')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
doFetch.setDebugger(debug)
|
doFetch.setDebugger(debug)
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'sky.com',
|
site: 'sky.com',
|
||||||
days: 2,
|
days: 2,
|
||||||
url({ date, channel }) {
|
url({ date, channel }) {
|
||||||
return `https://awk.epgsky.com/hawk/linear/schedule/${date.format('YYYYMMDD')}/${
|
return `https://awk.epgsky.com/hawk/linear/schedule/${date.format('YYYYMMDD')}/${
|
||||||
channel.site_id
|
channel.site_id
|
||||||
}`
|
}`
|
||||||
},
|
},
|
||||||
parser({ content, channel, date }) {
|
parser({ content, channel, date }) {
|
||||||
const programs = []
|
const programs = []
|
||||||
if (content) {
|
if (content) {
|
||||||
const items = JSON.parse(content) || null
|
const items = JSON.parse(content) || null
|
||||||
if (Array.isArray(items.schedule)) {
|
if (Array.isArray(items.schedule)) {
|
||||||
items.schedule
|
items.schedule
|
||||||
.filter(schedule => schedule.sid === channel.site_id)
|
.filter(schedule => schedule.sid === channel.site_id)
|
||||||
.forEach(schedule => {
|
.forEach(schedule => {
|
||||||
if (Array.isArray(schedule.events)) {
|
if (Array.isArray(schedule.events)) {
|
||||||
sortBy(schedule.events, p => p.st).forEach(event => {
|
sortBy(schedule.events, p => p.st).forEach(event => {
|
||||||
const start = dayjs.utc(event.st * 1000)
|
const start = dayjs.utc(event.st * 1000)
|
||||||
if (start.isSame(date, 'd')) {
|
if (start.isSame(date, 'd')) {
|
||||||
const image = `https://images.metadata.sky.com/pd-image/${event.programmeuuid}/16-9/640`
|
const image = `https://images.metadata.sky.com/pd-image/${event.programmeuuid}/16-9/640`
|
||||||
programs.push({
|
programs.push({
|
||||||
title: event.t,
|
title: event.t,
|
||||||
description: event.sy,
|
description: event.sy,
|
||||||
season: event.seasonnumber,
|
season: event.seasonnumber,
|
||||||
episode: event.episodenumber,
|
episode: event.episodenumber,
|
||||||
start,
|
start,
|
||||||
stop: start.add(event.d, 's'),
|
stop: start.add(event.d, 's'),
|
||||||
icon: image,
|
icon: image,
|
||||||
image
|
image
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels() {
|
async channels() {
|
||||||
const channels = {}
|
const channels = {}
|
||||||
const queues = [{ t: 'r', url: 'https://www.sky.com/tv-guide' }]
|
const queues = [{ t: 'r', url: 'https://www.sky.com/tv-guide' }]
|
||||||
await doFetch(queues, (queue, res) => {
|
await doFetch(queues, (queue, res) => {
|
||||||
// process regions
|
// process regions
|
||||||
if (queue.t === 'r') {
|
if (queue.t === 'r') {
|
||||||
const $ = cheerio.load(res)
|
const $ = cheerio.load(res)
|
||||||
const initialData = JSON.parse(decodeURIComponent($('#initialData').text()))
|
const initialData = JSON.parse(decodeURIComponent($('#initialData').text()))
|
||||||
initialData.state.epgData.regions.forEach(region => {
|
initialData.state.epgData.regions.forEach(region => {
|
||||||
queues.push({
|
queues.push({
|
||||||
t: 'c',
|
t: 'c',
|
||||||
url: `https://awk.epgsky.com/hawk/linear/services/${region.bouquet}/${region.subBouquet}`
|
url: `https://awk.epgsky.com/hawk/linear/services/${region.bouquet}/${region.subBouquet}`
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// process channels
|
// process channels
|
||||||
if (queue.t === 'c') {
|
if (queue.t === 'c') {
|
||||||
if (Array.isArray(res.services)) {
|
if (Array.isArray(res.services)) {
|
||||||
for (const ch of res.services) {
|
for (const ch of res.services) {
|
||||||
if (channels[ch.sid] === undefined) {
|
if (channels[ch.sid] === undefined) {
|
||||||
channels[ch.sid] = {
|
channels[ch.sid] = {
|
||||||
lang: 'en',
|
lang: 'en',
|
||||||
site_id: ch.sid,
|
site_id: ch.sid,
|
||||||
name: ch.t
|
name: ch.t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return Object.values(channels)
|
return Object.values(channels)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +1,66 @@
|
|||||||
const { parser, url, request } = require('./sky.de.config.js')
|
const { parser, url, request } = require('./sky.de.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-02-28', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-02-28', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '522',
|
site_id: '522',
|
||||||
xmltv_id: 'WarnerTVComedyHD.de'
|
xmltv_id: 'WarnerTVComedyHD.de'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url).toBe('https://www.sky.de/sgtvg/service/getBroadcastsForGrid')
|
expect(url).toBe('https://www.sky.de/sgtvg/service/getBroadcastsForGrid')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request method', () => {
|
it('can generate valid request method', () => {
|
||||||
expect(request.method).toBe('POST')
|
expect(request.method).toBe('POST')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request data', () => {
|
it('can generate valid request data', () => {
|
||||||
expect(request.data({ channel, date })).toMatchObject({
|
expect(request.data({ channel, date })).toMatchObject({
|
||||||
cil: [channel.site_id],
|
cil: [channel.site_id],
|
||||||
d: date.valueOf()
|
d: date.valueOf()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
title: 'King of Queens',
|
title: 'King of Queens',
|
||||||
description: 'Der Experte',
|
description: 'Der Experte',
|
||||||
category: 'Comedyserie',
|
category: 'Comedyserie',
|
||||||
start: '2022-02-26T23:05:00.000Z',
|
start: '2022-02-26T23:05:00.000Z',
|
||||||
stop: '2022-02-26T23:30:00.000Z',
|
stop: '2022-02-26T23:30:00.000Z',
|
||||||
season: '4',
|
season: '4',
|
||||||
episode: '11',
|
episode: '11',
|
||||||
image: 'http://sky.de/static/img/program_guide/1522936_s.jpg'
|
image: 'http://sky.de/static/img/program_guide/1522936_s.jpg'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'King of Queens',
|
title: 'King of Queens',
|
||||||
description: 'Speedy Gonzales',
|
description: 'Speedy Gonzales',
|
||||||
category: 'Comedyserie',
|
category: 'Comedyserie',
|
||||||
start: '2022-02-26T23:30:00.000Z',
|
start: '2022-02-26T23:30:00.000Z',
|
||||||
stop: '2022-02-26T23:55:00.000Z',
|
stop: '2022-02-26T23:55:00.000Z',
|
||||||
season: '4',
|
season: '4',
|
||||||
episode: '12',
|
episode: '12',
|
||||||
image: 'http://sky.de/static/img/program_guide/1522937_s.jpg'
|
image: 'http://sky.de/static/img/program_guide/1522937_s.jpg'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: '[]'
|
content: '[]'
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,46 +1,46 @@
|
|||||||
const { parser, url } = require('./stod2.is.config.js')
|
const { parser, url } = require('./stod2.is.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
|
|
||||||
const date = dayjs.utc('2025-01-03', 'YYYY-MM-DD').startOf('day')
|
const date = dayjs.utc('2025-01-03', 'YYYY-MM-DD').startOf('day')
|
||||||
const channel = { site_id: 'stod2', xmltv_id: 'Stod2.is' }
|
const channel = { site_id: 'stod2', xmltv_id: 'Stod2.is' }
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
const generatedUrl = url({ date, channel })
|
const generatedUrl = url({ date, channel })
|
||||||
expect(generatedUrl).toBe('https://api.stod2.is/dagskra/api/stod2/2025-01-03')
|
expect(generatedUrl).toBe('https://api.stod2.is/dagskra/api/stod2/2025-01-03')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = p.start.toISOString()
|
p.start = p.start.toISOString()
|
||||||
p.stop = p.stop.toISOString()
|
p.stop = p.stop.toISOString()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
title: 'Heimsókn',
|
title: 'Heimsókn',
|
||||||
sub_title: 'Telma Borgþórsdóttir',
|
sub_title: 'Telma Borgþórsdóttir',
|
||||||
description:
|
description:
|
||||||
'Frábærir þættir með Sindra Sindrasyni sem lítur inn hjá íslenskum fagurkerum. Heimilin eru jafn ólík og þau eru mörg en eiga það þó eitt sameiginlegt að vera sett saman af alúð og smekklegheitum. Sindri hefur líka einstakt lag á að ná fram því besta í viðmælendum sínum.',
|
'Frábærir þættir með Sindra Sindrasyni sem lítur inn hjá íslenskum fagurkerum. Heimilin eru jafn ólík og þau eru mörg en eiga það þó eitt sameiginlegt að vera sett saman af alúð og smekklegheitum. Sindri hefur líka einstakt lag á að ná fram því besta í viðmælendum sínum.',
|
||||||
actors: '',
|
actors: '',
|
||||||
directors: '',
|
directors: '',
|
||||||
start: '2025-01-03T08:00:00.000Z',
|
start: '2025-01-03T08:00:00.000Z',
|
||||||
stop: '2025-01-03T08:15:00.000Z'
|
stop: '2025-01-03T08:15:00.000Z'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({ content: '[]' })
|
const result = parser({ content: '[]' })
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,97 +1,97 @@
|
|||||||
const cheerio = require('cheerio')
|
const cheerio = require('cheerio')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
const { sortBy, uniqBy } = require('../../scripts/functions')
|
const { sortBy, uniqBy } = require('../../scripts/functions')
|
||||||
|
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'streamingtvguides.com',
|
site: 'streamingtvguides.com',
|
||||||
days: 2,
|
days: 2,
|
||||||
url({ channel }) {
|
url({ channel }) {
|
||||||
return `https://streamingtvguides.com/Channel/${channel.site_id}`
|
return `https://streamingtvguides.com/Channel/${channel.site_id}`
|
||||||
},
|
},
|
||||||
parser({ content, date }) {
|
parser({ content, date }) {
|
||||||
let programs = []
|
let programs = []
|
||||||
const items = parseItems(content)
|
const items = parseItems(content)
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
const $item = cheerio.load(item)
|
const $item = cheerio.load(item)
|
||||||
const start = parseStart($item)
|
const start = parseStart($item)
|
||||||
if (!date.isSame(start, 'd')) return
|
if (!date.isSame(start, 'd')) return
|
||||||
|
|
||||||
programs.push({
|
programs.push({
|
||||||
title: parseTitle($item),
|
title: parseTitle($item),
|
||||||
description: parseDescription($item),
|
description: parseDescription($item),
|
||||||
start,
|
start,
|
||||||
stop: parseStop($item)
|
stop: parseStop($item)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
programs = sortBy(uniqBy(programs, p => p.start), p => p.start.valueOf())
|
programs = sortBy(uniqBy(programs, p => p.start), p => p.start.valueOf())
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels() {
|
async channels() {
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const data = await axios
|
const data = await axios
|
||||||
.get('https://streamingtvguides.com/Preferences')
|
.get('https://streamingtvguides.com/Preferences')
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
|
|
||||||
let channels = []
|
let channels = []
|
||||||
|
|
||||||
const $ = cheerio.load(data)
|
const $ = cheerio.load(data)
|
||||||
$('#channel-group-all > div > div').each((i, el) => {
|
$('#channel-group-all > div > div').each((i, el) => {
|
||||||
const site_id = $(el).find('input').attr('value').replace('&', '&')
|
const site_id = $(el).find('input').attr('value').replace('&', '&')
|
||||||
const label = $(el).text().trim()
|
const label = $(el).text().trim()
|
||||||
const svgTitle = $(el).find('svg').attr('alt')
|
const svgTitle = $(el).find('svg').attr('alt')
|
||||||
const name = (label || svgTitle || '').replace(site_id, '').trim()
|
const name = (label || svgTitle || '').replace(site_id, '').trim()
|
||||||
|
|
||||||
if (!name || !site_id) return
|
if (!name || !site_id) return
|
||||||
|
|
||||||
channels.push({
|
channels.push({
|
||||||
lang: 'en',
|
lang: 'en',
|
||||||
site_id,
|
site_id,
|
||||||
name
|
name
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return channels
|
return channels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTitle($item) {
|
function parseTitle($item) {
|
||||||
return $item('.card-body > .prog-contains > .card-title')
|
return $item('.card-body > .prog-contains > .card-title')
|
||||||
.clone()
|
.clone()
|
||||||
.children()
|
.children()
|
||||||
.remove()
|
.remove()
|
||||||
.end()
|
.end()
|
||||||
.text()
|
.text()
|
||||||
.trim()
|
.trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDescription($item) {
|
function parseDescription($item) {
|
||||||
return $item('.card-body > .card-text').clone().children().remove().end().text().trim()
|
return $item('.card-body > .card-text').clone().children().remove().end().text().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStart($item) {
|
function parseStart($item) {
|
||||||
const date = $item('.card-body').clone().children().remove().end().text().trim()
|
const date = $item('.card-body').clone().children().remove().end().text().trim()
|
||||||
const [time] = date.split(' - ')
|
const [time] = date.split(' - ')
|
||||||
|
|
||||||
return dayjs.tz(time, 'YYYY-MM-DD HH:mm:ss [PST]', 'PST').utc()
|
return dayjs.tz(time, 'YYYY-MM-DD HH:mm:ss [PST]', 'PST').utc()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStop($item) {
|
function parseStop($item) {
|
||||||
const date = $item('.card-body').clone().children().remove().end().text().trim()
|
const date = $item('.card-body').clone().children().remove().end().text().trim()
|
||||||
const [, time] = date.split(' - ')
|
const [, time] = date.split(' - ')
|
||||||
|
|
||||||
return dayjs.tz(time, 'YYYY-MM-DD HH:mm:ss [PST]', 'PST').utc()
|
return dayjs.tz(time, 'YYYY-MM-DD HH:mm:ss [PST]', 'PST').utc()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(content) {
|
function parseItems(content) {
|
||||||
const $ = cheerio.load(content)
|
const $ = cheerio.load(content)
|
||||||
|
|
||||||
return $('.container').toArray()
|
return $('.container').toArray()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +1,43 @@
|
|||||||
const { url, parser } = require('./taiwanplus.com.config.js')
|
const { url, parser } = require('./taiwanplus.com.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2023-08-20', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2023-08-20', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '#',
|
site_id: '#',
|
||||||
xmltv_id: 'TaiwanPlusTV.tw',
|
xmltv_id: 'TaiwanPlusTV.tw',
|
||||||
lang: 'en',
|
lang: 'en',
|
||||||
logo: 'https://i.imgur.com/SfcZyqm.png'
|
logo: 'https://i.imgur.com/SfcZyqm.png'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe('https://www.taiwanplus.com/api/video/live/schedule/0')
|
expect(url({ channel, date })).toBe('https://www.taiwanplus.com/api/video/live/schedule/0')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
|
|
||||||
const results = parser({ content, date })
|
const results = parser({ content, date })
|
||||||
|
|
||||||
expect(results).toMatchObject([
|
expect(results).toMatchObject([
|
||||||
{
|
{
|
||||||
title: 'Master Class',
|
title: 'Master Class',
|
||||||
start: dayjs.utc('2023/08/20 00:00', 'YYYY/MM/DD HH:mm'),
|
start: dayjs.utc('2023/08/20 00:00', 'YYYY/MM/DD HH:mm'),
|
||||||
stop: dayjs.utc('2023/08/21 00:00', 'YYYY/MM/DD HH:mm'),
|
stop: dayjs.utc('2023/08/21 00:00', 'YYYY/MM/DD HH:mm'),
|
||||||
description:
|
description:
|
||||||
'From blockchain to Buddha statues, Taiwan’s culture is a kaleidoscope of old and new just waiting to be discovered.',
|
'From blockchain to Buddha statues, Taiwan’s culture is a kaleidoscope of old and new just waiting to be discovered.',
|
||||||
image: 'https://prod-img.taiwanplus.com/live-schedule/Single/S30668_20230810104937.webp',
|
image: 'https://prod-img.taiwanplus.com/live-schedule/Single/S30668_20230810104937.webp',
|
||||||
category: 'TaiwanPlus ✕ Discovery',
|
category: 'TaiwanPlus ✕ Discovery',
|
||||||
rating: '0+'
|
rating: '0+'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const results = parser({ content: '' })
|
const results = parser({ content: '' })
|
||||||
|
|
||||||
expect(results).toMatchObject([])
|
expect(results).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,49 +1,49 @@
|
|||||||
const { parser, url } = require('./tapdmv.com.config.js')
|
const { parser, url } = require('./tapdmv.com.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-10-04', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-10-04', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '94b7db9b-5bbd-47d3-a2d3-ce792342a756',
|
site_id: '94b7db9b-5bbd-47d3-a2d3-ce792342a756',
|
||||||
xmltv_id: 'TAPActionFlix.ph'
|
xmltv_id: 'TAPActionFlix.ph'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://epg.tapdmv.com/calendar/94b7db9b-5bbd-47d3-a2d3-ce792342a756?%24limit=10000&%24sort%5BcreatedAt%5D=-1&start=2022-10-04T00:00:00.000Z&end=2022-10-05T00:00:00.000Z'
|
'https://epg.tapdmv.com/calendar/94b7db9b-5bbd-47d3-a2d3-ce792342a756?%24limit=10000&%24sort%5BcreatedAt%5D=-1&start=2022-10-04T00:00:00.000Z&end=2022-10-05T00:00:00.000Z'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, date }).map(p => {
|
const result = parser({ content, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-10-04T01:00:00.000Z',
|
start: '2022-10-04T01:00:00.000Z',
|
||||||
stop: '2022-10-04T02:25:00.000Z',
|
stop: '2022-10-04T02:25:00.000Z',
|
||||||
title: 'The Devil Inside',
|
title: 'The Devil Inside',
|
||||||
description:
|
description:
|
||||||
'In Italy, a woman becomes involved in a series of unauthorized exorcisms during her mission to discover what happened to her mother, who allegedly murdered three people during her own exorcism.',
|
'In Italy, a woman becomes involved in a series of unauthorized exorcisms during her mission to discover what happened to her mother, who allegedly murdered three people during her own exorcism.',
|
||||||
category: 'Horror',
|
category: 'Horror',
|
||||||
image: 'https://s3.ap-southeast-1.amazonaws.com/epg.tapdmv.com/tapactionflix.png'
|
image: 'https://s3.ap-southeast-1.amazonaws.com/epg.tapdmv.com/tapactionflix.png'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json')),
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json')),
|
||||||
date
|
date
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,82 +1,82 @@
|
|||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'tataplay.com',
|
site: 'tataplay.com',
|
||||||
days: 1,
|
days: 1,
|
||||||
|
|
||||||
url({ date }) {
|
url({ date }) {
|
||||||
return `https://tm.tapi.videoready.tv/content-detail/pub/api/v2/channels/schedule?date=${date.format(
|
return `https://tm.tapi.videoready.tv/content-detail/pub/api/v2/channels/schedule?date=${date.format(
|
||||||
'DD-MM-YYYY'
|
'DD-MM-YYYY'
|
||||||
)}`
|
)}`
|
||||||
},
|
},
|
||||||
|
|
||||||
request: {
|
request: {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Accept: '*/*',
|
Accept: '*/*',
|
||||||
Origin: 'https://watch.tataplay.com',
|
Origin: 'https://watch.tataplay.com',
|
||||||
Referer: 'https://watch.tataplay.com/',
|
Referer: 'https://watch.tataplay.com/',
|
||||||
'User-Agent':
|
'User-Agent':
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
locale: 'ENG',
|
locale: 'ENG',
|
||||||
platform: 'web'
|
platform: 'web'
|
||||||
},
|
},
|
||||||
data({ channel }) {
|
data({ channel }) {
|
||||||
return { id: channel.site_id }
|
return { id: channel.site_id }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
parser(context) {
|
parser(context) {
|
||||||
let data = []
|
let data = []
|
||||||
try {
|
try {
|
||||||
const json = JSON.parse(context.content)
|
const json = JSON.parse(context.content)
|
||||||
const programs = json?.data?.epg || []
|
const programs = json?.data?.epg || []
|
||||||
|
|
||||||
data = programs.map(program => ({
|
data = programs.map(program => ({
|
||||||
title: program.title,
|
title: program.title,
|
||||||
start: program.startTime,
|
start: program.startTime,
|
||||||
stop: program.endTime,
|
stop: program.endTime,
|
||||||
description: program.desc,
|
description: program.desc,
|
||||||
category: program.category,
|
category: program.category,
|
||||||
icon: program.boxCoverImage
|
icon: program.boxCoverImage
|
||||||
}))
|
}))
|
||||||
} catch {
|
} catch {
|
||||||
data = []
|
data = []
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
},
|
},
|
||||||
|
|
||||||
async channels() {
|
async channels() {
|
||||||
const headers = {
|
const headers = {
|
||||||
Accept: '*/*',
|
Accept: '*/*',
|
||||||
Origin: 'https://watch.tataplay.com',
|
Origin: 'https://watch.tataplay.com',
|
||||||
Referer: 'https://watch.tataplay.com/',
|
Referer: 'https://watch.tataplay.com/',
|
||||||
'User-Agent':
|
'User-Agent':
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
locale: 'ENG',
|
locale: 'ENG',
|
||||||
platform: 'web'
|
platform: 'web'
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseUrl = 'https://tm.tapi.videoready.tv/portal-search/pub/api/v1/channels/schedule'
|
const baseUrl = 'https://tm.tapi.videoready.tv/portal-search/pub/api/v1/channels/schedule'
|
||||||
const initialUrl = `${baseUrl}?date=&languageFilters=&genreFilters=&limit=20&offset=0`
|
const initialUrl = `${baseUrl}?date=&languageFilters=&genreFilters=&limit=20&offset=0`
|
||||||
const initialResponse = await axios.get(initialUrl, { headers })
|
const initialResponse = await axios.get(initialUrl, { headers })
|
||||||
const total = initialResponse.data?.data?.total || 0
|
const total = initialResponse.data?.data?.total || 0
|
||||||
const channels = []
|
const channels = []
|
||||||
|
|
||||||
for (let offset = 0; offset < total; offset += 20) {
|
for (let offset = 0; offset < total; offset += 20) {
|
||||||
const url = `${baseUrl}?date=&languageFilters=&genreFilters=&limit=20&offset=${offset}`
|
const url = `${baseUrl}?date=&languageFilters=&genreFilters=&limit=20&offset=${offset}`
|
||||||
const response = await axios.get(url, { headers })
|
const response = await axios.get(url, { headers })
|
||||||
const page = response.data?.data?.channelList || []
|
const page = response.data?.data?.channelList || []
|
||||||
channels.push(...page)
|
channels.push(...page)
|
||||||
}
|
}
|
||||||
|
|
||||||
return channels.map(channel => ({
|
return channels.map(channel => ({
|
||||||
site_id: channel.id,
|
site_id: channel.id,
|
||||||
name: channel.title,
|
name: channel.title,
|
||||||
lang: 'en',
|
lang: 'en',
|
||||||
icon: channel.transparentImageUrl || channel.thumbnailImage
|
icon: channel.transparentImageUrl || channel.thumbnailImage
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,89 +1,89 @@
|
|||||||
const { parser, url, channels } = require('./tataplay.com.config.js')
|
const { parser, url, channels } = require('./tataplay.com.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2025-06-09', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2025-06-09', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = { site_id: '1001' }
|
const channel = { site_id: '1001' }
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://tm.tapi.videoready.tv/content-detail/pub/api/v2/channels/schedule?date=09-06-2025'
|
'https://tm.tapi.videoready.tv/content-detail/pub/api/v2/channels/schedule?date=09-06-2025'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
|
|
||||||
const results = parser({ content, date })
|
const results = parser({ content, date })
|
||||||
|
|
||||||
expect(results.length).toBe(2)
|
expect(results.length).toBe(2)
|
||||||
expect(results[0]).toMatchObject({
|
expect(results[0]).toMatchObject({
|
||||||
title: 'Yeh Rishta Kya Kehlata Hai',
|
title: 'Yeh Rishta Kya Kehlata Hai',
|
||||||
start: '2025-06-09T18:00:00.000Z',
|
start: '2025-06-09T18:00:00.000Z',
|
||||||
stop: '2025-06-09T18:30:00.000Z',
|
stop: '2025-06-09T18:30:00.000Z',
|
||||||
description: 'The story of the Rajshri family and their journey through life.',
|
description: 'The story of the Rajshri family and their journey through life.',
|
||||||
category: 'Drama',
|
category: 'Drama',
|
||||||
icon: 'https://img.tataplay.com/thumbnails/1001/yeh-rishta.jpg'
|
icon: 'https://img.tataplay.com/thumbnails/1001/yeh-rishta.jpg'
|
||||||
})
|
})
|
||||||
expect(results[1]).toMatchObject({
|
expect(results[1]).toMatchObject({
|
||||||
title: 'Anupamaa',
|
title: 'Anupamaa',
|
||||||
start: '2025-06-09T18:30:00.000Z',
|
start: '2025-06-09T18:30:00.000Z',
|
||||||
stop: '2025-06-09T19:00:00.000Z',
|
stop: '2025-06-09T19:00:00.000Z',
|
||||||
description: 'The story of Anupamaa, a housewife who rediscovers herself.',
|
description: 'The story of Anupamaa, a housewife who rediscovers herself.',
|
||||||
category: 'Drama',
|
category: 'Drama',
|
||||||
icon: 'https://img.tataplay.com/thumbnails/1001/anupamaa.jpg'
|
icon: 'https://img.tataplay.com/thumbnails/1001/anupamaa.jpg'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const content = JSON.stringify({ data: { epg: [] } })
|
const content = JSON.stringify({ data: { epg: [] } })
|
||||||
const results = parser({ content, date })
|
const results = parser({ content, date })
|
||||||
expect(results).toMatchObject([])
|
expect(results).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse channel list', async () => {
|
it('can parse channel list', async () => {
|
||||||
const mockResponse = {
|
const mockResponse = {
|
||||||
data: {
|
data: {
|
||||||
data: {
|
data: {
|
||||||
total: 2,
|
total: 2,
|
||||||
channelList: [
|
channelList: [
|
||||||
{
|
{
|
||||||
id: '1001',
|
id: '1001',
|
||||||
title: 'Star Plus',
|
title: 'Star Plus',
|
||||||
transparentImageUrl: 'https://img.tataplay.com/channels/1001/logo.png'
|
transparentImageUrl: 'https://img.tataplay.com/channels/1001/logo.png'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '1002',
|
id: '1002',
|
||||||
title: 'Sony TV',
|
title: 'Sony TV',
|
||||||
transparentImageUrl: 'https://img.tataplay.com/channels/1002/logo.png'
|
transparentImageUrl: 'https://img.tataplay.com/channels/1002/logo.png'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mock axios.get to return our test data
|
// Mock axios.get to return our test data
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
axios.get = jest.fn().mockResolvedValue(mockResponse)
|
axios.get = jest.fn().mockResolvedValue(mockResponse)
|
||||||
|
|
||||||
const results = await channels()
|
const results = await channels()
|
||||||
|
|
||||||
expect(results.length).toBe(2)
|
expect(results.length).toBe(2)
|
||||||
expect(results[0]).toMatchObject({
|
expect(results[0]).toMatchObject({
|
||||||
site_id: '1001',
|
site_id: '1001',
|
||||||
name: 'Star Plus',
|
name: 'Star Plus',
|
||||||
lang: 'en',
|
lang: 'en',
|
||||||
icon: 'https://img.tataplay.com/channels/1001/logo.png'
|
icon: 'https://img.tataplay.com/channels/1001/logo.png'
|
||||||
})
|
})
|
||||||
expect(results[1]).toMatchObject({
|
expect(results[1]).toMatchObject({
|
||||||
site_id: '1002',
|
site_id: '1002',
|
||||||
name: 'Sony TV',
|
name: 'Sony TV',
|
||||||
lang: 'en',
|
lang: 'en',
|
||||||
icon: 'https://img.tataplay.com/channels/1002/logo.png'
|
icon: 'https://img.tataplay.com/channels/1002/logo.png'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,60 +1,60 @@
|
|||||||
const { parser, url } = require('./teliatv.ee.config.js')
|
const { parser, url } = require('./teliatv.ee.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-20', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-20', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
lang: 'et',
|
lang: 'et',
|
||||||
site_id: 'et#1',
|
site_id: 'et#1',
|
||||||
xmltv_id: 'ETV.ee'
|
xmltv_id: 'ETV.ee'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date, channel })).toBe(
|
expect(url({ date, channel })).toBe(
|
||||||
'https://api.teliatv.ee/dtv-api/3.2/et/epg/guide?channelIds=1&relations=programmes&images=webGuideItemLarge&startAt=2021-11-21T00:00&startAtOp=lte&endAt=2021-11-20T00:00&endAtOp=gt'
|
'https://api.teliatv.ee/dtv-api/3.2/et/epg/guide?channelIds=1&relations=programmes&images=webGuideItemLarge&startAt=2021-11-21T00:00&startAtOp=lte&endAt=2021-11-20T00:00&endAtOp=gt'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid url with different language', () => {
|
it('can generate valid url with different language', () => {
|
||||||
const ruChannel = {
|
const ruChannel = {
|
||||||
lang: 'ru',
|
lang: 'ru',
|
||||||
site_id: 'ru#1',
|
site_id: 'ru#1',
|
||||||
xmltv_id: 'ETV.ee'
|
xmltv_id: 'ETV.ee'
|
||||||
}
|
}
|
||||||
expect(url({ date, channel: ruChannel })).toBe(
|
expect(url({ date, channel: ruChannel })).toBe(
|
||||||
'https://api.teliatv.ee/dtv-api/3.2/ru/epg/guide?channelIds=1&relations=programmes&images=webGuideItemLarge&startAt=2021-11-21T00:00&startAtOp=lte&endAt=2021-11-20T00:00&endAtOp=gt'
|
'https://api.teliatv.ee/dtv-api/3.2/ru/epg/guide?channelIds=1&relations=programmes&images=webGuideItemLarge&startAt=2021-11-21T00:00&startAtOp=lte&endAt=2021-11-20T00:00&endAtOp=gt'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-19T22:05:00.000Z',
|
start: '2021-11-19T22:05:00.000Z',
|
||||||
stop: '2021-11-19T22:55:00.000Z',
|
stop: '2021-11-19T22:55:00.000Z',
|
||||||
title: 'Inimjaht',
|
title: 'Inimjaht',
|
||||||
image:
|
image:
|
||||||
'https://inet-static.mw.elion.ee/resized/ri93Qj4OLXXvg7QAsUOcKMnIb3g=/570x330/filters:format(jpeg)/inet-static.mw.elion.ee/epg_images/9/b/17e48b3966e65c02.jpg'
|
'https://inet-static.mw.elion.ee/resized/ri93Qj4OLXXvg7QAsUOcKMnIb3g=/570x330/filters:format(jpeg)/inet-static.mw.elion.ee/epg_images/9/b/17e48b3966e65c02.jpg'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,72 +1,72 @@
|
|||||||
const { parser, url } = require('./tv.blue.ch.config.js')
|
const { parser, url } = require('./tv.blue.ch.config.js')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-01-17', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-01-17', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '1221',
|
site_id: '1221',
|
||||||
xmltv_id: 'BlueZoomD.ch'
|
xmltv_id: 'BlueZoomD.ch'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://services.sg101.prd.sctv.ch/catalog/tv/channels/list/(ids=1221;start=202201170000;end=202201180000;level=normal)'
|
'https://services.sg101.prd.sctv.ch/catalog/tv/channels/list/(ids=1221;start=202201170000;end=202201180000;level=normal)'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-01-16T23:30:00.000Z',
|
start: '2022-01-16T23:30:00.000Z',
|
||||||
stop: '2022-01-17T00:00:00.000Z',
|
stop: '2022-01-17T00:00:00.000Z',
|
||||||
title: 'Weekend on the Rocks',
|
title: 'Weekend on the Rocks',
|
||||||
description:
|
description:
|
||||||
' - «R.E.S.P.E.C.T», lieber Charles Nguela. Der Comedian tourt fleissig durch die Schweiz, macht für uns aber einen Halt, um in der neuen Ausgabe von «Weekend on the Rocks» mit Moderatorin Vania Spescha über die Entertainment-News der Woche zu plaudern.',
|
' - «R.E.S.P.E.C.T», lieber Charles Nguela. Der Comedian tourt fleissig durch die Schweiz, macht für uns aber einen Halt, um in der neuen Ausgabe von «Weekend on the Rocks» mit Moderatorin Vania Spescha über die Entertainment-News der Woche zu plaudern.',
|
||||||
image:
|
image:
|
||||||
'https://services.sg101.prd.sctv.ch/content/images/tv/broadcast/1221/t1221ddc59247d45_landscape_w1920.webp'
|
'https://services.sg101.prd.sctv.ch/content/images/tv/broadcast/1221/t1221ddc59247d45_landscape_w1920.webp'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response without image', () => {
|
it('can parse response without image', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content_without_image.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content_without_image.json'))
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-01-17T04:59:00.000Z',
|
start: '2022-01-17T04:59:00.000Z',
|
||||||
stop: '2022-01-17T05:00:00.000Z',
|
stop: '2022-01-17T05:00:00.000Z',
|
||||||
title: 'Lorem ipsum'
|
title: 'Lorem ipsum'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle wrong site id', () => {
|
it('can handle wrong site id', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/content_invalid_siteid.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/content_invalid_siteid.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,103 +1,103 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<channels>
|
<channels>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="24Kitchen.us@Bulgaria" site_id="96">24 Kitchen</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="24Kitchen.us@Bulgaria" site_id="96">24 Kitchen</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="78TV.bg" site_id="98">7/8 TV</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="78TV.bg" site_id="98">7/8 TV</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="AlJazeeraBalkans.ba" site_id="9">Al Jazeera</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="AlJazeeraBalkans.ba" site_id="9">Al Jazeera</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="AnimalPlanetEurope.uk" site_id="23">Animal Planet</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="AnimalPlanetEurope.uk" site_id="23">Animal Planet</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="92">AXN</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="92">AXN</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="AXNBlack.us" site_id="43">AXN Black</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="AXNBlack.us" site_id="43">AXN Black</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="AXNWhite.us" site_id="36">AXN White</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="AXNWhite.us" site_id="36">AXN White</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="BabyTV.uk" site_id="79">Baby TV</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="BabyTV.uk" site_id="79">Baby TV</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="BBCNews.uk" site_id="49">BBC News (former BBC World News)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="BBCNews.uk" site_id="49">BBC News (former BBC World News)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="BloombergTVBulgaria.bg" site_id="65">Bloomberg TV Bulgaria</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="BloombergTVBulgaria.bg" site_id="65">Bloomberg TV Bulgaria</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="BNT1.bg" site_id="57">BNT1 (БНТ1)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="BNT1.bg" site_id="57">BNT1 (БНТ1)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="BNT2.bg" site_id="99">BNT2 (БНТ2)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="BNT2.bg" site_id="99">BNT2 (БНТ2)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="BNT3.bg" site_id="82">BNT3 (БНТ3)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="BNT3.bg" site_id="82">BNT3 (БНТ3)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="BNT4.bg" site_id="64">BNT4 (БНТ4)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="BNT4.bg" site_id="64">BNT4 (БНТ4)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="bTV.bg" site_id="61">bTV</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="bTV.bg" site_id="61">bTV</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="bTVAction.bg" site_id="95">bTV Action</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="bTVAction.bg" site_id="95">bTV Action</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="bTVCinema.bg" site_id="58">bTV Cinema</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="bTVCinema.bg" site_id="58">bTV Cinema</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="bTVComedy.bg" site_id="81">bTV Comedy</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="bTVComedy.bg" site_id="81">bTV Comedy</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="bTVLady.bg" site_id="74">bTV Story (f.k.a bTV Lady)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="bTVLady.bg" site_id="74">bTV Story (f.k.a bTV Lady)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="BulgariaOnAir.bg" site_id="100">Bulgaria ON AIR (България Он Еър)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="BulgariaOnAir.bg" site_id="100">Bulgaria ON AIR (България Он Еър)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="84">Cartoon Network Bulgaria</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="84">Cartoon Network Bulgaria</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="CartoonitoWesternEurope.uk" site_id="80">Cartoonito (f.k.a Boomerang TV)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="CartoonitoWesternEurope.uk" site_id="80">Cartoonito (f.k.a Boomerang TV)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="Cinemania.rs" site_id="54">Cinemania</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="Cinemania.rs" site_id="54">Cinemania</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="CinemaxCentralEurope.hu@HD" site_id="21">Cinemax</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="CinemaxCentralEurope.hu@HD" site_id="21">Cinemax</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="Cinemax2CentralEurope.hu@HD" site_id="14">Cinemax 2</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="Cinemax2CentralEurope.hu@HD" site_id="14">Cinemax 2</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="29">CineStar TV</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="29">CineStar TV</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="33">CineStar TV Action&Thriller</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="33">CineStar TV Action&Thriller</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="CNN.us" site_id="47">CNN</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="CNN.us" site_id="47">CNN</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="CodeFashionTV.bg" site_id="10">Code Fashion TV</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="CodeFashionTV.bg" site_id="10">Code Fashion TV</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="CodeHealthTV.bg" site_id="11">Code Health TV</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="CodeHealthTV.bg" site_id="11">Code Health TV</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="CrimePlusInvestigation.uk" site_id="48">Crime & Investigation</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="CrimePlusInvestigation.uk" site_id="48">Crime & Investigation</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="Diema.bg" site_id="63">Diema</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="Diema.bg" site_id="63">Diema</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="DiemaFamily.bg" site_id="90">Diema Family</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="DiemaFamily.bg" site_id="90">Diema Family</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="DiemaSport.bg" site_id="16">Diema Sport</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="DiemaSport.bg" site_id="16">Diema Sport</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="DiemaSport2.bg" site_id="31">Diema Sport 2</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="DiemaSport2.bg" site_id="31">Diema Sport 2</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="DiemaSport3.bg" site_id="51">Diema Sport 3</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="DiemaSport3.bg" site_id="51">Diema Sport 3</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="DiscoveryChannel.bg" site_id="4">Discovery Channel</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="DiscoveryChannel.bg" site_id="4">Discovery Channel</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="DisneyChannel.bg" site_id="70">Disney Channel</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="DisneyChannel.bg" site_id="70">Disney Channel</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="20">Dizi (Timeless Drama Channel)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="20">Dizi (Timeless Drama Channel)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="87">Duck TV</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="87">Duck TV</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="DW.de" site_id="7">DW TV</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="DW.de" site_id="7">DW TV</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="EpicDrama.uk@Sweden" site_id="45">Epic Drama</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="EpicDrama.uk@Sweden" site_id="45">Epic Drama</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="Eurocom.bg" site_id="66">Eurocom</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="Eurocom.bg" site_id="66">Eurocom</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="EuronewsEnglish.fr" site_id="46">Euronews</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="EuronewsEnglish.fr" site_id="46">Euronews</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="TVEvropa.bg" site_id="91">Euronews Bulgaria (f.k.a Evropa TV)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="TVEvropa.bg" site_id="91">Euronews Bulgaria (f.k.a Evropa TV)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="Eurosport1.fr" site_id="67">Eurosport</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="Eurosport1.fr" site_id="67">Eurosport</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="Eurosport2.fr" site_id="50">Eurosport 2</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="Eurosport2.fr" site_id="50">Eurosport 2</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="Eurosport4K.fr" site_id="37">Eurosport 4K</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="Eurosport4K.fr" site_id="37">Eurosport 4K</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="FightKlub.pl@Bulgaria" site_id="24">Fightklub HD (Bulgaria)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="FightKlub.pl@Bulgaria" site_id="24">Fightklub HD (Bulgaria)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="FilmBox.nl@Bulgaria" site_id="18">FilmBox Basic</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="FilmBox.nl@Bulgaria" site_id="18">FilmBox Basic</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="FilmBoxExtra.nl@Bulgaria" site_id="34">FilmBox Extra</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="FilmBoxExtra.nl@Bulgaria" site_id="34">FilmBox Extra</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="FilmBoxStars.nl@Bulgaria" site_id="35">FilmBox Stars (FilmBox Plus)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="FilmBoxStars.nl@Bulgaria" site_id="35">FilmBox Stars (FilmBox Plus)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="FoodNetworkEMEA.us" site_id="40">Food Network HD</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="FoodNetworkEMEA.us" site_id="40">Food Network HD</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="France24.fr" site_id="1">France 24</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="France24.fr" site_id="1">France 24</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="HBOCentralEurope.hu" site_id="42">HBO</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="HBOCentralEurope.hu" site_id="42">HBO</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="HBO2CentralEurope.hu" site_id="17">HBO2</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="HBO2CentralEurope.hu" site_id="17">HBO2</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="HBO3CentralEurope.hu" site_id="15">HBO3</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="HBO3CentralEurope.hu" site_id="15">HBO3</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="HGTVLatinAmerica.us@Panregional" site_id="22">HGTV (Discovery Home & Garden)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="HGTVLatinAmerica.us@Panregional" site_id="22">HGTV (Discovery Home & Garden)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="38">History Bulgaria</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="38">History Bulgaria</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="InvestigationDiscoveryEurope.us" site_id="55">ID (Investigation Discovery)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="InvestigationDiscoveryEurope.us" site_id="55">ID (Investigation Discovery)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="Kanal3.bg" site_id="13">Kanal 3 (Канал 3)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="Kanal3.bg" site_id="13">Kanal 3 (Канал 3)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="NovaNews.bg" site_id="76">Kanal 4 (Канал 4)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="NovaNews.bg" site_id="76">Kanal 4 (Канал 4)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="KinoNova.bg" site_id="86">Kino Nova</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="KinoNova.bg" site_id="86">Kino Nova</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="LoveNature.ca" site_id="93">Love Nature</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="LoveNature.ca" site_id="93">Love Nature</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="75">Magic TV</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="75">Magic TV</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="MaxSport1.bg" site_id="41">MAX Sport 1</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="MaxSport1.bg" site_id="41">MAX Sport 1</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="MaxSport2.bg" site_id="56">MAX Sport 2</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="MaxSport2.bg" site_id="56">MAX Sport 2</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="MaxSport3.bg" site_id="28">MAX Sport 3</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="MaxSport3.bg" site_id="28">MAX Sport 3</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="MaxSport4.bg" site_id="12">MAX Sport 4</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="MaxSport4.bg" site_id="12">MAX Sport 4</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="MovieStar.bg" site_id="2">MovieSTAR</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="MovieStar.bg" site_id="2">MovieSTAR</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="MTVGlobal.uk" site_id="25">MTV Europe</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="MTVGlobal.uk" site_id="25">MTV Europe</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="NationalGeographic.bg" site_id="83">National Geographic</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="NationalGeographic.bg" site_id="83">National Geographic</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="NationalGeographicWild.bg" site_id="8">National Geographic Wild</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="NationalGeographicWild.bg" site_id="8">National Geographic Wild</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="NickJr.bg" site_id="97">Nick Jr</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="NickJr.bg" site_id="97">Nick Jr</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="Nickelodeon.bg" site_id="78">Nickelodeon</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="Nickelodeon.bg" site_id="78">Nickelodeon</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="Nicktoons.bg" site_id="94">Nicktoons</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="Nicktoons.bg" site_id="94">Nicktoons</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="Nostalgia.bg" site_id="26">Nostalgia TV</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="Nostalgia.bg" site_id="26">Nostalgia TV</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="NovaNews.bg" site_id="85">Nova News HD</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="NovaNews.bg" site_id="85">Nova News HD</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="NovaSport.bg" site_id="62">NOVA Sport</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="NovaSport.bg" site_id="62">NOVA Sport</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="Nova.bg" site_id="60">NOVA TV</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="Nova.bg" site_id="60">NOVA TV</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="RING.bg" site_id="59">Ring.bg (bTV Sport)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="RING.bg" site_id="59">Ring.bg (bTV Sport)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="RTL.de" site_id="6">RTL</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="RTL.de" site_id="6">RTL</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="SKAT.bg" site_id="5">SKAT TV</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="SKAT.bg" site_id="5">SKAT TV</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="SkyShowtime1.fi@Bulgaria" site_id="53">Skyshowtime 1</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="SkyShowtime1.fi@Bulgaria" site_id="53">Skyshowtime 1</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="SkyShowtime2.fi@Bulgaria" site_id="52">Skyshowtime 2</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="SkyShowtime2.fi@Bulgaria" site_id="52">Skyshowtime 2</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="StarChannel.bg" site_id="69">STAR Channel (f.k.a. FOX)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="StarChannel.bg" site_id="69">STAR Channel (f.k.a. FOX)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="StarCrime.bg" site_id="3">STAR Crime (f.k.a FOX Crime)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="StarCrime.bg" site_id="3">STAR Crime (f.k.a FOX Crime)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="StarLife.bg" site_id="30">STAR Life (f.k.a. FOX Life)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="StarLife.bg" site_id="30">STAR Life (f.k.a. FOX Life)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="SuperToons.bg" site_id="27">Super Toons</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="SuperToons.bg" site_id="27">Super Toons</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="History2.pl@Bulgaria" site_id="39">The History Channel 2</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="History2.pl@Bulgaria" site_id="39">The History Channel 2</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="88">The Voice TV</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="" site_id="88">The Voice TV</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="TLCBalkan.us" site_id="19">TLC</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="TLCBalkan.us" site_id="19">TLC</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="TravelChannelEMEA.uk" site_id="72">Travel Channel</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="TravelChannelEMEA.uk" site_id="72">Travel Channel</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="TV1.bg" site_id="71">TV1 Bulgaria</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="TV1.bg" site_id="71">TV1 Bulgaria</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="ViasatExplore.se" site_id="73">Viasat Explore</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="ViasatExplore.se" site_id="73">Viasat Explore</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="ViasatHistory.se" site_id="68">Viasat History</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="ViasatHistory.se" site_id="68">Viasat History</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="vijuTV1000.ru" site_id="32">Viasat Kino (TV1000)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="vijuTV1000.ru" site_id="32">Viasat Kino (TV1000)</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="ViasatNature.se" site_id="77">Viasat Nature</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="ViasatNature.se" site_id="77">Viasat Nature</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="ViasatTrueCrime.pl@Bulgaria" site_id="89">Viasat True Crime</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="ViasatTrueCrime.pl@Bulgaria" site_id="89">Viasat True Crime</channel>
|
||||||
<channel site="tv.dir.bg" lang="bg" xmltv_id="VivacomArena.bg" site_id="44">Vivacom Arena (Виваком Арена)</channel>
|
<channel site="tv.dir.bg" lang="bg" xmltv_id="VivacomArena.bg" site_id="44">Vivacom Arena (Виваком Арена)</channel>
|
||||||
</channels>
|
</channels>
|
||||||
|
|||||||
@@ -1,216 +1,216 @@
|
|||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const cheerio = require('cheerio')
|
const cheerio = require('cheerio')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
|
|
||||||
let sessionCache = null
|
let sessionCache = null
|
||||||
|
|
||||||
async function getSession(forceRefresh = false) {
|
async function getSession(forceRefresh = false) {
|
||||||
if (sessionCache && !forceRefresh) {
|
if (sessionCache && !forceRefresh) {
|
||||||
return sessionCache
|
return sessionCache
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const initResponse = await axios.get('https://tv.dir.bg/init')
|
const initResponse = await axios.get('https://tv.dir.bg/init')
|
||||||
|
|
||||||
if (!initResponse.data) {
|
if (!initResponse.data) {
|
||||||
throw new Error('No response data from init endpoint')
|
throw new Error('No response data from init endpoint')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract cookies from response headers
|
// Extract cookies from response headers
|
||||||
const setCookieHeader = initResponse.headers['set-cookie']
|
const setCookieHeader = initResponse.headers['set-cookie']
|
||||||
let xsrfToken = null
|
let xsrfToken = null
|
||||||
let dirSessionCookie = null
|
let dirSessionCookie = null
|
||||||
|
|
||||||
if (setCookieHeader) {
|
if (setCookieHeader) {
|
||||||
setCookieHeader.forEach(cookie => {
|
setCookieHeader.forEach(cookie => {
|
||||||
// Extract XSRF token from cookie
|
// Extract XSRF token from cookie
|
||||||
const xsrfMatch = cookie.match(/XSRF-TOKEN=([^;]+)/)
|
const xsrfMatch = cookie.match(/XSRF-TOKEN=([^;]+)/)
|
||||||
if (xsrfMatch) {
|
if (xsrfMatch) {
|
||||||
xsrfToken = decodeURIComponent(xsrfMatch[1])
|
xsrfToken = decodeURIComponent(xsrfMatch[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract dir_session cookie
|
// Extract dir_session cookie
|
||||||
const sessionMatch = cookie.match(/dir_session=([^;]+)/)
|
const sessionMatch = cookie.match(/dir_session=([^;]+)/)
|
||||||
if (sessionMatch) {
|
if (sessionMatch) {
|
||||||
dirSessionCookie = sessionMatch[1]
|
dirSessionCookie = sessionMatch[1]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const csrfToken = initResponse.data.csrfToken
|
const csrfToken = initResponse.data.csrfToken
|
||||||
|
|
||||||
if (!csrfToken) {
|
if (!csrfToken) {
|
||||||
throw new Error('No CSRF/XSRF token found in response')
|
throw new Error('No CSRF/XSRF token found in response')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build cookie string
|
// Build cookie string
|
||||||
let cookieString = ''
|
let cookieString = ''
|
||||||
if (xsrfToken) {
|
if (xsrfToken) {
|
||||||
cookieString += `XSRF-TOKEN=${encodeURIComponent(xsrfToken)}`
|
cookieString += `XSRF-TOKEN=${encodeURIComponent(xsrfToken)}`
|
||||||
}
|
}
|
||||||
if (dirSessionCookie) {
|
if (dirSessionCookie) {
|
||||||
if (cookieString) cookieString += '; '
|
if (cookieString) cookieString += '; '
|
||||||
cookieString += `dir_session=${dirSessionCookie}`
|
cookieString += `dir_session=${dirSessionCookie}`
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionCache = {
|
sessionCache = {
|
||||||
csrfToken,
|
csrfToken,
|
||||||
cookieString,
|
cookieString,
|
||||||
timestamp: Date.now()
|
timestamp: Date.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
return sessionCache
|
return sessionCache
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error getting session:', error.message)
|
console.error('Error getting session:', error.message)
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'tv.dir.bg',
|
site: 'tv.dir.bg',
|
||||||
days: 2,
|
days: 2,
|
||||||
url: 'https://tv.dir.bg/load/programs',
|
url: 'https://tv.dir.bg/load/programs',
|
||||||
request: {
|
request: {
|
||||||
maxContentLength: 125000000, // 10 MB
|
maxContentLength: 125000000, // 10 MB
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
async headers() {
|
async headers() {
|
||||||
try {
|
try {
|
||||||
const session = await getSession()
|
const session = await getSession()
|
||||||
return {
|
return {
|
||||||
'Cookie': session.cookieString,
|
'Cookie': session.cookieString,
|
||||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||||
'X-Requested-With': 'XMLHttpRequest'
|
'X-Requested-With': 'XMLHttpRequest'
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error getting headers:', error.message)
|
console.error('Error getting headers:', error.message)
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async data({ channel, date }) {
|
async data({ channel, date }) {
|
||||||
try {
|
try {
|
||||||
const session = await getSession()
|
const session = await getSession()
|
||||||
|
|
||||||
const params = new URLSearchParams()
|
const params = new URLSearchParams()
|
||||||
params.append('_token', session.csrfToken)
|
params.append('_token', session.csrfToken)
|
||||||
params.append('channel', channel.site_id)
|
params.append('channel', channel.site_id)
|
||||||
params.append('day', date.format('YYYY-MM-DD'))
|
params.append('day', date.format('YYYY-MM-DD'))
|
||||||
|
|
||||||
return params
|
return params
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error preparing request data:', error.message)
|
console.error('Error preparing request data:', error.message)
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
parser({ content, date }) {
|
parser({ content, date }) {
|
||||||
const programs = []
|
const programs = []
|
||||||
const items = parseItems(content)
|
const items = parseItems(content)
|
||||||
|
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
const prev = programs[programs.length - 1]
|
const prev = programs[programs.length - 1]
|
||||||
const $item = cheerio.load(item)
|
const $item = cheerio.load(item)
|
||||||
let start = parseStart($item, date)
|
let start = parseStart($item, date)
|
||||||
|
|
||||||
if (prev) {
|
if (prev) {
|
||||||
if (start.isBefore(prev.start)) {
|
if (start.isBefore(prev.start)) {
|
||||||
start = start.add(1, 'd')
|
start = start.add(1, 'd')
|
||||||
}
|
}
|
||||||
prev.stop = start
|
prev.stop = start
|
||||||
}
|
}
|
||||||
|
|
||||||
const stop = start.add(30, 'm')
|
const stop = start.add(30, 'm')
|
||||||
programs.push({
|
programs.push({
|
||||||
title: parseTitle($item),
|
title: parseTitle($item),
|
||||||
start,
|
start,
|
||||||
stop
|
stop
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
|
|
||||||
async channels() {
|
async channels() {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get('https://tv.dir.bg/channels')
|
const response = await axios.get('https://tv.dir.bg/channels')
|
||||||
const $ = cheerio.load(response.data)
|
const $ = cheerio.load(response.data)
|
||||||
|
|
||||||
const channels = []
|
const channels = []
|
||||||
|
|
||||||
$('.channel_cont').each((_index, element) => {
|
$('.channel_cont').each((_index, element) => {
|
||||||
const $element = $(element)
|
const $element = $(element)
|
||||||
|
|
||||||
const $link = $element.find('a.channel_link')
|
const $link = $element.find('a.channel_link')
|
||||||
const href = $link.attr('href')
|
const href = $link.attr('href')
|
||||||
|
|
||||||
const $img = $element.find('img')
|
const $img = $element.find('img')
|
||||||
const name = $img.attr('alt')
|
const name = $img.attr('alt')
|
||||||
const logo = $img.attr('src')
|
const logo = $img.attr('src')
|
||||||
|
|
||||||
const site_id = href ? href.match(/\/programa\/(\d+)/)?.[1] : ''
|
const site_id = href ? href.match(/\/programa\/(\d+)/)?.[1] : ''
|
||||||
|
|
||||||
if (site_id && name) {
|
if (site_id && name) {
|
||||||
channels.push({
|
channels.push({
|
||||||
lang: 'bg',
|
lang: 'bg',
|
||||||
site_id: site_id,
|
site_id: site_id,
|
||||||
name: name.trim(),
|
name: name.trim(),
|
||||||
logo: logo ? (logo.startsWith('http') ? logo : `https://tv.dir.bg${logo}`) : null
|
logo: logo ? (logo.startsWith('http') ? logo : `https://tv.dir.bg${logo}`) : null
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return channels
|
return channels
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching channels:', error.message)
|
console.error('Error fetching channels:', error.message)
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
clearSession() {
|
clearSession() {
|
||||||
sessionCache = null
|
sessionCache = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStart($item, date) {
|
function parseStart($item, date) {
|
||||||
const time = $item('.broadcast-time').text().trim()
|
const time = $item('.broadcast-time').text().trim()
|
||||||
const dateString = `${date.format('YYYY-MM-DD')} ${time}`
|
const dateString = `${date.format('YYYY-MM-DD')} ${time}`
|
||||||
|
|
||||||
return dayjs.tz(dateString, 'YYYY-MM-DD HH:mm', 'Europe/Sofia')
|
return dayjs.tz(dateString, 'YYYY-MM-DD HH:mm', 'Europe/Sofia')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function parseTitle($item) {
|
function parseTitle($item) {
|
||||||
return $item('.broadcast-title').text()
|
return $item('.broadcast-title').text()
|
||||||
.replace(/\s+/g, ' ')
|
.replace(/\s+/g, ' ')
|
||||||
.trim()
|
.trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(content) {
|
function parseItems(content) {
|
||||||
try {
|
try {
|
||||||
const json = JSON.parse(content)
|
const json = JSON.parse(content)
|
||||||
|
|
||||||
if (!json || json.status !== true) {
|
if (!json || json.status !== true) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
const $ = cheerio.load(json.html)
|
const $ = cheerio.load(json.html)
|
||||||
const items = $('.broadcast-item').toArray()
|
const items = $('.broadcast-item').toArray()
|
||||||
|
|
||||||
return items
|
return items
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Error parsing items:', error.message)
|
console.error('❌ Error parsing items:', error.message)
|
||||||
console.error('Error stack:', error.stack)
|
console.error('Error stack:', error.stack)
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,50 +1,50 @@
|
|||||||
const { parser, url } = require('./tv.dir.bg.config.js')
|
const { parser, url } = require('./tv.dir.bg.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2025-06-30', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2025-06-30', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '61',
|
site_id: '61',
|
||||||
xmltv_id: 'BTV.bg'
|
xmltv_id: 'BTV.bg'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url).toBe('https://tv.dir.bg/load/programs')
|
expect(url).toBe('https://tv.dir.bg/load/programs')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const results = parser({ content, date }).map(p => {
|
const results = parser({ content, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(results.length).toBe(63)
|
expect(results.length).toBe(63)
|
||||||
|
|
||||||
expect(results[0]).toMatchObject({
|
expect(results[0]).toMatchObject({
|
||||||
start: '2025-06-30T03:00:00.000Z',
|
start: '2025-06-30T03:00:00.000Z',
|
||||||
stop: '2025-06-30T03:30:00.000Z',
|
stop: '2025-06-30T03:30:00.000Z',
|
||||||
title: 'Светът на здравето'
|
title: 'Светът на здравето'
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(results[62]).toMatchObject({
|
expect(results[62]).toMatchObject({
|
||||||
start: '2025-07-01T02:00:00.000Z',
|
start: '2025-07-01T02:00:00.000Z',
|
||||||
stop: '2025-07-01T02:30:00.000Z',
|
stop: '2025-07-01T02:30:00.000Z',
|
||||||
title: 'Убийства в Рая , сезон 1 , епизод 7'
|
title: 'Убийства в Рая , сезон 1 , епизод 7'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,54 +1,54 @@
|
|||||||
const { parser, url } = require('./tv.lv.config.js')
|
const { parser, url } = require('./tv.lv.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2023-11-30', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2023-11-30', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: 'ltv1',
|
site_id: 'ltv1',
|
||||||
xmltv_id: 'LTV1.lv'
|
xmltv_id: 'LTV1.lv'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://www.tv.lv/programme/listing/none/30-11-2023?filter=channel&subslug=ltv1'
|
'https://www.tv.lv/programme/listing/none/30-11-2023?filter=channel&subslug=ltv1'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const results = parser({ content }).map(p => {
|
const results = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(results.length).toBe(40)
|
expect(results.length).toBe(40)
|
||||||
|
|
||||||
expect(results[0]).toMatchObject({
|
expect(results[0]).toMatchObject({
|
||||||
start: '2023-11-29T22:05:00.000Z',
|
start: '2023-11-29T22:05:00.000Z',
|
||||||
stop: '2023-11-29T22:35:00.000Z',
|
stop: '2023-11-29T22:35:00.000Z',
|
||||||
title: 'Ielas garumā. Pārdaugavas koka arhitektūra',
|
title: 'Ielas garumā. Pārdaugavas koka arhitektūra',
|
||||||
description: '',
|
description: '',
|
||||||
category: ''
|
category: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(results[39]).toMatchObject({
|
expect(results[39]).toMatchObject({
|
||||||
start: '2023-11-30T21:30:00.000Z',
|
start: '2023-11-30T21:30:00.000Z',
|
||||||
stop: '2023-11-30T22:30:00.000Z',
|
stop: '2023-11-30T22:30:00.000Z',
|
||||||
title: 'Latvijas Sirdsdziesma',
|
title: 'Latvijas Sirdsdziesma',
|
||||||
description: '',
|
description: '',
|
||||||
category: ''
|
category: ''
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const results = parser({
|
const results = parser({
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(results).toMatchObject([])
|
expect(results).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,147 +1,147 @@
|
|||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
|
|
||||||
const API_ENDPOINT = 'https://tv-at-prod.yo-digital.com/at-bifrost'
|
const API_ENDPOINT = 'https://tv-at-prod.yo-digital.com/at-bifrost'
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
'Device-Id': crypto.randomUUID(),
|
'Device-Id': crypto.randomUUID(),
|
||||||
app_key: 'CTnKA63ruKM0JM1doxAXwwyQLLmQiEiy',
|
app_key: 'CTnKA63ruKM0JM1doxAXwwyQLLmQiEiy',
|
||||||
app_version: '02.0.1260',
|
app_version: '02.0.1260',
|
||||||
'X-User-Agent': 'web|web|Firefox-120|02.0.1260|1',
|
'X-User-Agent': 'web|web|Firefox-120|02.0.1260|1',
|
||||||
'x-request-tracking-id': crypto.randomUUID()
|
'x-request-tracking-id': crypto.randomUUID()
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'tv.magenta.at',
|
site: 'tv.magenta.at',
|
||||||
days: 2,
|
days: 2,
|
||||||
request: {
|
request: {
|
||||||
headers,
|
headers,
|
||||||
cache: {
|
cache: {
|
||||||
ttl: 60 * 60 * 1000 // 1 hour
|
ttl: 60 * 60 * 1000 // 1 hour
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
url: function ({ channel, date }) {
|
url: function ({ channel, date }) {
|
||||||
return `${API_ENDPOINT}/epg/channel/schedules/v2?station_ids=${
|
return `${API_ENDPOINT}/epg/channel/schedules/v2?station_ids=${
|
||||||
channel.site_id
|
channel.site_id
|
||||||
}&date=${date.format('YYYY-MM-DD')}&hour_offset=${date.format('H')}&hour_range=3&natco_code=at`
|
}&date=${date.format('YYYY-MM-DD')}&hour_offset=${date.format('H')}&hour_range=3&natco_code=at`
|
||||||
},
|
},
|
||||||
async parser({ content, channel, date }) {
|
async parser({ content, channel, date }) {
|
||||||
let programs = []
|
let programs = []
|
||||||
if (!content) return programs
|
if (!content) return programs
|
||||||
|
|
||||||
let items = parseItems(JSON.parse(content), channel)
|
let items = parseItems(JSON.parse(content), channel)
|
||||||
if (!items.length) return programs
|
if (!items.length) return programs
|
||||||
|
|
||||||
const promises = [3, 6, 9, 12, 15, 18, 21].map(i =>
|
const promises = [3, 6, 9, 12, 15, 18, 21].map(i =>
|
||||||
axios.get(
|
axios.get(
|
||||||
`${API_ENDPOINT}/epg/channel/schedules/v2?station_ids=${channel.site_id}&date=${date.format(
|
`${API_ENDPOINT}/epg/channel/schedules/v2?station_ids=${channel.site_id}&date=${date.format(
|
||||||
'YYYY-MM-DD'
|
'YYYY-MM-DD'
|
||||||
)}&hour_offset=${i}&hour_range=3&natco_code=at`,
|
)}&hour_offset=${i}&hour_range=3&natco_code=at`,
|
||||||
{ headers }
|
{ headers }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
await Promise.allSettled(promises)
|
await Promise.allSettled(promises)
|
||||||
.then(results => {
|
.then(results => {
|
||||||
results.forEach(r => {
|
results.forEach(r => {
|
||||||
if (r.status === 'fulfilled') {
|
if (r.status === 'fulfilled') {
|
||||||
const parsed = parseItems(r.value.data, channel)
|
const parsed = parseItems(r.value.data, channel)
|
||||||
|
|
||||||
items = items.concat(parsed)
|
items = items.concat(parsed)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
|
|
||||||
for (let item of items) {
|
for (let item of items) {
|
||||||
const detail = await loadProgramDetails(item)
|
const detail = await loadProgramDetails(item)
|
||||||
programs.push({
|
programs.push({
|
||||||
title: item.description,
|
title: item.description,
|
||||||
description: parseDescription(detail),
|
description: parseDescription(detail),
|
||||||
date: parseDate(item),
|
date: parseDate(item),
|
||||||
category: parseCategory(item),
|
category: parseCategory(item),
|
||||||
image: detail.poster_image_url,
|
image: detail.poster_image_url,
|
||||||
actors: parseRoles(detail, 'Schauspieler'),
|
actors: parseRoles(detail, 'Schauspieler'),
|
||||||
directors: parseRoles(detail, 'Regisseur'),
|
directors: parseRoles(detail, 'Regisseur'),
|
||||||
producers: parseRoles(detail, 'Produzent'),
|
producers: parseRoles(detail, 'Produzent'),
|
||||||
season: parseSeason(item),
|
season: parseSeason(item),
|
||||||
episode: parseEpisode(item),
|
episode: parseEpisode(item),
|
||||||
start: parseStart(item),
|
start: parseStart(item),
|
||||||
stop: parseStop(item)
|
stop: parseStop(item)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels() {
|
async channels() {
|
||||||
const data = await axios
|
const data = await axios
|
||||||
.get(`${API_ENDPOINT}/epg/channel?natco_code=at`, { headers })
|
.get(`${API_ENDPOINT}/epg/channel?natco_code=at`, { headers })
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
|
|
||||||
return data.channels.map(item => {
|
return data.channels.map(item => {
|
||||||
return {
|
return {
|
||||||
lang: 'de',
|
lang: 'de',
|
||||||
site_id: item.station_id,
|
site_id: item.station_id,
|
||||||
name: item.title
|
name: item.title
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadProgramDetails(item) {
|
async function loadProgramDetails(item) {
|
||||||
if (!item.program_id) return {}
|
if (!item.program_id) return {}
|
||||||
const url = `${API_ENDPOINT}/details/series/${item.program_id}?natco_code=at`
|
const url = `${API_ENDPOINT}/details/series/${item.program_id}?natco_code=at`
|
||||||
const data = await axios
|
const data = await axios
|
||||||
.get(url, { headers })
|
.get(url, { headers })
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
|
|
||||||
return data || {}
|
return data || {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDate(item) {
|
function parseDate(item) {
|
||||||
return item && item.release_year ? item.release_year.toString() : null
|
return item && item.release_year ? item.release_year.toString() : null
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStart(item) {
|
function parseStart(item) {
|
||||||
return dayjs(item.start_time)
|
return dayjs(item.start_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStop(item) {
|
function parseStop(item) {
|
||||||
return dayjs(item.end_time)
|
return dayjs(item.end_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(data, channel) {
|
function parseItems(data, channel) {
|
||||||
if (!data || !data.channels) return []
|
if (!data || !data.channels) return []
|
||||||
const channelData = data.channels[channel.site_id]
|
const channelData = data.channels[channel.site_id]
|
||||||
if (!channelData) return []
|
if (!channelData) return []
|
||||||
return channelData
|
return channelData
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseCategory(item) {
|
function parseCategory(item) {
|
||||||
if (!item.genres) return null
|
if (!item.genres) return null
|
||||||
return item.genres.map(genre => genre.id)
|
return item.genres.map(genre => genre.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseSeason(item) {
|
function parseSeason(item) {
|
||||||
if (item.season_display_number === 'Folgen') return null
|
if (item.season_display_number === 'Folgen') return null
|
||||||
return item.season_number
|
return item.season_number
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseEpisode(item) {
|
function parseEpisode(item) {
|
||||||
if (item.episode_number) return parseInt(item.episode_number)
|
if (item.episode_number) return parseInt(item.episode_number)
|
||||||
if (item.season_display_number === 'Folgen') return item.season_number
|
if (item.season_display_number === 'Folgen') return item.season_number
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDescription(item) {
|
function parseDescription(item) {
|
||||||
if (!item.details) return null
|
if (!item.details) return null
|
||||||
return item.details.description
|
return item.details.description
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseRoles(item, role_name) {
|
function parseRoles(item, role_name) {
|
||||||
if (!item.roles) return null
|
if (!item.roles) return null
|
||||||
return item.roles.filter(role => role.role_name === role_name).map(role => role.person_name)
|
return item.roles.filter(role => role.role_name === role_name).map(role => role.person_name)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,122 +1,122 @@
|
|||||||
const { DateTime } = require('luxon')
|
const { DateTime } = require('luxon')
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const { uniqBy } = require('../../scripts/functions')
|
const { uniqBy } = require('../../scripts/functions')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'tv.mail.ru',
|
site: 'tv.mail.ru',
|
||||||
days: 2,
|
days: 2,
|
||||||
delay: 1000,
|
delay: 1000,
|
||||||
url({ channel, date }) {
|
url({ channel, date }) {
|
||||||
return `https://tv.mail.ru/ajax/channel/?region_id=70&channel_id=${
|
return `https://tv.mail.ru/ajax/channel/?region_id=70&channel_id=${
|
||||||
channel.site_id
|
channel.site_id
|
||||||
}&date=${date.format('YYYY-MM-DD')}`
|
}&date=${date.format('YYYY-MM-DD')}`
|
||||||
},
|
},
|
||||||
parser({ content, date }) {
|
parser({ content, date }) {
|
||||||
const programs = []
|
const programs = []
|
||||||
const items = parseItems(content)
|
const items = parseItems(content)
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
const prev = programs[programs.length - 1]
|
const prev = programs[programs.length - 1]
|
||||||
let start = parseStart(item, date)
|
let start = parseStart(item, date)
|
||||||
if (prev) {
|
if (prev) {
|
||||||
if (start < prev.start) {
|
if (start < prev.start) {
|
||||||
start = start.plus({ days: 1 })
|
start = start.plus({ days: 1 })
|
||||||
date = date.add(1, 'd')
|
date = date.add(1, 'd')
|
||||||
}
|
}
|
||||||
prev.stop = start
|
prev.stop = start
|
||||||
}
|
}
|
||||||
const stop = start.plus({ hours: 1 })
|
const stop = start.plus({ hours: 1 })
|
||||||
programs.push({
|
programs.push({
|
||||||
title: item.name,
|
title: item.name,
|
||||||
category: parseCategory(item),
|
category: parseCategory(item),
|
||||||
start,
|
start,
|
||||||
stop
|
stop
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels() {
|
async channels() {
|
||||||
const regions = [5506, 1096, 1125, 285]
|
const regions = [5506, 1096, 1125, 285]
|
||||||
|
|
||||||
let channels = []
|
let channels = []
|
||||||
for (let region of regions) {
|
for (let region of regions) {
|
||||||
const totalPages = await getTotalPageCount(region)
|
const totalPages = await getTotalPageCount(region)
|
||||||
const pages = Array.from(Array(totalPages).keys())
|
const pages = Array.from(Array(totalPages).keys())
|
||||||
for (let page of pages) {
|
for (let page of pages) {
|
||||||
const data = await axios
|
const data = await axios
|
||||||
.get('https://tv.mail.ru/ajax/channel/list/', {
|
.get('https://tv.mail.ru/ajax/channel/list/', {
|
||||||
params: { page },
|
params: { page },
|
||||||
headers: {
|
headers: {
|
||||||
cookie: `s=fver=0|geo=${region};`
|
cookie: `s=fver=0|geo=${region};`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
|
|
||||||
data.channels.forEach(item => {
|
data.channels.forEach(item => {
|
||||||
channels.push({
|
channels.push({
|
||||||
lang: 'ru',
|
lang: 'ru',
|
||||||
name: item.name,
|
name: item.name,
|
||||||
site_id: item.id
|
site_id: item.id
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return uniqBy(channels, 'site_id')
|
return uniqBy(channels, 'site_id')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getTotalPageCount(region) {
|
async function getTotalPageCount(region) {
|
||||||
const data = await axios
|
const data = await axios
|
||||||
.get('https://tv.mail.ru/ajax/channel/list/', {
|
.get('https://tv.mail.ru/ajax/channel/list/', {
|
||||||
params: { page: 0 },
|
params: { page: 0 },
|
||||||
headers: {
|
headers: {
|
||||||
cookie: `s=fver=0|geo=${region};`
|
cookie: `s=fver=0|geo=${region};`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
|
|
||||||
return data.total
|
return data.total
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStart(item, date) {
|
function parseStart(item, date) {
|
||||||
const dateString = `${date.format('YYYY-MM-DD')} ${item.start}`
|
const dateString = `${date.format('YYYY-MM-DD')} ${item.start}`
|
||||||
|
|
||||||
return DateTime.fromFormat(dateString, 'yyyy-MM-dd HH:mm', { zone: 'Europe/Moscow' }).toUTC()
|
return DateTime.fromFormat(dateString, 'yyyy-MM-dd HH:mm', { zone: 'Europe/Moscow' }).toUTC()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseCategory(item) {
|
function parseCategory(item) {
|
||||||
const categories = {
|
const categories = {
|
||||||
1: 'Фильм',
|
1: 'Фильм',
|
||||||
2: 'Сериал',
|
2: 'Сериал',
|
||||||
6: 'Документальное',
|
6: 'Документальное',
|
||||||
7: 'Телемагазин',
|
7: 'Телемагазин',
|
||||||
8: 'Позновательное',
|
8: 'Позновательное',
|
||||||
10: 'Другое',
|
10: 'Другое',
|
||||||
14: 'ТВ-шоу',
|
14: 'ТВ-шоу',
|
||||||
16: 'Досуг,Хобби',
|
16: 'Досуг,Хобби',
|
||||||
17: 'Ток-шоу',
|
17: 'Ток-шоу',
|
||||||
18: 'Юмористическое',
|
18: 'Юмористическое',
|
||||||
23: 'Музыка',
|
23: 'Музыка',
|
||||||
24: 'Развлекательное',
|
24: 'Развлекательное',
|
||||||
25: 'Игровое',
|
25: 'Игровое',
|
||||||
26: 'Новости'
|
26: 'Новости'
|
||||||
}
|
}
|
||||||
|
|
||||||
return categories[item.category_id]
|
return categories[item.category_id]
|
||||||
? {
|
? {
|
||||||
lang: 'ru',
|
lang: 'ru',
|
||||||
value: categories[item.category_id]
|
value: categories[item.category_id]
|
||||||
}
|
}
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(content) {
|
function parseItems(content) {
|
||||||
const json = JSON.parse(content)
|
const json = JSON.parse(content)
|
||||||
if (!Array.isArray(json.schedule) || !json.schedule[0]) return []
|
if (!Array.isArray(json.schedule) || !json.schedule[0]) return []
|
||||||
const event = json.schedule[0].event || []
|
const event = json.schedule[0].event || []
|
||||||
|
|
||||||
return [...event.past, ...event.current]
|
return [...event.past, ...event.current]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,77 +1,77 @@
|
|||||||
const { parser, url } = require('./tv.mail.ru.config.js')
|
const { parser, url } = require('./tv.mail.ru.config.js')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-24', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-24', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '2785',
|
site_id: '2785',
|
||||||
xmltv_id: '21TV.am'
|
xmltv_id: '21TV.am'
|
||||||
}
|
}
|
||||||
const content = fs.readFileSync(path.join(__dirname, '__data__', 'content.json'), 'utf8')
|
const content = fs.readFileSync(path.join(__dirname, '__data__', 'content.json'), 'utf8')
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://tv.mail.ru/ajax/channel/?region_id=70&channel_id=2785&date=2021-11-24'
|
'https://tv.mail.ru/ajax/channel/?region_id=70&channel_id=2785&date=2021-11-24'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const result = parser({ content, date }).map(p => {
|
const result = parser({ content, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-24T20:35:00.000Z',
|
start: '2021-11-24T20:35:00.000Z',
|
||||||
stop: '2021-11-24T22:40:00.000Z',
|
stop: '2021-11-24T22:40:00.000Z',
|
||||||
title: 'Նոնստոպ․ Տեսահոլովակներ',
|
title: 'Նոնստոպ․ Տեսահոլովակներ',
|
||||||
category: {
|
category: {
|
||||||
lang: 'ru',
|
lang: 'ru',
|
||||||
value: 'Музыка'
|
value: 'Музыка'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2021-11-24T22:40:00.000Z',
|
start: '2021-11-24T22:40:00.000Z',
|
||||||
stop: '2021-11-24T23:40:00.000Z',
|
stop: '2021-11-24T23:40:00.000Z',
|
||||||
title: 'Վերջին թագավորությունը',
|
title: 'Վերջին թագավորությունը',
|
||||||
category: {
|
category: {
|
||||||
lang: 'ru',
|
lang: 'ru',
|
||||||
value: 'Сериал'
|
value: 'Сериал'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2021-11-24T23:40:00.000Z',
|
start: '2021-11-24T23:40:00.000Z',
|
||||||
stop: '2021-11-25T00:25:00.000Z',
|
stop: '2021-11-25T00:25:00.000Z',
|
||||||
title: 'Պրոֆեսիոնալները',
|
title: 'Պրոֆեսիոնալները',
|
||||||
category: {
|
category: {
|
||||||
lang: 'ru',
|
lang: 'ru',
|
||||||
value: 'Позновательное'
|
value: 'Позновательное'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2021-11-25T00:25:00.000Z',
|
start: '2021-11-25T00:25:00.000Z',
|
||||||
stop: '2021-11-25T01:25:00.000Z',
|
stop: '2021-11-25T01:25:00.000Z',
|
||||||
title: 'Նոնստոպ․ Տեսահոլովակներ',
|
title: 'Նոնստոպ․ Տեսահոլովակներ',
|
||||||
category: {
|
category: {
|
||||||
lang: 'ru',
|
lang: 'ru',
|
||||||
value: 'Музыка'
|
value: 'Музыка'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.join(__dirname, '__data__', 'no_content.json'), 'utf8')
|
content: fs.readFileSync(path.join(__dirname, '__data__', 'no_content.json'), 'utf8')
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,92 +1,92 @@
|
|||||||
const { parser, url, request } = require('./tv.yandex.ru.config.js')
|
const { parser, url, request } = require('./tv.yandex.ru.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
|
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
jest.mock('axios')
|
jest.mock('axios')
|
||||||
|
|
||||||
const date = dayjs.utc('2023-11-26').startOf('d')
|
const date = dayjs.utc('2023-11-26').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '16',
|
site_id: '16',
|
||||||
xmltv_id: 'ChannelOne.ru'
|
xmltv_id: 'ChannelOne.ru'
|
||||||
}
|
}
|
||||||
axios.get.mockImplementation(url => {
|
axios.get.mockImplementation(url => {
|
||||||
if (url === 'https://tv.yandex.ru/?date=2023-11-26&grid=all&period=all-day') {
|
if (url === 'https://tv.yandex.ru/?date=2023-11-26&grid=all&period=all-day') {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
headers: {},
|
headers: {},
|
||||||
data: fs.readFileSync(path.resolve(__dirname, '__data__/content.html'))
|
data: fs.readFileSync(path.resolve(__dirname, '__data__/content.html'))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (url === 'https://tv.yandex.ru/api/120809?date=2023-11-26&grid=all&period=all-day') {
|
if (url === 'https://tv.yandex.ru/api/120809?date=2023-11-26&grid=all&period=all-day') {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
headers: {},
|
headers: {},
|
||||||
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/schedule.json')))
|
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/schedule.json')))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
url ===
|
url ===
|
||||||
'https://tv.yandex.ru/api/120809/main/chunk?page=0&date=2023-11-26&period=all-day&offset=0&limit=11'
|
'https://tv.yandex.ru/api/120809/main/chunk?page=0&date=2023-11-26&period=all-day&offset=0&limit=11'
|
||||||
) {
|
) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
headers: {},
|
headers: {},
|
||||||
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/schedule0.json')))
|
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/schedule0.json')))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (url === 'https://tv.yandex.ru/api/120809/event?eventId=217749657&programCoId=') {
|
if (url === 'https://tv.yandex.ru/api/120809/event?eventId=217749657&programCoId=') {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
headers: {},
|
headers: {},
|
||||||
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/program.json')))
|
data: JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/program.json')))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date })).toBe('https://tv.yandex.ru/?date=2023-11-26&grid=all&period=all-day')
|
expect(url({ date })).toBe('https://tv.yandex.ru/?date=2023-11-26&grid=all&period=all-day')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request headers', () => {
|
it('can generate valid request headers', () => {
|
||||||
expect(request.headers).toMatchObject({
|
expect(request.headers).toMatchObject({
|
||||||
Cookie:
|
Cookie:
|
||||||
'i=eIUfSP+/mzQWXcH+Cuz8o1vY+D2K8fhBd6Sj0xvbPZeO4l3cY+BvMp8fFIuM17l6UE1Z5+R2a18lP00ex9iYVJ+VT+c=; ' +
|
'i=eIUfSP+/mzQWXcH+Cuz8o1vY+D2K8fhBd6Sj0xvbPZeO4l3cY+BvMp8fFIuM17l6UE1Z5+R2a18lP00ex9iYVJ+VT+c=; ' +
|
||||||
'spravka=dD0xNzM0MjA0NjM4O2k9MTI1LjE2NC4xNDkuMjAwO0Q9QTVCQ0IyOTI5RDQxNkU5NkEyOTcwMTNDMzZGMDAzNjRDNTFFNDM4QkE2Q0IyOTJDRjhCOTZDRDIzODdBQzk2MzRFRDc5QTk2Qjc2OEI1MUY5MTM5M0QzNkY3OEQ2OUY3OTUwNkQ3RjBCOEJGOEJDMjAwMTQ0RDUwRkFCMDNEQzJFMDI2OEI5OTk5OUJBNEFERUYwOEQ1MjUwQTE0QTI3RDU1MEQwM0U0O3U9MTczNDIwNDYzODUyNDYyNzg1NDtoPTIxNTc0ZTc2MDQ1ZjcwMDBkYmY0NTVkM2Q2ZWMyM2Y1; ' +
|
'spravka=dD0xNzM0MjA0NjM4O2k9MTI1LjE2NC4xNDkuMjAwO0Q9QTVCQ0IyOTI5RDQxNkU5NkEyOTcwMTNDMzZGMDAzNjRDNTFFNDM4QkE2Q0IyOTJDRjhCOTZDRDIzODdBQzk2MzRFRDc5QTk2Qjc2OEI1MUY5MTM5M0QzNkY3OEQ2OUY3OTUwNkQ3RjBCOEJGOEJDMjAwMTQ0RDUwRkFCMDNEQzJFMDI2OEI5OTk5OUJBNEFERUYwOEQ1MjUwQTE0QTI3RDU1MEQwM0U0O3U9MTczNDIwNDYzODUyNDYyNzg1NDtoPTIxNTc0ZTc2MDQ1ZjcwMDBkYmY0NTVkM2Q2ZWMyM2Y1; ' +
|
||||||
'yandexuid=1197179041732383499; ' +
|
'yandexuid=1197179041732383499; ' +
|
||||||
'yashr=4682342911732383504; ' +
|
'yashr=4682342911732383504; ' +
|
||||||
'yuidss=1197179041732383499; ' +
|
'yuidss=1197179041732383499; ' +
|
||||||
'user_display=824'
|
'user_display=824'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', async () => {
|
it('can parse response', async () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'))
|
||||||
const result = (await parser({ content, date, channel })).map(p => {
|
const result = (await parser({ content, date, channel })).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2023-11-26T01:35:00.000Z',
|
start: '2023-11-26T01:35:00.000Z',
|
||||||
stop: '2023-11-26T02:10:00.000Z',
|
stop: '2023-11-26T02:10:00.000Z',
|
||||||
title: 'ПОДКАСТ.ЛАБ. Мелодии моей жизни',
|
title: 'ПОДКАСТ.ЛАБ. Мелодии моей жизни',
|
||||||
category: 'досуг',
|
category: 'досуг',
|
||||||
description:
|
description:
|
||||||
'Впереди вся ночь и есть о чем поговорить. Фильмы, музыка, любовь, звезды, еда, мода, анекдоты, спорт, деньги, настоящее, будущее - все это в творческом эксперименте.\nЛариса Гузеева читает любовные письма. Леонид Якубович рассказывает, кого не берут в пилоты. Арина Холина - какой секс способен довести до мужа или до развода. Валерий Сюткин на ходу сочиняет песню для Карины Кросс и Вали Карнавал. Дмитрий Дибров дарит новую жизнь любимой "Антропологии". Денис Казанский - все о футболе, хоккее и не только.\n"ПОДКАСТЫ. ЛАБ" - серия подкастов разной тематики, которые невозможно проспать. Интеллектуальные дискуссии после полуночи с самыми компетентными экспертами и актуальными спикерами.'
|
'Впереди вся ночь и есть о чем поговорить. Фильмы, музыка, любовь, звезды, еда, мода, анекдоты, спорт, деньги, настоящее, будущее - все это в творческом эксперименте.\nЛариса Гузеева читает любовные письма. Леонид Якубович рассказывает, кого не берут в пилоты. Арина Холина - какой секс способен довести до мужа или до развода. Валерий Сюткин на ходу сочиняет песню для Карины Кросс и Вали Карнавал. Дмитрий Дибров дарит новую жизнь любимой "Антропологии". Денис Казанский - все о футболе, хоккее и не только.\n"ПОДКАСТЫ. ЛАБ" - серия подкастов разной тематики, которые невозможно проспать. Интеллектуальные дискуссии после полуночи с самыми компетентными экспертами и актуальными спикерами.'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', async () => {
|
it('can handle empty guide', async () => {
|
||||||
const result = await parser({
|
const result = await parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, '__data__', 'no_content.html'), 'utf8')
|
content: fs.readFileSync(path.resolve(__dirname, '__data__', 'no_content.html'), 'utf8')
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,338 +1,338 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<channels>
|
<channels>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="14">RTS Maribor</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="14">RTS Maribor</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="17">TV Veseljak Golica</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="17">TV Veseljak Golica</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="26">Discovery Channel</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="26">Discovery Channel</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="110">Hayat Plus</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="110">Hayat Plus</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000028">AMC</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000028">AMC</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000043">History Channel</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000043">History Channel</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000048">History Channel</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000048">History Channel</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000074">Disney Channel</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000074">Disney Channel</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000080">Folk Plus</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000080">Folk Plus</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000155">Disney Junior</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000155">Disney Junior</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000181">Alfa TV MAK</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000181">Alfa TV MAK</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000223">MTV 3</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000223">MTV 3</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000224">Naša TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000224">Naša TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000267">Alfa TV BiH</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000267">Alfa TV BiH</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000283">INFO TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000283">INFO TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000291">Animal Planet</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000291">Animal Planet</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000302">Nickelodeon</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000302">Nickelodeon</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000470">TV Nakupi</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000470">TV Nakupi</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000477">HBO</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000477">HBO</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000478">HBO 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000478">HBO 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000479">HBO 3</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000479">HBO 3</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000480">Cinemax</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000480">Cinemax</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000481">Cinemax 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000481">Cinemax 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000503">RT Doc</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000503">RT Doc</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000505">Discovery Science</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000505">Discovery Science</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000506">DTX</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000506">DTX</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000507">ID</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000507">ID</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000517">Freedom</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000517">Freedom</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000547">Filmbox Premium</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000547">Filmbox Premium</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000615">E!</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000615">E!</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000765">Pink Serije</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000765">Pink Serije</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000766">Pink Koncert</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000766">Pink Koncert</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000767">Pink’n’Roll</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000767">Pink’n’Roll</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000792">Sonce TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000792">Sonce TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000793">Prva World</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000793">Prva World</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000794">Prva Max</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000794">Prva Max</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000795">Happy Reality</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000795">Happy Reality</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000796">Happy Reality 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000796">Happy Reality 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000797">Prva Files</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000797">Prva Files</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000798">Prva Kick</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000798">Prva Kick</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000799">Prva Life</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000799">Prva Life</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000800">Prva Plus</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000800">Prva Plus</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000801">Adria</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000801">Adria</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000802">One Adria</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000802">One Adria</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000803">Folx Slovenija</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000803">Folx Slovenija</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000807">BBC News</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000807">BBC News</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000808">Dom TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000808">Dom TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000812">Espreso TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000812">Espreso TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000813">Duck TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000813">Duck TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000814">Non Stop</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000814">Non Stop</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000815">Hit TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000815">Hit TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000816">Bloomberg Adria</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000816">Bloomberg Adria</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000817">Arena Sport 1 Premium</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000817">Arena Sport 1 Premium</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000818">Megafon TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000818">Megafon TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000820">CineStar TV 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000820">CineStar TV 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000821">LH TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000821">LH TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000825">English Club TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000825">English Club TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000826">Harmonika TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000826">Harmonika TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000827">GLAM</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000827">GLAM</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000828">XXXTazy</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000828">XXXTazy</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000829">Angels</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000829">Angels</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000830">BooB</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000830">BooB</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000831">Capable Hole</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000831">Capable Hole</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000832">Devils Home</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000832">Devils Home</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000833">Foxy Dolls</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000833">Foxy Dolls</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000834">MIxxx</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000834">MIxxx</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000835">Prva TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000835">Prva TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000868">BIR TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000868">BIR TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000870">KIC TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000870">KIC TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000871">Kitchen TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000871">Kitchen TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000874">Mediaset Italia</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000874">Mediaset Italia</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000875">TgCom24</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000875">TgCom24</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="2000000001">R Kanal+</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="2000000001">R Kanal+</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="2000000039">Cartoon Network</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="2000000039">Cartoon Network</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="2000000041">RTV Shqiptar</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="2000000041">RTV Shqiptar</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="2000000045">Europe by Satellite</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="2000000045">Europe by Satellite</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="2000000050">RTV Atlas</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="2000000050">RTV Atlas</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="3sat.de" site_id="1000640">3SAT</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="3sat.de" site_id="1000640">3SAT</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="24Kitchen.us@Slovenia" site_id="1000307">24Kitchen Adria</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="24Kitchen.us@Slovenia" site_id="1000307">24Kitchen Adria</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="360TuneBox.nl" site_id="1000558">360 Tunebox</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="360TuneBox.nl" site_id="1000558">360 Tunebox</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="AgroTV.rs" site_id="1000686">Agro TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="AgroTV.rs" site_id="1000686">Agro TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="AlJazeeraBalkans.ba" site_id="1000180">Al Jazeera Balkans</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="AlJazeeraBalkans.ba" site_id="1000180">Al Jazeera Balkans</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Alsat.mk" site_id="1000219">Alsat Macedoniae</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Alsat.mk" site_id="1000219">Alsat Macedoniae</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="AMCEurope.uk@Portugal@Slovenia" site_id="1000523">AMC</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="AMCEurope.uk@Portugal@Slovenia" site_id="1000523">AMC</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="AnixeHDSerie.de" site_id="1000057">Anixe</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="AnixeHDSerie.de" site_id="1000057">Anixe</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ArenaEsport.rs" site_id="1000683">TV Arena Esport</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ArenaEsport.rs" site_id="1000683">TV Arena Esport</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ArenaFight.rs" site_id="1000777">Arena Fight</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ArenaFight.rs" site_id="1000777">Arena Fight</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ArenaSport1.rs" site_id="1000688">Arena Sport 1</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ArenaSport1.rs" site_id="1000688">Arena Sport 1</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ArenaSport2.rs" site_id="1000689">Arena Sport 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ArenaSport2.rs" site_id="1000689">Arena Sport 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ArenaSport3.rs" site_id="1000787">Arena Sport 3</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ArenaSport3.rs" site_id="1000787">Arena Sport 3</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ArenaSport4.rs" site_id="1000788">Arena Sport 4</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ArenaSport4.rs" site_id="1000788">Arena Sport 4</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="arte.fr" site_id="1000026">Arte</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="arte.fr" site_id="1000026">Arte</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ATMTV.si" site_id="1000001">ATM Kranjska Gora</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ATMTV.si" site_id="1000001">ATM Kranjska Gora</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="B92.rs" site_id="1000207">B92</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="B92.rs" site_id="1000207">B92</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BabyTV.uk" site_id="82">Baby TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BabyTV.uk" site_id="82">Baby TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BalkanErotic.si" site_id="1000645">Balkan Erotic</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BalkanErotic.si" site_id="1000645">Balkan Erotic</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BalkanikaTV.bg" site_id="2000000027">Balkanika Music TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BalkanikaTV.bg" site_id="2000000027">Balkanika Music TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BalkanTripTV.rs" site_id="1000685">TV Balkan Trip</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BalkanTripTV.rs" site_id="1000685">TV Balkan Trip</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BBCEarth.uk@Romania" site_id="1000482">BBC Earth</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BBCEarth.uk@Romania" site_id="1000482">BBC Earth</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BBCFirst.uk@Poland" site_id="1000652">BBC First</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BBCFirst.uk@Poland" site_id="1000652">BBC First</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BHT1.ba" site_id="1000182">BHT 1</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BHT1.ba" site_id="1000182">BHT 1</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BKTV.si" site_id="1000265">BK TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BKTV.si" site_id="1000265">BK TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BN2.ba" site_id="129">BN TV 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BN2.ba" site_id="129">BN TV 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BNMusic.ba" site_id="1000067">BN Music</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BNMusic.ba" site_id="1000067">BN Music</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CartoonitoCEE.uk" site_id="2000000032">Cartoonito</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CartoonitoCEE.uk" site_id="2000000032">Cartoonito</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BoomTV.si" site_id="124">Aktual TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BoomTV.si" site_id="124">Aktual TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BRIO.si" site_id="1000368">BRIO</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="BRIO.si" site_id="1000368">BRIO</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Carousel.ru" site_id="1000273">Karousel</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Carousel.ru" site_id="1000273">Karousel</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CBSRealityEMEA.uk" site_id="44">CBS Reality</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CBSRealityEMEA.uk" site_id="44">CBS Reality</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CGTN.cn" site_id="125">CGTN</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CGTN.cn" site_id="125">CGTN</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ChannelOne.ru" site_id="1000272">Channel One Russia</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ChannelOne.ru" site_id="1000272">Channel One Russia</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CineStarTV1.rs" site_id="1000085">CineStar TV 1</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CineStarTV1.rs" site_id="1000085">CineStar TV 1</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CineStarTVAction.rs" site_id="1000427">Cinestar Action & Thriller</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CineStarTVAction.rs" site_id="1000427">Cinestar Action & Thriller</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CineStarTVComedy.hr" site_id="1000617">Cinestar Comedy</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CineStarTVComedy.hr" site_id="1000617">Cinestar Comedy</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CineStarTVFantasy.hr" site_id="1000618">Cinestar Fantasy</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CineStarTVFantasy.hr" site_id="1000618">Cinestar Fantasy</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CineStarTVPremiere1.hr" site_id="1000431">Cinestar Premiere</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CineStarTVPremiere1.hr" site_id="1000431">Cinestar Premiere</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CineStarTVPremiere2.hr" site_id="1000430">Cinestar Premiere 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CineStarTVPremiere2.hr" site_id="1000430">Cinestar Premiere 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ClubMTVEurope.uk" site_id="126">Club MTV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ClubMTVEurope.uk" site_id="126">Club MTV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CMCTV.hr" site_id="1000156">CMC - Croatian Music Channel</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CMCTV.hr" site_id="1000156">CMC - Croatian Music Channel</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CNNInternational.us@MENA" site_id="25">CNN International</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CNNInternational.us@MENA" site_id="25">CNN International</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CrimePlusInvestigation.uk" site_id="1000153">Crime & Investigation Channel</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="CrimePlusInvestigation.uk" site_id="1000153">Crime & Investigation Channel</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="DasErste.de" site_id="1000059">Das Erste (ARD)</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="DasErste.de" site_id="1000059">Das Erste (ARD)</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="DaVinci.de" site_id="1000055">Da Vinci</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="DaVinci.de" site_id="1000055">Da Vinci</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="DivaAdria.us" site_id="2000000040">Diva</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="DivaAdria.us" site_id="2000000040">Diva</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="DMSat.rs" site_id="2000000026">DM SAT Televizija</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="DMSat.rs" site_id="2000000026">DM SAT Televizija</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="DocuBox.nl" site_id="1000551">Docubox</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="DocuBox.nl" site_id="1000551">Docubox</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Domkino.ru" site_id="1000274">Dom Kino</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Domkino.ru" site_id="1000274">Dom Kino</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="DorcelXXX.nl" site_id="1000486">Dorcel TV XXX</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="DorcelXXX.nl" site_id="1000486">Dorcel TV XXX</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Duna.hu" site_id="1000648">Duna</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Duna.hu" site_id="1000648">Duna</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="DunaWorld.hu" site_id="1000786">Duna World</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="DunaWorld.hu" site_id="1000786">Duna World</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="DuskTV.nl" site_id="1000373">Dusk</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="DuskTV.nl" site_id="1000373">Dusk</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ELTA2.ba" site_id="1000179">Elta 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ELTA2.ba" site_id="1000179">Elta 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ELTA1HD.ba" site_id="1000240">Elta TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ELTA1HD.ba" site_id="1000240">Elta TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="EpicDrama.uk@Sweden" site_id="1000501">Epic Drama</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="EpicDrama.uk@Sweden" site_id="1000501">Epic Drama</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ePosavjeTV.si" site_id="1000651">ePosavje TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ePosavjeTV.si" site_id="1000651">ePosavje TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="EroX.nl" site_id="1000559">Erox</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="EroX.nl" site_id="1000559">Erox</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="EroXXX.nl" site_id="1000553">Eroxxx</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="EroXXX.nl" site_id="1000553">Eroxxx</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ETV.si" site_id="1000641">ETV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ETV.si" site_id="1000641">ETV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="EuronewsEnglish.fr" site_id="1000764">Euronews</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="EuronewsEnglish.fr" site_id="1000764">Euronews</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Eurosport1.fr@Germany" site_id="1000044">Eurosport (NEM)</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Eurosport1.fr@Germany" site_id="1000044">Eurosport (NEM)</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Eurosport1.fr" site_id="1000025">Eurosport</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Eurosport1.fr" site_id="1000025">Eurosport</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Eurosport2.fr" site_id="1000504">Eurosport 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Eurosport2.fr" site_id="1000504">Eurosport 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Eurosport4K.fr" site_id="1000728">Eurosport</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Eurosport4K.fr" site_id="1000728">Eurosport</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="EWTN.us@Europe" site_id="36">EWTN Europe</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="EWTN.us@Europe" site_id="36">EWTN Europe</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ExodusTV.si" site_id="1000455">Exodus</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ExodusTV.si" site_id="1000455">Exodus</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Extreme.si" site_id="1000646">Extreme</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Extreme.si" site_id="1000646">Extreme</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ExtremeSportsChannel.nl" site_id="37">Extreme Sports</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ExtremeSportsChannel.nl" site_id="37">Extreme Sports</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FashionBox.nl" site_id="1000556">Fashionbox</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FashionBox.nl" site_id="1000556">Fashionbox</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FashionTVEurope.fr" site_id="1000056">Fashion TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FashionTVEurope.fr" site_id="1000056">Fashion TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FastFunBox.nl" site_id="1000552">Fastnfunbox</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FastFunBox.nl" site_id="1000552">Fastnfunbox</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Federalnatelevizija.ba" site_id="1000183">FTV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Federalnatelevizija.ba" site_id="1000183">FTV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FenFolkTV.bg" site_id="1000545">FenFolk TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FenFolkTV.bg" site_id="1000545">FenFolk TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FenTV.bg" site_id="1000544">FEN TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FenTV.bg" site_id="1000544">FEN TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FightBox.nl" site_id="1000550">Fightbox</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FightBox.nl" site_id="1000550">Fightbox</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FilmBoxArthouse.nl" site_id="1000557">Filmbox Art House</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FilmBoxArthouse.nl" site_id="1000557">Filmbox Art House</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FilmBoxExtra.nl@Bulgaria" site_id="1000548">Filmbox Extra</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FilmBoxExtra.nl@Bulgaria" site_id="1000548">Filmbox Extra</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FilmBoxStars.nl@Bulgaria" site_id="1000549">Filmbox Stars</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FilmBoxStars.nl@Bulgaria" site_id="1000549">Filmbox Stars</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Fox.rs" site_id="1000308">STAR</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Fox.rs" site_id="1000308">STAR</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FoxCrime.rs" site_id="1000310">STAR Crime</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FoxCrime.rs" site_id="1000310">STAR Crime</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FoxLife.rs" site_id="1000309">STAR Life</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FoxLife.rs" site_id="1000309">STAR Life</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FoxMovies.si" site_id="1000311">STAR Movies</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FoxMovies.si" site_id="1000311">STAR Movies</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="France2.fr" site_id="1000639">FR2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="France2.fr" site_id="1000639">FR2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="France24.fr@English" site_id="1000159">France 24 English</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="France24.fr@English" site_id="1000159">France 24 English</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="France24.fr@French" site_id="1000158">France 24 French</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="France24.fr@French" site_id="1000158">France 24 French</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FunBoxUHD.nl" site_id="1000521">Funbox</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="FunBoxUHD.nl" site_id="1000521">Funbox</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Gametoon.nl" site_id="1000554">Gametoon</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Gametoon.nl" site_id="1000554">Gametoon</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="GeaTV.si" site_id="1000034">Gea TV Plus</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="GeaTV.si" site_id="1000034">Gea TV Plus</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="GOLDTV.si" site_id="1000407">GOLD TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="GOLDTV.si" site_id="1000407">GOLD TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="GolicaTV.si" site_id="2000000056">TV Zlati zvoki</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="GolicaTV.si" site_id="2000000056">TV Zlati zvoki</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Happy.rs" site_id="1000209">Happy TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Happy.rs" site_id="1000209">Happy TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Hayat.ba" site_id="1000236">Hayat</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Hayat.ba" site_id="1000236">Hayat</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HayatFolk.ba" site_id="1000284">Hayat Folk</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HayatFolk.ba" site_id="1000284">Hayat Folk</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HemaTV.ba" site_id="1000233">Hema</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HemaTV.ba" site_id="1000233">Hema</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HGTVLatinAmerica.us@Panregional" site_id="1000730">HGTV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HGTVLatinAmerica.us@Panregional" site_id="1000730">HGTV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="History2.pl" site_id="1000619">H2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="History2.pl" site_id="1000619">H2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HotPleasure.si" site_id="1000644">Hot Pleasure</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HotPleasure.si" site_id="1000644">Hot Pleasure</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HotXXL.si" site_id="1000643">Hot XXL</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HotXXL.si" site_id="1000643">Hot XXL</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HRT1.hr" site_id="105">HRT 1</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HRT1.hr" site_id="105">HRT 1</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HRT2.hr" site_id="106">HRT 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HRT2.hr" site_id="106">HRT 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HustlerHD.nl" site_id="1000306">Hustler TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HustlerHD.nl" site_id="1000306">Hustler TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HustlerTVEurope.nl" site_id="1000018">Hustler TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="HustlerTVEurope.nl" site_id="1000018">Hustler TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="JimJamEurope.uk" site_id="1000509">Jim Jam</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="JimJamEurope.uk" site_id="1000509">Jim Jam</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000285">Jugoton TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000285">Jugoton TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="kabeleins.de" site_id="61">Kabel 1</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="kabeleins.de" site_id="61">Kabel 1</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Kanal5.mk" site_id="1000268">Kanal 5</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Kanal5.mk" site_id="1000268">Kanal 5</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="KanalA.si" site_id="1000370">Kanal A</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="KanalA.si" site_id="1000370">Kanal A</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Kanali7.al" site_id="1000174">Tring 7</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Kanali7.al" site_id="1000174">Tring 7</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="KINO.si" site_id="1000366">KINO</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="KINO.si" site_id="1000366">KINO</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Klasik.hr" site_id="1000154">Klasik</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Klasik.hr" site_id="1000154">Klasik</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="KoroskaTV.si" site_id="1000474">Koroška TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="KoroskaTV.si" site_id="1000474">Koroška TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="M1.hu" site_id="1000647">M1</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="M1.hu" site_id="1000647">M1</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="M2.hu" site_id="1000050">M2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="M2.hu" site_id="1000050">M2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="M5.hu" site_id="1000650">M5</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="M5.hu" site_id="1000650">M5</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Mezzo.fr" site_id="91">Mezzo</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Mezzo.fr" site_id="91">Mezzo</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MezzoLive.fr" site_id="1000518">Mezzo Live</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MezzoLive.fr" site_id="1000518">Mezzo Live</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MilfTV.si" site_id="1000491">Milf TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MilfTV.si" site_id="1000491">Milf TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MinimaxCEE.cz" site_id="1000262">Minimax</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MinimaxCEE.cz" site_id="1000262">Minimax</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MrezaTV.hr" site_id="1000193">Mreža TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MrezaTV.hr" site_id="1000193">Mreža TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MRT1.mk" site_id="1000222">MTV 1</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MRT1.mk" site_id="1000222">MTV 1</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MRT2.mk" site_id="1000199">MTV 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MRT2.mk" site_id="1000199">MTV 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MTV00s.uk" site_id="50">MTV 00s</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MTV00s.uk" site_id="50">MTV 00s</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MTV80s.uk" site_id="51">MTV 80s</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MTV80s.uk" site_id="51">MTV 80s</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MTV90s.uk" site_id="136">MTV 90s</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MTV90s.uk" site_id="136">MTV 90s</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MTVGlobal.uk" site_id="1000496">MTV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MTVGlobal.uk" site_id="1000496">MTV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MTVHitsEurope.uk" site_id="127">MTV Hits</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MTVHitsEurope.uk" site_id="127">MTV Hits</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MTVLive.uk" site_id="1000497">MTV Live</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MTVLive.uk" site_id="1000497">MTV Live</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MuzykaPervogo.ru" site_id="1000275">Muzika Pervogo</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="MuzykaPervogo.ru" site_id="1000275">Muzika Pervogo</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="NarodnaTV.rs" site_id="1000269">Narodna TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="NarodnaTV.rs" site_id="1000269">Narodna TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="NationalGeographic.si" site_id="1000049">National Geographic</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="NationalGeographic.si" site_id="1000049">National Geographic</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="NationalGeographicWild.si" site_id="1000167">National Geographic Wild</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="NationalGeographicWild.si" site_id="1000167">National Geographic Wild</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="NetTV.si" site_id="12">Net TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="NetTV.si" site_id="12">Net TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="NetXXL.si" site_id="1000228">Net XXL</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="NetXXL.si" site_id="1000228">Net XXL</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="NHKWorldJapan.jp" site_id="1000102">NHK World</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="NHKWorldJapan.jp" site_id="1000102">NHK World</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Nickelodeon.si" site_id="1000301">Nickelodeon</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Nickelodeon.si" site_id="1000301">Nickelodeon</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="NickJr.si" site_id="1000426">Nick JR</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="NickJr.si" site_id="1000426">Nick JR</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Nova24TV2.si" site_id="1000531">Nova 24 TV 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Nova24TV2.si" site_id="1000531">Nova 24 TV 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Nova24TV.si" site_id="1000432">Nova 24 TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Nova24TV.si" site_id="1000432">Nova 24 TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="NTVICKakanj.ba" site_id="1000235">NTV IC Kakanj</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="NTVICKakanj.ba" site_id="1000235">NTV IC Kakanj</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="OBN.ba" site_id="152">OBN</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="OBN.ba" site_id="152">OBN</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="OKanal.ba" site_id="1000186">O Kanal</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="OKanal.ba" site_id="1000186">O Kanal</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ORF1.at" site_id="66">ORF1</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ORF1.at" site_id="66">ORF1</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ORF2Europe.at" site_id="67">ORF2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ORF2Europe.at" site_id="67">ORF2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="OronTV.si" site_id="1000360">TV Oron</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="OronTV.si" site_id="1000360">TV Oron</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="OTO.si" site_id="1000365">OTO</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="OTO.si" site_id="1000365">OTO</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="OTV.hr" site_id="1000190">OTV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="OTV.hr" site_id="1000190">OTV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="OTVValentino.ba" site_id="1000073">OTV Valentino</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="OTVValentino.ba" site_id="1000073">OTV Valentino</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PeTV.si" site_id="1000101">PETV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PeTV.si" site_id="1000101">PETV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkExtra.rs" site_id="1000095">Pink Extra</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkExtra.rs" site_id="1000095">Pink Extra</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkFilm.rs" site_id="1000096">Pink Film</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkFilm.rs" site_id="1000096">Pink Film</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000094">Pink Folk</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000094">Pink Folk</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkHits.rs" site_id="1000789">Pink Hits</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkHits.rs" site_id="1000789">Pink Hits</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkMusic.rs" site_id="1000097">Pink Music</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkMusic.rs" site_id="1000097">Pink Music</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkPlus.rs" site_id="107">Pink Plus</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkPlus.rs" site_id="107">Pink Plus</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkReality.rs" site_id="1000351">Pink Reality</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkReality.rs" site_id="1000351">Pink Reality</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkSI.rs" site_id="1000361">Pink SI</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkSI.rs" site_id="1000361">Pink SI</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkWorld.rs" site_id="1000352">Pink World</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkWorld.rs" site_id="1000352">Pink World</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkZabava.rs" site_id="1000353">Pink Zabava</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PinkZabava.rs" site_id="1000353">Pink Zabava</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PlanetEva.si" site_id="1000494">Planet Eva</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PlanetEva.si" site_id="1000494">Planet Eva</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PlanetTV2.si" site_id="1000485">Planet TV 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PlanetTV2.si" site_id="1000485">Planet TV 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PlanetTV.si" site_id="1000278">Planet TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PlanetTV.si" site_id="1000278">Planet TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PlayHouse.si" site_id="1000294">Play House</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="PlayHouse.si" site_id="1000294">Play House</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="POPTV.si" site_id="1000371">POP TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="POPTV.si" site_id="1000371">POP TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ProSieben.de" site_id="69">Pro 7</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ProSieben.de" site_id="69">Pro 7</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Prva.rs" site_id="1000210">Prva</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Prva.rs" site_id="1000210">Prva</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Rai1.it" site_id="1000625">RAI 1</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Rai1.it" site_id="1000625">RAI 1</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Rai2.it" site_id="1000626">RAI 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Rai2.it" site_id="1000626">RAI 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Rai3.it" site_id="1000627">RAI 3</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Rai3.it" site_id="1000627">RAI 3</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="REDxxx.si" site_id="1000490">RED xxx</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="REDxxx.si" site_id="1000490">RED xxx</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RT.ru" site_id="2000000028">RT</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RT.ru" site_id="2000000028">RT</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTK1.xk" site_id="2000000015">RTK Kosova</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTK1.xk" site_id="2000000015">RTK Kosova</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTL2.hr" site_id="1000322">RTL 2 HR</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTL2.hr" site_id="1000322">RTL 2 HR</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTL.de" site_id="70">RTL</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTL.de" site_id="70">RTL</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTL.hr" site_id="1000314">RTL Televizija</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTL.hr" site_id="1000314">RTL Televizija</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTLKetto.hu" site_id="71">RTL2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTLKetto.hu" site_id="71">RTL2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTLKockica.hr" site_id="1000355">RTL Kockica</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTLKockica.hr" site_id="1000355">RTL Kockica</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTLLiving.de" site_id="1000323">RTL Living</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTLLiving.de" site_id="1000323">RTL Living</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTLSuper.de" site_id="73">Super RTL</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTLSuper.de" site_id="73">Super RTL</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTRSTV.ba" site_id="1000185">RTRS</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTRSTV.ba" site_id="1000185">RTRS</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTS1.rs" site_id="1000211">RTS 1</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTS1.rs" site_id="1000211">RTS 1</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTS2.rs" site_id="1000212">RTS 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTS2.rs" site_id="1000212">RTS 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTSKlasika.rs" site_id="108">RTS</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTSKlasika.rs" site_id="108">RTS</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTVi.ru" site_id="1000666">RTVi</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTVi.ru" site_id="1000666">RTVi</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTVVikom.ba" site_id="1000188">Vikom TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="RTVVikom.ba" site_id="1000188">Vikom TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SAT1.de" site_id="72">SAT1</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SAT1.de" site_id="72">SAT1</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SciFi.rs" site_id="1000614">Sci Fi</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SciFi.rs" site_id="1000614">Sci Fi</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ServusTV.at" site_id="1000086">Servus TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ServusTV.at" site_id="1000086">Servus TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SexationTV.si" site_id="1000408">Sexation</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SexationTV.si" site_id="1000408">Sexation</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SIPTV.si" site_id="1000498">SIP TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SIPTV.si" site_id="1000498">SIP TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Sitel.mk" site_id="1000201">TV Sitel</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Sitel.mk" site_id="1000201">TV Sitel</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SkyNewsInternational.uk" site_id="2000000002">Sky News</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SkyNewsInternational.uk" site_id="2000000002">Sky News</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Sport1.de" site_id="60">SPORT1</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Sport1.de" site_id="60">SPORT1</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SportTV1.si" site_id="1000338">Šport TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SportTV1.si" site_id="1000338">Šport TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SportTV2.si" site_id="1000339">Šport TV 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SportTV2.si" site_id="1000339">Šport TV 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SportTV3.si" site_id="1000384">Šport TV 3</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SportTV3.si" site_id="1000384">Šport TV 3</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="StingrayFestival4K.ca" site_id="1000527">Festival</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="StingrayFestival4K.ca" site_id="1000527">Festival</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SuperONE.hu@HD" site_id="1000342">Super One</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="SuperONE.hu@HD" site_id="1000342">Super One</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="T2Info.si" site_id="1000543">T-2 Info</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="T2Info.si" site_id="1000543">T-2 Info</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Telecafe.ru" site_id="1000456">Telecafe</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Telecafe.ru" site_id="1000456">Telecafe</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TelmaTV.mk" site_id="1000226">Telma TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TelmaTV.mk" site_id="1000226">Telma TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TLCBalkan.us" site_id="1000763">TLC</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TLCBalkan.us" site_id="1000763">TLC</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TlnovelasEuropa.mx" site_id="100">TL Novelas Europe</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TlnovelasEuropa.mx" site_id="100">TL Novelas Europe</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TNTMusic.ru" site_id="1000664">TNT Music</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TNTMusic.ru" site_id="1000664">TNT Music</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TopTV.si" site_id="1000356">TOP TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TopTV.si" site_id="1000356">TOP TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ToxicTV.rs" site_id="1000684">TV Toxic</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ToxicTV.rs" site_id="1000684">TV Toxic</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TraceSportStars.fr" site_id="1000169">Trace Sport Stars</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TraceSportStars.fr" site_id="1000169">Trace Sport Stars</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TraceUrban.fr" site_id="47">Trace Urban</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TraceUrban.fr" site_id="47">Trace Urban</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TravelChannelEMEA.uk" site_id="1000168">Travel Channel</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TravelChannelEMEA.uk" site_id="1000168">Travel Channel</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000511">Travelxp 4K</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000511">Travelxp 4K</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Travelxp.in" site_id="1000500">Travelxp</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Travelxp.in" site_id="1000500">Travelxp</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TringAction.al" site_id="1000227">Tring Action</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TringAction.al" site_id="1000227">Tring Action</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TringShqip.al" site_id="1000216">Tring Shqip</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TringShqip.al" site_id="1000216">Tring Shqip</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TringTring.al" site_id="1000217">Tring Tring</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TringTring.al" site_id="1000217">Tring Tring</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TrzicTV.si" site_id="1000620">Tržič TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TrzicTV.si" site_id="1000620">Tržič TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TV3.si" site_id="1000510">TV 3</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TV3.si" site_id="1000510">TV 3</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000405">TV 8</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="1000405">TV 8</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TV24.mk" site_id="1000772">24 Vesti</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TV24.mk" site_id="1000772">24 Vesti</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVArena.si" site_id="1000529">Arena TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVArena.si" site_id="1000529">Arena TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="122">TV AS</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="" site_id="122">TV AS</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVCelje.si" site_id="1000065">TV Celje</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVCelje.si" site_id="1000065">TV Celje</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVCGMNE.me" site_id="109">MNE</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVCGMNE.me" site_id="109">MNE</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVDugaPlus.rs" site_id="1000035">TV Duga Novi Sad</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVDugaPlus.rs" site_id="1000035">TV Duga Novi Sad</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVEInternacionalEuropeAsia.es" site_id="98">TVE</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVEInternacionalEuropeAsia.es" site_id="98">TVE</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVGaleja.si" site_id="1000343">TV Galeja</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVGaleja.si" site_id="1000343">TV Galeja</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVIDEA.si" site_id="123">TV IDEA</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVIDEA.si" site_id="123">TV IDEA</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVJadran.hr" site_id="1000194">TV Jadran</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVJadran.hr" site_id="1000194">TV Jadran</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVKCN1.rs" site_id="1000078">KCN</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVKCN1.rs" site_id="1000078">KCN</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVKCN2.rs" site_id="1000103">KCN Music</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVKCN2.rs" site_id="1000103">KCN Music</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVKCN3.rs" site_id="2000000046">KCN 3</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVKCN3.rs" site_id="2000000046">KCN 3</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVKoperCapodistria.si" site_id="1000624">TV Koper</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVKoperCapodistria.si" site_id="1000624">TV Koper</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVMaribor.si" site_id="1000623">TV Maribor</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVMaribor.si" site_id="1000623">TV Maribor</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVMiklavz.si" site_id="1000727">TV Miklavž</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVMiklavz.si" site_id="1000727">TV Miklavž</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVSA.ba" site_id="1000187">TV Sarajevo</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVSA.ba" site_id="1000187">TV Sarajevo</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVSLO1.si" site_id="1000259">SLO 1</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVSLO1.si" site_id="1000259">SLO 1</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVSLO2.si" site_id="1000260">SLO 2</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVSLO2.si" site_id="1000260">SLO 2</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVSLO3.si" site_id="1000555">SLO 3</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVSLO3.si" site_id="1000555">SLO 3</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVSlonExtra.ba" site_id="1000776">TV Slon</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVSlonExtra.ba" site_id="1000776">TV Slon</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVVijesti.me" site_id="1000775">Vijesti</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="TVVijesti.me" site_id="1000775">Vijesti</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Vaskanal.si" site_id="1000002">Vaš kanal</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Vaskanal.si" site_id="1000002">Vaš kanal</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="VeseljakTV.si" site_id="13">Best TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="VeseljakTV.si" site_id="13">Best TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ViasatExplore.se" site_id="1000045">Viasat Explore</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ViasatExplore.se" site_id="1000045">Viasat Explore</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ViasatHistory.se" site_id="1000046">Viasat History</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ViasatHistory.se" site_id="1000046">Viasat History</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ViasatNature.se" site_id="1000081">Viasat Nature</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ViasatNature.se" site_id="1000081">Viasat Nature</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="vijuTV1000.ru" site_id="1000010">TV1000</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="vijuTV1000.ru" site_id="1000010">TV1000</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Vitel.si" site_id="2000000048">Vitel</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Vitel.si" site_id="2000000048">Vitel</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="VividRedHD.us" site_id="1000508">Vivid Red</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="VividRedHD.us" site_id="1000508">Vivid Red</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="VividTVEurope.uk" site_id="1000489">Vivid TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="VividTVEurope.uk" site_id="1000489">Vivid TV</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="VizionPlus.al" site_id="1000079">Tring Vizion+</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="VizionPlus.al" site_id="1000079">Tring Vizion+</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="VOX.de" site_id="78">VOX</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="VOX.de" site_id="78">VOX</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Vremya.ru" site_id="1000276">Vremya</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Vremya.ru" site_id="1000276">Vremya</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="VTV.si" site_id="2000000044">VTV Velenje</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="VTV.si" site_id="2000000044">VTV Velenje</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="vZIVOsi.si" site_id="2000000043">vŽivo.si</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="vZIVOsi.si" site_id="2000000043">vŽivo.si</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Z1.hr" site_id="151">Z1 televizija</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="Z1.hr" site_id="151">Z1 televizija</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ZDF.de" site_id="1000064">ZDF</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ZDF.de" site_id="1000064">ZDF</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ZdravaTV7.hr" site_id="1000266">Zdrava Televizija</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ZdravaTV7.hr" site_id="1000266">Zdrava Televizija</channel>
|
||||||
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ZdravaTV.si" site_id="1000616">Zdrava TV</channel>
|
<channel site="tv2go.t-2.net" lang="sl" xmltv_id="ZdravaTV.si" site_id="1000616">Zdrava TV</channel>
|
||||||
</channels>
|
</channels>
|
||||||
|
|||||||
@@ -1,68 +1,68 @@
|
|||||||
const { parser, url, request } = require('./tv2go.t-2.net.config.js')
|
const { parser, url, request } = require('./tv2go.t-2.net.config.js')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-19', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-19', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '1000259',
|
site_id: '1000259',
|
||||||
xmltv_id: 'TVSlovenija1.si'
|
xmltv_id: 'TVSlovenija1.si'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ date, channel })).toBe(
|
expect(url({ date, channel })).toBe(
|
||||||
'https://tv2go.t-2.net/Catherine/api/9.4/json/464830403846070/d79cf4dc84f2131689f426956b8d40de/client/tv/getEpg'
|
'https://tv2go.t-2.net/Catherine/api/9.4/json/464830403846070/d79cf4dc84f2131689f426956b8d40de/client/tv/getEpg'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request headers', () => {
|
it('can generate valid request headers', () => {
|
||||||
expect(request.headers).toMatchObject({
|
expect(request.headers).toMatchObject({
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid request data', () => {
|
it('can generate valid request data', () => {
|
||||||
expect(request.data({ date, channel })).toMatchObject({
|
expect(request.data({ date, channel })).toMatchObject({
|
||||||
locale: 'sl-SI',
|
locale: 'sl-SI',
|
||||||
channelId: [1000259],
|
channelId: [1000259],
|
||||||
startTime: 1637280000000,
|
startTime: 1637280000000,
|
||||||
endTime: 1637366400000,
|
endTime: 1637366400000,
|
||||||
imageInfo: [{ height: 500, width: 1100 }],
|
imageInfo: [{ height: 500, width: 1100 }],
|
||||||
includeBookmarks: false,
|
includeBookmarks: false,
|
||||||
includeShow: true
|
includeShow: true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.join(__dirname, '__data__', 'content.json'), 'utf8')
|
const content = fs.readFileSync(path.join(__dirname, '__data__', 'content.json'), 'utf8')
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-19T00:50:00.000Z',
|
start: '2021-11-19T00:50:00.000Z',
|
||||||
stop: '2021-11-19T01:15:00.000Z',
|
stop: '2021-11-19T01:15:00.000Z',
|
||||||
title: 'Dnevnik Slovencev v Italiji',
|
title: 'Dnevnik Slovencev v Italiji',
|
||||||
category: ['Informativni'],
|
category: ['Informativni'],
|
||||||
description:
|
description:
|
||||||
'Dnevnik Slovencev v Italiji je informativna oddaja, v kateri novinarji poročajo predvsem o dnevnih dogodkih med Slovenci v Italiji.',
|
'Dnevnik Slovencev v Italiji je informativna oddaja, v kateri novinarji poročajo predvsem o dnevnih dogodkih med Slovenci v Italiji.',
|
||||||
image: 'https://tv2go.t-2.net/static/media/img/epg/max_crop/EPG_IMG_2927405.jpg'
|
image: 'https://tv2go.t-2.net/static/media/img/epg/max_crop/EPG_IMG_2927405.jpg'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: 'Invalid API client identifier'
|
content: 'Invalid API client identifier'
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,99 +1,99 @@
|
|||||||
const cheerio = require('cheerio')
|
const cheerio = require('cheerio')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
const uniqBy = require('../../scripts/functions')
|
const uniqBy = require('../../scripts/functions')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'tvcesoir.fr',
|
site: 'tvcesoir.fr',
|
||||||
days: 2,
|
days: 2,
|
||||||
url: function ({ date, channel }) {
|
url: function ({ date, channel }) {
|
||||||
return `https://www.tvcesoir.fr/programme-tv/programme/chaine/${
|
return `https://www.tvcesoir.fr/programme-tv/programme/chaine/${
|
||||||
channel.site_id
|
channel.site_id
|
||||||
}.html?dt=${date.format('YYYY-MM-DD')}`
|
}.html?dt=${date.format('YYYY-MM-DD')}`
|
||||||
},
|
},
|
||||||
parser: function ({ content, date, channel }) {
|
parser: function ({ content, date, channel }) {
|
||||||
const programs = []
|
const programs = []
|
||||||
const items = parseItems(content)
|
const items = parseItems(content)
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
const prev = programs[programs.length - 1]
|
const prev = programs[programs.length - 1]
|
||||||
const $item = cheerio.load(item)
|
const $item = cheerio.load(item)
|
||||||
let start = parseStart($item, date, channel)
|
let start = parseStart($item, date, channel)
|
||||||
if (prev) {
|
if (prev) {
|
||||||
if (start.isBefore(prev.start)) {
|
if (start.isBefore(prev.start)) {
|
||||||
start = start.add(1, 'd')
|
start = start.add(1, 'd')
|
||||||
date = date.add(1, 'd')
|
date = date.add(1, 'd')
|
||||||
}
|
}
|
||||||
prev.stop = start
|
prev.stop = start
|
||||||
}
|
}
|
||||||
const stop = start.add(30, 'm')
|
const stop = start.add(30, 'm')
|
||||||
programs.push({
|
programs.push({
|
||||||
title: parseTitle($item),
|
title: parseTitle($item),
|
||||||
start,
|
start,
|
||||||
stop
|
stop
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels() {
|
async channels() {
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
|
|
||||||
const providers = ['-1', '-2', '-3', '-4', '-5']
|
const providers = ['-1', '-2', '-3', '-4', '-5']
|
||||||
|
|
||||||
const channels = []
|
const channels = []
|
||||||
for (let provider of providers) {
|
for (let provider of providers) {
|
||||||
const data = await axios
|
const data = await axios
|
||||||
.post('https://www.tvcesoir.fr/guide/schedule', null, {
|
.post('https://www.tvcesoir.fr/guide/schedule', null, {
|
||||||
params: {
|
params: {
|
||||||
provider,
|
provider,
|
||||||
region: 'France',
|
region: 'France',
|
||||||
TVperiod: 'Night',
|
TVperiod: 'Night',
|
||||||
date: dayjs().format('YYYY-MM-DD'),
|
date: dayjs().format('YYYY-MM-DD'),
|
||||||
st: 0,
|
st: 0,
|
||||||
u_time: 2155,
|
u_time: 2155,
|
||||||
is_mobile: 1
|
is_mobile: 1
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
|
|
||||||
const $ = cheerio.load(data)
|
const $ = cheerio.load(data)
|
||||||
$('.channelname').each((i, el) => {
|
$('.channelname').each((i, el) => {
|
||||||
const name = $(el).find('center > a:eq(1)').text()
|
const name = $(el).find('center > a:eq(1)').text()
|
||||||
const url = $(el).find('center > a:eq(1)').attr('href')
|
const url = $(el).find('center > a:eq(1)').attr('href')
|
||||||
const [, number, slug] = url.match(/\/(\d+)\/(.*)\.html$/)
|
const [, number, slug] = url.match(/\/(\d+)\/(.*)\.html$/)
|
||||||
|
|
||||||
channels.push({
|
channels.push({
|
||||||
lang: 'fr',
|
lang: 'fr',
|
||||||
name,
|
name,
|
||||||
site_id: `${number}/${slug}`
|
site_id: `${number}/${slug}`
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return uniqBy(channels, x => x.site_id)
|
return uniqBy(channels, x => x.site_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStart($item, date) {
|
function parseStart($item, date) {
|
||||||
const timeString = $item('td:eq(0)').text().trim()
|
const timeString = $item('td:eq(0)').text().trim()
|
||||||
const dateString = `${date.format('YYYY-MM-DD')} ${timeString}`
|
const dateString = `${date.format('YYYY-MM-DD')} ${timeString}`
|
||||||
|
|
||||||
return dayjs.tz(dateString, 'YYYY-MM-DD HH[h]mm', 'Europe/Rome')
|
return dayjs.tz(dateString, 'YYYY-MM-DD HH[h]mm', 'Europe/Rome')
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTitle($item) {
|
function parseTitle($item) {
|
||||||
return $item('td:eq(1)').text().trim()
|
return $item('td:eq(1)').text().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(content) {
|
function parseItems(content) {
|
||||||
const $ = cheerio.load(content)
|
const $ = cheerio.load(content)
|
||||||
|
|
||||||
return $('table.table > tbody > tr').toArray()
|
return $('table.table > tbody > tr').toArray()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,50 +1,50 @@
|
|||||||
const { parser, url } = require('./tvcesoir.fr.config.js')
|
const { parser, url } = require('./tvcesoir.fr.config.js')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2023-11-24', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2023-11-24', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '847049/tf-1',
|
site_id: '847049/tf-1',
|
||||||
xmltv_id: 'TF1.fr'
|
xmltv_id: 'TF1.fr'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://www.tvcesoir.fr/programme-tv/programme/chaine/847049/tf-1.html?dt=2023-11-24'
|
'https://www.tvcesoir.fr/programme-tv/programme/chaine/847049/tf-1.html?dt=2023-11-24'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'))
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'))
|
||||||
const results = parser({ content, channel, date }).map(p => {
|
const results = parser({ content, channel, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(results[0]).toMatchObject({
|
expect(results[0]).toMatchObject({
|
||||||
start: '2023-11-24T01:00:00.000Z',
|
start: '2023-11-24T01:00:00.000Z',
|
||||||
stop: '2023-11-24T01:10:00.000Z',
|
stop: '2023-11-24T01:10:00.000Z',
|
||||||
title: "Tirage de l'Euro Millions"
|
title: "Tirage de l'Euro Millions"
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(results[26]).toMatchObject({
|
expect(results[26]).toMatchObject({
|
||||||
start: '2023-11-24T22:45:00.000Z',
|
start: '2023-11-24T22:45:00.000Z',
|
||||||
stop: '2023-11-24T23:15:00.000Z',
|
stop: '2023-11-24T23:15:00.000Z',
|
||||||
title: 'Juge Arthur'
|
title: 'Juge Arthur'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, './__data__/no_content.html'), 'utf8')
|
content: fs.readFileSync(path.resolve(__dirname, './__data__/no_content.html'), 'utf8')
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,52 +1,52 @@
|
|||||||
const { parser, url } = require('./tvcubana.icrt.cu.config.js')
|
const { parser, url } = require('./tvcubana.icrt.cu.config.js')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-22', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-22', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: 'cv',
|
site_id: 'cv',
|
||||||
xmltv_id: 'CubavisionNacional.cu'
|
xmltv_id: 'CubavisionNacional.cu'
|
||||||
}
|
}
|
||||||
let content = fs.readFileSync(path.resolve(__dirname, './__data__/content.json'), {encoding: 'utf8'})
|
let content = fs.readFileSync(path.resolve(__dirname, './__data__/content.json'), {encoding: 'utf8'})
|
||||||
// in the specific case of this site, the unicode escape sequences are double-escaped
|
// in the specific case of this site, the unicode escape sequences are double-escaped
|
||||||
content = content.replace(/\\\\u([0-9a-fA-F]{4})/g, '\\u$1')
|
content = content.replace(/\\\\u([0-9a-fA-F]{4})/g, '\\u$1')
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe('https://www.tvcubana.icrt.cu/cartv/cv/lunes.php')
|
expect(url({ channel, date })).toBe('https://www.tvcubana.icrt.cu/cartv/cv/lunes.php')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate valid url for next day', () => {
|
it('can generate valid url for next day', () => {
|
||||||
expect(url({ channel, date: date.add(2, 'd') })).toBe(
|
expect(url({ channel, date: date.add(2, 'd') })).toBe(
|
||||||
'https://www.tvcubana.icrt.cu/cartv/cv/miercoles.php'
|
'https://www.tvcubana.icrt.cu/cartv/cv/miercoles.php'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const result = parser({ date, channel, content }).map(p => {
|
const result = parser({ date, channel, content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-22T05:40:00.000Z',
|
start: '2021-11-22T05:40:00.000Z',
|
||||||
stop: '2021-11-22T05:50:00.000Z',
|
stop: '2021-11-22T05:50:00.000Z',
|
||||||
title: 'CARIBE NOTICIAS',
|
title: 'CARIBE NOTICIAS',
|
||||||
description: 'EMISIÓN DE CIERRE.'
|
description: 'EMISIÓN DE CIERRE.'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, './__data__/no_content.html'), 'utf8')
|
content: fs.readFileSync(path.resolve(__dirname, './__data__/no_content.html'), 'utf8')
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
const { parser, url } = require('./tvguide.myjcom.jp.config.js')
|
const { parser, url } = require('./tvguide.myjcom.jp.config.js')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2022-01-14', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-01-14', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: '120_200_4',
|
site_id: '120_200_4',
|
||||||
name: 'Star Channel 1',
|
name: 'Star Channel 1',
|
||||||
xmltv_id: 'StarChannel1.jp'
|
xmltv_id: 'StarChannel1.jp'
|
||||||
}
|
}
|
||||||
const content = fs.readFileSync(path.resolve(__dirname, './__data__/content.json'), 'utf8')
|
const content = fs.readFileSync(path.resolve(__dirname, './__data__/content.json'), 'utf8')
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
const result = url({ date, channel })
|
const result = url({ date, channel })
|
||||||
expect(result).toBe('https://tvguide.myjcom.jp/api/getEpgInfo/?channels=120_200_4_20220114')
|
expect(result).toBe('https://tvguide.myjcom.jp/api/getEpgInfo/?channels=120_200_4_20220114')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const result = parser({ date, channel, content }).map(p => {
|
const result = parser({ date, channel, content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2022-01-13T20:00:00.000Z',
|
start: '2022-01-13T20:00:00.000Z',
|
||||||
stop: '2022-01-13T21:00:00.000Z',
|
stop: '2022-01-13T21:00:00.000Z',
|
||||||
title: '[5.1]フードロア:タマリンド',
|
title: '[5.1]フードロア:タマリンド',
|
||||||
description:
|
description:
|
||||||
'HBO(R)アジア製作。日本の齊藤工などアジアの監督が、各国の食をテーマに描いたアンソロジーシリーズ。(全8話)(19年 シンガポール 56分)',
|
'HBO(R)アジア製作。日本の齊藤工などアジアの監督が、各国の食をテーマに描いたアンソロジーシリーズ。(全8話)(19年 シンガポール 56分)',
|
||||||
image:
|
image:
|
||||||
'https://tvguide.myjcom.jp/monomedia/si/2022/20220114/7305523/image/7743d17b655b8d2274ca58b74f2f095c.jpg',
|
'https://tvguide.myjcom.jp/monomedia/si/2022/20220114/7305523/image/7743d17b655b8d2274ca58b74f2f095c.jpg',
|
||||||
category: 'ドラマ'
|
category: 'ドラマ'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: fs.readFileSync(path.resolve(__dirname, './__data__/no_content.json'), 'utf8')
|
content: fs.readFileSync(path.resolve(__dirname, './__data__/no_content.json'), 'utf8')
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,97 +1,97 @@
|
|||||||
const cheerio = require('cheerio')
|
const cheerio = require('cheerio')
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const { DateTime } = require('luxon')
|
const { DateTime } = require('luxon')
|
||||||
const { uniqBy } = require('../../scripts/functions')
|
const { uniqBy } = require('../../scripts/functions')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'tvhebdo.com',
|
site: 'tvhebdo.com',
|
||||||
days: 2,
|
days: 2,
|
||||||
url: function ({ channel, date }) {
|
url: function ({ channel, date }) {
|
||||||
return `https://www.tvhebdo.com/horaire-tele/${channel.site_id}/date/${date.format(
|
return `https://www.tvhebdo.com/horaire-tele/${channel.site_id}/date/${date.format(
|
||||||
'YYYY-MM-DD'
|
'YYYY-MM-DD'
|
||||||
)}`
|
)}`
|
||||||
},
|
},
|
||||||
parser: function ({ content, date }) {
|
parser: function ({ content, date }) {
|
||||||
let programs = []
|
let programs = []
|
||||||
const items = parseItems(content)
|
const items = parseItems(content)
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
const prev = programs[programs.length - 1]
|
const prev = programs[programs.length - 1]
|
||||||
const $item = cheerio.load(item)
|
const $item = cheerio.load(item)
|
||||||
let start = parseStart($item, date)
|
let start = parseStart($item, date)
|
||||||
if (prev) {
|
if (prev) {
|
||||||
if (start < prev.start) {
|
if (start < prev.start) {
|
||||||
start = start.plus({ days: 1 })
|
start = start.plus({ days: 1 })
|
||||||
}
|
}
|
||||||
prev.stop = start
|
prev.stop = start
|
||||||
}
|
}
|
||||||
let stop = start.plus({ minutes: 30 })
|
let stop = start.plus({ minutes: 30 })
|
||||||
programs.push({
|
programs.push({
|
||||||
title: parseTitle($item),
|
title: parseTitle($item),
|
||||||
start,
|
start,
|
||||||
stop
|
stop
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels() {
|
async channels() {
|
||||||
|
|
||||||
let items = []
|
let items = []
|
||||||
const offsets = [
|
const offsets = [
|
||||||
0, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260, 280, 300, 320, 340, 360
|
0, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260, 280, 300, 320, 340, 360
|
||||||
]
|
]
|
||||||
for (let offset of offsets) {
|
for (let offset of offsets) {
|
||||||
const url = `https://www.tvhebdo.com/horaire/gr/offset/${offset}/gr_id/0/date/2022-05-11/time/12:00:00`
|
const url = `https://www.tvhebdo.com/horaire/gr/offset/${offset}/gr_id/0/date/2022-05-11/time/12:00:00`
|
||||||
console.log(url)
|
console.log(url)
|
||||||
const html = await axios
|
const html = await axios
|
||||||
.get(url, {
|
.get(url, {
|
||||||
headers: {
|
headers: {
|
||||||
Cookie:
|
Cookie:
|
||||||
'distributeur=8004264; __utmz=222163677.1652094266.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _gcl_au=1.1.656635701.1652094273; tvh=3c2kaml9u14m83v91bg4dqgaf3; __utmc=222163677; IR_gbd=tvhebdo.com; IR_MPI=cf76b363-cf87-11ec-93f5-13daf79f8f76%7C1652367602625; __utma=222163677.2064368965.1652094266.1652281202.1652281479.3; __utmt=1; IR_MPS=1652284935955%7C1652284314367; _uetsid=0d8e2e60d13b11ec850db551304ae9e7; _uetvid=80456fa0b26e11ec9bf94951ce79b5f8; __utmb=222163677.19.9.1652284953979; __atuvc=30%7C19; __atuvs=627bdb98682bc242006'
|
'distributeur=8004264; __utmz=222163677.1652094266.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _gcl_au=1.1.656635701.1652094273; tvh=3c2kaml9u14m83v91bg4dqgaf3; __utmc=222163677; IR_gbd=tvhebdo.com; IR_MPI=cf76b363-cf87-11ec-93f5-13daf79f8f76%7C1652367602625; __utma=222163677.2064368965.1652094266.1652281202.1652281479.3; __utmt=1; IR_MPS=1652284935955%7C1652284314367; _uetsid=0d8e2e60d13b11ec850db551304ae9e7; _uetvid=80456fa0b26e11ec9bf94951ce79b5f8; __utmb=222163677.19.9.1652284953979; __atuvc=30%7C19; __atuvs=627bdb98682bc242006'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
const $ = cheerio.load(html)
|
const $ = cheerio.load(html)
|
||||||
const rows = $('table.gr_row').toArray()
|
const rows = $('table.gr_row').toArray()
|
||||||
items = items.concat(rows)
|
items = items.concat(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
let channels = []
|
let channels = []
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
const $item = cheerio.load(item)
|
const $item = cheerio.load(item)
|
||||||
const name = $item('.gr_row_head > div > a.gr_row_head_logo.link_to_station > img').attr(
|
const name = $item('.gr_row_head > div > a.gr_row_head_logo.link_to_station > img').attr(
|
||||||
'alt'
|
'alt'
|
||||||
)
|
)
|
||||||
const url = $item('.gr_row_head > div > div.gr_row_head_poste > a').attr('href')
|
const url = $item('.gr_row_head > div > div.gr_row_head_poste > a').attr('href')
|
||||||
const [, site_id] = url.match(/horaire-tele\/(.*)/) || [null, null]
|
const [, site_id] = url.match(/horaire-tele\/(.*)/) || [null, null]
|
||||||
channels.push({
|
channels.push({
|
||||||
lang: 'fr',
|
lang: 'fr',
|
||||||
site_id,
|
site_id,
|
||||||
name
|
name
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return uniqBy(channels, x => x.site_id)
|
return uniqBy(channels, x => x.site_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTitle($item) {
|
function parseTitle($item) {
|
||||||
return $item('.titre').first().text().trim()
|
return $item('.titre').first().text().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStart($item, date) {
|
function parseStart($item, date) {
|
||||||
const time = $item('.heure').text()
|
const time = $item('.heure').text()
|
||||||
|
|
||||||
return DateTime.fromFormat(`${date.format('YYYY-MM-DD')} ${time}`, 'yyyy-MM-dd HH:mm', {
|
return DateTime.fromFormat(`${date.format('YYYY-MM-DD')} ${time}`, 'yyyy-MM-dd HH:mm', {
|
||||||
zone: 'America/Toronto'
|
zone: 'America/Toronto'
|
||||||
}).toUTC()
|
}).toUTC()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(content) {
|
function parseItems(content) {
|
||||||
const $ = cheerio.load(content)
|
const $ = cheerio.load(content)
|
||||||
|
|
||||||
return $(
|
return $(
|
||||||
'#main_container > div.liste_container > table > tbody > tr[class^=liste_row_style_]'
|
'#main_container > div.liste_container > table > tbody > tr[class^=liste_row_style_]'
|
||||||
).toArray()
|
).toArray()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +1,45 @@
|
|||||||
const { parser, url } = require('./tvheute.at.config.js')
|
const { parser, url } = require('./tvheute.at.config.js')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
const { readFileSync } = require('fs')
|
const { readFileSync } = require('fs')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
const date = dayjs.utc('2021-11-08', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2021-11-08', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = { site_id: 'orf1', xmltv_id: 'ORF1.at' }
|
const channel = { site_id: 'orf1', xmltv_id: 'ORF1.at' }
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url({ channel, date })).toBe(
|
expect(url({ channel, date })).toBe(
|
||||||
'https://tvheute.at/part/channel-shows/partial/orf1/08-11-2021'
|
'https://tvheute.at/part/channel-shows/partial/orf1/08-11-2021'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
expect(parser({ date, channel, content: readFileSync(path.resolve(__dirname, './__data__/content.html'), 'utf8') })).toMatchObject([
|
expect(parser({ date, channel, content: readFileSync(path.resolve(__dirname, './__data__/content.html'), 'utf8') })).toMatchObject([
|
||||||
{
|
{
|
||||||
start: '2021-11-08T05:00:00.000Z',
|
start: '2021-11-08T05:00:00.000Z',
|
||||||
stop: '2021-11-08T05:10:00.000Z',
|
stop: '2021-11-08T05:10:00.000Z',
|
||||||
title: 'Monchhichi (Wh.)',
|
title: 'Monchhichi (Wh.)',
|
||||||
category: 'Kids',
|
category: 'Kids',
|
||||||
description:
|
description:
|
||||||
'Roger hat sich Ärger mit Dr. Bellows eingehandelt, der ihn für einen Monat strafversetzen möchte. Einmal mehr hadert Roger mit dem Schicksal, dass er keinen eigenen Flaschengeist besitzt, der ihm aus der Patsche helfen kann. Jeannie schlägt vor, ihm Cousine Marilla zu schicken. Doch Tony ist strikt dagegen. Als ein Zaubererpärchen im exotischen Bühnenoutfit für die Zeit von Rogers Abwesenheit sein Apartment in Untermiete bezieht, glaubt Roger, Jeannie habe ihm ihre Verwandte doch noch gesandt.',
|
'Roger hat sich Ärger mit Dr. Bellows eingehandelt, der ihn für einen Monat strafversetzen möchte. Einmal mehr hadert Roger mit dem Schicksal, dass er keinen eigenen Flaschengeist besitzt, der ihm aus der Patsche helfen kann. Jeannie schlägt vor, ihm Cousine Marilla zu schicken. Doch Tony ist strikt dagegen. Als ein Zaubererpärchen im exotischen Bühnenoutfit für die Zeit von Rogers Abwesenheit sein Apartment in Untermiete bezieht, glaubt Roger, Jeannie habe ihm ihre Verwandte doch noch gesandt.',
|
||||||
image: 'https://tvheute.at/images/orf1/monchhichi_kids--1895216560-00.jpg'
|
image: 'https://tvheute.at/images/orf1/monchhichi_kids--1895216560-00.jpg'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: '2021-11-08T17:00:00.000Z',
|
start: '2021-11-08T17:00:00.000Z',
|
||||||
stop: '2021-11-08T17:10:00.000Z',
|
stop: '2021-11-08T17:10:00.000Z',
|
||||||
title: 'ZIB 18'
|
title: 'ZIB 18'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: readFileSync(path.resolve(__dirname, './__data__/no_content.html'), 'utf8')
|
content: readFileSync(path.resolve(__dirname, './__data__/no_content.html'), 'utf8')
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user