Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2959af0ac | ||
|
|
1062769e13 | ||
|
|
bcfd38cb19 | ||
|
|
3876463747 | ||
|
|
8411e28b0a | ||
|
|
5f228031e1 | ||
|
|
21881c43a7 | ||
|
|
d72cc13659 | ||
|
|
3a325f4cb3 | ||
|
|
59ba4f298e | ||
|
|
fd1df8ac0b | ||
|
|
65c2ed8208 | ||
|
|
054adcd9ec | ||
|
|
51a830bb2c | ||
|
|
cedf4cb9cf |
No files matched your search
+13
-71
@@ -8,79 +8,12 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
working-directory: ${{ GITHUB_WORKSPACE }}
|
working-directory: ${{ github.workspace }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install Docker
|
- name: Setup docker
|
||||||
run: |
|
uses: https://git.claeyscloud.com/david/gitea-actions/setup-docker@main
|
||||||
echo "Checking docker installation"
|
|
||||||
if command -v docker &> /dev/null; then
|
|
||||||
echo "Docker installation found"
|
|
||||||
else
|
|
||||||
echo "Docker installation not found. Docker will be installed"
|
|
||||||
curl -fsSL https://get.docker.com | sh
|
|
||||||
fi
|
|
||||||
- name: Install npm dependencies
|
|
||||||
run: |
|
|
||||||
echo "Installing fetch"
|
|
||||||
install_node=$false
|
|
||||||
if ! command -v node &> /dev/null; then
|
|
||||||
echo "No version of NodeJS detected"
|
|
||||||
install_node=true
|
|
||||||
else
|
|
||||||
node_version=$(node -v)
|
|
||||||
node_version=${node_version:1} # Remove 'v' at the beginning
|
|
||||||
node_version=${node_version%\.*} # Remove trailing ".*".
|
|
||||||
node_version=${node_version%\.*} # Remove trailing ".*".
|
|
||||||
node_version=$(($node_version)) # Convert the NodeJS version number from a string to an integer.
|
|
||||||
if [ $node_version -lt 24 ]; then
|
|
||||||
echo "node version : " $node_version
|
|
||||||
echo $"removing outdated npm version"
|
|
||||||
install_node=true
|
|
||||||
apt-get remove nodejs npm
|
|
||||||
apt-get purge nodejs
|
|
||||||
rm -rf /usr/local/bin/npm
|
|
||||||
rm -rf /usr/local/share/man/man1/node*
|
|
||||||
rm -rf /usr/local/lib/dtrace/node.d
|
|
||||||
rm -rf ~/.npm
|
|
||||||
rm -rf ~/.node-gyp
|
|
||||||
rm -rf /opt/local/bin/node
|
|
||||||
rm -rf opt/local/include/node
|
|
||||||
rm -rf /opt/local/lib/node_modules
|
|
||||||
rm -rf /usr/local/lib/node*
|
|
||||||
rm -rf /usr/local/include/node*
|
|
||||||
rm -rf /usr/local/bin/node*
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $install_node; then
|
|
||||||
NODE_MAJOR=24
|
|
||||||
echo "Installing node ${NODE_MAJOR}"
|
|
||||||
if test -f /etc/apt/keyrings/nodesource.gpg; then
|
|
||||||
rm /etc/apt/keyrings/nodesource.gpg
|
|
||||||
fi
|
|
||||||
if test -f /etc/apt/sources.list.d/nodesource.list; then
|
|
||||||
rm /etc/apt/sources.list.d/nodesource.list
|
|
||||||
fi
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y -q ca-certificates curl gnupg
|
|
||||||
mkdir -p /etc/apt/keyrings
|
|
||||||
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
|
||||||
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y -q nodejs
|
|
||||||
npm install npm --global
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "node version : " $(node -v)
|
|
||||||
|
|
||||||
package='node-fetch'
|
|
||||||
if [ `npm list -g | grep -c $package` -eq 0 ]; then
|
|
||||||
npm install -g $package
|
|
||||||
fi
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: https://github.com/docker/setup-buildx-action@v3
|
|
||||||
- name: Login to Gitea container registry
|
- name: Login to Gitea container registry
|
||||||
uses: https://github.com/docker/login-action@v3
|
uses: https://github.com/docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
@@ -92,6 +25,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
|
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
|
||||||
|
- name: Login to Lavaforge container registry
|
||||||
|
uses: https://github.com/docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: lavaforge.org
|
||||||
|
username: ${{ secrets.LAVAFORGE_USERNAME }}
|
||||||
|
password: ${{ secrets.LAVAFORGE_PASSWORD }}
|
||||||
- name: Extract metadata (tags, labels) for Docker
|
- name: Extract metadata (tags, labels) for Docker
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
@@ -104,11 +43,14 @@ jobs:
|
|||||||
images: |
|
images: |
|
||||||
davidquinonescl/epg-info
|
davidquinonescl/epg-info
|
||||||
git.claeyscloud.com/david/epg-info
|
git.claeyscloud.com/david/epg-info
|
||||||
|
lavaforge.org/davidquinonescl/epg-info
|
||||||
|
flavor: |
|
||||||
|
latest=true
|
||||||
tags: |
|
tags: |
|
||||||
type=semver,pattern={{raw}}
|
type=semver,pattern={{raw}}
|
||||||
type=sha
|
type=sha
|
||||||
- name: Update docker Hub Description
|
- name: Update docker Hub Description
|
||||||
uses: https://github.com/peter-evans/dockerhub-description@v5
|
uses: https://git.claeyscloud.com/david/gitea-actions/dockerhub-description@main
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
|
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
|
||||||
|
|||||||
@@ -4,14 +4,20 @@ This repo builds and Docker image of [iptv-org/epg](https://github.com/iptv-org/
|
|||||||
The purpose is to make the deployment easier and more suitable for different environments.
|
The purpose is to make the deployment easier and more suitable for different environments.
|
||||||
|
|
||||||
The original repository of this image is hosted on https://git.claeyscloud.com/david/epg-info-docker.<br>
|
The original repository of this image is hosted on https://git.claeyscloud.com/david/epg-info-docker.<br>
|
||||||
A public mirror is available at https://github.com/davidclaeysquinones/epg-info-docker.
|
A mirror of this repository can be found in https://github.com/davidclaeysquinones/epg-info-docker and in [lavaforge](https://lavaforge.org/davidquinonescl/epg-info-docker).
|
||||||
|
|
||||||
|
The image is distributed in the following container registries :
|
||||||
|
- [gitea](https://git.claeyscloud.com/david/-/packages/container/epg-info/latest)
|
||||||
|
- [lavaforge](https://lavaforge.org/davidquinonescl/-/packages/container/epg-info/latest)
|
||||||
|
- [github](https://github.com/davidclaeysquinones/epg-info-docker/pkgs/container/epg-info)
|
||||||
|
- [docker hub](https://hub.docker.com/repository/docker/davidquinonescl/epg-info/general)
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
[Node](https://nodejs.org/en)<br>
|
[Node](https://nodejs.org/en)<br>
|
||||||
[pm2](https://www.npmjs.com/package/pm2)<br>
|
[pm2](https://www.npmjs.com/package/pm2)<br>
|
||||||
[serve](https://www.npmjs.com/package/serve)<br>
|
[serve](https://www.npmjs.com/package/serve)<br>
|
||||||
|
|
||||||
The image is based on `node:22-alpine` in order to be more lightweight.
|
The image is based on `node:24-alpine` in order to be more lightweight.
|
||||||
The `pm2` and `serve` packages are used in order to run the application in the container.
|
The `pm2` and `serve` packages are used in order to run the application in the container.
|
||||||
## Docker image
|
## Docker image
|
||||||
|
|
||||||
@@ -40,11 +46,11 @@ This the list of the provided custom fixes :
|
|||||||
|
|
||||||
| Provider | Author(s) | Status |
|
| Provider | Author(s) | Status |
|
||||||
|--------------------|------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|--------------------|------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| movistarplus.es | [davidclaeysquinones](https://github.com/davidclaeysquinones) | [PR](https://github.com/iptv-org/epg/pull/2440) pending approval |
|
| movistarplus.es | | |
|
||||||
| orangetv.orange.es | [fraudiay79](https://github.com/fraudiay79) and [davidclaeysquinones](https://github.com/davidclaeysquinones) | [PR](https://github.com/iptv-org/epg/pull/2485) merged since commit [8a8262e](https://github.com/iptv-org/epg/commit/8a8262eacb46b2d35df7eb11f46de22263eab053) |
|
| orangetv.orange.es | | |
|
||||||
| pickx.be | [davidclaeysquinones](https://github.com/davidclaeysquinones) and [BellezaEmporium](https://github.com/BellezaEmporium) | [PR](https://github.com/iptv-org/epg/pull/2525) merged since commit [fd91a9c](https://github.com/iptv-org/epg/commit/fd91a9c532b476f6e192a564371d30e766b762ab) |
|
| pickx.be | [davidclaeysquinones](https://github.com/davidclaeysquinones) | In testing |
|
||||||
| telenet.tv | [davidclaeysquinones](https://github.com/davidclaeysquinones) | [PR](https://github.com/iptv-org/epg/pull/2429) merged since commit [fd382db](https://github.com/iptv-org/epg/commit/fd382db08da7a96150928b8dcfef115e29e661d3) |
|
| telenet.tv | | |
|
||||||
| web.magentatv.de | [klausellus-wallace](https://github.com/klausellus-wallace) | [PR](https://github.com/iptv-org/epg/pull/2458) merged since commit [61afe09](https://github.com/iptv-org/epg/commit/61afe090b6e7892cc5426457d960e9452222f885) |
|
| web.magentatv.de | | |
|
||||||
|
|
||||||
If for some reason you want to include your own provider fixes this is possible by creation a mapping in the `/fixes` folder.<br>
|
If for some reason you want to include your own provider fixes this is possible by creation a mapping in the `/fixes` folder.<br>
|
||||||
The expected structure is */fixes/`provider_name`/`provider_name`.config.js*.<br>
|
The expected structure is */fixes/`provider_name`/`provider_name`.config.js*.<br>
|
||||||
@@ -265,3 +271,22 @@ Sometimes a new version of this image will be bound to the same source commit. T
|
|||||||
[05-19-2026](https://github.com/iptv-org/epg/commit/157e77c50b08aa587e126095cedc330716d78fa0)
|
[05-19-2026](https://github.com/iptv-org/epg/commit/157e77c50b08aa587e126095cedc330716d78fa0)
|
||||||
- 1.0.85
|
- 1.0.85
|
||||||
[06-09-2026](https://github.com/iptv-org/epg/commit/ed40bb597a0c538368988822e1c0413d370a4d5c)
|
[06-09-2026](https://github.com/iptv-org/epg/commit/ed40bb597a0c538368988822e1c0413d370a4d5c)
|
||||||
|
- 1.0.86
|
||||||
|
[07-09-2026](https://github.com/iptv-org/epg/commit/0d5e1ff08b7a133f157d18fd945792498d5ea6cb)
|
||||||
|
- 1.0.87
|
||||||
|
[07-19-2026](https://github.com/iptv-org/epg/commit/1525e895fad70151e1895691bbf2e3426bf65920)
|
||||||
|
- 1.0.88
|
||||||
|
[08-05-2026](https://github.com/iptv-org/epg/commit/a7ce846b4e761ed37cfb968dc774d693a986fc88)
|
||||||
|
- 1.0.89
|
||||||
|
[09-02-2026](https://github.com/iptv-org/epg/commit/335458005387e07417a98399eb423c78d62a3bd9)
|
||||||
|
- 1.0.90
|
||||||
|
[09-21-2026](https://github.com/iptv-org/epg/commit/c5a88bcc6b09d75b32a0b22e6312db785cd9eb80)
|
||||||
|
- 1.0.91
|
||||||
|
[10-04-2026](https://github.com/iptv-org/epg/commit/aab705c6b90decfad2c9b27d1d6dbc8eeab9bbfd)
|
||||||
|
- 1.0.92
|
||||||
|
[10-23-2026](https://github.com/iptv-org/epg/commit/4abfae092f79fd3808ccadab65dc1873bcf6d259)
|
||||||
|
- 1.0.93
|
||||||
|
[10-25-2026](https://github.com/iptv-org/epg/commit/916c225d0a5e44534f09853674769c57005e61e5)
|
||||||
|
- 1.0.94
|
||||||
|
[10-26-2026](https://github.com/iptv-org/epg/commit/2c3e24fdab86140181878af00e01e9b440962d9b)
|
||||||
|
<br> Add fix for Pickx.be provder
|
||||||
@@ -1,19 +1,18 @@
|
|||||||
//https://github.com/iptv-org/epg/blob/master/sites/movistarplus.es/movistarplus.es.config.js
|
//https://github.com/iptv-org/epg/blob/master/sites/movistarplus.es/movistarplus.es.config.js
|
||||||
|
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const cheerio = require('cheerio')
|
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
|
const utc = require('dayjs/plugin/utc')
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
|
dayjs.tz.setDefault('Europe/Madrid')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'movistarplus.es',
|
site: 'movistarplus.es',
|
||||||
days: 2,
|
days: 2,
|
||||||
url({ channel, date }) {
|
url({ channel, date }) {
|
||||||
return `https://www.movistarplus.es/programacion-tv/${channel.site_id}/${date.format('YYYY-MM-DD')}`
|
return `https://ottcache.dof6.com/movistarplus/webplayer/OTT/epg?from=${date.format('YYYY-MM-DDTHH:mm:ss')}&span=1&channel=${channel.site_id}&version=8&mdrm=true&tlsstream=true&demarcation=18`
|
||||||
},
|
},
|
||||||
request: {
|
request: {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -25,122 +24,97 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
maxRedirects: 5
|
maxRedirects: 5
|
||||||
},
|
},
|
||||||
async parser({ content, date }) {
|
async parser({ content }) {
|
||||||
let programs = []
|
let programs = []
|
||||||
const $ = cheerio.load(content)
|
let items = await parseItems(content)
|
||||||
|
if (!items.length) return programs
|
||||||
const programDivs = $('div[id^="ele-"]').toArray()
|
|
||||||
|
|
||||||
for (let i = 0; i < programDivs.length; i++) {
|
|
||||||
const el = $(programDivs[i])
|
|
||||||
|
|
||||||
const title = el.find('li.title').text().trim()
|
|
||||||
if (!title) continue
|
|
||||||
|
|
||||||
const timeText = el.find('li.time').text().trim()
|
|
||||||
if (!timeText) continue
|
|
||||||
|
|
||||||
const [hours, minutes] = timeText.split(':').map(h => parseInt(h, 10))
|
|
||||||
|
|
||||||
// Parse time in Spain timezone (Europe/Madrid)
|
|
||||||
let startDate = dayjs.tz(
|
|
||||||
`${date.format('YYYY-MM-DD')} ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`,
|
|
||||||
'YYYY-MM-DD HH:mm',
|
|
||||||
'Europe/Madrid'
|
|
||||||
)
|
|
||||||
|
|
||||||
// If the time is in early morning (before 5 AM), it's the next day
|
|
||||||
if (hours < 5) {
|
|
||||||
startDate = startDate.add(1, 'day')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate end time from next program's start time
|
|
||||||
let endDate
|
|
||||||
if (i < programDivs.length - 1) {
|
|
||||||
const nextEl = $(programDivs[i + 1])
|
|
||||||
const nextTimeText = nextEl.find('li.time').text().trim()
|
|
||||||
if (nextTimeText) {
|
|
||||||
const [nextHours, nextMinutes] = nextTimeText.split(':').map(h => parseInt(h, 10))
|
|
||||||
endDate = dayjs.tz(
|
|
||||||
`${date.format('YYYY-MM-DD')} ${nextHours.toString().padStart(2, '0')}:${nextMinutes.toString().padStart(2, '0')}`,
|
|
||||||
'YYYY-MM-DD HH:mm',
|
|
||||||
'Europe/Madrid'
|
|
||||||
)
|
|
||||||
|
|
||||||
// If the next time is in early morning (before 5 AM), it's the next day
|
|
||||||
if (nextHours < 5) {
|
|
||||||
endDate = endDate.add(1, 'day')
|
|
||||||
}
|
|
||||||
|
|
||||||
// If end time is still before or same as start time, add another day
|
|
||||||
if (endDate.isBefore(startDate) || endDate.isSame(startDate)) {
|
|
||||||
endDate = endDate.add(1, 'day')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no end time, use start of next day
|
|
||||||
if (!endDate) {
|
|
||||||
endDate = startDate.add(1, 'day').startOf('day')
|
|
||||||
}
|
|
||||||
|
|
||||||
const programLink = el.find('a').attr('href')
|
|
||||||
let description = null
|
|
||||||
|
|
||||||
if (programLink) {
|
|
||||||
description = await getProgramDescription(programLink).catch(() => null)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
items.forEach(el => {
|
||||||
programs.push({
|
programs.push({
|
||||||
title,
|
title: el.title,
|
||||||
description,
|
description: el.description,
|
||||||
start: startDate,
|
icon: el.icon,
|
||||||
stop: endDate
|
images: el.images,
|
||||||
|
season: el.season,
|
||||||
|
episode: el.episode,
|
||||||
|
start: el.start,
|
||||||
|
stop: el.stop
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels() {
|
async channels() {
|
||||||
const html = await axios
|
const json = await axios
|
||||||
.get('https://www.movistarplus.es/programacion-tv', {
|
.get(
|
||||||
headers: {
|
'https://ottcache.dof6.com/movistarplus/webplayer/OTT/contents/channels?mdrm=true&tlsstream=true&demarcation=18&version=8'
|
||||||
'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',
|
|
||||||
Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
|
|
||||||
const $ = cheerio.load(html)
|
// Load JSON, CodCadenaTv is the closest to the old MVSTR site ch. ID
|
||||||
let scheme = $('script:contains(ItemList)').html()
|
return json.map(channel => {
|
||||||
scheme = JSON.parse(scheme)
|
|
||||||
|
|
||||||
return scheme.itemListElement.map(el => {
|
|
||||||
const urlParts = el.item.url.split('/')
|
|
||||||
const site_id = urlParts.pop().toLowerCase()
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
lang: 'es',
|
lang: 'es',
|
||||||
name: el.item.name,
|
site_id: channel.CodCadenaTv,
|
||||||
site_id
|
name: channel.Nombre,
|
||||||
|
logo: channel.Logo || channel.Logos?.[0]?.uri || null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getProgramDescription(programUrl) {
|
function parseImages(images) {
|
||||||
const response = await axios.get(programUrl, {
|
return images.filter(image => image.id === 'watch2tgr-end').map(image => image.uri)
|
||||||
headers: {
|
}
|
||||||
'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',
|
async function parseItems(content) {
|
||||||
Referer: 'https://www.movistarplus.es/programacion-tv/'
|
try {
|
||||||
|
const data = JSON.parse(content)
|
||||||
|
const programs = Array.isArray(data) ? data : [data]
|
||||||
|
return await Promise.all(
|
||||||
|
programs.map(async json => {
|
||||||
|
const start = dayjs.utc(Number(json?.FechaHoraInicio))
|
||||||
|
const stop = dayjs.utc(Number(json?.FechaHoraFin))
|
||||||
|
const ficha = json?.Ficha || null
|
||||||
|
if (!ficha) {
|
||||||
|
return {
|
||||||
|
title: json?.Titulo || '',
|
||||||
|
description: json?.Resena || '',
|
||||||
|
icon: json?.Imagen || '',
|
||||||
|
images: json.Imagenes ? parseImages(json.Imagenes) : [],
|
||||||
|
start,
|
||||||
|
stop
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const fichaJson = await axios.get(ficha).then(r => r.data)
|
||||||
|
return {
|
||||||
|
title: json?.Titulo || fichaJson?.Titulo || '',
|
||||||
|
description: fichaJson?.Descripcion || json?.Resena || '',
|
||||||
|
icon: fichaJson?.Imagen || '',
|
||||||
|
images: fichaJson.Imagenes ? parseImages(fichaJson.Imagenes) : [],
|
||||||
|
actors: fichaJson?.Actores || [],
|
||||||
|
directors: fichaJson?.Directores || [],
|
||||||
|
classification: fichaJson?.Clasificacion || '',
|
||||||
|
season: fichaJson?.Temporada || null,
|
||||||
|
episode: fichaJson?.NumeroEpisodio || null,
|
||||||
|
start,
|
||||||
|
stop
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return {
|
||||||
|
title: json?.Titulo || '',
|
||||||
|
description: json?.Resena || '',
|
||||||
|
icon: json?.Imagen || '',
|
||||||
|
images: json.Imagenes ? parseImages(json.Imagenes) : [],
|
||||||
|
start,
|
||||||
|
stop
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
)
|
||||||
const $ = cheerio.load(response.data)
|
} catch {
|
||||||
const description = $('.show-content .text p').first().text().trim() || null
|
return []
|
||||||
|
}
|
||||||
return description
|
|
||||||
}
|
}
|
||||||
@@ -9,10 +9,12 @@ dayjs.extend(utc)
|
|||||||
|
|
||||||
doFetch.setDebugger(debug)
|
doFetch.setDebugger(debug)
|
||||||
|
|
||||||
const API_PROGRAM_ENDPOINT = 'https://epg.orangetv.orange.es/epg/Smartphone_Android/1_PRO'
|
const API_PROGRAM_ENDPOINT = 'https://epg.orangetv.orange.es/epg/SmartTV_Android/1_PRO'
|
||||||
const API_CHANNEL_ENDPOINT =
|
|
||||||
'https://pc.orangetv.orange.es/pc/api/rtv/v1/GetChannelList?bouquet_id=1&model_external_id=PC&filter_unsupported_channels=false&client=json'
|
|
||||||
const API_IMAGE_ENDPOINT = 'https://pc.orangetv.orange.es/pc/api/rtv/v1/images'
|
const API_IMAGE_ENDPOINT = 'https://pc.orangetv.orange.es/pc/api/rtv/v1/images'
|
||||||
|
const API_CHANNEL_ENDPOINT =
|
||||||
|
'https://pc.orangetv.orange.es/pc/api/rtv/v1/GetChannelList?bouquet_external_id=1_PRO&model_external_id=PC&filter_unsupported_channels=true&max_pr_level=8&client=json'
|
||||||
|
|
||||||
|
const caches = {}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'orangetv.orange.es',
|
site: 'orangetv.orange.es',
|
||||||
@@ -25,20 +27,31 @@ module.exports = {
|
|||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36'
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
url: function({ date, segment = 1 }) {
|
url({ date }) {
|
||||||
return `${API_PROGRAM_ENDPOINT}/${date.format('YYYYMMDD')}_8h_${segment}.json`
|
return segmentUrl(date)
|
||||||
},
|
},
|
||||||
async parser({ content, channel, date }) {
|
async parser({ content, channel, date }) {
|
||||||
const programs = []
|
const programs = []
|
||||||
const items = parseItems(content, channel)
|
const items = parseItems(content, channel)
|
||||||
if (items.length) {
|
const queues = []
|
||||||
const queues = [
|
// fetch other segments or use cache if exist
|
||||||
module.exports.url({ date, segment: 2 }),
|
for (let i = 2; i <= 3; i++) {
|
||||||
module.exports.url({ date, segment: 3 })
|
const url = segmentUrl(date, i)
|
||||||
]
|
if (caches[url] !== undefined) {
|
||||||
await doFetch(queues, (url, res) => {
|
items.push(...parseItems(caches[url], channel))
|
||||||
|
} else {
|
||||||
|
queues.push({ url, params: module.exports.request })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (queues.length) {
|
||||||
|
await doFetch(queues, (queue, res) => {
|
||||||
|
if (caches[queue.url] === undefined) {
|
||||||
|
caches[queue.url] = res
|
||||||
|
}
|
||||||
items.push(...parseItems(res, channel))
|
items.push(...parseItems(res, channel))
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
if (items.length) {
|
||||||
programs.push(
|
programs.push(
|
||||||
...items.map(item => {
|
...items.map(item => {
|
||||||
return {
|
return {
|
||||||
@@ -75,6 +88,10 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function segmentUrl(date, segment = 1) {
|
||||||
|
return `${API_PROGRAM_ENDPOINT}/${date.format('YYYYMMDD')}_8h_${segment}.json`
|
||||||
|
}
|
||||||
|
|
||||||
function parseIcon(item) {
|
function parseIcon(item) {
|
||||||
if (item.attachments.length) {
|
if (item.attachments.length) {
|
||||||
const cover = item.attachments.find(i => i.name.match(/cover/i))
|
const cover = item.attachments.find(i => i.name.match(/cover/i))
|
||||||
@@ -94,7 +111,7 @@ function parseItems(content, channel) {
|
|||||||
typeof content === 'string' ? JSON.parse(content) : Array.isArray(content) ? content : []
|
typeof content === 'string' ? JSON.parse(content) : Array.isArray(content) ? content : []
|
||||||
if (Array.isArray(json)) {
|
if (Array.isArray(json)) {
|
||||||
json
|
json
|
||||||
.filter(i => i.channelExternalId === channel.site_id)
|
.filter(i => String(i.channelExternalId) === String(channel.site_id))
|
||||||
.forEach(i => {
|
.forEach(i => {
|
||||||
result.push(...i.programs)
|
result.push(...i.programs)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,412 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<channels>
|
||||||
|
<channel site="pickx.be" site_id="1143" lang="fr" xmltv_id="MaghrebTV.be@SD">Maghreb TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1043" lang="en" xmltv_id="">Netflix</channel>
|
||||||
|
<channel site="pickx.be" site_id="1058" lang="fr" xmltv_id="NationalGeographicWild.fr@SD">National Geographic Wild F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1190" lang="nl" xmltv_id="NationalGeographicWild.nl@SD">National Geographic Wild N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1130" lang="de" xmltv_id="DasErste.de@SD">Das Erste</channel>
|
||||||
|
<channel site="pickx.be" site_id="1093" lang="fr" xmltv_id="TipikVision.be@SD">TIPIK vision</channel>
|
||||||
|
<channel site="pickx.be" site_id="1131" lang="de" xmltv_id="ZDF.de@SD">ZDF</channel>
|
||||||
|
<channel site="pickx.be" site_id="1195" lang="nl" xmltv_id="DobbitTV.be@NL">Dobbit TV N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1149" lang="nl" xmltv_id="VTM2.be@HD">VTM 2 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1011" lang="fr" xmltv_id="PickxPlus.be@FR">Pickx+ F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1155" lang="nl" xmltv_id="PickxPlus.be@NL">Pickx+ N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1065" lang="fr" xmltv_id="DobbitTV.be@FR">Dobbit TV F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1001" lang="fr" xmltv_id="Tipik.be@HD">TIPIK HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1201" lang="nl" xmltv_id="PlattelandsTV.be@SD">Plattelands</channel>
|
||||||
|
<channel site="pickx.be" site_id="1174" lang="nl" xmltv_id="DisneyJunior.nl@SD">Disney Jr. N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1036" lang="fr" xmltv_id="PickxPlus.be@FRHD">Pickx+ F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1182" lang="nl" xmltv_id="PickxPlus.be@NLHD">Pickx+ N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1016" lang="fr" xmltv_id="AB3.be@HD">AB3 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1054" lang="fr" xmltv_id="DiscoveryChannel.fr@SD">Discovery F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1054" lang="fr" xmltv_id="DiscoveryChannel.fr@HD">Disc HD F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1098" lang="fr" xmltv_id="MezzoLive.fr@SD">MezzoLive</channel>
|
||||||
|
<channel site="pickx.be" site_id="1002" lang="fr" xmltv_id="RTLTVI.be@HD">RTL tvi HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1004" lang="fr" xmltv_id="RTLPlug.be@HD">RTL plug HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1110" lang="fr" xmltv_id="Telesambre.be@SD">Télé Sambre</channel>
|
||||||
|
<channel site="pickx.be" site_id="1113" lang="fr" xmltv_id="Vedia.be@SD">Védia</channel>
|
||||||
|
<channel site="pickx.be" site_id="1111" lang="fr" xmltv_id="">TV Com</channel>
|
||||||
|
<channel site="pickx.be" site_id="1112" lang="fr" xmltv_id="TVLux.be@SD">TV Lux</channel>
|
||||||
|
<channel site="pickx.be" site_id="1106" lang="fr" xmltv_id="Matele.be@SD">MaTélé</channel>
|
||||||
|
<channel site="pickx.be" site_id="1044" lang="fr" xmltv_id="">Disney+</channel>
|
||||||
|
<channel site="pickx.be" site_id="1167" lang="nl" xmltv_id="BBCFirst.uk@Benelux">BBC First</channel>
|
||||||
|
<channel site="pickx.be" site_id="1171" lang="nl" xmltv_id="Nickelodeon.nl@HD">nick N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1157" lang="nl" xmltv_id="Play6.be@SD">Play6</channel>
|
||||||
|
<channel site="pickx.be" site_id="1157" lang="nl" xmltv_id="Play6.be@HD">Play6 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1129" lang="fr" xmltv_id="France24.fr@FrenchHD">France 24 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1128" lang="fr" xmltv_id="EuronewsFrench.fr@SD">Euronews F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1150" lang="nl" xmltv_id="VTM3.be@HD">VTM 3 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1063" lang="fr" xmltv_id="CrimeDistrict.fr@SD">Crime District</channel>
|
||||||
|
<channel site="pickx.be" site_id="1092" lang="fr" xmltv_id="BelRTL.be@HD">bel RTL HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1196" lang="nl" xmltv_id="EclipsTV.be@SD">Eclips</channel>
|
||||||
|
<channel site="pickx.be" site_id="1017" lang="fr" xmltv_id="ABXplore.be@HD">ABXPLO HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1194" lang="nl" xmltv_id="Njam.be@HD">Njam! HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1194" lang="nl" xmltv_id="Njam.be@SD">Njam!</channel>
|
||||||
|
<channel site="pickx.be" site_id="1020" lang="fr" xmltv_id="arte.fr@HD">arte HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1187" lang="nl" xmltv_id="AnimalPlanet.nl@HD">Animal Pl HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1154" lang="nl" xmltv_id="Ketnet.be@HD">Ketnet HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1161" lang="nl" xmltv_id="NPO1.nl@HD">NPO 1 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1162" lang="nl" xmltv_id="NPO2.nl@HD">NPO 2 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1163" lang="nl" xmltv_id="NPO3.nl@HD">NPO 3 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1037" lang="fr" xmltv_id="Be1.be@SD">Be1</channel>
|
||||||
|
<channel site="pickx.be" site_id="1039" lang="fr" xmltv_id="BeCine.be@SD">Be Ciné</channel>
|
||||||
|
<channel site="pickx.be" site_id="1038" lang="fr" xmltv_id="BeSeries.be@SD">Be Séries</channel>
|
||||||
|
<channel site="pickx.be" site_id="1040" lang="fr" xmltv_id="CinePlusOCS.fr@SD">Ciné+OCS</channel>
|
||||||
|
<channel site="pickx.be" site_id="1041" lang="fr" xmltv_id="CinePlusFrisson.fr@SD">Ciné+Frisson</channel>
|
||||||
|
<channel site="pickx.be" site_id="1042" lang="fr" xmltv_id="CinePlusClassic.be@SD">Ciné+Classic</channel>
|
||||||
|
<channel site="pickx.be" site_id="1200" lang="nl" xmltv_id="OUTtv.nl@SD">OUT tv</channel>
|
||||||
|
<channel site="pickx.be" site_id="1007" lang="fr" xmltv_id="France3.fr@HD">France 3 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1018" lang="fr" xmltv_id="France4.fr@HD">France 4 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1019" lang="fr" xmltv_id="France5.fr@HD">France 5 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1015" lang="fr" xmltv_id="LN24.be@SD">LN24</channel>
|
||||||
|
<channel site="pickx.be" site_id="1160" lang="nl" xmltv_id="VTMGold.be@SD">VTM Gold</channel>
|
||||||
|
<channel site="pickx.be" site_id="1227" lang="en" xmltv_id="PenthouseGold.us@SD">Penthouse Gold</channel>
|
||||||
|
<channel site="pickx.be" site_id="1204" lang="nl" xmltv_id="PickxPlusSports1.be@NL">Pickx+ Sports 1 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1205" lang="nl" xmltv_id="PickxPlusSports2.be@NL">Pickx+ Sports 2 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1206" lang="nl" xmltv_id="PickxPlusSports3.be@NL">Pickx+ Sports 3 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1207" lang="nl" xmltv_id="PickxPlusSports4.be@NL">Pickx+ Sports 4 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1208" lang="nl" xmltv_id="PickxPlusSports5.be@NL">Pickx+ Sports 5 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1209" lang="nl" xmltv_id="PickxPlusSports6.be@NL">Pickx+ Sports 6 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1211" lang="nl" xmltv_id="PickxPlusSports8.be@NLHD">Pickx+ Sports 8 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1212" lang="nl" xmltv_id="PickxPlusSports9.be@NLHD">Pickx+ Sports 9 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1228" lang="en" xmltv_id="DuskTV.nl@SD">Dusk</channel>
|
||||||
|
<channel site="pickx.be" site_id="1203" lang="nl" xmltv_id="PickxLive.be@NLHD">Pickx Sports Pop-up N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1156" lang="nl" xmltv_id="PickxPlusSports1.be@NLHD">Pickx+ Sports 1 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1205" lang="nl" xmltv_id="PickxPlusSports2.be@NLHD">Pickx+ Sports 2 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1206" lang="nl" xmltv_id="PickxPlusSports3.be@NLHD">Pickx+ Sports 3 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1207" lang="nl" xmltv_id="PickxPlusSports4.be@NLHD">Pickx+ Sports 4 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1208" lang="nl" xmltv_id="PickxPlusSports5.be@NLHD">Pickx+ Sports 5 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1209" lang="nl" xmltv_id="PickxPlusSports6.be@NLHD">Pickx+ Sports 6 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1084" lang="fr" xmltv_id="DAZN1.uk@France">DAZN 1 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1217" lang="nl" xmltv_id="DAZN1.uk@Netherlands">DAZN 1 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1085" lang="fr" xmltv_id="DAZN2.uk@France">DAZN 2 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1218" lang="nl" xmltv_id="DAZN2.uk@Netherlands">DAZN 2 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1084" lang="fr" xmltv_id="DAZN1.uk@FranceHD">DAZN 1 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1217" lang="nl" xmltv_id="DAZN1.uk@NetherlandsHD">DAZN 1 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1085" lang="fr" xmltv_id="DAZN2.uk@FranceHD">DAZN 2 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1218" lang="nl" xmltv_id="DAZN2.uk@NetherlandsHD">DAZN 2 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1071" lang="fr" xmltv_id="PickxPlusSports2.be@FR">Pickx+ Sports 1 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1073" lang="fr" xmltv_id="PickxPlusSports3.be@FR">Pickx+ Sports 3 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1074" lang="fr" xmltv_id="PickxPlusSports4.be@FR">Pickx+ Sports 4 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1075" lang="fr" xmltv_id="PickxPlusSports5.be@FR">Pickx+ Sports 5 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1076" lang="fr" xmltv_id="PickxPlusSports6.be@FR">Pickx+ Sports 6 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1078" lang="fr" xmltv_id="PickxPlusSports8.be@FRHD">Pickx+ Sports 8 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1079" lang="fr" xmltv_id="PickxPlusSports9.be@FRHD">Pickx+ Sports 9 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1080" lang="fr" xmltv_id="PickxPlusSports10.be@FRHD">Pickx+ Sports 10 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1010" lang="fr" xmltv_id="PickxLive.be@FRHD">Pickx Sports Pop-up F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1012" lang="fr" xmltv_id="PickxPlusSports1.be@FRHD">Pickx+ Sports 1 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1072" lang="fr" xmltv_id="PickxPlusSports2.be@FRHD">Pickx+ Sports 2 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1073" lang="fr" xmltv_id="PickxPlusSports3.be@FRHD">Pickx+ Sports 3 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1074" lang="fr" xmltv_id="PickxPlusSports4.be@FRHD">Pickx+ Sports 4 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1075" lang="fr" xmltv_id="PickxPlusSports5.be@FRHD">Pickx+ Sports 5 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1076" lang="fr" xmltv_id="PickxPlusSports6.be@FRHD">Pickx+ Sports 6 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1213" lang="nl" xmltv_id="PickxPlusSports10.be@NLHD">Pickx+ Sports 10 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1236" lang="nl" xmltv_id="StuBru.be@SD">StuBru</channel>
|
||||||
|
<channel site="pickx.be" site_id="1256" lang="fr" xmltv_id="PromiusPickxInfoChannel.be@SD">InfoChannel</channel>
|
||||||
|
<channel site="pickx.be" site_id="1114" lang="nl" xmltv_id="VlaamsParlementTV.be@SD">Vlaamsparlement.tv</channel>
|
||||||
|
<channel site="pickx.be" site_id="1064" lang="fr" xmltv_id="E.fr@HD">E! HD F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1197" lang="nl" xmltv_id="EEurope.nl@HD">E! HD N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1024" lang="fr" xmltv_id="DisneyChannel.fr@HD">Disn Ch HD F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1173" lang="nl" xmltv_id="DisneyChannel.nl@HD">Disn Ch HD N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1140" lang="fr" xmltv_id="2MMonde.ma@SD">2M Monde</channel>
|
||||||
|
<channel site="pickx.be" site_id="1172" lang="nl" xmltv_id="VTMLife.be@HD">VTM Life HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1159" lang="nl" xmltv_id="KanaalZ.be@HD">Kanaal Z HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1014" lang="fr" xmltv_id="CanalZ.be@HD">Canal Z HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1046" lang="fr" xmltv_id="TVBreizh.fr@HD">TV Breizh HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1049" lang="fr" xmltv_id="TCMCinema.fr@HD">TCM Cinéma HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1048" lang="fr" xmltv_id="Syfy.fr@HD">SyFy HD F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1047" lang="fr" xmltv_id="13emeRue.fr@HD">13è Rue HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1045" lang="fr" xmltv_id="Action.fr@HD">Action HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1222" lang="nl" xmltv_id="Sport10.be@SD">Sport 10</channel>
|
||||||
|
<channel site="pickx.be" site_id="1034" lang="fr" xmltv_id="Gulli.fr@HD">Gulli HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1186" lang="nl" xmltv_id="NationalGeographic.nl@HD">NGC HD N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1089" lang="en" xmltv_id="Motorvision.de@SD">Motorvision+</channel>
|
||||||
|
<channel site="pickx.be" site_id="1021" lang="fr" xmltv_id="TV5MondeFranceBelgiumSwitzerlandMonaco.fr@HD">TV5 Monde HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1089" lang="en" xmltv_id="Motorvision.de@HD">Motorvision+ HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1050" lang="fr" xmltv_id="ComedyCentral.fr@SD">Comedy Central F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1030" lang="fr" xmltv_id="NickelodeonJunior.fr@SD">nick jr F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1151" lang="nl" xmltv_id="VTM4.be@HD">VTM 4 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1203" lang="nl" xmltv_id="PickxLive.be@NL">Pickx Showcase N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1147" lang="nl" xmltv_id="Play4.be@HD">Play4 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1148" lang="nl" xmltv_id="Play5.be@HD">Play5 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1081" lang="fr" xmltv_id="DAZNProLeague1.uk@FranceHD">DAZN Pro League 1 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1081" lang="fr" xmltv_id="DAZNProLeague1.uk@France">DAZN Pro League 1 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1193" lang="nl" xmltv_id="TLC.nl@SD">TLC</channel>
|
||||||
|
<channel site="pickx.be" site_id="1172" lang="nl" xmltv_id="VTMLife.be@SD">VTM Life</channel>
|
||||||
|
<channel site="pickx.be" site_id="1056" lang="fr" xmltv_id="Trek.fr@HD">TREK HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1214" lang="nl" xmltv_id="DAZNProLeague1.uk@NetherlandsHD">DAZN Pro League 1 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1214" lang="nl" xmltv_id="DAZNProLeague1.uk@Netherlands">DAZN Pro League 1 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1082" lang="fr" xmltv_id="DAZNProLeague2.uk@FranceHD">DAZN Pro League 2 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1082" lang="fr" xmltv_id="DAZNProLeague2.uk@France">DAZN Pro League 2 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1215" lang="nl" xmltv_id="DAZNProLeague2.uk@NetherlandsHD">DAZN Pro League 2 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1215" lang="nl" xmltv_id="DAZNProLeague2.uk@Netherlands">DAZN Pro League 2 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1132" lang="de" xmltv_id="RTL.de@SD">RTL</channel>
|
||||||
|
<channel site="pickx.be" site_id="1051" lang="fr" xmltv_id="TMC.fr@HD">TMC HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1158" lang="nl" xmltv_id="Play7.be@HD">Play7 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1068" lang="fr" xmltv_id="MyZenTV.fr@SD">MyZen.tv</channel>
|
||||||
|
<channel site="pickx.be" site_id="1057" lang="fr" xmltv_id="MuseumTVFrench.fr@SD">Museum TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1103" lang="fr" xmltv_id="ACTV.be@HD">Antenne Centre HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1115" lang="nl" xmltv_id="ATV.be@HD">ATV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1116" lang="nl" xmltv_id="AVS.be@HD">AVS HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1013" lang="nl" xmltv_id="Bruzz.be@HD">BRUZZ HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1009" lang="fr" xmltv_id="BX1.be@HD">bx1 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1104" lang="fr" xmltv_id="Bouke.be@HD">Bouké HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1105" lang="fr" xmltv_id="CanalZoom.be@HD">Canal Zoom HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1117" lang="nl" xmltv_id="FocusTV.be@HD">Focus TV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1106" lang="fr" xmltv_id="Matele.be@HD">MaTélé HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1107" lang="fr" xmltv_id="Notele.be@HD">No Télé HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1118" lang="nl" xmltv_id="RingTV.be@HD">Ring TV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1119" lang="nl" xmltv_id="ROBTV.be@HD">ROBTV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1108" lang="fr" xmltv_id="QU4TRELiegeMedia.be@HD">Quatre HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1120" lang="nl" xmltv_id="RTVKempen.be@HD">RTV Kempen HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1121" lang="nl" xmltv_id="RTVMech.be@HD">RTV Mech HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1109" lang="fr" xmltv_id="TeleMB.be@HD">Télé MB HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1110" lang="fr" xmltv_id="Telesambre.be@HD">Télé Sambre HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1122" lang="nl" xmltv_id="TVLimburg.be@HD">TV Limburg HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1112" lang="fr" xmltv_id="TVLux.be@HD">TV Lux HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1123" lang="nl" xmltv_id="TVOost.be@HD">TV Oost HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1113" lang="fr" xmltv_id="Vedia.be@HD">Védia HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1124" lang="nl" xmltv_id="WTV.be@HD">WTV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1224" lang="nl" xmltv_id="MentTV.be@HD">Ment TV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1192" lang="nl" xmltv_id="InsightTV.nl@SD">INPLUS</channel>
|
||||||
|
<channel site="pickx.be" site_id="1053" lang="fr" xmltv_id="TF1SeriesFilms.fr@SD">TF1 Séries Films</channel>
|
||||||
|
<channel site="pickx.be" site_id="1223" lang="nl" xmltv_id="QMusic.be@SD">Q-Music Kijk Live</channel>
|
||||||
|
<channel site="pickx.be" site_id="1165" lang="en" xmltv_id="BBCTwo.uk@HD">BBC Two HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1221" lang="nl" xmltv_id="Eurosport2.fr@NetherlandsHD">Eurosp2 HD N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1029" lang="fr" xmltv_id="Boomerang.fr@HD">Boom F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1180" lang="nl" xmltv_id="Cartoonito.uk@HD">Cartoonito HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1026" lang="fr" xmltv_id="CartoonNetworkCEE.uk@FranceHD">Cartoon F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1176" lang="nl" xmltv_id="CartoonNetworkWesternEurope.uk@NetherlandsHD">Cartoon N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1188" lang="nl" xmltv_id="InvestigationDiscovery.nl@HD">Inv Disc HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1271" lang="en" xmltv_id="WSport.za@SD">W Sports</channel>
|
||||||
|
<channel site="pickx.be" site_id="1025" lang="fr" xmltv_id="DisneyJr.fr@HD">Disney Jr. F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1059" lang="fr" xmltv_id="ScienceVieTV.fr@HD">Sc et Vie TV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1060" lang="fr" xmltv_id="HistoireTV.fr@HD">Histoire HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1189" lang="nl" xmltv_id="History.nl@HD">History HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1136" lang="fr" xmltv_id="Rai1.it@HD">RAI Uno HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1137" lang="fr" xmltv_id="Rai2.it@HD">RAI Due HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1138" lang="fr" xmltv_id="Rai3.it@HD">RAI Tre HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1195" lang="nl" xmltv_id="DobbitTV.be@NLHD">Dobbit N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1130" lang="de" xmltv_id="DasErste.de@HD">Das Erste HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1183" lang="nl" xmltv_id="ComedyCentral.nl@HD">Comedy Central N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1127" lang="fr" xmltv_id="LCI.fr@HD">LCI HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1033" lang="fr" xmltv_id="Mangas.fr@HD">Mangas HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1131" lang="de" xmltv_id="ZDF.de@HD">ZDF HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1226" lang="en" xmltv_id="DorcelXXX.nl@HD">Dorcel XXX HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1225" lang="nl" xmltv_id="PassieXXX.nl@HD">Passie XXX HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1229" lang="en" xmltv_id="PinkX.fr@HD">Pink HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1031" lang="fr" xmltv_id="TiJi.fr@HD">Tiji HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1096" lang="fr" xmltv_id="TraceUrban.fr@HD">Trace HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1032" lang="fr" xmltv_id="CanalJ.fr@HD">Canal J HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1198" lang="en" xmltv_id="FashionTVEurope.fr@HD">Fashion TV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1102" lang="fr" xmltv_id="Melody.fr@HD">Melody.tv HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1199" lang="nl" xmltv_id="MTV.nl@HD">MTV N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1141" lang="fr" xmltv_id="AlAoula.ma@HD">Al Aoula HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1142" lang="fr" xmltv_id="AlJazeera.qa@EnglishHD">Al Jazeera HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1090" lang="fr" xmltv_id="Automotolachaine.fr@HD">AUTOMOTO HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1095" lang="fr" xmltv_id="RFMTV.fr@HD">RFM TV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1132" lang="de" xmltv_id="RTL.de@HD">RTL Deutschland HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1134" lang="fr" xmltv_id="TVEInternacionalEuropeAsia.es@HD">TVE International HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1062" lang="fr" xmltv_id="Animaux.fr@HD">Animaux HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1126" lang="en" xmltv_id="EuronewsEnglish.fr@HD">Euronews E HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1128" lang="fr" xmltv_id="EuronewsFrench.fr@HD">Euronews F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1295" lang="nl" xmltv_id="HGTV.be@SD">HGTV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1046" lang="fr" xmltv_id="TVBreizh.fr@SD">TV Breizh</channel>
|
||||||
|
<channel site="pickx.be" site_id="1060" lang="fr" xmltv_id="HistoireTV.fr@SD">Histoire</channel>
|
||||||
|
<channel site="pickx.be" site_id="1094" lang="fr" xmltv_id="RadioContact.be@SD">ContactV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1137" lang="fr" xmltv_id="Rai2.it@SD">RAI Due</channel>
|
||||||
|
<channel site="pickx.be" site_id="1185" lang="nl" xmltv_id="DiscoveryChannel.nl@SD">Discovery N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1020" lang="fr" xmltv_id="arte.fr@SD">Arte</channel>
|
||||||
|
<channel site="pickx.be" site_id="1045" lang="fr" xmltv_id="Action.fr@SD">Action</channel>
|
||||||
|
<channel site="pickx.be" site_id="1026" lang="fr" xmltv_id="CartoonNetworkCEE.uk@France">Cartoon F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1176" lang="nl" xmltv_id="CartoonNetworkWesternEurope.uk@Netherlands">Cartoon N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1056" lang="fr" xmltv_id="Trek.fr@SD">TREK</channel>
|
||||||
|
<channel site="pickx.be" site_id="1024" lang="fr" xmltv_id="DisneyChannel.fr@SD">Disn Ch F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1061" lang="fr" xmltv_id="UshuaiaTV.fr@SD">Ushuaïa</channel>
|
||||||
|
<channel site="pickx.be" site_id="1004" lang="fr" xmltv_id="RTLPlug.be@SD">RTL plug</channel>
|
||||||
|
<channel site="pickx.be" site_id="1134" lang="fr" xmltv_id="TVEInternacionalEuropeAsia.es@SD">TVE Int</channel>
|
||||||
|
<channel site="pickx.be" site_id="1096" lang="fr" xmltv_id="TraceUrban.fr@SD">TraceUrban</channel>
|
||||||
|
<channel site="pickx.be" site_id="1191" lang="nl" xmltv_id="DiscoveryScienceEurope.uk@Netherlands">Discovery Science</channel>
|
||||||
|
<channel site="pickx.be" site_id="1021" lang="fr" xmltv_id="TV5MondeFranceBelgiumSwitzerlandMonaco.fr@SD">TV5 Monde</channel>
|
||||||
|
<channel site="pickx.be" site_id="1198" lang="en" xmltv_id="FashionTVEurope.fr@SD">FashionTV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1125" lang="en" xmltv_id="CNNInternational.us@MENA">CNN</channel>
|
||||||
|
<channel site="pickx.be" site_id="1159" lang="nl" xmltv_id="KanaalZ.be@SD">Kanaal Z</channel>
|
||||||
|
<channel site="pickx.be" site_id="1014" lang="fr" xmltv_id="CanalZ.be@SD">Canal Z</channel>
|
||||||
|
<channel site="pickx.be" site_id="1144" lang="nl" xmltv_id="VRT1.be@SD">VRT 1</channel>
|
||||||
|
<channel site="pickx.be" site_id="1019" lang="fr" xmltv_id="France5.fr@SD">France 5</channel>
|
||||||
|
<channel site="pickx.be" site_id="1171" lang="nl" xmltv_id="Nickelodeon.nl@SD">nickelodeon N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1146" lang="nl" xmltv_id="VTM.be@SD">VTM</channel>
|
||||||
|
<channel site="pickx.be" site_id="1017" lang="fr" xmltv_id="ABXplore.be@SD">ABXPLORE</channel>
|
||||||
|
<channel site="pickx.be" site_id="1095" lang="fr" xmltv_id="RFMTV.fr@SD">RFM TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1149" lang="nl" xmltv_id="VTM2.be@SD">VTM 2</channel>
|
||||||
|
<channel site="pickx.be" site_id="1033" lang="fr" xmltv_id="Mangas.fr@SD">Mangas</channel>
|
||||||
|
<channel site="pickx.be" site_id="1161" lang="nl" xmltv_id="NPO1.nl@SD">NPO 1</channel>
|
||||||
|
<channel site="pickx.be" site_id="1136" lang="fr" xmltv_id="Rai1.it@SD">RAI Uno</channel>
|
||||||
|
<channel site="pickx.be" site_id="1062" lang="fr" xmltv_id="Animaux.fr@SD">Animaux</channel>
|
||||||
|
<channel site="pickx.be" site_id="1032" lang="fr" xmltv_id="CanalJ.fr@SD">Canal J</channel>
|
||||||
|
<channel site="pickx.be" site_id="1016" lang="fr" xmltv_id="AB3.be@SD">AB3</channel>
|
||||||
|
<channel site="pickx.be" site_id="1001" lang="fr" xmltv_id="Tipik.be@SD">RTBF TIPIK</channel>
|
||||||
|
<channel site="pickx.be" site_id="1000" lang="fr" xmltv_id="LaUne.be@SD">RTBF La Une</channel>
|
||||||
|
<channel site="pickx.be" site_id="1048" lang="fr" xmltv_id="Syfy.fr@SD">SyFy F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1055" lang="fr" xmltv_id="NationalGeographic.fr@SD">National Geographic F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1148" lang="nl" xmltv_id="Play5.be@SD">Play5</channel>
|
||||||
|
<channel site="pickx.be" site_id="1127" lang="fr" xmltv_id="LCI.fr@SD">LCI</channel>
|
||||||
|
<channel site="pickx.be" site_id="1005" lang="fr" xmltv_id="TF1.fr@SD">TF1</channel>
|
||||||
|
<channel site="pickx.be" site_id="1166" lang="en" xmltv_id="BBCNews.uk@Europe">BBC News</channel>
|
||||||
|
<channel site="pickx.be" site_id="1003" lang="fr" xmltv_id="RTLClub.be@SD">RTL club</channel>
|
||||||
|
<channel site="pickx.be" site_id="1164" lang="en" xmltv_id="BBCOne.uk@London">BBC One</channel>
|
||||||
|
<channel site="pickx.be" site_id="1002" lang="fr" xmltv_id="RTLTVI.be@SD">RTL tvi</channel>
|
||||||
|
<channel site="pickx.be" site_id="1129" lang="fr" xmltv_id="France24.fr@French">France 24 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1009" lang="fr" xmltv_id="BX1.be@SD">bx1</channel>
|
||||||
|
<channel site="pickx.be" site_id="1087" lang="fr" xmltv_id="Eurosport1.fr@France">Eurosport F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1163" lang="nl" xmltv_id="NPO3.nl@SD">NPO 3</channel>
|
||||||
|
<channel site="pickx.be" site_id="1162" lang="nl" xmltv_id="NPO2.nl@SD">NPO 2</channel>
|
||||||
|
<channel site="pickx.be" site_id="1018" lang="fr" xmltv_id="France4.fr@SD">France 4</channel>
|
||||||
|
<channel site="pickx.be" site_id="1150" lang="nl" xmltv_id="VTM3.be@SD">VTM 3</channel>
|
||||||
|
<channel site="pickx.be" site_id="1147" lang="nl" xmltv_id="Play4.be@SD">Play4</channel>
|
||||||
|
<channel site="pickx.be" site_id="1145" lang="nl" xmltv_id="VRTCanvas.be@SD">VRT Canvas</channel>
|
||||||
|
<channel site="pickx.be" site_id="1126" lang="en" xmltv_id="EuronewsEnglish.fr@SD">Euronews E</channel>
|
||||||
|
<channel site="pickx.be" site_id="1186" lang="nl" xmltv_id="NationalGeographic.nl@SD">National Geographic N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1006" lang="fr" xmltv_id="France2.fr@SD">France 2</channel>
|
||||||
|
<channel site="pickx.be" site_id="1007" lang="fr" xmltv_id="France3.fr@SD">France 3</channel>
|
||||||
|
<channel site="pickx.be" site_id="1088" lang="fr" xmltv_id="Eurosport2.fr@France">Eurosp2 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1187" lang="nl" xmltv_id="AnimalPlanet.nl@SD">Animal Planet</channel>
|
||||||
|
<channel site="pickx.be" site_id="1220" lang="nl" xmltv_id="Eurosport1.fr@Netherlands">Eurosport N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1031" lang="fr" xmltv_id="TiJi.fr@SD">Tiji</channel>
|
||||||
|
<channel site="pickx.be" site_id="1049" lang="fr" xmltv_id="TCMCinema.fr@SD">TCM Cinéma</channel>
|
||||||
|
<channel site="pickx.be" site_id="1226" lang="fr" xmltv_id="DorcelXXX.nl@SD">Dorcel XXX</channel>
|
||||||
|
<channel site="pickx.be" site_id="1059" lang="fr" xmltv_id="ScienceVieTV.fr@SD">Science et Vie TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1029" lang="fr" xmltv_id="Boomerang.fr@SD">Boomerang F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1064" lang="fr" xmltv_id="E.fr@SD">E! F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1047" lang="fr" xmltv_id="13emeRue.fr@SD">13è Rue</channel>
|
||||||
|
<channel site="pickx.be" site_id="1090" lang="fr" xmltv_id="Automotolachaine.fr@SD">AUTOMOTO</channel>
|
||||||
|
<channel site="pickx.be" site_id="1070" lang="fr" xmltv_id="PickxLive.be@FR">Pickx Showcase F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1124" lang="nl" xmltv_id="WTV.be@SD">WTV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1117" lang="nl" xmltv_id="FocusTV.be@SD">Focus TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1115" lang="nl" xmltv_id="ATV.be@SD">ATV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1122" lang="nl" xmltv_id="TVLimburg.be@SD">TV Limburg</channel>
|
||||||
|
<channel site="pickx.be" site_id="1119" lang="nl" xmltv_id="ROBTV.be@SD">ROBTV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1197" lang="nl" xmltv_id="EEurope.nl@SD">E! N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1123" lang="nl" xmltv_id="TVOost.be@SD">TV Oost</channel>
|
||||||
|
<channel site="pickx.be" site_id="1013" lang="nl" xmltv_id="Bruzz.be@SD">BRUZZ</channel>
|
||||||
|
<channel site="pickx.be" site_id="1120" lang="nl" xmltv_id="RTVKempen.be@SD">RTV Kempen O</channel>
|
||||||
|
<channel site="pickx.be" site_id="1121" lang="nl" xmltv_id="RTVMech.be@SD">RTV Mech</channel>
|
||||||
|
<channel site="pickx.be" site_id="1118" lang="nl" xmltv_id="RingTV.be@SD">Ring TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1107" lang="fr" xmltv_id="Notele.be@SD">No Télé</channel>
|
||||||
|
<channel site="pickx.be" site_id="1025" lang="fr" xmltv_id="DisneyJr.fr@SD">Disney Jr. F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1109" lang="fr" xmltv_id="TeleMB.be@SD">Télé MB</channel>
|
||||||
|
<channel site="pickx.be" site_id="1141" lang="fr" xmltv_id="AlAoula.ma@SD">Al Aoula</channel>
|
||||||
|
<channel site="pickx.be" site_id="1067" lang="fr" xmltv_id="MTV.fr@SD">MTV F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1199" lang="nl" xmltv_id="MTV.nl@SD">MTV N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1183" lang="nl" xmltv_id="ComedyCentral.nl@SD">Comedy Central N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1104" lang="fr" xmltv_id="Bouke.be@SD">Bouké</channel>
|
||||||
|
<channel site="pickx.be" site_id="1105" lang="fr" xmltv_id="CanalZoom.be@SD">Canal Zoom</channel>
|
||||||
|
<channel site="pickx.be" site_id="1103" lang="fr" xmltv_id="ACTV.be@SD">Antenne C</channel>
|
||||||
|
<channel site="pickx.be" site_id="1225" lang="nl" xmltv_id="PassieXXX.nl@SD">Passie XXX</channel>
|
||||||
|
<channel site="pickx.be" site_id="1178" lang="nl" xmltv_id="NickJr.nl@SD">nick jr N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1189" lang="nl" xmltv_id="History.nl@SD">History</channel>
|
||||||
|
<channel site="pickx.be" site_id="1102" lang="fr" xmltv_id="Melody.fr@SD">Melody.tv</channel>
|
||||||
|
<channel site="pickx.be" site_id="1142" lang="fr" xmltv_id="AlJazeera.qa@English">Al Jazeera</channel>
|
||||||
|
<channel site="pickx.be" site_id="1135" lang="fr" xmltv_id="KTO.fr@SD">KTO</channel>
|
||||||
|
<channel site="pickx.be" site_id="1179" lang="nl" xmltv_id="Nicktoons.nl@SD">nick Toons</channel>
|
||||||
|
<channel site="pickx.be" site_id="1005" lang="fr" xmltv_id="TF1.fr@HD">TF1 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1229" lang="fr" xmltv_id="PinkX.fr@SD">Pink</channel>
|
||||||
|
<channel site="pickx.be" site_id="1061" lang="fr" xmltv_id="UshuaiaTV.fr@HD">Ushuaïa HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1097" lang="nl" xmltv_id="StingrayClassica.ca@SD">Classica</channel>
|
||||||
|
<channel site="pickx.be" site_id="1185" lang="nl" xmltv_id="DiscoveryChannel.nl@HD">Disc HD N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1222" lang="nl" xmltv_id="Sport10.be@HD">Sport 10 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1055" lang="fr" xmltv_id="NationalGeographic.fr@HD">NGC HD F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1144" lang="nl" xmltv_id="VRT1.be@HD">VRT 1 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1003" lang="fr" xmltv_id="RTLClub.be@HD">RTL club HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1220" lang="nl" xmltv_id="Eurosport1.fr@NetherlandsHD">Eurosp HD N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1006" lang="fr" xmltv_id="France2.fr@HD">France 2 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1210" lang="nl" xmltv_id="PickxPlusSports7.be@NL">Pickx+ Sports 7 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1188" lang="nl" xmltv_id="InvestigationDiscovery.nl@SD">Inv Disc</channel>
|
||||||
|
<channel site="pickx.be" site_id="1212" lang="nl" xmltv_id="PickxPlusSports9.be@NL">Pickx+ Sports 9 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1213" lang="nl" xmltv_id="PickxPlusSports10.be@NL">Pickx+ Sports 10 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1211" lang="nl" xmltv_id="PickxPlusSports8.be@NL">Pickx+ Sports 8 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1080" lang="fr" xmltv_id="PickxPlusSports10.be@FR">Pickx+ Sports 10 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1077" lang="fr" xmltv_id="PickxPlusSports7.be@FR">Pickx+ Sports 7 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1078" lang="fr" xmltv_id="PickxPlusSports8.be@FR">Pickx+ Sports 8 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1079" lang="fr" xmltv_id="PickxPlusSports9.be@FR">Pickx+ Sports 9 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1221" lang="nl" xmltv_id="Eurosport2.fr@Netherlands">Eurosp2 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1077" lang="fr" xmltv_id="PickxPlusSports7.be@FRHD">Pickx+ Sports 7 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1210" lang="nl" xmltv_id="PickxPlusSports7.be@NLHD">Pickx+ Sports 7 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1165" lang="en" xmltv_id="BBCTwo.uk@England">BBC Two</channel>
|
||||||
|
<channel site="pickx.be" site_id="1146" lang="nl" xmltv_id="VTM.be@HD">VTM HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1151" lang="nl" xmltv_id="VTM4.be@SD">VTM 4</channel>
|
||||||
|
<channel site="pickx.be" site_id="1008" lang="fr" xmltv_id="LaTrois.be@SD">La Trois</channel>
|
||||||
|
<channel site="pickx.be" site_id="1180" lang="nl" xmltv_id="Cartoonito.uk@SD">Cartoonito</channel>
|
||||||
|
<channel site="pickx.be" site_id="1145" lang="nl" xmltv_id="VRTCanvas.be@HD">VRT Canvas HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1170" lang="nl" xmltv_id="Ketnet.be@SD">Ketnet</channel>
|
||||||
|
<channel site="pickx.be" site_id="1023" lang="fr" xmltv_id="Nickelodeon.fr@SD">nick F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1224" lang="nl" xmltv_id="MentTV.be@SD">Ment TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1000" lang="fr" xmltv_id="LaUne.be@HD">La Une HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1173" lang="nl" xmltv_id="DisneyChannel.nl@SD">Disn Ch N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1008" lang="fr" xmltv_id="LaTrois.be@HD">La Trois HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1108" lang="fr" xmltv_id="QU4TRELiegeMedia.be@SD">Quatre</channel>
|
||||||
|
<channel site="pickx.be" site_id="1133" lang="de" xmltv_id="">BRF Fernsehen</channel>
|
||||||
|
<channel site="pickx.be" site_id="1245" lang="de" xmltv_id="">BRF 1</channel>
|
||||||
|
<channel site="pickx.be" site_id="1261" lang="en" xmltv_id="">Test VRT ENG</channel>
|
||||||
|
<channel site="pickx.be" site_id="1265" lang="en" xmltv_id="">Test 977</channel>
|
||||||
|
<channel site="pickx.be" site_id="1266" lang="en" xmltv_id="">Test RTBF ENG</channel>
|
||||||
|
<channel site="pickx.be" site_id="1267" lang="en" xmltv_id="">Test RTL ENG</channel>
|
||||||
|
<channel site="pickx.be" site_id="1268" lang="en" xmltv_id="">Test DPG ENG</channel>
|
||||||
|
<channel site="pickx.be" site_id="1277" lang="en" xmltv_id="">Test 998</channel>
|
||||||
|
<channel site="pickx.be" site_id="1302" lang="en" xmltv_id="">Horse and Country</channel>
|
||||||
|
<channel site="pickx.be" site_id="2000" lang="en" xmltv_id="">Sanity Check Live 01</channel>
|
||||||
|
<channel site="pickx.be" site_id="1069" lang="fr" xmltv_id="">Pickx+ F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1246" lang="fr" xmltv_id="">RTBF La Prem1ère</channel>
|
||||||
|
<channel site="pickx.be" site_id="1247" lang="fr" xmltv_id="">RTBF VivaCité</channel>
|
||||||
|
<channel site="pickx.be" site_id="1248" lang="fr" xmltv_id="">RTBF Musiq'3</channel>
|
||||||
|
<channel site="pickx.be" site_id="1249" lang="fr" xmltv_id="">RTBF Classic21</channel>
|
||||||
|
<channel site="pickx.be" site_id="1250" lang="fr" xmltv_id="">RTBF Tipik Radio</channel>
|
||||||
|
<channel site="pickx.be" site_id="1251" lang="fr" xmltv_id="">bel RTL</channel>
|
||||||
|
<channel site="pickx.be" site_id="1252" lang="fr" xmltv_id="">MINT</channel>
|
||||||
|
<channel site="pickx.be" site_id="1253" lang="fr" xmltv_id="">Contact</channel>
|
||||||
|
<channel site="pickx.be" site_id="1254" lang="fr" xmltv_id="">Nostalgie</channel>
|
||||||
|
<channel site="pickx.be" site_id="1255" lang="fr" xmltv_id="">LN Radio</channel>
|
||||||
|
<channel site="pickx.be" site_id="1294" lang="fr" xmltv_id="">Test 984</channel>
|
||||||
|
<channel site="pickx.be" site_id="1296" lang="fr" xmltv_id="">RTL district</channel>
|
||||||
|
<channel site="pickx.be" site_id="2001" lang="fr" xmltv_id="">Sanity Check Radio</channel>
|
||||||
|
<channel site="pickx.be" site_id="2002" lang="fr" xmltv_id="">Sanity Check Live 02</channel>
|
||||||
|
<channel site="pickx.be" site_id="2003" lang="fr" xmltv_id="">Sanity Check Live 03</channel>
|
||||||
|
<channel site="pickx.be" site_id="2004" lang="fr" xmltv_id="">Sanity Check Live 04</channel>
|
||||||
|
<channel site="pickx.be" site_id="2005" lang="fr" xmltv_id="">Sanity Check Live 05</channel>
|
||||||
|
<channel site="pickx.be" site_id="2006" lang="fr" xmltv_id="">Sanity Check Live 06</channel>
|
||||||
|
<channel site="pickx.be" site_id="2007" lang="fr" xmltv_id="">Sanity Check Live 07</channel>
|
||||||
|
<channel site="pickx.be" site_id="2008" lang="fr" xmltv_id="">Sanity Check Live 08</channel>
|
||||||
|
<channel site="pickx.be" site_id="2009" lang="fr" xmltv_id="">Sanity Check Live 09</channel>
|
||||||
|
<channel site="pickx.be" site_id="2010" lang="fr" xmltv_id="">Sanity Check Live 10</channel>
|
||||||
|
<channel site="pickx.be" site_id="2011" lang="fr" xmltv_id="">Sanity Check Live 11</channel>
|
||||||
|
<channel site="pickx.be" site_id="2012" lang="fr" xmltv_id="">Sanity Check Live 12</channel>
|
||||||
|
<channel site="pickx.be" site_id="2020" lang="fr" xmltv_id="">Sanity Check Live 20</channel>
|
||||||
|
<channel site="pickx.be" site_id="3350" lang="fr" xmltv_id="">NTVBE Test 11</channel>
|
||||||
|
<channel site="pickx.be" site_id="3351" lang="fr" xmltv_id="">NTVBE Test 12</channel>
|
||||||
|
<channel site="pickx.be" site_id="3352" lang="fr" xmltv_id="">NTVBE Test 13</channel>
|
||||||
|
<channel site="pickx.be" site_id="3353" lang="fr" xmltv_id="">NTVBE Test 14</channel>
|
||||||
|
<channel site="pickx.be" site_id="3354" lang="fr" xmltv_id="">NTVBE Test 15</channel>
|
||||||
|
<channel site="pickx.be" site_id="1139" lang="it" xmltv_id="">Mediaset Italia</channel>
|
||||||
|
<channel site="pickx.be" site_id="1152" lang="nl" xmltv_id="">Studio 100 TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1153" lang="nl" xmltv_id="">Proximus Showcase N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1169" lang="nl" xmltv_id="">Studio 100 TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1184" lang="nl" xmltv_id="">STAR Channel</channel>
|
||||||
|
<channel site="pickx.be" site_id="1202" lang="nl" xmltv_id="">Pickx+ N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1230" lang="nl" xmltv_id="">Radio 1</channel>
|
||||||
|
<channel site="pickx.be" site_id="1231" lang="nl" xmltv_id="">Radio 2 Antwerpen</channel>
|
||||||
|
<channel site="pickx.be" site_id="1232" lang="nl" xmltv_id="">Radio 2 Limburg</channel>
|
||||||
|
<channel site="pickx.be" site_id="1233" lang="nl" xmltv_id="">Radio 2 Oost-Vlaanderen</channel>
|
||||||
|
<channel site="pickx.be" site_id="1234" lang="nl" xmltv_id="">Radio 2 Vlaam-Brabant</channel>
|
||||||
|
<channel site="pickx.be" site_id="1235" lang="nl" xmltv_id="">Radio 2 West-Vlaanderen</channel>
|
||||||
|
<channel site="pickx.be" site_id="1237" lang="nl" xmltv_id="">MNM</channel>
|
||||||
|
<channel site="pickx.be" site_id="1238" lang="nl" xmltv_id="">MNM Hits</channel>
|
||||||
|
<channel site="pickx.be" site_id="1239" lang="nl" xmltv_id="">Klara</channel>
|
||||||
|
<channel site="pickx.be" site_id="1240" lang="nl" xmltv_id="">Klara Continuo</channel>
|
||||||
|
<channel site="pickx.be" site_id="1241" lang="nl" xmltv_id="">Radio Bene</channel>
|
||||||
|
<channel site="pickx.be" site_id="1242" lang="nl" xmltv_id="">De Tijdloze</channel>
|
||||||
|
<channel site="pickx.be" site_id="1243" lang="nl" xmltv_id="">Qmusic</channel>
|
||||||
|
<channel site="pickx.be" site_id="1244" lang="nl" xmltv_id="">JOE</channel>
|
||||||
|
<channel site="pickx.be" site_id="1278" lang="nl" xmltv_id="">Play Crime</channel>
|
||||||
|
<channel site="pickx.be" site_id="1284" lang="nl" xmltv_id="">Frame</channel>
|
||||||
|
<channel site="pickx.be" site_id="1301" lang="nl" xmltv_id="">Pickx Crime</channel>
|
||||||
|
</channels>
|
||||||
@@ -1,133 +1,150 @@
|
|||||||
//https://github.com/iptv-org/epg/blob/e4f92bb2a2768dcba3dbbd52b19d78d96bebc31e/sites/pickx.be/pickx.be.config.js
|
|
||||||
|
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
|
const utc = require('dayjs/plugin/utc')
|
||||||
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
|
|
||||||
let apiVersion
|
dayjs.extend(utc)
|
||||||
|
dayjs.extend(timezone)
|
||||||
|
|
||||||
|
const API_ENDPOINT = 'https://api.prod-ntvbe.tvapi-web.pickx.be'
|
||||||
|
const API_IMAGE_ENDPOINT =
|
||||||
|
'https://experience-cache.cdi.streaming.proximustv.be/posterserver/poster/EPG'
|
||||||
|
|
||||||
|
const TIMEZONE = 'Europe/Brussels'
|
||||||
|
|
||||||
|
// every tray of the AVS backend is addressed through
|
||||||
|
// /{tenant}/{version}/{cluster}/{locale}/{platform}/{property}, where the cluster is the access
|
||||||
|
// level ("A" is anonymous, which is enough for the public guide) and the platform has to be WEB
|
||||||
|
const BASE_PATH = '/AGL/1.5/A/{locale}/WEB/PXS'
|
||||||
|
|
||||||
|
// the locale only selects the language of the labels the API itself emits, never the language of
|
||||||
|
// the guide, so a channel keeps its broadcast language whichever locale is requested
|
||||||
|
const LOCALES = { en: 'ENG', fr: 'FRA', nl: 'NLD', de: 'DEU' }
|
||||||
|
|
||||||
|
const LANGUAGES = {
|
||||||
|
ara: 'ar',
|
||||||
|
deu: 'de',
|
||||||
|
eng: 'en',
|
||||||
|
fra: 'fr',
|
||||||
|
ita: 'it',
|
||||||
|
nld: 'nl',
|
||||||
|
spa: 'es'
|
||||||
|
}
|
||||||
|
|
||||||
|
// the channel tray refuses any page wider than this
|
||||||
|
const CHANNELS_PER_PAGE = 100
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'pickx.be',
|
site: 'pickx.be',
|
||||||
days: 2,
|
days: 2,
|
||||||
async url({ channel, date }) {
|
|
||||||
if (!apiVersion) {
|
|
||||||
await fetchApiVersion()
|
|
||||||
}
|
|
||||||
|
|
||||||
return `https://px-epg.azureedge.net/airings/${apiVersion}/${date.format(
|
|
||||||
'YYYY-MM-DD'
|
|
||||||
)}/channel/${channel.site_id}?timezone=Europe%2FBrussels`
|
|
||||||
},
|
|
||||||
request: {
|
request: {
|
||||||
headers: {
|
headers: {
|
||||||
Origin: 'https://www.pickx.be',
|
Origin: 'https://tv.pickx.be',
|
||||||
Referer: 'https://www.pickx.be/'
|
Referer: 'https://tv.pickx.be/'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
parser({ channel, content }) {
|
url({ channel, date }) {
|
||||||
|
// the guide is cut into Brussels days, while the grabber hands us a UTC moment. Both edges
|
||||||
|
// are resolved from their own calendar date, because adding a day to the start would add a
|
||||||
|
// flat 24 hours and so cut the 25 hour day short, or overrun the 23 hour one, when the
|
||||||
|
// Brussels clock shifts
|
||||||
|
const start = brusselsMidnight(date)
|
||||||
|
const stop = brusselsMidnight(date.add(1, 'd'))
|
||||||
|
|
||||||
|
// from/to paginates the channels of the tray, not their programs, so asking for a single
|
||||||
|
// channel still returns its whole day
|
||||||
|
return `${API_ENDPOINT}${basePath(channel.lang)}/TRAY/EPG?from=1&to=1&filter_channelIds=${
|
||||||
|
channel.site_id
|
||||||
|
}&filter_startTime=${start.valueOf()}&filter_endTime=${stop.valueOf()}`
|
||||||
|
},
|
||||||
|
parser({ content }) {
|
||||||
const programs = []
|
const programs = []
|
||||||
if (content) {
|
parseItems(content).forEach(item => {
|
||||||
const items = JSON.parse(content)
|
const data = item.metadata
|
||||||
items.forEach(item => {
|
if (!data) return
|
||||||
|
|
||||||
programs.push({
|
programs.push({
|
||||||
title: item.program.title,
|
title: data.title,
|
||||||
sub_title: item.program.episodeTitle,
|
sub_title: data.episodeTitle,
|
||||||
description: item.program.description,
|
description: data.longDescription || data.shortDescription,
|
||||||
category: item.program.translatedCategory?.[channel.lang]
|
category: data.genres,
|
||||||
? item.program.translatedCategory[channel.lang]
|
image: parseImage(data),
|
||||||
: item.program.category.split('.')[1],
|
season: data.season,
|
||||||
image: item.program.posterFileName
|
episode: data.episodeNumber,
|
||||||
? `https://experience-cache.cdi.streaming.proximustv.be/posterserver/poster/EPG/${item.program.posterFileName}`
|
actors: data.actors,
|
||||||
: null,
|
director: data.directors,
|
||||||
season: item.program.seasonNumber,
|
date: data.year,
|
||||||
episode: item.program.episodeNumber,
|
country: data.country,
|
||||||
actors: item.program.actors,
|
start: dayjs(data.airingStartTime),
|
||||||
director: item.program.director ? [item.program.director] : null,
|
stop: dayjs(data.airingEndTime)
|
||||||
start: dayjs(item.programScheduleStart),
|
|
||||||
stop: dayjs(item.programScheduleEnd)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels() {
|
async channels() {
|
||||||
let channels = []
|
const channels = []
|
||||||
|
|
||||||
const query = {
|
for (let from = 1; ; from += CHANNELS_PER_PAGE) {
|
||||||
operationName: 'getChannels',
|
const data = await fetchChannels(from)
|
||||||
variables: {
|
if (!data) break
|
||||||
language: 'fr',
|
|
||||||
queryParams: {},
|
|
||||||
id: '0',
|
|
||||||
params: {
|
|
||||||
shouldReadFromCache: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
query: `query getChannels($language: String!, $queryParams: ChannelQueryParams, $id: String, $params: ChannelParams) {
|
|
||||||
channels(language: $language, queryParams: $queryParams, id: $id, params: $params) {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
language
|
|
||||||
radio
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await axios
|
const items = data.containers || []
|
||||||
.post('https://api.proximusmwc.be/tiams/v3/graphql', query)
|
items.forEach(item => {
|
||||||
.then(r => r.data)
|
const metadata = item.metadata
|
||||||
.catch(console.error)
|
if (!metadata) return
|
||||||
|
|
||||||
data.data.channels.forEach(channel => {
|
|
||||||
let lang = channel.language || 'fr'
|
|
||||||
if (channel.language === 'ger') lang = 'de'
|
|
||||||
|
|
||||||
channels.push({
|
channels.push({
|
||||||
lang,
|
lang: LANGUAGES[metadata.channelLanguage] || 'fr',
|
||||||
site_id: channel.id,
|
site_id: String(metadata.channelId),
|
||||||
name: channel.name
|
name: metadata.channelName
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (!items.length || channels.length >= data.total) break
|
||||||
|
}
|
||||||
|
|
||||||
return channels
|
return channels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchApiVersion() {
|
function basePath(lang) {
|
||||||
const hashUrl = 'https://www.pickx.be/nl/televisie/tv-gids'
|
return BASE_PATH.replace('{locale}', LOCALES[lang] || LOCALES.nl)
|
||||||
const hashData = await axios
|
|
||||||
.get(hashUrl)
|
|
||||||
.then(r => {
|
|
||||||
const re = /"hashes":\["(.*)"\]/
|
|
||||||
const match = r.data.match(re)
|
|
||||||
if (match && match[1]) {
|
|
||||||
return match[1]
|
|
||||||
} else {
|
|
||||||
throw new Error('React app version hash not found')
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.catch(console.error)
|
|
||||||
|
|
||||||
const versionUrl = `https://www.pickx.be/api/s-${hashData}`
|
function brusselsMidnight(date) {
|
||||||
const response = await axios.get(versionUrl, {
|
return dayjs.tz(date.format('YYYY-MM-DD'), TIMEZONE).startOf('d')
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchChannels(from) {
|
||||||
|
return axios
|
||||||
|
.get(`${API_ENDPOINT}${basePath('nl')}/TRAY/LIVECHANNELS`, {
|
||||||
|
params: { from, to: from + CHANNELS_PER_PAGE - 1 },
|
||||||
headers: {
|
headers: {
|
||||||
Origin: 'https://www.pickx.be',
|
Origin: 'https://tv.pickx.be',
|
||||||
Referer: 'https://www.pickx.be/'
|
Referer: 'https://tv.pickx.be/'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.then(r => r.data.resultObj)
|
||||||
|
.catch(console.error)
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseImage(data) {
|
||||||
|
const filename = data.pictureUrl || data.extendedMetadata?.images?.landscapePoster
|
||||||
|
|
||||||
|
return filename ? `${API_IMAGE_ENDPOINT}/${filename}` : null
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseItems(content) {
|
||||||
|
if (!content) return []
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
try {
|
try {
|
||||||
if (response.status === 200) {
|
const data = JSON.parse(content)
|
||||||
apiVersion = response.data.version
|
// the tray nests the programs of each requested channel under their own container
|
||||||
resolve()
|
const channel = data?.resultObj?.containers?.[0]
|
||||||
} else {
|
|
||||||
console.error(`Failed to fetch API version. Status: ${response.status}`)
|
return channel?.containers || []
|
||||||
reject(`Failed to fetch API version. Status: ${response.status}`)
|
} catch {
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
console.error('Error during fetchApiVersion:', error)
|
|
||||||
reject(error)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
@@ -1,135 +1,215 @@
|
|||||||
//https://github.com/iptv-org/epg/blob/e4f92bb2a2768dcba3dbbd52b19d78d96bebc31e/sites/telenet.tv/telenet.tv.config.js
|
//https://github.com/iptv-org/epg/blob/master/sites/web.magentatv.de/web.magentatv.de.config.js
|
||||||
|
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
|
const utc = require('dayjs/plugin/utc')
|
||||||
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
|
|
||||||
const API_STATIC_ENDPOINT = 'https://static.spark.telenet.tv/eng/web/epg-service-lite/be'
|
let X_CSRFTOKEN
|
||||||
const API_PROD_ENDPOINT = 'https://spark-prod-be.gnp.cloud.telenet.tv/eng/web/linear-service/v2'
|
let Cookie
|
||||||
const API_IMAGE_ENDPOINT = 'https://staticqbr-prod-be.gnp.cloud.telenet.tv/image-service'
|
const cookiesToExtract = ['JSESSIONID', 'CSESSIONID', 'CSRFSESSION']
|
||||||
|
|
||||||
|
dayjs.extend(utc)
|
||||||
|
dayjs.extend(customParseFormat)
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'telenet.tv',
|
site: 'web.magentatv.de',
|
||||||
days: 2,
|
days: 2,
|
||||||
|
url: 'https://api.prod.sngtv.magentatv.de/EPG/JSON/PlayBillList',
|
||||||
request: {
|
request: {
|
||||||
cache: {
|
method: 'POST',
|
||||||
ttl: 60 * 60 * 1000 // 1 hour
|
async headers() {
|
||||||
|
return await setHeaders()
|
||||||
|
},
|
||||||
|
data({ channel, date }) {
|
||||||
|
return {
|
||||||
|
count: -1,
|
||||||
|
isFillProgram: 1,
|
||||||
|
offset: 0,
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
include:
|
||||||
|
'endtime,genres,id,name,starttime,channelid,pictures,introduce,subName,seasonNum,subNum,cast,country,producedate,externalIds',
|
||||||
|
name: 'playbill'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
type: 2,
|
||||||
|
begintime: date.format('YYYYMMDD000000'),
|
||||||
|
channelid: channel.site_id,
|
||||||
|
endtime: date.add(1, 'd').format('YYYYMMDD000000')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
url: function ({ date, channel }) {
|
parser({ content }) {
|
||||||
return `${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date.format('YYYYMMDD')}000000`
|
const programs = []
|
||||||
},
|
const items = parseItems(content)
|
||||||
async parser({ content, channel, date }) {
|
items.forEach(item => {
|
||||||
let programs = []
|
|
||||||
let items = parseItems(content, channel)
|
|
||||||
if (!items.length) return programs
|
|
||||||
const promises = [
|
|
||||||
axios.get(
|
|
||||||
`${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date.format('YYYYMMDD')}060000`,
|
|
||||||
{
|
|
||||||
responseType: 'arraybuffer'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
axios.get(
|
|
||||||
`${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date.format('YYYYMMDD')}120000`,
|
|
||||||
{
|
|
||||||
responseType: 'arraybuffer'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
axios.get(
|
|
||||||
`${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date.format('YYYYMMDD')}180000`,
|
|
||||||
{
|
|
||||||
responseType: 'arraybuffer'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
await Promise.allSettled(promises)
|
|
||||||
.then(results => {
|
|
||||||
results.forEach(r => {
|
|
||||||
if (r.status === 'fulfilled') {
|
|
||||||
const parsed = parseItems(r.value.data, channel)
|
|
||||||
|
|
||||||
items = items.concat(parsed)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(console.error)
|
|
||||||
|
|
||||||
for (let item of items) {
|
|
||||||
const detail = await loadProgramDetails(item, channel)
|
|
||||||
programs.push({
|
programs.push({
|
||||||
title: item.title,
|
title: item.name,
|
||||||
subTitle: detail.episodeName,
|
description: item.introduce,
|
||||||
icon: parseIcon(item),
|
image: parseImage(item),
|
||||||
description: detail.longDescription,
|
icon: parseImage(item),
|
||||||
category: detail.genres,
|
category: parseCategory(item),
|
||||||
actors: detail.actors,
|
|
||||||
season: parseSeason(detail),
|
|
||||||
episode: parseEpisode(detail),
|
|
||||||
start: parseStart(item),
|
start: parseStart(item),
|
||||||
stop: parseStop(item)
|
stop: parseStop(item),
|
||||||
|
sub_title: item.subName,
|
||||||
|
season: item.seasonNum,
|
||||||
|
episode: item.subNum,
|
||||||
|
directors: parseDirectors(item),
|
||||||
|
producers: parseProducers(item),
|
||||||
|
adapters: parseAdapters(item),
|
||||||
|
country: item.country?.toUpperCase(),
|
||||||
|
date: item.producedate,
|
||||||
|
urls: parseUrls(item)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels() {
|
async channels() {
|
||||||
|
const url = 'https://api.prod.sngtv.magentatv.de/EPG/JSON/AllChannel'
|
||||||
|
const body = {
|
||||||
|
channelNamespace: 2,
|
||||||
|
filterlist: [
|
||||||
|
{
|
||||||
|
key: 'IsHide',
|
||||||
|
value: '-1'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
metaDataVer: 'Channel/1.1',
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
include: '/channellist/logicalChannel/contentId,/channellist/logicalChannel/name',
|
||||||
|
name: 'logicalChannel'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returnSatChannel: 0
|
||||||
|
}
|
||||||
|
const params = {
|
||||||
|
headers: await setHeaders()
|
||||||
|
}
|
||||||
|
|
||||||
const data = await axios
|
const data = await axios
|
||||||
.get(`${API_PROD_ENDPOINT}/channels?cityId=28001&language=en&productClass=Orion-DASH`)
|
.post(url, body, params)
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
|
|
||||||
return data.map(item => {
|
return data.channellist.map(item => {
|
||||||
return {
|
return {
|
||||||
lang: 'nl',
|
lang: 'de',
|
||||||
site_id: item.id,
|
site_id: item.contentId,
|
||||||
name: item.name
|
name: item.name
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadProgramDetails(item, channel) {
|
function parseCategory(item) {
|
||||||
if (!item.id) return {}
|
return item.genres
|
||||||
const url = `${API_PROD_ENDPOINT}/replayEvent/${item.id}?returnLinearContent=true&language=${channel.lang}`
|
? item.genres
|
||||||
const data = await axios
|
.replace('und', ',')
|
||||||
.get(url)
|
.split(',')
|
||||||
.then(r => r.data)
|
.map(i => i.trim())
|
||||||
.catch(console.log)
|
: []
|
||||||
|
}
|
||||||
|
|
||||||
return data || {}
|
function parseDirectors(item) {
|
||||||
|
if (!item.cast || !item.cast.director) return []
|
||||||
|
return item.cast.director
|
||||||
|
.replace('und', ',')
|
||||||
|
.split(',')
|
||||||
|
.map(i => i.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseProducers(item) {
|
||||||
|
if (!item.cast || !item.cast.producer) return []
|
||||||
|
return item.cast.producer
|
||||||
|
.replace('und', ',')
|
||||||
|
.split(',')
|
||||||
|
.map(i => i.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseAdapters(item) {
|
||||||
|
if (!item.cast || !item.cast.adaptor) return []
|
||||||
|
return item.cast.adaptor
|
||||||
|
.replace('und', ',')
|
||||||
|
.split(',')
|
||||||
|
.map(i => i.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseUrls(item) {
|
||||||
|
// currently only a imdb id is returned by the api, thus we can construct the url here
|
||||||
|
if (!item.externalIds) return []
|
||||||
|
return JSON.parse(item.externalIds)
|
||||||
|
.filter(externalId => externalId.type === 'imdb' && externalId.id)
|
||||||
|
.map(externalId => ({ system: 'imdb', value: `https://www.imdb.com/title/${externalId.id}` }))
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseImage(item) {
|
||||||
|
if (!Array.isArray(item.pictures) || !item.pictures.length) return null
|
||||||
|
|
||||||
|
return item.pictures[0].href
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStart(item) {
|
function parseStart(item) {
|
||||||
return dayjs.unix(item.startTime)
|
return dayjs.utc(item.starttime, 'YYYY-MM-DD HH:mm:ss')
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseStop(item) {
|
function parseStop(item) {
|
||||||
return dayjs.unix(item.endTime)
|
return dayjs.utc(item.endtime, 'YYYY-MM-DD HH:mm:ss')
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(content, channel) {
|
function parseItems(content) {
|
||||||
if (!content) return []
|
|
||||||
const data = JSON.parse(content)
|
const data = JSON.parse(content)
|
||||||
if (!data || !Array.isArray(data.entries)) return []
|
if (!data || !Array.isArray(data.playbilllist)) return []
|
||||||
const channelData = data.entries.find(e => e.channelId === channel.site_id)
|
|
||||||
if (!channelData) return []
|
|
||||||
|
|
||||||
return Array.isArray(channelData.events) ? channelData.events : []
|
return data.playbilllist
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseSeason(detail) {
|
async function fetchCookieAndToken() {
|
||||||
if (!detail.seasonNumber) return null
|
// Only fetch the cookies and csrfToken if they are not already set
|
||||||
if (String(detail.seasonNumber).length > 2) return null
|
if (X_CSRFTOKEN && Cookie) {
|
||||||
return detail.seasonNumber
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseEpisode(detail) {
|
try {
|
||||||
if (!detail.episodeNumber) return null
|
const response = await axios.request({
|
||||||
if (String(detail.episodeNumber).length > 3) return null
|
url: 'https://api.prod.sngtv.magentatv.de/EPG/JSON/Authenticate',
|
||||||
return detail.episodeNumber
|
params: {
|
||||||
|
SID: 'firstup',
|
||||||
|
T: 'Windows_chrome_118'
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
data: '{"terminalid":"00:00:00:00:00:00","mac":"00:00:00:00:00:00","terminaltype":"WEBTV","utcEnable":1,"timezone":"Etc/GMT0","userType":3,"terminalvendor":"Unknown"}'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Extract the cookies specified in cookiesToExtract
|
||||||
|
const setCookieHeader = response.headers['set-cookie'] || []
|
||||||
|
const extractedCookies = []
|
||||||
|
cookiesToExtract.forEach(cookieName => {
|
||||||
|
const regex = new RegExp(`${cookieName}=(.+?)(;|$)`)
|
||||||
|
const match = setCookieHeader.find(header => regex.test(header))
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
const cookieString = regex.exec(match)[0]
|
||||||
|
extractedCookies.push(cookieString)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// check if we recieved a csrfToken only then store the values
|
||||||
|
if (!response.data.csrfToken) {
|
||||||
|
console.log('csrfToken not found in the response.')
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseIcon(item) {
|
X_CSRFTOKEN = response.data.csrfToken
|
||||||
return `${API_IMAGE_ENDPOINT}/intent/${item.id}/posterTile`
|
Cookie = extractedCookies.join(' ')
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setHeaders() {
|
||||||
|
await fetchCookieAndToken()
|
||||||
|
|
||||||
|
return { X_CSRFTOKEN, Cookie }
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user