Compare commits

..
107 Commits
Author SHA1 Message Date
david 8edb33819e update readme
Build docker container / build (push) Successful in 15m56s
2026-10-29 09:29:05 +01:00
david 6fe29e4d71 update readme
Build docker container / build (push) Successful in 2m51s
2026-10-27 12:25:57 +01:00
david 0ff4dc7c7a fix issue with custom fix 2026-10-27 12:25:05 +01:00
david f2959af0ac update readme
Build docker container / build (push) Successful in 3m33s
2026-10-27 10:52:21 +01:00
david 1062769e13 add fixes to pick.be provider 2026-10-27 10:45:02 +01:00
david bcfd38cb19 update custom fixes to latest code 2026-10-27 10:43:05 +01:00
david 3876463747 update readme
Build docker container / build (push) Successful in 3m5s
2026-10-25 15:52:20 +01:00
david 8411e28b0a update readme 2026-10-25 15:51:44 +01:00
david 5f228031e1 update readme
Build docker container / build (push) Successful in 4m4s
2026-10-23 14:28:36 +02:00
david 21881c43a7 update readme
Build docker container / build (push) Successful in 4m44s
2026-10-06 10:59:36 +02:00
david d72cc13659 update action 2026-09-30 15:40:07 +02:00
david 3a325f4cb3 update readme
Build docker container / build (push) Successful in 11m48s
2026-09-25 13:01:38 +02:00
david 59ba4f298e update readme
Build docker container / build (push) Successful in 15m16s
2026-09-08 13:09:58 +02:00
david fd1df8ac0b update readme 2026-08-05 11:33:24 +02:00
david 65c2ed8208 update build action 2026-08-05 11:27:01 +02:00
david 054adcd9ec update readme
Build docker container / build (push) Successful in 17m47s
2026-08-05 10:52:22 +02:00
david 51a830bb2c update readme and build action
Build docker container / build (push) Successful in 21m24s
2026-07-22 09:20:10 +02:00
david cedf4cb9cf update readme
Build docker container / build (push) Successful in 23m6s
2026-07-09 15:45:11 +02:00
david 09b2a32c7e update readme
Build docker container / build (push) Successful in 19m37s
2026-06-09 08:20:41 +02:00
david faf359760e update readme
Build docker container / build (push) Successful in 14m3s
2026-05-22 08:44:09 +02:00
david d1c2a2cce6 update readme
Build docker container / build (push) Successful in 21m35s
2026-04-17 08:34:17 +02:00
david f10acb48dd update readme
Build docker container / build (push) Successful in 10m44s
2026-04-13 09:59:08 +02:00
david 97b2e2b7c9 fix issues in docker file
Build docker container / build (push) Successful in 9m6s
2026-04-01 16:37:22 +02:00
david 421bebb294 update readme
Build docker container / build (push) Failing after 14m5s
2026-04-01 15:44:22 +02:00
david b77bf97acd update readme
Build docker container / build (push) Successful in 8m43s
2026-03-23 08:41:38 +01:00
david b671040deb update readme
Build docker container / build (push) Successful in 8m43s
2026-03-16 09:12:30 +01:00
david 86e66ede1d update readme and update custom fixes
Build docker container / build (push) Successful in 15m44s
2026-02-24 12:46:24 +01:00
david c113fd0bbc update readme
Build docker container / build (push) Successful in 10m25s
2026-02-18 12:56:29 +01:00
david 54f8e6b157 update action 2026-02-18 12:54:40 +01:00
david be44be878c change action
Build docker container / build (push) Successful in 7m33s
2026-02-12 10:17:30 +01:00
david 1700fbe251 update readme
Build docker container / build (push) Failing after 1m49s
2026-02-12 08:59:35 +01:00
david b760bbdf3e update action 2026-02-12 08:58:18 +01:00
david 8c609f5515 update action 2026-02-09 15:48:15 +01:00
david ff31a3b737 update action 2026-02-09 15:32:40 +01:00
david 123285107d update action
Build docker container / build (push) Successful in 8m2s
2026-02-09 10:16:06 +01:00
david 3d13569146 update action 2026-02-09 09:57:40 +01:00
david e9bc6f5246 update action
Build docker container / build (push) Failing after 6m51s
2026-02-09 09:37:49 +01:00
david 5c662bae69 update docker action + readme
Build docker container / build (push) Failing after 7m26s
2026-02-09 09:25:34 +01:00
David Claeys eece21742c update readme
Build docker container / build (push) Successful in 8m2s
2026-01-08 13:44:06 +01:00
David Claeys ee126cf60c update readme
Build docker container / build (push) Successful in 8m51s
2025-12-24 14:25:57 +01:00
David Claeys db28863295 update readme
Build docker container / build (push) Successful in 11m38s
2025-11-26 11:26:24 +01:00
David Claeys 223a4ea6b5 update readme
Build docker container / build (push) Successful in 7m36s
2025-11-19 10:53:46 +01:00
David Claeys e6ee948355 update readme
Build docker container / build (push) Successful in 9m23s
2025-10-09 14:18:30 +02:00
David Claeys 2662567576 update readme
Build docker container / build (push) Successful in 18m38s
2025-09-25 09:36:24 +02:00
David Claeys 309038bb4a update readme + config
Build docker container / build (push) Successful in 25m21s
2025-07-15 09:24:34 +02:00
David Claeys 3b019df919 update readme
Build docker container / build (push) Successful in 8m14s
2025-07-07 08:53:11 +02:00
David Claeys 1cf21ddb98 update readme
Build docker container / build (push) Successful in 8m52s
2025-06-27 11:15:21 +02:00
David Claeys 0aeb48fe2f update readme
Build docker container / build (push) Successful in 6m37s
2025-06-17 08:10:34 +02:00
David Claeys 70c7ee79b0 update readme
Build docker container / build (push) Successful in 8m4s
2025-06-02 11:13:55 +02:00
David Claeys 62937901c2 update readme
Build docker container / build (push) Successful in 6m34s
2025-05-16 08:42:21 +02:00
David Claeys 4e5a2b4d27 update readme
Build docker container / build (push) Successful in 6m3s
2025-04-23 08:43:25 +02:00
David Claeys ab9a8d7160 add delay option
Build docker container / build (push) Successful in 6m12s
2025-04-14 09:15:43 +02:00
David Claeys e080a976a6 update readme
Build docker container / build (push) Successful in 13m7s
2025-04-09 10:23:29 +02:00
David Claeys 252a7b23aa bugfixes
Build docker container / build (push) Failing after 20m44s
2025-04-07 09:02:22 +02:00
David Claeys 0a4d9c4452 update readme
Build docker container / build (push) Successful in 12m5s
2025-04-04 08:25:49 +02:00
David Claeys 6939823646 update readme
Build docker container / build (push) Successful in 7m3s
2025-03-27 08:32:17 +01:00
David Claeys 60503e87ed update readme
Build docker container / build (push) Successful in 7m23s
2025-03-20 10:00:44 +01:00
David Claeys 2f732b6dcc update readme
Build docker container / build (push) Successful in 6m14s
2025-03-11 08:09:05 +01:00
David Claeys 1f999d1c3c update readme
Build docker container / build (push) Successful in 4m55s
2025-03-07 09:11:14 +01:00
David Claeys 3f5b36a878 update readme
Build docker container / build (push) Successful in 5m10s
2025-02-26 08:41:29 +01:00
David Claeys f1c905f5dd update readme
Build docker container / build (push) Successful in 5m44s
2025-02-18 08:44:54 +01:00
David Claeys d83069f300 update pickx.be 2025-02-18 08:44:02 +01:00
David Claeys 092ad56487 update readme
Build docker container / build (push) Successful in 9m37s
2025-02-11 10:02:04 +01:00
David Claeys cfedd1e091 update build actions 2025-02-06 16:56:56 +01:00
David Claeys 7bf14e4f10 update readme
Build docker container / build (push) Successful in 5m2s
2025-02-05 09:04:30 +01:00
David Claeys 1521795dd8 update readme
Build docker container / build (push) Successful in 7m0s
2025-02-03 08:45:34 +01:00
David Claeys 645569dc97 update readme
Build docker container / build (push) Successful in 4m1s
2025-01-30 10:11:58 +01:00
David Claeys 113b6b678e update readme
Build docker container / build (push) Successful in 8m42s
2025-01-29 08:44:29 +01:00
David Claeys 512d8257fd update readme
Build docker container / build (push) Successful in 6m56s
2025-01-27 08:34:53 +01:00
David Claeys db7680861e update readme
Build docker container / build (push) Successful in 9m2s
2025-01-23 12:40:25 +01:00
David Claeys 8623771537 change fixes + change readme
Build docker container / build (push) Successful in 5m7s
2025-01-21 11:54:21 +01:00
David Claeys 4199210593 update readme
Build docker container / build (push) Successful in 4m16s
2025-01-20 08:14:36 +01:00
David Claeys 3c9432d1f3 update readme
Build docker container / build (push) Successful in 2m32s
2025-01-17 08:35:13 +01:00
David Claeys fa76db456f update readme
Build docker container / build (push) Successful in 2m12s
2025-01-15 08:39:08 +01:00
David Claeys b434ce505b update readme + fix issue api url
Build docker container / build (push) Has been cancelled
2025-01-14 10:45:29 +01:00
David Claeys 2d3ffcbd42 update readme
Build docker container / build (push) Successful in 8m11s
2025-01-14 09:23:45 +01:00
David Claeys c4c0bf5270 update readme
Build docker container / build (push) Successful in 2m30s
2025-01-13 11:01:30 +01:00
David Claeys 8736114213 update orangetv.orange.es 2025-01-13 11:00:37 +01:00
David Claeys 075ac41e2a update readme + fix Dockefile
Build docker container / build (push) Successful in 9m7s
2025-01-09 15:23:28 +01:00
David Claeys c7dc12f4bb update readme
Build docker container / build (push) Failing after 2m3s
2025-01-09 14:49:30 +01:00
David Claeys 3a7f23577a update readme
Build docker container / build (push) Failing after 12m15s
2025-01-06 08:37:52 +01:00
David Claeys 02725264fd update readme 2024-12-31 21:15:59 +01:00
David Claeys ef25f64dcd orangetv rename + update readme
Build docker container / build (push) Successful in 2m7s
2024-12-31 18:31:29 +01:00
David Claeys 47e8a82c41 update readme
Build docker container / build (push) Successful in 2m8s
2024-12-31 08:38:51 +01:00
David Claeys 5be16e5544 update readme
Build docker container / build (push) Successful in 8m35s
2024-12-27 12:18:43 +01:00
David Claeys 91ad05ab89 update readme
Build docker container / build (push) Successful in 8m52s
2024-12-24 08:57:04 +01:00
David Claeys e9116631d8 update organtv.es channels file 2024-12-24 08:55:37 +01:00
David Claeys 330099049a update readme
Build docker container / build (push) Successful in 2m29s
2024-12-20 08:28:54 +01:00
David Claeys 06dca856ad update readme 2024-12-20 08:28:09 +01:00
David Claeys b042f5ac8e provider fixes + version update 2024-12-20 08:26:15 +01:00
David Claeys 4ba2fce7cf update dockerfile
Build docker container / build (push) Successful in 7m33s
2024-12-18 11:27:05 +01:00
David Claeys 3c66cce5dd update readme
Build docker container / build (push) Successful in 10m17s
2024-12-18 10:18:51 +01:00
David Claeys 50ae72364c update readme + mayor updates 2024-12-18 10:17:15 +01:00
David Claeys 490520775f update readme
Build docker container / build (push) Successful in 8m55s
2024-12-16 09:12:10 +01:00
David Claeys 8231301a53 update readme
Build docker container / build (push) Successful in 13m56s
2024-12-12 08:42:22 +01:00
David Claeys 2e8e8fb440 update readme
Build docker container / build (push) Successful in 14m48s
2024-12-09 08:35:29 +01:00
David Claeys ff1928a09f update readme
Build docker container / build (push) Successful in 11m4s
2024-12-07 09:44:47 +01:00
David Claeys 1ff85a3a26 update readme
Build docker container / build (push) Successful in 8m5s
2024-12-05 09:06:29 +01:00
David Claeys 6b723e1776 update readme
Build docker container / build (push) Successful in 11m34s
2024-12-04 08:38:48 +01:00
David Claeys 8aacebad42 remove log 2024-12-03 09:54:41 +01:00
David Claeys d388307b85 update readme
Build docker container / build (push) Successful in 7m17s
2024-12-03 09:50:42 +01:00
David Claeys e04ec220e3 update movistarplus channel grabber 2024-12-03 09:48:53 +01:00
David Claeys 6ff94a3848 update readme 2024-12-03 08:27:30 +01:00
David Claeys 1f885bbd1c update readme
Build docker container / build (push) Successful in 8m36s
2024-12-02 20:04:38 +01:00
David Claeys e99af0bc2b update readme 2024-12-02 19:47:52 +01:00
David Claeys 2f86d79697 update orangetv channel list 2024-12-02 15:48:54 +01:00
David Claeys 0e72cce51f update orangetv.es custom fix 2024-12-02 14:05:42 +01:00
15 changed files with 1252 additions and 664 deletions

