mirror of
https://github.com/iptv-org/epg
synced 2026-09-06 12:00:09 -04:00
220 lines
6.1 KiB
JavaScript
220 lines
6.1 KiB
JavaScript
const axios = require('axios')
|
|
const dayjs = require('dayjs')
|
|
const utc = require('dayjs/plugin/utc')
|
|
|
|
dayjs.extend(utc)
|
|
|
|
const API_URL = 'https://rail-router.discovery.indazn.com/eu/v10/Rail'
|
|
const IMAGE_API_URL = 'https://image.discovery.indazn.com/eu/v3/linear-channel/none'
|
|
const DEFAULT_COUNTRY = 'de'
|
|
const SUPPORTED_COUNTRIES =
|
|
'ad ae af ag ai al am ao aq ar at au aw ax az ba bb bd be bf bg bh bi bj bl bm bn bo bq br bs bt bv bw bz ca cc cd cf cg ch ci ck cl cm co cr cv cw cx cy cz de dj dk dm do dz ec ee eg eh er es et fi fj fk fm fo fr ga gb gd ge gf gh gl gm gn gp gq gr gs gt gu gw gy hk hm hn hr ht hu id ie il in io iq is it jm jo jp ke kg kh ki km kn kr kw ky kz la lb lc li lk lr ls lt lu lv ly ma mc md me mf mg mh mk ml mm mn mo mp mq mr ms mt mu mv mw mx my mz na nc ne nf ng ni nl no np nr nu nz om pa pe pf pg ph pk pl pm pn ps pt pw py qa re ro rs rw sa sb sc sd se sg sh si sj sk sl sn so sr ss st sv sx sz tc td tf tg th tj tk tl tm tn to tr tt tv tw tz ua ug um us uy uz vc ve vg vi vn vu wf ws xk ye yt za zm zw'.split(
|
|
' '
|
|
)
|
|
const COUNTRY_LANGUAGES = {
|
|
ar: 'es',
|
|
at: 'de',
|
|
be: 'fr',
|
|
bo: 'es',
|
|
br: 'pt',
|
|
ch: 'de',
|
|
cl: 'es',
|
|
co: 'es',
|
|
cr: 'es',
|
|
de: 'de',
|
|
do: 'es',
|
|
ec: 'es',
|
|
es: 'es',
|
|
fr: 'fr',
|
|
gt: 'es',
|
|
hn: 'es',
|
|
it: 'it',
|
|
jp: 'ja',
|
|
li: 'de',
|
|
lu: 'fr',
|
|
mc: 'fr',
|
|
mx: 'es',
|
|
ni: 'es',
|
|
nl: 'nl',
|
|
pa: 'es',
|
|
pe: 'es',
|
|
pt: 'pt',
|
|
py: 'es',
|
|
sv: 'es',
|
|
tw: 'zh',
|
|
uy: 'es',
|
|
ve: 'es'
|
|
}
|
|
const PREFERRED_COUNTRIES = {
|
|
de: 'de',
|
|
en: 'gb',
|
|
es: 'es',
|
|
fr: 'fr',
|
|
it: 'it',
|
|
ja: 'jp',
|
|
nl: 'nl',
|
|
pt: 'pt',
|
|
zh: 'tw'
|
|
}
|
|
const HEADERS = {
|
|
Accept: 'application/json, text/plain, */*',
|
|
Referer: 'https://www.dazn.com/'
|
|
}
|
|
|
|
module.exports = {
|
|
site: 'dazn.com',
|
|
days: 3,
|
|
url({ channel }) {
|
|
const { country } = parseSiteId(channel.site_id)
|
|
|
|
return createApiUrl(country, channel.lang || getLanguage(country))
|
|
},
|
|
request: {
|
|
headers: HEADERS,
|
|
cache: {
|
|
ttl: 5 * 60 * 1000
|
|
}
|
|
},
|
|
parser({ content, channel, date }) {
|
|
const data = parseData(content)
|
|
const tiles = Array.isArray(data?.Tiles) ? data.Tiles : []
|
|
const { assetId } = parseSiteId(channel.site_id)
|
|
const tile = tiles.find(item => item.AssetId === assetId)
|
|
|
|
if (!tile?.LinearSchedule) return []
|
|
|
|
const schedule = tile.LinearSchedule
|
|
const programs = [
|
|
schedule.Now,
|
|
schedule.Next,
|
|
...(Array.isArray(schedule.Later) ? schedule.Later : [])
|
|
].filter(Boolean)
|
|
|
|
return programs
|
|
.filter(item => item.Start && item.End && dayjs.utc(item.Start).isSame(date, 'day'))
|
|
.map(parseProgram)
|
|
},
|
|
async channels({ country, lang } = {}) {
|
|
if (country) return loadChannels(country, lang)
|
|
|
|
const channelsByAssetAndLanguage = new Map()
|
|
for (const supportedCountry of SUPPORTED_COUNTRIES) {
|
|
for (const channel of await loadChannels(supportedCountry)) {
|
|
const { assetId, country } = parseSiteId(channel.site_id)
|
|
const key = `${assetId}#${channel.lang}`
|
|
const current = channelsByAssetAndLanguage.get(key)
|
|
|
|
if (!current || isPreferredCountry(country, channel.lang)) {
|
|
channelsByAssetAndLanguage.set(key, channel)
|
|
}
|
|
}
|
|
}
|
|
|
|
return Array.from(channelsByAssetAndLanguage.values())
|
|
}
|
|
}
|
|
|
|
async function loadChannels(country, lang) {
|
|
country = country.toLowerCase()
|
|
if (!SUPPORTED_COUNTRIES.includes(country)) {
|
|
throw new Error(`Unsupported DAZN country: ${country}`)
|
|
}
|
|
|
|
const language = lang || getLanguage(country)
|
|
const { data } = await axios.get(createApiUrl(country, language), { headers: HEADERS })
|
|
const tiles = Array.isArray(data?.Tiles) ? data.Tiles : []
|
|
|
|
return tiles
|
|
.filter(tile => tile.AssetId && tile.Title)
|
|
.map(tile => ({
|
|
lang: language,
|
|
site_id: createSiteId(country, tile.AssetId),
|
|
name: tile.Title,
|
|
logo: createImageUrl(tile.LogoImage, {
|
|
resizeAction: 'contain',
|
|
width: 68,
|
|
height: 56,
|
|
format: 'png'
|
|
})
|
|
}))
|
|
}
|
|
|
|
function createApiUrl(country, language) {
|
|
const params = new URLSearchParams({
|
|
platform: 'web',
|
|
id: 'Livetvschedule',
|
|
country,
|
|
brand: 'dazn',
|
|
languageCode: language
|
|
})
|
|
|
|
return `${API_URL}?${params}`
|
|
}
|
|
|
|
function createSiteId(country, assetId) {
|
|
return country === DEFAULT_COUNTRY ? assetId : `${country}#${assetId}`
|
|
}
|
|
|
|
function parseSiteId(siteId) {
|
|
const separator = siteId.indexOf('#')
|
|
|
|
if (separator === -1) return { country: DEFAULT_COUNTRY, assetId: siteId }
|
|
|
|
return {
|
|
country: siteId.slice(0, separator),
|
|
assetId: siteId.slice(separator + 1)
|
|
}
|
|
}
|
|
|
|
function getLanguage(country) {
|
|
return COUNTRY_LANGUAGES[country] || 'en'
|
|
}
|
|
|
|
function isPreferredCountry(country, language) {
|
|
return country === PREFERRED_COUNTRIES[language]
|
|
}
|
|
|
|
function parseData(content) {
|
|
try {
|
|
return typeof content === 'string' ? JSON.parse(content) : content
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
function parseProgram(item) {
|
|
const program = {
|
|
title: item.Title,
|
|
start: item.Start,
|
|
stop: item.End
|
|
}
|
|
|
|
if (item.EpisodeTitle) program.subTitle = item.EpisodeTitle
|
|
if (item.Description) program.description = item.Description
|
|
if (item.EventYear) program.date = item.EventYear
|
|
if (item.TvRating) program.rating = item.TvRating
|
|
|
|
const categories = (Array.isArray(item.Genre) ? item.Genre : [])
|
|
.map(genre => genre?.name)
|
|
.filter(Boolean)
|
|
if (item.ProgramType) categories.push(item.ProgramType)
|
|
if (categories.length) program.categories = [...new Set(categories)]
|
|
|
|
const image = item.BackgroundImage || item.GradientBackgroundImage || item.Image
|
|
const icon = createImageUrl(image)
|
|
if (icon) program.icon = icon
|
|
|
|
return program
|
|
}
|
|
|
|
function createImageUrl(
|
|
image,
|
|
{ resizeAction = 'fill', width = 856, height = 481, format = 'webp' } = {}
|
|
) {
|
|
if (!image?.Id) return null
|
|
|
|
return `${IMAGE_API_URL}/${encodeURIComponent(
|
|
image.Id
|
|
)}/${resizeAction}/center/center/none/80/${width}/${height}/${format}/image?brand=dazn`
|
|
}
|