Files
epg/sites/www.magenta.tv/www.magenta.tv.test.js
T

263 lines
7.5 KiB
JavaScript
Raw Normal View History

2026-05-13 23:20:54 +02:00
const fs = require('fs')
const path = require('path')
const crypto = require('crypto')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const customParseFormat = require('dayjs/plugin/customParseFormat')
dayjs.extend(customParseFormat)
dayjs.extend(utc)
jest.mock('axios')
const fixture = JSON.parse(fs.readFileSync(path.resolve(__dirname, '__data__/content.json'), 'utf8'))
const date = dayjs.utc('2026-05-11', 'YYYY-MM-DD').startOf('d')
const channel = {
site_id: '262270504164',
xmltv_id: 'Sat1.de'
}
beforeEach(() => {
jest.resetModules()
jest.restoreAllMocks()
})
function loadConfig() {
const axios = require('axios')
const config = require('./www.magenta.tv.config.js')
return {
axios,
...config
}
}
it('can generate valid url', async () => {
const { axios, url } = loadConfig()
jest
.spyOn(crypto, 'randomUUID')
.mockReturnValueOnce('device-id')
.mockReturnValueOnce('session-id')
.mockReturnValueOnce('manifest-call-id')
.mockReturnValueOnce('schedule-call-id')
axios.get.mockImplementation(url => {
if (url === 'https://prod.dcm.telekom-dienste.de/v1/settings/web-mtv/manifest') {
return Promise.resolve({ data: fixture.manifest })
}
return Promise.reject(new Error('unexpected request'))
})
const result = await url({ channel, date })
expect(result).toBe(
'https://feed.entertainment.tv.theplatform.eu/f/mdeprod/mdeprod-all-channel-schedules?byId=262270504164&byListingTime=2026-05-11T00%3A00%3A00.000Z%7E2026-05-12T00%3A00%3A00.000Z&byLocationId=http%3A%2F%2Fdata.entertainment.tv.theplatform.eu%2Fentertainment%2Fdata%2FLocation%2F245991976396&cid=session-id%3A%3Aschedule-call-id'
)
expect(axios.get).toHaveBeenCalledWith(
'https://prod.dcm.telekom-dienste.de/v1/settings/web-mtv/manifest',
expect.objectContaining({
headers: {
'X-DT-Call-ID': 'manifest-call-id',
'X-DT-Session-ID': 'session-id'
},
params: expect.objectContaining({
deviceId: 'device-id',
sid: 'session-id',
deviceModel: 'WEB2_FTV',
portal: 'release',
subscriberType: 'FTV_FREEMIUM_DT',
$redirect: false
})
})
)
})
it('can map a channel feed entry', () => {
const { axios, channels } = loadConfig()
axios.get.mockImplementation((url) => {
if (url === 'https://prod.dcm.telekom-dienste.de/v1/settings/web-mtv/manifest') {
return Promise.resolve({ data: fixture.manifest })
}
if (new URL(url).searchParams.get('range') === '1-100') {
return Promise.resolve({ data: fixture.channels })
}
return Promise.resolve({ data: { entries: [] } })
})
return channels().then(result => {
expect(result[0]).toMatchObject({
lang: 'de',
site_id: '259549736360',
name: 'Das Erste'
})
})
})
it('can ignore radio channels', async () => {
const { axios, channels } = loadConfig()
axios.get.mockImplementation((url) => {
if (url === 'https://prod.dcm.telekom-dienste.de/v1/settings/web-mtv/manifest') {
return Promise.resolve({ data: fixture.manifest })
}
if (new URL(url).searchParams.get('range') === '1-100') {
return Promise.resolve({ data: fixture.channels })
}
return Promise.resolve({ data: { entries: [] } })
})
const result = await channels()
expect(result).toHaveLength(1)
expect(result[0].name).toBe('Das Erste')
})
it('can paginate channels', async () => {
const { axios, channels } = loadConfig()
jest
.spyOn(crypto, 'randomUUID')
.mockReturnValueOnce('device-id')
.mockReturnValueOnce('session-id')
.mockReturnValueOnce('manifest-call-id')
.mockImplementation(() => 'call-id')
const page1 = {
entries: Array.from({ length: 100 }, (_, index) => ({
id: `http://data.entertainment.tv.theplatform.eu/entertainment/data/ChannelSchedule/${1000 + index}`,
title: `Channel ${index + 1}`,
stations: {
[`station-${index}`]: {
title: `Channel ${index + 1}`,
thumbnails: {
stationLogo: {
url: `https://example.com/${index + 1}.png`
}
}
}
},
'dt$isRadio': false
}))
}
const page2 = {
entries: [
{
id: 'http://data.entertainment.tv.theplatform.eu/entertainment/data/ChannelSchedule/2001',
title: 'Channel 101',
stations: {
'station-101': {
title: 'Channel 101',
thumbnails: {
stationLogo: {
url: 'https://example.com/101.png'
}
}
}
},
'dt$isRadio': false
}
]
}
axios.get.mockImplementation((url, options) => {
if (url === 'https://prod.dcm.telekom-dienste.de/v1/settings/web-mtv/manifest') {
return Promise.resolve({ data: fixture.manifest })
}
const range = new URL(url).searchParams.get('range')
if (range === '1-100') return Promise.resolve({ data: page1 })
if (range === '101-200') return Promise.resolve({ data: page2 })
return Promise.reject(new Error(`unexpected request ${url} ${JSON.stringify(options)}`))
})
const result = await channels()
expect(result).toHaveLength(101)
expect(result[0]).toMatchObject({
site_id: '1000',
name: 'Channel 1'
})
expect(result[100]).toMatchObject({
site_id: '2001',
name: 'Channel 101'
})
})
it('can parse response', async () => {
const { parser } = loadConfig()
const result = await parser({ content: JSON.stringify(fixture.schedule), channel })
const serialized = result.map(program => ({
...program,
start: program.start.toJSON(),
stop: program.stop.toJSON()
}))
expect(serialized).toMatchObject([
{
start: '2026-05-11T00:10:00.000Z',
stop: '2026-05-11T01:07:00.000Z',
title: 'FBI: Special Crime Unit',
sub_title: 'Aufstand',
description:
'Eine gigantische Explosion in Brooklyn ruft das FBI auf den Plan. Hinweise deuten auf eine vorsätzliche Fremdeinwirkung hin.',
category: ['200-Serie', 'Krimi', 'Action', 'Thriller'],
season: 8,
episode: 7,
country: 'US',
date: '2025'
}
])
})
it('can handle empty guide', async () => {
const { parser } = loadConfig()
const result = await parser({
channel,
content: '{"entries":[{"id":"http://data.entertainment.tv.theplatform.eu/entertainment/data/ChannelSchedule/262270504164","listings":[]}]}'
})
expect(result).toMatchObject([])
})
it('can handle listings without program', async () => {
const { parser } = loadConfig()
const result = await parser({
channel,
content:
'{"entries":[{"id":"http://data.entertainment.tv.theplatform.eu/entertainment/data/ChannelSchedule/262270504164","listings":[{"startTime":1,"endTime":2}]}]}'
})
expect(result).toMatchObject([])
})
it('can build a UTC schedule window', async () => {
const { axios, url } = loadConfig()
jest
.spyOn(crypto, 'randomUUID')
.mockReturnValueOnce('device-id')
.mockReturnValueOnce('session-id')
.mockReturnValueOnce('manifest-call-id')
.mockReturnValueOnce('schedule-call-id')
axios.get.mockResolvedValue({ data: fixture.manifest })
const result = await url({
channel,
date
})
expect(new URL(result).searchParams.get('byListingTime')).toBe(
'2026-05-11T00:00:00.000Z~2026-05-12T00:00:00.000Z'
)
})