No files matched your search

+24 -14
View File
@@ -8,21 +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: 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:
@@ -32,18 +23,38 @@ jobs:
- name: Login to DockerHub container registry - name: Login to DockerHub container registry
uses: https://github.com/docker/login-action@v3 uses: https://github.com/docker/login-action@v3
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
with: with:
labels: |
org.opencontainers.image.title=epg-info
org.opencontainers.image.description=Docker image of https://github.com/iptv-org/epg
org.opencontainers.image.authors=Davidquinonescl
org.opencontainers.image.documentation=https://git.claeyscloud.com/david/epg-info-docker/src/branch/main/README.md
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
uses: https://git.claeyscloud.com/david/gitea-actions/dockerhub-description@main
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
repository: davidquinonescl/epg-info
- name: Build and push - name: Build and push
uses: https://github.com/docker/build-push-action@v5 uses: https://github.com/docker/build-push-action@v5
with: with:
@@ -51,4 +62,3 @@ jobs:
push: true push: true
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
+5
View File
@@ -24,6 +24,11 @@ jobs:
id: meta id: meta
uses: docker/metadata-action@v5 uses: docker/metadata-action@v5
with: with:
labels: |
org.opencontainers.image.title=epg-info
org.opencontainers.image.description=Docker image of https://github.com/iptv-org/epg
org.opencontainers.image.authors=Davidquinonescl
org.opencontainers.image.documentation=https://github.com/davidclaeysquinones/epg-info-docker/blob/main/README.md
images: ghcr.io/davidclaeysquinones/epg-info images: ghcr.io/davidclaeysquinones/epg-info
tags: | tags: |
type=semver,pattern={{raw}} type=semver,pattern={{raw}}
+20 -10
View File
@@ -1,9 +1,10 @@
FROM node:21-alpine FROM node:24-alpine
ARG GIT_REPO=https://github.com/iptv-org/epg.git ARG GIT_REPO=https://github.com/iptv-org/epg.git
ARG GIT_BRANCH=master ARG GIT_BRANCH=master
ENV CRON_SCHEDULE="0 0,12 * * *" ENV CRON_SCHEDULE="0 0,12 * * *"
ENV API_URL="https://iptv-org.github.io/api" ENV API_URL="https://iptv-org.github.io/api"
ENV DAYS=14 ENV DAYS=14
ENV DELAY=0
ENV MAX_CONNECTIONS=10 ENV MAX_CONNECTIONS=10
ENV ENABLE_FIXES=false ENV ENABLE_FIXES=false
ARG BIN_FOLDER=/bin ARG BIN_FOLDER=/bin
@@ -23,32 +24,41 @@ RUN apk update \
&& mkdir $(echo "${BIN_FOLDER}/${EPG_FOLDER}") -p \ && mkdir $(echo "${BIN_FOLDER}/${EPG_FOLDER}") -p \
&& git -C $(echo "${BIN_FOLDER}") clone --depth 1 -b $(echo "${GIT_BRANCH} ${GIT_REPO}") \ && git -C $(echo "${BIN_FOLDER}") clone --depth 1 -b $(echo "${GIT_BRANCH} ${GIT_REPO}") \
&& cd $WORKDIR && npm install && npm update \ && cd $WORKDIR && npm install && npm update \
&& rm .eslintrc.json \ && rm -rf .sites \
&& rm -rf .husky \
&& rm -rf .github \ && rm -rf .github \
&& rm -rf .git \ && rm -rf .git \
&& rm .gitignore \ && rm Dockerfile \
&& rm CONTRIBUTING.md \ && rm .gitignore \
&& rm LICENSE \ && rm -f CONTRIBUTING.md \
&& rm README.md \ && rm -f GUIDES.md \
&& rm SITES.md \ && rm -f LICENSE \
&& rm -f README.md \
&& rm -f SITES.md \
&& rm -rf tests \ && rm -rf tests \
&& rm sites/**/readme.md \ && rm -f sites/**/readme.md \
&& rm -rf sites/**/__data__ \ && rm -rf sites/**/__data__ \
&& rm sites/**/**.test.js \ && rm -f sites/**/**.test.js \
&& rm -rf node_modules/**/.package-lock.json \ && rm -rf node_modules/**/.package-lock.json \
&& rm -rf node_modules/**/.tsconfig.json \ && rm -rf node_modules/**/.tsconfig.json \
&& rm -rf node_modules/**/.tsconfig.tsbuildinfo.json \ && rm -rf node_modules/**/.tsconfig.tsbuildinfo.json \
&& rm -rf node_modules/**/.github \ && rm -rf node_modules/**/.github \
&& rm -rf node_modules/**/docs \ && rm -rf node_modules/**/docs \
&& rm -rf node_modules/**/LICENSE \ && rm -rf node_modules/**/LICENSE \
&& rm -rf node_modules/**/license \
&& rm -rf node_modules/**/**.md \ && rm -rf node_modules/**/**.md \
&& rm -rf node_modules/**/**/LICENSE \
&& rm -rf node_modules/**/**/license \
&& rm -rf node_modules/**/**/.github \
&& rm -rf node_modules/**/**/**.md \
&& ln -s /config/channels.xml $(echo "${WORKDIR}/channels.xml") \ && ln -s /config/channels.xml $(echo "${WORKDIR}/channels.xml") \
&& mkdir /public && mkdir /public
COPY start.sh $WORKDIR COPY start.sh $WORKDIR
COPY serve.json $WORKDIR COPY serve.json $WORKDIR
COPY pm2.config.js $WORKDIR
RUN chmod +x "$START_SCRIPT" \ RUN chmod +x "$START_SCRIPT" \
&& apk del git curl \ && apk del git curl \
&& rm -rf /var/cache/apk/* && rm -rf /var/cache/apk/*
SHELL ["/bin/bash", "-c"] SHELL ["/bin/bash", "-c"]
ENTRYPOINT bash $START_SCRIPT chron-schedule="$CRON_SCHEDULE" work-dir="$WORKDIR" days="$DAYS" max_connections="$MAX_CONNECTIONS" enable_fixes="$ENABLE_FIXES" api_url="$API_URL" ENTRYPOINT bash $START_SCRIPT chron-schedule="$CRON_SCHEDULE" work-dir="$WORKDIR" days="$DAYS" delay=$DELAY max_connections="$MAX_CONNECTIONS" enable_fixes="$ENABLE_FIXES" api_url="$API_URL"
EXPOSE 3000 EXPOSE 3000
+169 -10
View File
@@ -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:21-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
@@ -38,13 +44,13 @@ If you have suggestions or a problem with them please submit an issue.
This the list of the provided custom fixes : 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.es | [fraudiay79](https://github.com/fraudiay79) and [davidclaeysquinones](https://github.com/davidclaeysquinones) | PR not submitted | | orangetv.orange.es | | |
| pickx.be | [davidclaeysquinones](https://github.com/davidclaeysquinones) and [BellezaEmporium](https://github.com/BellezaEmporium) | [PR](https://github.com/iptv-org/epg/pull/2480) pending approval | | 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) pending approval | | 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>
@@ -56,6 +62,7 @@ It is recommended that you take existing provider code as a base for your custom
|-------------------------------|----------------------------------------------------------------------------|----------------------------------| |-------------------------------|----------------------------------------------------------------------------|----------------------------------|
| CRON_SCHEDULE | CRON expression describing the recurrence for epg retrieval. | `0 0,12 * * *` | | CRON_SCHEDULE | CRON expression describing the recurrence for epg retrieval. | `0 0,12 * * *` |
| DAYS | Describes the desired amount of days in the future for for epg retrieval. | 14 | | DAYS | Describes the desired amount of days in the future for for epg retrieval. | 14 |
| DELAY | Delay between requests in milliseconds | 0 |
| MAX_CONNECTIONS | The maximum amount of parallel connections that can be established | 10 | | MAX_CONNECTIONS | The maximum amount of parallel connections that can be established | 10 |
| ENABLE_FIXES | Some fixes to providers take a long time to be merged into the main branch.<br>When this option is enabled some of these fixes will also be included.<br>The source code for these fixes can be seen under the `fixes` folder.<br> Recreate the container when changing this variable in order for it to take effect | false | | ENABLE_FIXES | Some fixes to providers take a long time to be merged into the main branch.<br>When this option is enabled some of these fixes will also be included.<br>The source code for these fixes can be seen under the `fixes` folder.<br> Recreate the container when changing this variable in order for it to take effect | false |
| API_URL | The endpoint where channel information will be grabbed | `https://iptv-org.github.io/api` | | API_URL | The endpoint where channel information will be grabbed | `https://iptv-org.github.io/api` |
@@ -135,4 +142,156 @@ Sometimes a new version of this image will be bound to the same source commit. T
- 1.0.21 - 1.0.21
[11-28-2024](https://github.com/iptv-org/epg/commit/da18b70ddb1c3950e5a315411fd9aeaf60b6092c)<br>Add orangetv.es [11-28-2024](https://github.com/iptv-org/epg/commit/da18b70ddb1c3950e5a315411fd9aeaf60b6092c)<br>Add orangetv.es
- 1.0.22 - 1.0.22
[11-30-2024](https://github.com/iptv-org/epg/commit/1883338c0aee9909ac4567312b25701d10a765f2) [11-30-2024](https://github.com/iptv-org/epg/commit/1883338c0aee9909ac4567312b25701d10a765f2)
- 1.0.23
[12-02-2024](https://github.com/iptv-org/epg/commit/296d6162ecbeb1b3c3e392845187d30624d50aa2)
- 1.0.24
[12-02-2024](https://github.com/iptv-org/epg/commit/296d6162ecbeb1b3c3e392845187d30624d50aa2)<br>Fix for movistarplus.es channel grabber
- 1.0.25
[12-04-2024](https://github.com/iptv-org/epg/commit/864e0ac2c4761d926b203a85a382a4bdc87fbc17)
- 1.0.26
[12-05-2024](https://github.com/iptv-org/epg/commit/581441834af6f089c3930ad2d7ff1de2c701a6d9)
- 1.0.27
[12-07-2024](https://github.com/iptv-org/epg/commit/ce4f3e69358385d1fb8e79df8129c63d6314a802)
- 1.0.28
[12-08-2024](https://github.com/iptv-org/epg/commit/f9c8fc1b2dd63465564aba0c720096574980c58f)
- 1.0.29
[12-11-2024](https://github.com/iptv-org/epg/commit/581f5e0ca94bd6d05c33f53951df078d702b2510)
- 1.0.30
[12-16-2024](https://github.com/iptv-org/epg/commit/b9bbd32d354315eb292e3b82da09785e575a9781)
- 1.0.31
[12-17-2024](https://github.com/iptv-org/epg/commit/7237a62d94c5691f7f467b334f846efce93b08ff)<br>Fix for Pickx.be + mayor program updates
- 1.0.32
[12-20-2024](https://github.com/iptv-org/epg/commit/f00d53cb7be3cd7f6625897709cab005fe1b3dc4)
- 1.0.33
[12-21-2024](https://github.com/iptv-org/epg/commit/c108aa586e25d2e8914baeca6c05cc6755718665)
- 1.0.34
[12-27-2024](https://github.com/iptv-org/epg/commit/141fc210c4b7109e8ba09299d4f49c451ae0db4e)
- 1.0.35
[12-31-2024 06:25](https://github.com/iptv-org/epg/commit/7e7efaa48717d6b96f6d05aa9cf73271750d788b)
- 1.0.36
[12-31-2024 17:32](https://github.com/iptv-org/epg/commit/5ffe285c1e5882e905c5aaee672849f6f89e5cf3)
- 1.0.37
[01-09-2025](https://github.com/iptv-org/epg/commit/8e39af2a4d7c15f442a3e686144278e97151d46e)
- 1.0.38
[01-13-2025](https://github.com/iptv-org/epg/commit/9a565f16f4016e49d17b762477e0f6d29bb0f970)
- 1.0.39
[01-14-2025](https://github.com/iptv-org/epg/commit/76df1541d8b0b90533ea74dcbb7815c27425b608)
- 1.0.40
[01-14-2025](https://github.com/iptv-org/epg/commit/76df1541d8b0b90533ea74dcbb7815c27425b608)<br> Fixes issue with api url
- 1.0.41
[01-15-2025](https://github.com/iptv-org/epg/commit/65331dff1c6728c3012e314e51d40da85d2d7f3c)
- 1.0.42
[01-15-2025](https://github.com/iptv-org/epg/commit/5958c77c65a652285da64ad8a77d137306ca46d7)
- 1.0.43
[01-20-2025](https://github.com/iptv-org/epg/commit/7b2cfba7f5d4df8c01ff74a7c26d7695cb750244)
- 1.0.44
[01-21-2025](https://github.com/iptv-org/epg/commit/b69d61af5e46cea4f7dcb15a00d897397c23defa)
- 1.0.45
[01-23-2025](https://github.com/iptv-org/epg/commit/bc4b7fcfd51325cc597ccce13821f355dd0fbc72)
- 1.0.46
[01-27-2025](https://github.com/iptv-org/epg/commit/a45a346ec83cae3863b8d0e1cbe7abd99d6fef36)
- 1.0.47
[01-29-2025](https://github.com/iptv-org/epg/commit/106ae083d243df825958dcf4fea1d48d2765cf72)
- 1.0.48
[01-30-2025](https://github.com/iptv-org/epg/commit/e57dfaff41f498ffbfe79ecadd37f7f254dad0cc)
- 1.0.49
[02-02-2025](https://github.com/iptv-org/epg/commit/6b45cd9bd60058fdb7b974ad610c2d6565317f3b)
- 1.0.50
[02-05-2025](https://github.com/iptv-org/epg/commit/7f6849869f7182ddfa1a01b08a160ff8d2129441)
- 1.0.51
[02-11-2025](https://github.com/iptv-org/epg/commit/6cbe64f2dde47a3eb042cac35932989a7eefb2db)
- 1.0.52
[02-18-2025](https://github.com/iptv-org/epg/commit/39c4c5143e7cf7591ac49227e73e564be70c7615)
- 1.0.53
[02-23-2025](https://github.com/iptv-org/epg/commit/2721fe1ba06761fd06799a233dda27af6184fd17)
- 1.0.54
[03-07-2025](https://github.com/iptv-org/epg/commit/40c9af82d6f7f4e562cd239237fdf46a396d5728)
- 1.0.55
[03-11-2025](https://github.com/iptv-org/epg/commit/40c9af82d6f7f4e562cd239237fdf46a396d5728)
- 1.0.56
[03-16-2025](https://github.com/iptv-org/epg/commit/cf82b4089ef00c1fc94b7751652bfa598f8ab06a)
- 1.0.57
[03-25-2025](https://github.com/iptv-org/epg/commit/138842009bb3f9135430cdc667502ffa51d4a295)
- 1.0.58
[04-04-2025](https://github.com/iptv-org/epg/commit/4df25c92bcad1e4892640f532eae71cf9f5e7b95)
- 1.0.59
[04-04-2025](https://github.com/iptv-org/epg/commit/4df25c92bcad1e4892640f532eae71cf9f5e7b95)<br>Includes fixes for new configuration changes
- 1.0.60
[04-07-2025](https://github.com/iptv-org/epg/commit/7e1fbcbe154f4efd5c81341351cceb06f71b79a0)
- 1.0.61
[04-07-2025](https://github.com/iptv-org/epg/commit/7e1fbcbe154f4efd5c81341351cceb06f71b79a0)<br>Add delay option
- 1.0.62
[04-22-2025](https://github.com/iptv-org/epg/commit/db56a4d6c0ec7f1169ae60361b623dc032365e47)
- 1.0.63
[05-10-2025](https://github.com/iptv-org/epg/commit/db56a4d6c0ec7f1169ae60361b623dc032365e47)
- 1.0.64
[06-02-2025](https://github.com/iptv-org/epg/commit/cb7e91d3938804618625e381a7fd139e11dfa380)
- 1.0.65
[06-16-2025](https://github.com/iptv-org/epg/commit/e0fdf221e2d2707fe7a9d06a4c2797672888c0eb)
- 1.0.66
[06-26-2025](https://github.com/iptv-org/epg/commit/93f857f3c36cbe00e76fceb4ad875d8e6f6ec6aa)
- 1.0.67
[07-07-2025](https://github.com/iptv-org/epg/commit/3107571168eea356e6fa6311519e3777db99b5a6)
- 1.0.68
[07-14-2025](https://github.com/iptv-org/epg/commit/10685b064d9cc65c1a22234a19527da53d544cbf)
- 1.0.69
[09-21-2025](https://github.com/iptv-org/epg/commit/69774a7e6a2c752d769ad5dfdc41b3fe4baeace1)
- 1.0.70
[10-07-2025](https://github.com/iptv-org/epg/commit/eebfcc8278dc31e9ef17ebbd298d4af061cdc23f)
- 1.0.71
[11-15-2025](https://github.com/iptv-org/epg/commit/4ed1e39d95da18d54628525f9173b7b7f7ae1d21)
- 1.0.72
[11-23-2025](https://github.com/iptv-org/epg/commit/9b331e6cfab19ad2f683b212aa079aac07fe72fe)
- 1.0.73
[12-24-2025](https://github.com/iptv-org/epg/commit/ba1fb58194464a6c50a597ac28a35dc8a4895038)
- 1.0.74
[01-06-2026](https://github.com/iptv-org/epg/commit/cbe17252ca7ef70780600952cf97790f352c8c15)
- 1.0.75
[02-07-2026](https://github.com/iptv-org/epg/commit/c1b3ef5a0e22979ffe06e4e688366eadc05b8537)
- 1.0.76
[02-10-2026](https://github.com/iptv-org/epg/commit/de08d7df85184bb6418cabf56501a9faed2889be)
- 1.0.77
[02-18-2026](https://github.com/iptv-org/epg/commit/a1168b74f5d51a26fdf51129c9af7a296f04b9f6)
- 1.0.78
[02-23-2026](https://github.com/iptv-org/epg/commit/e4f92bb2a2768dcba3dbbd52b19d78d96bebc31e)
<br>Updates custom fixes to latest code
<br>Includes fix for pickx.be provider
- 1.0.79
[03-16-2026](https://github.com/iptv-org/epg/commit/d10c95f326b8c36798c47e63bfd28ec0f116f974)
- 1.0.80
[03-23-2026](https://github.com/iptv-org/epg/commit/9d6339bf0f22444fa8967f0a5b2af64d13a7cdc3)
- 1.0.81
[04-01-2026](https://github.com/iptv-org/epg/commit/03250d4a07eae90200d9e0af6962776e91d7a0c1)
- 1.0.82
[04-13-2026](https://github.com/iptv-org/epg/commit/d27160fd2b8f0509e76de0463aa5f6466c832095)
- 1.0.83
[04-17-2026](https://github.com/iptv-org/epg/commit/ce691529a58dbf9d4776563aea6dec8cd0914c06)
- 1.0.84
[05-19-2026](https://github.com/iptv-org/epg/commit/157e77c50b08aa587e126095cedc330716d78fa0)
- 1.0.85
[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.0.95
[10-26-2026](https://github.com/iptv-org/epg/commit/2c3e24fdab86140181878af00e01e9b440962d9b)
<br> Solves issue in Telenet.TV custom fix
- 1.0.96
[10-29-2026](https://github.com/iptv-org/epg/commit/ae9cc64f9497c602ec2f6e17857ae38b3aa1ff05)
+2 -1
View File
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<channels> <channels>
<!--This is a sample of a channel you can add look at https://github.com/iptv-org/epg/tree/master/sites for the complete list--> <!--This is a sample of a channel you can add look at https://github.com/iptv-org/epg/tree/master/sites for the complete list-->
<channel site="movistarplus.es" lang="es" xmltv_id="24Horas.es" site_id="24H">24 Horas</channel> <channel site="pickx.be" lang="nl" xmltv_id="Een.be" site_id="UID50037">VRT 1</channel>
<!--<channel site="movistarplus.es" lang="es" xmltv_id="24Horas.es" site_id="24H">24 Horas</channel>-->
</channels> </channels>
+97 -55
View File
@@ -1,78 +1,120 @@
const { DateTime } = require('luxon') //https://github.com/iptv-org/epg/blob/master/sites/movistarplus.es/movistarplus.es.config.js
const API_PROGRAM_ENDPOINT = 'https://comunicacion.movistarplus.es' const axios = require('axios')
const API_IMAGE_ENDPOINT = 'https://www.movistarplus.es/recorte/n/externov'; const dayjs = require('dayjs')
const timezone = require('dayjs/plugin/timezone')
const utc = require('dayjs/plugin/utc')
dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.tz.setDefault('Europe/Madrid')
module.exports = { module.exports = {
site: 'movistarplus.es', site: 'movistarplus.es',
days: 2, days: 2,
url: function ({ channel, date }) { url({ channel, date }) {
return `${API_PROGRAM_ENDPOINT}/wp-admin/admin-ajax.php` 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: {
method: 'POST',
headers: { headers: {
Origin: API_PROGRAM_ENDPOINT, 'User-Agent':
Referer: `${API_PROGRAM_ENDPOINT}/programacion/`, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
"Content-Type" : 'application/x-www-form-urlencoded; charset=UTF-8', Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
}, 'Accept-Language': 'es-ES,es;q=0.9,en;q=0.8',
data: function ({ channel, date }) { Referer: 'https://www.movistarplus.es/programacion-tv'
return {
action: 'getProgramation',
day: date.format('YYYY-MM-DD'),
"channels[]": channel.site_id,
};
}, },
maxRedirects: 5
}, },
parser({ content, channel, date }) { async parser({ content }) {
let programs = [] let programs = []
let items = parseItems(content, channel); let items = await parseItems(content)
if (!items.length) return programs; if (!items.length) return programs
items.forEach(item => {
let startTime = DateTime.fromFormat(
`${item.f_evento_rejilla}`,
'yyyy-MM-dd HH:mm:ss',
{ zone: 'Europe/Madrid' }
).toUTC();
let stopTime = DateTime.fromFormat(
`${item.f_fin_evento_rejilla}`,
'yyyy-MM-dd HH:mm:ss',
{ zone: 'Europe/Madrid' }
).toUTC()
// Adjust stop time if it's on the next day
if (stopTime < startTime) {
stopTime = stopTime.plus({ days: 1 });
}
items.forEach(el => {
programs.push({ programs.push({
title: item.des_evento_rejilla, title: el.title,
icon: parseIcon(item, channel), description: el.description,
category: item.des_genero, icon: el.icon,
start: startTime, images: el.images,
stop: stopTime, season: el.season,
episode: el.episode,
start: el.start,
stop: el.stop
}) })
}) })
return programs return programs
}, },
} async channels() {
const json = await axios
.get(
'https://ottcache.dof6.com/movistarplus/webplayer/OTT/contents/channels?mdrm=true&tlsstream=true&demarcation=18&version=8'
)
.then(r => r.data)
.catch(console.log)
function parseIcon(item, channel) { // Load JSON, CodCadenaTv is the closest to the old MVSTR site ch. ID
if(item.cod_elemento_emision) return json.map(channel => {
{ return {
return `${API_IMAGE_ENDPOINT}/M${channel.site_id}P${item.cod_elemento_emision}` lang: 'es',
site_id: channel.CodCadenaTv,
name: channel.Nombre,
logo: channel.Logo || channel.Logos?.[0]?.uri || null
}
})
} }
return ''
} }
function parseItems(content, channel) { function parseImages(images) {
const json = typeof content === 'string' ? JSON.parse(content) : content; return images.filter(image => image.id === 'watch2tgr-end').map(image => image.uri)
const data = json.channelsProgram; }
if (data.length !== 1) return []; async function parseItems(content) {
return data[0]; 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
}
}
}
})
)
} catch {
return []
}
} }
-172
View File
@@ -1,172 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel site="orangetv.es" lang="es" xmltv_id="La1.es" site_id="1010">LA 1 HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="La2.es" site_id="1062">La 2 HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="24Horas.es" site_id="12051">24h horas</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Teledeporte.es" site_id="1063">TDP HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Clan.es" site_id="1064">Clan HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Antena3.es" site_id="1011">Antena 3 HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Cuatro.es" site_id="1012">Cuatro HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Telecinco.es" site_id="1013">Telecinco HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LaSexta.es" site_id="1014">laSexta HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Selekt.es" site_id="11045">SELEKT</channel>
<channel site="orangetv.es" lang="es" xmltv_id="StarChannelSpain.es" site_id="11001">STAR Channel</channel>
<channel site="orangetv.es" lang="es" xmltv_id="AMC.es" site_id="11011">AMC</channel>
<channel site="orangetv.es" lang="es" xmltv_id="AMCBreak.es" site_id="11009">AMC Break</channel>
<channel site="orangetv.es" lang="es" xmltv_id="AMCCrime.es" site_id="11042">AMC CRIME</channel>
<channel site="orangetv.es" lang="es" xmltv_id="WarnerTV.es" site_id="11007">Warner TV</channel>
<channel site="orangetv.es" lang="es" xmltv_id="AXN.es" site_id="11002">AXN</channel>
<channel site="orangetv.es" lang="es" xmltv_id="ComedyCentral.es" site_id="11005">Comedy Central</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Calle13Universal.es" site_id="11003">Calle 13</channel>
<channel site="orangetv.es" lang="es" xmltv_id="XTRM.es" site_id="12057">XTRM</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Syfy.es" site_id="11004">SYFY</channel>
<channel site="orangetv.es" lang="es" xmltv_id="COSMO.es" site_id="11006">Cosmo</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Enfamilia.es" site_id="11063">Enfamilia</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Decasa.es" site_id="11027">Decasa</channel>
<channel site="orangetv.es" lang="es" xmltv_id="CanalCocina.es" site_id="11020">CanalCocina</channel>
<channel site="orangetv.es" lang="es" xmltv_id="RuntimeSeries.es" site_id="11093">Runtime Series</channel>
<channel site="orangetv.es" lang="es" xmltv_id="FactoriadeFiccion.es" site_id="1032">FDF</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Neox.es" site_id="1027">Neox</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Energy.es" site_id="1030">Energy</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Atreseries.es" site_id="1042">Atreseries</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Divinity.es" site_id="1034">Divinity</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Nova.es" site_id="1028">Nova</channel>
<channel site="orangetv.es" lang="es" xmltv_id="CanalHollywood.es" site_id="11010">Canal Hollywood</channel>
<channel site="orangetv.es" lang="es" xmltv_id="AXNMovies.es" site_id="11008">AXN Movies</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Somos.es" site_id="11029">Somos</channel>
<channel site="orangetv.es" lang="es" xmltv_id="TCM.es" site_id="11012">TCM</channel>
<channel site="orangetv.es" lang="es" xmltv_id="SundanceTV.es" site_id="11052">Sundance TV</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Dark.es" site_id="11053">Dark</channel>
<channel site="orangetv.es" lang="es" xmltv_id="RuntimeCineSeries.es" site_id="1089">Runtime Cine y Series</channel>
<channel site="orangetv.es" lang="es" xmltv_id="RuntimeCineTerror.es" site_id="11091">Runtime Thriller/Terror</channel>
<channel site="orangetv.es" lang="es" xmltv_id="RuntimeAccion.es" site_id="11094">Runtime Acción</channel>
<channel site="orangetv.es" lang="es" xmltv_id="RuntimeComedia.es" site_id="11092">Runtime Comedia</channel>
<channel site="orangetv.es" lang="es" xmltv_id="RuntimeCrimen.es" site_id="11095">Runtime Crimen</channel>
<channel site="orangetv.es" lang="es" xmltv_id="RuntimeRomance.es" site_id="11096">Runtime Romance</channel>
<channel site="orangetv.es" lang="es" xmltv_id="RunTimeClasico.es" site_id="11097">RunTime Clásico</channel>
<channel site="orangetv.es" lang="es" xmltv_id="CinesVerdiTV.es" site_id="11098">Cines Verdi TV</channel>
<channel site="orangetv.es" lang="es" xmltv_id="CineFeelGood.es" site_id="11099">Cine Feel Good</channel>
<channel site="orangetv.es" lang="es" xmltv_id="ParamountNetwork.es" site_id="12032">Paramount Network</channel>
<channel site="orangetv.es" lang="es" xmltv_id="DreamWorksChannel.es" site_id="1085">Dreamworks</channel>
<channel site="orangetv.es" lang="es" xmltv_id="BomCine.es" site_id="2063">Bom Cine</channel>
<channel site="orangetv.es" lang="es" xmltv_id="DKISS.es" site_id="1044">DKISS</channel>
<channel site="orangetv.es" lang="es" xmltv_id="TEN.es" site_id="12054">Ten</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Odisea.es" site_id="11018">Odisea</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Mega.es" site_id="1016">Mega</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Trece.es" site_id="1017">TR3CE</channel>
<channel site="orangetv.es" lang="es" xmltv_id="DMAX.es" site_id="1018">DMAX</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LaOtra.es" site_id="2061">La otra HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Boing.es" site_id="1021">Boing</channel>
<channel site="orangetv.es" lang="es" xmltv_id="ToonGogglesenEspanol.us" site_id="11100">Toon Goggles</channel>
<channel site="orangetv.es" lang="es" xmltv_id="NickJr.es" site_id="11055">Nick JR</channel>
<channel site="orangetv.es" lang="es" xmltv_id="DisneyJunior.es" site_id="11015">Disney Junior</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Nickelodeon.es" site_id="11016">Nick</channel>
<channel site="orangetv.es" lang="es" xmltv_id="BeMad.es" site_id="1043">Be Mad TV</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Historia.es" site_id="11019">Canal Historia</channel>
<channel site="orangetv.es" lang="es" xmltv_id="NationalGeographic.es" site_id="11017">National Geographic</channel>
<channel site="orangetv.es" lang="es" xmltv_id="NationalGeographicWild.es" site_id="1008">NatGeo Wild</channel>
<channel site="orangetv.es" lang="es" xmltv_id="DiscoveryChannel.es" site_id="1039">Discovery</channel>
<channel site="orangetv.es" lang="es" xmltv_id="NatureTime.es" site_id="1084">NatureTime</channel>
<channel site="orangetv.es" lang="es" xmltv_id="La7.es" site_id="2011">7RM HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LevanteTV.es" site_id="2070">Levante TV</channel>
<channel site="orangetv.es" lang="es" xmltv_id="CanalSur.es" site_id="1035">Canal Sur</channel>
<channel site="orangetv.es" lang="es" xmltv_id="CanalSur2.es" site_id="2022">CanalSur 2</channel>
<channel site="orangetv.es" lang="es" xmltv_id="CanalSurAndalucia.es" site_id="2031">Andalucía TV</channel>
<channel site="orangetv.es" lang="es" xmltv_id="7TVAndalucia.e" site_id="2065">7 TV Andalucia</channel>
<channel site="orangetv.es" lang="es" xmltv_id="TV3.es" site_id="2008">TV3 HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="TV3CAT.es" site_id="1036">TV3CAT</channel>
<channel site="orangetv.es" lang="es" xmltv_id="324.es" site_id="2050">3/24</channel>
<channel site="orangetv.es" lang="es" xmltv_id="" site_id="2067">TV Castellon</channel>
<channel site="orangetv.es" lang="es" xmltv_id="La8Mediterraneo.es" site_id="2062">8 Mediterraneo</channel>
<channel site="orangetv.es" lang="es" xmltv_id="APunt.es" site_id="2057">A punt HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="IB3.es" site_id="2013">IB3 HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="TelevisionCanaria.es" site_id="2059">RTV Canaria HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="ETB1.es" site_id="2014">ETB1 HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="ETB2.es" site_id="1037">ETB2 HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="ETB3.es" site_id="2032">ETB3</channel>
<channel site="orangetv.es" lang="es" xmltv_id="ETB4.es" site_id="2037">ETB4</channel>
<channel site="orangetv.es" lang="es" xmltv_id="ETBBasque.es" site_id="1037">ETB Basque</channel>
<channel site="orangetv.es" lang="es" xmltv_id="GaliciaTVEuropa.es" site_id="2052">TVG HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="TVG2.es" site_id="2053">TVG2 HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="TPA7.es" site_id="2009">TPA HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="TeleVigo.es" site_id="2068">Televigo</channel>
<channel site="orangetv.es" lang="es" xmltv_id="GaliciaTVEuropa.es" site_id="1038">Galicia TV</channel>
<channel site="orangetv.es" lang="es" xmltv_id="CeutaTV.es" site_id="2002">TV Ceuta</channel>
<channel site="orangetv.es" lang="es" xmltv_id="TVR.es" site_id="2055">TVR HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="NavarraTV.es" site_id="2060">Navarra TV HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="" site_id="2029">Navarra TV2</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Telemadrid.es" site_id="12050">Telemadrid HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="RealMadridTV.es" site_id="12052">Real Madrid</channel>
<channel site="orangetv.es" lang="es" xmltv_id="SevillaFCTV.es" site_id="2081">SEVILLA FC Televisión</channel>
<channel site="orangetv.es" lang="es" xmltv_id="BetisTV.es" site_id="1019">Betis TV</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeonesporMovistarPlusPlus.es" site_id="1023">M+ Liga de Campeones</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeones1porMovistarPlusPlus.es" site_id="1050">M+ Liga de Campeones 2</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeones2porMovistarPlusPlus.es" site_id="1051">M+ Liga de Campeones 3</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeones3porMovistarPlusPlus.es" site_id="1052">M+ Liga de Campeones 4</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeones4porMovistarPlusPlus.es" site_id="1053">M+ Liga de Campeones 5</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeones5porMovistarPlusPlus.es" site_id="1054">M+ Liga de Campeones 6</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeones6porMovistarPlusPlus.es" site_id="1055">M+ Liga de Campeones 7</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeones7porMovistarPlusPlus.es" site_id="1056">M+ Liga de Campeones 8</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeones8porMovistarPlusPlus.es" site_id="11036">M+ Liga de Campeones 9</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeones9porMovistarPlusPlus.es" site_id="1096">M+ Liga de Campeones 10</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeones10porMovistarPlusPlus.es" site_id="1097">M+ Liga de Campeones 11</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeones11porMovistarPlusPlus.es" site_id="1098">M+ Liga de Campeones 12</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeones12porMovistarPlusPlus.es" site_id="1099">M+ Liga de Campeones 13</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeones13porMovistarPlusPlus.es" site_id="11065">M+ Liga de Campeones 14</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeones14porMovistarPlusPlus.es" site_id="11066">M+ Liga de Campeones 15</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeones15porMovistarPlusPlus.es" site_id="11067">M+ Liga de Campeones 16</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LigadeCampeones16porMovistarPlusPlus.es" site_id="11068">M+ Liga de Campeones 17</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LaLigaTVUHDporMovistarPlusPlus.es" site_id="11043">M LALIGA TV UHD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LaLigaTVporMovistarPlusPlus.es" site_id="11013">M+ LALIGA TV</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LaLiga1porMovistarPlusPlus.es" site_id="11026">M+ LALIGA TV 2</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LaLigaTV2porMovistarPlusPlus.es" site_id="1057">M+ LALIGATV 3</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LaLigaTV3porMovistarPlusPlus.es" site_id="1058">M+ LALIGATV 4</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LaLigaTV.es" site_id="11129">LA LIGA TV</channel>
<channel site="orangetv.es" lang="es" xmltv_id="DAZNLaLiga" site_id="11077">DAZN LALIGA</channel>
<channel site="orangetv.es" lang="es" xmltv_id="DAZNLaLiga2" site_id="11080">DAZN LALIGA 2</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LaLigaHypermotion.es" site_id="11083">LALIGATV HYPERMOTION</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LaLigaHypermotion2.es" site_id="11084">LALIGATV HYPERMOTION 2</channel>
<channel site="orangetv.es" lang="es" xmltv_id="LaLigaHypermotion3.es" site_id="11085">LALIGATV HYPERMOTION 3</channel>
<channel site="orangetv.es" lang="es" xmltv_id="GOLPLAY.es" site_id="11031">GOL PLAY</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Mezzo.fr" site_id="1031">Mezzo HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="MTV00s.uk" site_id="1026">MTV 00s</channel>
<channel site="orangetv.es" lang="es" xmltv_id="HITTV.es" site_id="2046">HIT TV</channel>
<channel site="orangetv.es" lang="es" xmltv_id="MTV.es" site_id="11050">MTV España</channel>
<channel site="orangetv.es" lang="es" xmltv_id="MTVLive.us" site_id="11051">MTV Live</channel>
<channel site="orangetv.es" lang="es" xmltv_id="SolMusica.es" site_id="11119">Sol Música</channel>
<channel site="orangetv.es" lang="es" xmltv_id="StingrayClassica.ca" site_id="12003">Classica HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="StingrayFestival4K.ca" site_id="11060">Festival 4K</channel>
<channel site="orangetv.es" lang="es" xmltv_id="StingrayDJAZZ.ca" site_id="12004">Djazz</channel>
<channel site="orangetv.es" lang="es" xmltv_id="StingrayiConcerts.ca" site_id="12002">iConcerts</channel>
<channel site="orangetv.es" lang="es" xmltv_id="MezzoLive.fr" site_id="12005">MezzoLiveHD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="TraceLatina.fr" site_id="11106">TRACE Latina</channel>
<channel site="orangetv.es" lang="es" xmltv_id="TraceUrban.fr" site_id="11107">TRACE Urban</channel>
<channel site="orangetv.es" lang="es" xmltv_id="CaracolTV.co" site_id="1029">Caracol TV</channel>
<channel site="orangetv.es" lang="es" xmltv_id="EWTNEspanaLatinAmerica.us" site_id="1068">EWTN</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Gulli.fr" site_id="1077">Gulli</channel>
<channel site="orangetv.es" lang="es" xmltv_id="France2.fr" site_id="1082">France 2</channel>
<channel site="orangetv.es" lang="es" xmltv_id="France5" site_id="1083">France 5</channel>
<channel site="orangetv.es" lang="es" xmltv_id="TraceSportStars.fr" site_id="1095">Trace Sport Stars</channel>
<channel site="orangetv.es" lang="es" xmltv_id="TV5MondeEurope.fr" site_id="11023">TV5MONDE</channel>
<channel site="orangetv.es" lang="es" xmltv_id="QwestTV.fr" site_id="1088">Qwest TV</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Eurosport1.fr" site_id="11035">Eurosport 1</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Eurosport2.fr" site_id="11059">Eurosport 2</channel>
<channel site="orangetv.es" lang="es" xmltv_id="MyZenTV.fr" site_id="11070">Myzen TV</channel>
<channel site="orangetv.es" lang="es" xmltv_id="FightSports.us" site_id="12007">FightSports</channel>
<channel site="orangetv.es" lang="es" xmltv_id="FightBoxHD.nl" site_id="1091">Fight Box HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Gametoon.es" site_id="1086">Gametoon</channel>
<channel site="orangetv.es" lang="es" xmltv_id="EuronewsSpanish.fr" site_id="1090">Euronews</channel>
<channel site="orangetv.es" lang="es" xmltv_id="ElToroTV.es" site_id="11049">El Toro TV</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Motorvision.de" site_id="11105">Motorvision</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Esport3.es" site_id="2038">Esport3</channel>
<channel site="orangetv.es" lang="es" xmltv_id="BBCNewsEurope.uk" site_id="11021">BBC World HD</channel>
<channel site="orangetv.es" lang="es" xmltv_id="CNNInternationalEurope.us" site_id="11022">CNN</channel>
<channel site="orangetv.es" lang="es" xmltv_id="DWEspanol.de" site_id="11024">Deutsche Welle</channel>
<channel site="orangetv.es" lang="es" xmltv_id="AlJazeeraEnglish.qa" site_id="11025">Al Jazeera</channel>
<channel site="orangetv.es" lang="es" xmltv_id="PROTV.ba" site_id="11028">Pro TV</channel>
<channel site="orangetv.es" lang="es" xmltv_id="Ubeat.es" site_id="11061">Ubeat</channel>
<channel site="orangetv.es" lang="es" xmltv_id="OUTtv.ca" site_id="11072">OUTtv</channel>
<channel site="orangetv.es" lang="es" xmltv_id="BUENVIAJE.es" site_id="11112">¡BUENVIAJE!</channel>
<channel site="orangetv.es" lang="es" xmltv_id="TennisChannel.us" site_id="11120">Tennis Channel</channel>
<channel site="orangetv.es" lang="es" xmltv_id="NauticalChannel.it" site_id="11128">Nautical Channel</channel>
</channels>
-81
View File
@@ -1,81 +0,0 @@
// credit for this fix goes to fraudiay79 and to davidclaeysquinones for their work
// the PR is not submitted since the test suite for this provider needs to be developed
// for now the source code can be found at https://github.com/davidclaeysquinones/epg/tree/orangetv.orange.es
const dayjs = require('dayjs')
const API_PROGRAM_ENDPOINT = 'https://epg.orangetv.orange.es/epg/Smartphone_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'
module.exports = {
site: 'orangetv.es',
days: 2,
request: {
cache: {
ttl: 60 * 60 * 1000 // 1 hour
}
},
url({ date }) {
return `${API_PROGRAM_ENDPOINT}/${date.format('YYYYMMDD')}_8h_1.json`
},
parser: function ({ content, channel }) {
let programs = []
const items = parseItems(content, channel)
items.forEach(item => {
programs.push({
title: item.name,
description: item.description,
season: item.seriesSeason || null,
episode: item.episodeId || null,
icon: parseIcon(item),
start: dayjs.utc(item.startDate) || null,
stop: dayjs.utc(item.endDate) || null,
})
})
return programs
},
async channels() {
const axios = require('axios')
const data = await axios
.get(API_CHANNEL_ENDPOINT)
.then(r => r.data)
.catch(console.log)
return data.response.map(item => {
return {
lang: 'es',
name: item.name,
site_id: item.externalChannelId
}
})
}
}
function parseIcon(item){
if(item.attachments.length > 0){
const cover = item.attachments.find(i => i.name === "COVER" || i.name === "cover")
if(cover)
{
return `${API_IMAGE_ENDPOINT}${cover.value}`;
}
}
return ''
}
function parseItems(content, channel) {
const json = typeof content === 'string' ? JSON.parse(content) : content
const channelData = json.find(i => i.channelExternalId == channel.site_id);
if(!channelData)
return [];
return channelData.programs;
}
@@ -0,0 +1,121 @@
//https://github.com/iptv-org/epg/blob/master/sites/orangetv.orange.es/orangetv.orange.es.config.js
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const doFetch = require('@ntlab/sfetch')
const debug = require('debug')('site:orangetv.orange.es')
dayjs.extend(utc)
doFetch.setDebugger(debug)
const API_PROGRAM_ENDPOINT = 'https://epg.orangetv.orange.es/epg/SmartTV_Android/1_PRO'
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 = {
site: 'orangetv.orange.es',
days: 2,
request: {
cache: {
ttl: 24 * 60 * 60 * 1000 // 1 day
},
headers: {
'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({ date }) {
return segmentUrl(date)
},
async parser({ content, channel, date }) {
const programs = []
const items = parseItems(content, channel)
const queues = []
// fetch other segments or use cache if exist
for (let i = 2; i <= 3; i++) {
const url = segmentUrl(date, i)
if (caches[url] !== undefined) {
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))
})
}
if (items.length) {
programs.push(
...items.map(item => {
return {
title: item.name,
sub_title: item.seriesName,
description: item.description,
category: parseGenres(item),
season: item.seriesSeason ? parseInt(item.seriesSeason) : null,
episode: item.episodeId ? parseInt(item.episodeId) : null,
icon: parseIcon(item),
start: dayjs.utc(item.startDate),
stop: dayjs.utc(item.endDate)
}
})
)
}
return programs
},
async channels() {
const axios = require('axios')
const data = await axios
.get(API_CHANNEL_ENDPOINT)
.then(r => r.data)
.catch(console.error)
return data.response.map(item => {
return {
lang: 'es',
name: item.name,
site_id: item.externalChannelId
}
})
}
}
function segmentUrl(date, segment = 1) {
return `${API_PROGRAM_ENDPOINT}/${date.format('YYYYMMDD')}_8h_${segment}.json`
}
function parseIcon(item) {
if (item.attachments.length) {
const cover = item.attachments.find(i => i.name.match(/cover/i))
if (cover) {
return `${API_IMAGE_ENDPOINT}${cover.value}`
}
}
}
function parseGenres(item) {
return item.genres.map(i => i.name)
}
function parseItems(content, channel) {
const result = []
const json =
typeof content === 'string' ? JSON.parse(content) : Array.isArray(content) ? content : []
if (Array.isArray(json)) {
json
.filter(i => String(i.channelExternalId) === String(channel.site_id))
.forEach(i => {
result.push(...i.programs)
})
}
return result
}
+412
View File
@@ -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&apos;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>
+127 -174
View File
@@ -1,197 +1,150 @@
// credit for this fix goes to davidclaeysquinones for his PR on https://github.com/iptv-org/epg/pull/2430 and to BellezaEmporium for his PR on https://github.com/iptv-org/epg/pull/2480
const axios = require('axios') const axios = require('axios')
const dayjs = require('dayjs') const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc') const utc = require('dayjs/plugin/utc')
const timezone = require('dayjs/plugin/timezone')
let apiVersion
let isApiVersionFetched = false
;(async () => {
try {
await fetchApiVersion()
isApiVersionFetched = true
} catch (error) {
console.error('Error during script initialization:', error)
}
})()
dayjs.extend(utc) 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,
apiVersion: function () {
return apiVersion
},
fetchApiVersion: fetchApiVersion, // Export fetchApiVersion
url: async function ({ channel, date }) {
while (!isApiVersionFetched) {
await new Promise(resolve => setTimeout(resolve, 100)) // Wait for 100 milliseconds
}
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({
title: item.program.title, programs.push({
sub_title: item.program.episodeTitle, title: data.title,
description: item.program.description, sub_title: data.episodeTitle,
category: item.program.translatedCategory?.[channel.lang] description: data.longDescription || data.shortDescription,
? item.program.translatedCategory[channel.lang] category: data.genres,
: item.program.category.split('.')[1], image: parseImage(data),
image: item.program.posterFileName season: data.season,
? `https://experience-cache.proximustv.be/posterserver/poster/EPG/w-166_h-110/${item.program.posterFileName}` episode: data.episodeNumber,
: null, actors: data.actors,
season: item.program.seasonNumber, director: data.directors,
episode: item.program.episodeNumber, date: data.year,
actors: item.program.actors, country: data.country,
director: item.program.director ? [item.program.director] : null, start: dayjs(data.airingStartTime),
start: dayjs.utc(item.programScheduleStart), stop: dayjs(data.airingEndTime)
stop: dayjs.utc(item.programScheduleEnd)
})
}) })
} })
return programs return programs
}, },
async channels({ lang = '' }) { async channels() {
const query = { const channels = []
operationName: 'getChannels',
variables: {
language: lang,
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
channelReferenceNumber
name
callLetter
number
logo {
key
url
__typename
}
language
hd
radio
replayable
ottReplayable
playable
ottPlayable
recordable
subscribed
cloudRecordable
catchUpWindowInHours
isOttNPVREnabled
ottNPVRStart
subscription {
channelRef
subscribed
upselling {
upsellable
packages
__typename
}
__typename
}
packages
__typename
}
}`
}
const result = await axios
.post('https://api.proximusmwc.be/tiams/v2/graphql', query)
.then(r => r.data)
.catch(console.error)
return ( for (let from = 1; ; from += CHANNELS_PER_PAGE) {
result?.data?.channels const data = await fetchChannels(from)
.filter( if (!data) break
channel =>
!channel.radio && (!lang || channel.language === (lang === 'de' ? 'ger' : lang))
)
.map(channel => {
return {
lang: channel.language === 'ger' ? 'de' : channel.language,
site_id: channel.id,
name: channel.name
}
}) || []
)
}
}
function fetchApiVersion() {
return new Promise(async (resolve, reject) => {
try {
// load pickx bundle and get react version hash (regex).
// it's not the best way to get the version but it's the only way to get it.
// find bundle version const items = data.containers || []
const minBundleVer = "https://www.pickx.be/minimal-bundle-version" items.forEach(item => {
const bundleVerData = await axios.get(minBundleVer, { const metadata = item.metadata
headers: { if (!metadata) return
Origin: 'https://www.pickx.be',
Referer: 'https://www.pickx.be/' channels.push({
} lang: LANGUAGES[metadata.channelLanguage] || 'fr',
site_id: String(metadata.channelId),
name: metadata.channelName
})
}) })
if (bundleVerData.status !== 200) { if (!items.length || channels.length >= data.total) break
console.error(`Failed to fetch bundle version. Status: ${bundleVerData.status}`)
reject(`Failed to fetch bundle version. Status: ${bundleVerData.status}`)
} else {
const bundleVer = bundleVerData.data.version
// get the minified JS app bundle
const bundleUrl = `https://components.pickx.be/pxReactPlayer/${bundleVer}/bundle.min.js`
// now, find the react hash inside the bundle URL
const bundle = await axios.get(bundleUrl).then(r => {
const re = /REACT_APP_VERSION_HASH:"([^"]+)"/
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-${bundle.replace('/REACT_APP_VERSION_HASH:"', '')}`
const response = await axios.get(versionUrl, {
headers: {
Origin: 'https://www.pickx.be',
Referer: 'https://www.pickx.be/'
}
})
if (response.status === 200) {
apiVersion = response.data.version
resolve()
} else {
console.error(`Failed to fetch API version. Status: ${response.status}`)
reject(`Failed to fetch API version. Status: ${response.status}`)
}
}
} catch (error) {
console.error('Error during fetchApiVersion:', error)
reject(error)
} }
})
} return channels
}
}
function basePath(lang) {
return BASE_PATH.replace('{locale}', LOCALES[lang] || LOCALES.nl)
}
function brusselsMidnight(date) {
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: {
Origin: 'https://tv.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 []
try {
const data = JSON.parse(content)
// the tray nests the programs of each requested channel under their own container
const channel = data?.resultObj?.containers?.[0]
return channel?.containers || []
} catch {
return []
}
}
+189 -66
View File
@@ -1,11 +1,20 @@
// credit for this fix goes to davidclaeysquinones for his PR on https://github.com/iptv-org/epg/pull/2429 //https://github.com/iptv-org/epg/blob/master/sites/telenet.tv/telenet.tv.config.js
const axios = require('axios') const axios = require('axios')
const dayjs = require('dayjs') const dayjs = require('dayjs')
const doFetch = require('@ntlab/sfetch')
const API_STATIC_ENDPOINT = 'https://static.spark.telenet.tv/eng/web/epg-service-lite/be' const API_STATIC_ENDPOINT = 'https://staticqbr-prod-be.gnp.cloud.telenet.tv/eng/web/epg-service-lite/be'
const API_PROD_ENDPOINT = 'https://spark-prod-be.gnp.cloud.telenet.tv/eng/web/linear-service/v2' const API_PROD_ENDPOINT = 'https://spark-prod-be.gnp.cloud.telenet.tv/eng/web/linear-service/v2'
const API_IMAGE_ENDPOINT = 'https://staticqbr-prod-be.gnp.cloud.telenet.tv/image-service'; const API_IMAGE_ENDPOINT = 'https://staticqbr-prod-be.gnp.cloud.telenet.tv/image-service'
// a segment holds 6 hours of guide for every channel at once, so it is kept around
// and shared between all the channels of the same day
const segments = {}
// which day emitted an event, per channel, so a broadcast running past midnight is not repeated
// by the day it ends in
const claimed = {}
module.exports = { module.exports = {
site: 'telenet.tv', site: 'telenet.tv',
@@ -15,68 +24,42 @@ module.exports = {
ttl: 60 * 60 * 1000 // 1 hour ttl: 60 * 60 * 1000 // 1 hour
} }
}, },
url: function ({ date, channel }) { url: function ({ date, channel, segment = 0 }) {
return `${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date.format('YYYYMMDDHHmmss')}` return `${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date.format(
'YYYYMMDD'
)}${segment.toString().padStart(2, '0')}0000`
}, },
async parser({ content, channel, date }) { async parser({ content, channel, date }) {
let programs = [] const items = await loadItems({ content, channel, date })
let items = parseItems(content, channel) if (!items.length) return []
if (!items.length) return programs
const promises = [
axios.get(
`${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date
.add(6, 'h')
.format('YYYYMMDDHHmmss')}`,
{
responseType: 'arraybuffer'
}
),
axios.get(
`${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date
.add(12, 'h')
.format('YYYYMMDDHHmmss')}`,
{
responseType: 'arraybuffer'
}
),
axios.get(
`${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date
.add(18, 'h')
.format('YYYYMMDDHHmmss')}`,
{
responseType: 'arraybuffer'
}
)
]
await Promise.allSettled(promises) const details = await loadProgramDetails(items, channel)
.then(results => {
results.forEach(r => {
if (r.status === 'fulfilled') {
const parsed = parseItems(r.value.data, channel)
items = items.concat(parsed) return items.map((item, index) => {
} const detail = details[index] || {}
})
})
.catch(console.error)
for (let item of items) { return {
const detail = await loadProgramDetails(item, channel)
programs.push({
title: item.title, title: item.title,
subTitle: detail.episodeName || item.seriesName,
icon: parseIcon(item), icon: parseIcon(item),
description: detail.longDescription, image: parseImage(item),
description: detail.longDescription || detail.shortDescription,
category: detail.genres, category: detail.genres,
actors: detail.actors, actors: detail.actors,
directors: detail.directors,
producers: detail.producers,
season: parseSeason(detail), season: parseSeason(detail),
episode: parseEpisode(detail), episode: parseEpisode(detail),
date: parseYear(detail),
country: detail.countryOfOrigin,
rating: parseRating(detail, item),
language: parseLanguages(detail, item),
subtitles: parseSubtitles(detail, item),
new: Boolean(detail.premiere || item.premiere),
start: parseStart(item), start: parseStart(item),
stop: parseStop(item) stop: parseStop(item)
}) }
} })
return programs
}, },
async channels() { async channels() {
const data = await axios const data = await axios
@@ -94,15 +77,63 @@ module.exports = {
} }
} }
async function loadProgramDetails(item, channel) { async function loadItems({ content, channel, date }) {
if (!item.id) return {} const urls = [0, 6, 12, 18].map(segment => module.exports.url({ date, channel, segment }))
const url = `${API_PROD_ENDPOINT}/replayEvent/${item.id}?returnLinearContent=true&language=${channel.lang}`
const data = await axios
.get(url)
.then(r => r.data)
.catch(console.log)
return data || {} // the first segment has already been downloaded by the grabber itself
cacheSegment(urls[0], content)
const missing = urls.filter(url => segments[url] === undefined)
if (missing.length) {
await doFetch(missing, (url, res) => cacheSegment(url, res))
}
const items = urls.flatMap(url => findEvents(segments[url], channel)).filter(isBroadcast)
// an event that spans a boundary is listed twice: by both segments, or by both days
return uniqueItems(items, channel, date)
}
// `res` is left out when a request fails, but only when sfetch is checking results, which is a
// setting shared with the other sites using it, so every program is built from its event first
async function loadProgramDetails(items, channel) {
const details = []
const queues = items
.map((item, index) => ({ item, index }))
.filter(({ item }) => item.id)
.map(({ item, index }) => ({
url: `${API_PROD_ENDPOINT}/replayEvent/${item.id}?returnLinearContent=true&language=${channel.lang}`,
index
}))
if (queues.length) {
await doFetch(queues, (queue, res) => {
if (res) details[queue.index] = res
})
}
return details
}
function cacheSegment(url, content) {
if (segments[url] !== undefined) return
const entries = parseEntries(content)
// a failed download must not be cached, the next channel gets to retry it
if (entries.length) segments[url] = entries
}
// the grabber hands over the raw response, while axios has already parsed the ones fetched here
function parseEntries(content) {
if (!content) return []
try {
const data = Array.isArray(content.entries) ? content : JSON.parse(content)
return Array.isArray(data.entries) ? data.entries : []
} catch (err) {
console.error(`Unable to parse guide: ${err.message}!`)
return []
}
} }
function parseStart(item) { function parseStart(item) {
@@ -113,16 +144,41 @@ function parseStop(item) {
return dayjs.unix(item.endTime) return dayjs.unix(item.endTime)
} }
function parseItems(content, channel) { // telenet fills the hours a channel is off air with "Geen uitzending", often several in a row.
if (!content) return [] // Nothing is behind them, so they are dropped and the guide simply has a hole there.
const data = JSON.parse(content) function isBroadcast(item) {
if (!data || !Array.isArray(data.entries)) return [] return !/^geen uitzending\b/i.test(item.title || '')
const channelData = data.entries.find(e => e.channelId === channel.site_id) }
function findEvents(entries, channel) {
if (!Array.isArray(entries)) return []
const channelData = entries.find(e => e.channelId === channel.site_id)
if (!channelData) return [] if (!channelData) return []
return Array.isArray(channelData.events) ? channelData.events : [] return Array.isArray(channelData.events) ? channelData.events : []
} }
// Both guards are needed: the local set drops an event listed by two segments of this day, while
// the claim drops one the previous day already emitted. Re-parsing a day it claimed itself stays
// idempotent, so parsing the same day twice keeps returning the same programs.
function uniqueItems(items, channel, date) {
const day = date.format('YYYYMMDD')
const claimedByChannel = claimed[channel.site_id] || (claimed[channel.site_id] = new Map())
const seen = new Set()
return items.filter(item => {
if (seen.has(item.id)) return false
const owner = claimedByChannel.get(item.id)
if (owner !== undefined && owner !== day) return false
seen.add(item.id)
claimedByChannel.set(item.id, day)
return true
})
}
function parseSeason(detail) { function parseSeason(detail) {
if (!detail.seasonNumber) return null if (!detail.seasonNumber) return null
if (String(detail.seasonNumber).length > 2) return null if (String(detail.seasonNumber).length > 2) return null
@@ -135,6 +191,73 @@ function parseEpisode(detail) {
return detail.episodeNumber return detail.episodeNumber
} }
function parseYear(detail) {
if (!detail.productionDate) return null
if (!/^\d{4}$/.test(String(detail.productionDate))) return null
return detail.productionDate
}
// the minimum age follows the Kijkwijzer (NICAM) classification
function parseRating(detail, item) {
const minimumAge = detail.minimumAge != null ? detail.minimumAge : item.minimumAge
if (minimumAge == null || minimumAge === '') {
if (detail.isAdult || item.isAdult) return { system: 'Kijkwijzer', value: '18' }
return null
}
return { system: 'Kijkwijzer', value: String(minimumAge) }
}
function parseLanguages(detail, item) {
return parseLangCodes(detail.audioLanguages || item.audioLanguages)
}
function parseSubtitles(detail, item) {
const captions = parseLangCodes(detail.captionLanguages || item.captionLanguages)
const signed = parseLangCodes(detail.signLanguages || item.signLanguages)
return [
...captions.map(language => ({ language })),
...signed.map(language => ({ type: 'deaf-signed', language }))
]
}
// the same language can be listed more than once, once per purpose (e.g. audio description)
function parseLangCodes(languages) {
if (!Array.isArray(languages)) return []
return [...new Set(languages.map(language => language.lang).filter(Boolean))]
}
// Three assets hang off one event id. Only the poster is always there: over a day of the guide,
// episodeStill answered for 91% of programmes and titleTreatment for 66%, and nothing in the event
// says which, so all three are emitted and a reader has to expect a 404.
//
// Poster first because the DTD asks for the most authoritative image first -- though Telenet's own
// player prefers the still, its bundle carrying the literal list ['episodeStill','posterTile'].
const IMAGE_INTENTS = [
// Key art cropped to 2:3, always from the season or the movie, never per episode.
{ intent: 'posterTile', type: 'poster', orient: 'P' },
// 16:9; a real production still for two thirds, season or show artwork for the rest. The app
// picks the landscape image on `type` alone, so dropping this one hides it there silently.
{ intent: 'episodeStill', type: 'still', orient: 'L' },
// A transparent wordmark, which is none of the DTD's five types, so `system` is all it has.
{ intent: 'titleTreatment', orient: 'L' },
]
function parseIcon(item) { function parseIcon(item) {
return `${API_IMAGE_ENDPOINT}/intent/${item.id}/posterTile`; return imageUrl(item, 'posterTile')
}
function imageUrl(item, intent) {
return `${API_IMAGE_ENDPOINT}/intent/${item.id}/${intent}`
}
// <icon> repeats the poster because the two elements are read by different clients: <icon> has only
// a src, while <image> is the one that can say what the picture is.
function parseImage(item) {
return IMAGE_INTENTS.map(({ intent, type, orient }) => ({
...(type ? { type } : {}),
orient,
system: intent,
value: imageUrl(item, intent),
}))
} }
@@ -1,16 +1,13 @@
// credit for this fix goes to klausellus-wallace for his PR on https://github.com/iptv-org/epg/pull/2458 //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 utc = require('dayjs/plugin/utc')
const customParseFormat = require('dayjs/plugin/customParseFormat') const customParseFormat = require('dayjs/plugin/customParseFormat')
const fetch = require('node-fetch')
const { upperCase } = require('lodash')
let X_CSRFTOKEN let X_CSRFTOKEN
let COOKIE let Cookie
const cookiesToExtract = ['JSESSIONID', 'CSESSIONID', 'CSRFSESSION'] const cookiesToExtract = ['JSESSIONID', 'CSESSIONID', 'CSRFSESSION']
const extractedCookies = {}
dayjs.extend(utc) dayjs.extend(utc)
dayjs.extend(customParseFormat) dayjs.extend(customParseFormat)
@@ -21,10 +18,9 @@ module.exports = {
url: 'https://api.prod.sngtv.magentatv.de/EPG/JSON/PlayBillList', url: 'https://api.prod.sngtv.magentatv.de/EPG/JSON/PlayBillList',
request: { request: {
method: 'POST', method: 'POST',
headers: function () { async headers() {
return setHeaders() return await setHeaders()
}, },
data({ channel, date }) { data({ channel, date }) {
return { return {
count: -1, count: -1,
@@ -32,7 +28,8 @@ module.exports = {
offset: 0, offset: 0,
properties: [ properties: [
{ {
include: 'endtime,genres,id,name,starttime,channelid,pictures,introduce,subName,seasonNum,subNum,cast,country,producedate,externalIds', include:
'endtime,genres,id,name,starttime,channelid,pictures,introduce,subName,seasonNum,subNum,cast,country,producedate,externalIds',
name: 'playbill' name: 'playbill'
} }
], ],
@@ -43,14 +40,15 @@ module.exports = {
} }
} }
}, },
parser: function ({ content }) { parser({ content }) {
let programs = [] const programs = []
const items = parseItems(content) const items = parseItems(content)
items.forEach(item => { items.forEach(item => {
programs.push({ programs.push({
title: item.name, title: item.name,
description: item.introduce, description: item.introduce,
image: parseImage(item), image: parseImage(item),
icon: parseImage(item),
category: parseCategory(item), category: parseCategory(item),
start: parseStart(item), start: parseStart(item),
stop: parseStop(item), stop: parseStop(item),
@@ -60,7 +58,7 @@ module.exports = {
directors: parseDirectors(item), directors: parseDirectors(item),
producers: parseProducers(item), producers: parseProducers(item),
adapters: parseAdapters(item), adapters: parseAdapters(item),
country: upperCase(item.country), country: item.country?.toUpperCase(),
date: item.producedate, date: item.producedate,
urls: parseUrls(item) urls: parseUrls(item)
}) })
@@ -115,15 +113,15 @@ function parseCategory(item) {
} }
function parseDirectors(item) { function parseDirectors(item) {
if (!item.cast || !item.cast.director) return []; if (!item.cast || !item.cast.director) return []
return item.cast.director return item.cast.director
.replace('und', ',') .replace('und', ',')
.split(',') .split(',')
.map(i => i.trim()); .map(i => i.trim())
} }
function parseProducers(item) { function parseProducers(item) {
if (!item.cast || !item.cast.producer) return []; if (!item.cast || !item.cast.producer) return []
return item.cast.producer return item.cast.producer
.replace('und', ',') .replace('und', ',')
.split(',') .split(',')
@@ -131,7 +129,7 @@ function parseProducers(item) {
} }
function parseAdapters(item) { function parseAdapters(item) {
if (!item.cast || !item.cast.adaptor) return []; if (!item.cast || !item.cast.adaptor) return []
return item.cast.adaptor return item.cast.adaptor
.replace('und', ',') .replace('und', ',')
.split(',') .split(',')
@@ -140,7 +138,7 @@ function parseAdapters(item) {
function parseUrls(item) { function parseUrls(item) {
// currently only a imdb id is returned by the api, thus we can construct the url here // currently only a imdb id is returned by the api, thus we can construct the url here
if (!item.externalIds) return []; if (!item.externalIds) return []
return JSON.parse(item.externalIds) return JSON.parse(item.externalIds)
.filter(externalId => externalId.type === 'imdb' && externalId.id) .filter(externalId => externalId.type === 'imdb' && externalId.id)
.map(externalId => ({ system: 'imdb', value: `https://www.imdb.com/title/${externalId.id}` })) .map(externalId => ({ system: 'imdb', value: `https://www.imdb.com/title/${externalId.id}` }))
@@ -167,66 +165,51 @@ function parseItems(content) {
return data.playbilllist return data.playbilllist
} }
// Function to try to fetch COOKIE and X_CSRFTOKEN async function fetchCookieAndToken() {
function fetchCookieAndToken() { // Only fetch the cookies and csrfToken if they are not already set
return fetch( if (X_CSRFTOKEN && Cookie) {
'https://api.prod.sngtv.magentatv.de/EPG/JSON/Authenticate?SID=firstup&T=Windows_chrome_118', return
{ }
headers: {
accept: 'application/json, text/javascript, */*; q=0.01', try {
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', const response = await axios.request({
'sec-fetch-dest': 'empty', url: 'https://api.prod.sngtv.magentatv.de/EPG/JSON/Authenticate',
'sec-fetch-mode': 'cors', params: {
'sec-fetch-site': 'same-origin', SID: 'firstup',
'x-requested-with': 'XMLHttpRequest', T: 'Windows_chrome_118'
Referer: 'https://web.magentatv.de/',
'Referrer-Policy': 'strict-origin-when-cross-origin'
}, },
body: '{"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"}', method: 'POST',
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
} }
)
.then(response => {
// Check if the response status is OK (2xx)
if (!response.ok) {
throw new Error('HTTP request failed')
}
// Extract the set-cookie header X_CSRFTOKEN = response.data.csrfToken
const setCookieHeader = response.headers.raw()['set-cookie'] Cookie = extractedCookies.join(' ')
} catch (error) {
// Extract the cookies specified in cookiesToExtract console.error(error)
cookiesToExtract.forEach(cookieName => { }
const regex = new RegExp(`${cookieName}=(.+?)(;|$)`)
const match = setCookieHeader.find(header => regex.test(header))
if (match) {
const cookieValue = regex.exec(match)[1]
extractedCookies[cookieName] = cookieValue
}
})
return response.json()
})
.then(data => {
if (data.csrfToken) {
X_CSRFTOKEN = data.csrfToken
COOKIE = `JSESSIONID=${extractedCookies.JSESSIONID}; CSESSIONID=${extractedCookies.CSESSIONID}; CSRFSESSION=${extractedCookies.CSRFSESSION}; JSESSIONID=${extractedCookies.JSESSIONID};`
} else {
console.log('csrfToken not found in the response.')
}
})
.catch(error => {
console.error(error)
})
} }
function setHeaders() { async function setHeaders() {
return fetchCookieAndToken().then(() => { await fetchCookieAndToken()
return {
X_CSRFTOKEN: X_CSRFTOKEN, return { X_CSRFTOKEN, Cookie }
'Content-Type': 'application/json', }
Cookie: COOKIE
}
})
}
+23
View File
@@ -0,0 +1,23 @@
module.exports = {
apps: [
{
name: 'serve',
script: 'npx serve -- public',
instances: 1,
watch: false,
autorestart: true
},
{
name: 'grab',
script: process.env.SITE
? `npm run grab -- --site=${process.env.SITE} ${
process.env.CLANG ? `--lang=${process.env.CLANG}` : ''
} --output=public/guide.xml`
: `npm run grab -- --gzip --channels=channels.xml --output=public/guide.xml`,
cron_restart: process.env.CRON_SCHEDULE || null,
instances: 1,
watch: false,
autorestart: false
}
]
}
+5 -6
View File
@@ -6,9 +6,10 @@ for arg in "$@"; do
chron-schedule=*) chron_schedule="${arg#*=}" ;; chron-schedule=*) chron_schedule="${arg#*=}" ;;
work-dir=*) work_dir="${arg#*=}" ;; work-dir=*) work_dir="${arg#*=}" ;;
days=*) days="${arg#*=}" ;; days=*) days="${arg#*=}" ;;
delay=*) delay="${arg#*=}" ;;
max_connections=*) max_connections="${arg#*=}" ;; max_connections=*) max_connections="${arg#*=}" ;;
enable_fixes=*) enable_fixes="${arg#*=}" ;; enable_fixes=*) enable_fixes="${arg#*=}" ;;
api_url=*) api_url="${arg#*=}" ;; api_url=*) api_url="${arg#*=}" ;;
esac esac
done done
@@ -16,6 +17,7 @@ echo "chron_schedule : ${chron_schedule}"
cd $work_dir cd $work_dir
echo "working dir : " $(pwd) echo "working dir : " $(pwd)
echo "days : ${days}" echo "days : ${days}"
echo "delay : ${delay}"
echo "max_connections : ${max_connections}" echo "max_connections : ${max_connections}"
echo "enable_fixes : ${enable_fixes}" echo "enable_fixes : ${enable_fixes}"
echo "api url : ${api_url}" echo "api url : ${api_url}"
@@ -24,10 +26,7 @@ if [ "$enable_fixes" = true ] ; then
cp -R /fixes/* /bin/epg/sites/ cp -R /fixes/* /bin/epg/sites/
fi fi
sed -i -E "s/(https:\x2f\x2fiptv-org.github.io\x2fapi)/$api_url/g" $work_dir/scripts/core/apiClient.ts sed -i -E "s/(https:\x2f\x2fiptv-org.github.io\x2fapi$\123filename\125)/$api_url$\123filename\125/g" $work_dir/scripts/core/apiClient.ts
pm2 --name epg start npm -- run serve
npm run grab -- --channels=channels.xml --maxConnections=$max_connections --days=$days --gzip
ln -s $work_dir/guide.xml /public/guide.xml ln -s $work_dir/guide.xml /public/guide.xml
ln -s $work_dir/guide.xml.gz /public/guide.xml.gz ln -s $work_dir/guide.xml.gz /public/guide.xml.gz
npm run grab -- --channels=channels.xml --cron="$chron_schedule" --maxConnections=$max_connections --days=$days --gzip pm2-runtime pm2.config.js --name epg --node-args="--no-autorestart --cron-restart="$chron_schedule" --maxConnections=$max_connections --days=$days --delay=$delay"