mirror of
https://github.com/iptv-org/epg.git
synced 2026-07-23 19:47:44 +02:00
Merge pull request #3203 from luuvasara/fix/dna-fi-grabber
Fix dna.fi guide: full-day results, hard errors on bad responses
This commit is contained in:
@@ -1,20 +1,35 @@
|
||||
const axios = require('axios')
|
||||
const dayjs = require('dayjs')
|
||||
const utc = require('dayjs/plugin/utc')
|
||||
const timezone = require('dayjs/plugin/timezone')
|
||||
|
||||
dayjs.extend(utc)
|
||||
dayjs.extend(timezone)
|
||||
|
||||
// The API groups programmes into broadcast days that start at 04:00
|
||||
// Europe/Helsinki. Requesting exactly that window (instead of a fixed
|
||||
// UTC+2 offset) keeps the interval aligned year-round; a misaligned
|
||||
// interval gets answered with a "303 See Other" to a widened window.
|
||||
// Without an explicit `limit` the API paginates 20 items per response,
|
||||
// so only the first ~20 programmes of each day would be returned.
|
||||
const dayStart = date => dayjs.tz(date.format('YYYY-MM-DD'), 'Europe/Helsinki').add(4, 'h')
|
||||
|
||||
module.exports = {
|
||||
site: 'dna.fi',
|
||||
days: 2,
|
||||
url({ date, channel }) {
|
||||
const beginTimestamp = date.add(2, 'h').valueOf()
|
||||
const endTimestamp = date.add(1, 'd').add(2, 'h').subtract(1, 's').valueOf()
|
||||
const beginTimestamp = dayStart(date).valueOf()
|
||||
const endTimestamp = dayStart(date.add(1, 'd')).subtract(1, 's').valueOf()
|
||||
|
||||
return `https://mts-pro-envoy-vip.dna.fi/hbx/api/pub/xrtv/g/media?q=channel:${channel.site_id}&q=profile:pr&q=start-interval:${beginTimestamp}/${endTimestamp}`
|
||||
return `https://mts-pro-envoy-vip.dna.fi/hbx/api/pub/xrtv/g/media?q=channel:${channel.site_id}&q=profile:pr&q=start-interval:${beginTimestamp}/${endTimestamp}&limit=1000`
|
||||
},
|
||||
parser({ content, date }) {
|
||||
parser({ content }) {
|
||||
let programs = []
|
||||
let items = parseItems(content, date)
|
||||
let items = parseItems(content)
|
||||
items.forEach(item => {
|
||||
const data = item?._embedded?.['xrtv:meta']?.data
|
||||
if (!data?.start) return
|
||||
|
||||
programs.push({
|
||||
title: data?.title,
|
||||
subtitle: data?.episode_title,
|
||||
@@ -27,8 +42,8 @@ module.exports = {
|
||||
images: parseImages(item),
|
||||
directors: parseCast(data, 'director'),
|
||||
actors: parseCast(data, 'actors'),
|
||||
start: dayjs(data?.start),
|
||||
stop: dayjs(data?.end)
|
||||
start: dayjs(data.start),
|
||||
stop: dayjs(data.end)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -80,20 +95,17 @@ function parseImages(item) {
|
||||
return Array.isArray(images) ? images.map(image => image.src) : []
|
||||
}
|
||||
|
||||
function parseItems(content, date) {
|
||||
try {
|
||||
const data = JSON.parse(content)
|
||||
let items = data?._embedded?.['xrtv:media-item']
|
||||
items = Array.isArray(items) ? items : []
|
||||
items = items.filter(item => {
|
||||
const start = item?._embedded?.['xrtv:meta']?.data?.start
|
||||
if (!start) return false
|
||||
function parseItems(content) {
|
||||
if (!content) return []
|
||||
|
||||
return date.isSame(dayjs(start), 'day')
|
||||
})
|
||||
|
||||
return items
|
||||
} catch {
|
||||
return []
|
||||
// Let malformed content (e.g. an HTML error page) throw, so the grab
|
||||
// is reported as an error instead of silently producing no programmes.
|
||||
const data = JSON.parse(content)
|
||||
if (!data?.page) {
|
||||
throw new Error('Unexpected response structure')
|
||||
}
|
||||
|
||||
const items = data?._embedded?.['xrtv:media-item']
|
||||
|
||||
return Array.isArray(items) ? items : []
|
||||
}
|
||||
|
||||
@@ -15,7 +15,14 @@ const channel = {
|
||||
|
||||
it('can generate valid url', async () => {
|
||||
expect(url({ date, channel })).toBe(
|
||||
'https://mts-pro-envoy-vip.dna.fi/hbx/api/pub/xrtv/g/media?q=channel:ch-216356&q=profile:pr&q=start-interval:1736906400000/1736992799000'
|
||||
'https://mts-pro-envoy-vip.dna.fi/hbx/api/pub/xrtv/g/media?q=channel:ch-216356&q=profile:pr&q=start-interval:1736906400000/1736992799000&limit=1000'
|
||||
)
|
||||
})
|
||||
|
||||
it('can generate valid url during daylight saving time', async () => {
|
||||
const dstDate = dayjs.utc('2025-07-15', 'YYYY-MM-DD').startOf('d')
|
||||
expect(url({ date: dstDate, channel })).toBe(
|
||||
'https://mts-pro-envoy-vip.dna.fi/hbx/api/pub/xrtv/g/media?q=channel:ch-216356&q=profile:pr&q=start-interval:1752541200000/1752627599000&limit=1000'
|
||||
)
|
||||
})
|
||||
|
||||
@@ -136,3 +143,10 @@ it('can handle empty guide', () => {
|
||||
|
||||
expect(results).toMatchObject([])
|
||||
})
|
||||
|
||||
it('throws on unexpected response', () => {
|
||||
expect(() => parser({ date, content: '<html>Error</html>' })).toThrow()
|
||||
expect(() => parser({ date, content: '{"message":"Internal Server Error"}' })).toThrow(
|
||||
'Unexpected response structure'
|
||||
)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user