Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8edb33819e | ||
|
|
6fe29e4d71 | ||
|
|
0ff4dc7c7a | ||
|
|
f2959af0ac | ||
|
|
1062769e13 | ||
|
|
bcfd38cb19 | ||
|
|
3876463747 | ||
|
|
8411e28b0a | ||
|
|
5f228031e1 | ||
|
|
21881c43a7 | ||
|
|
d72cc13659 | ||
|
|
3a325f4cb3 | ||
|
|
59ba4f298e | ||
|
|
fd1df8ac0b | ||
|
|
65c2ed8208 | ||
|
|
054adcd9ec | ||
|
|
51a830bb2c | ||
|
|
cedf4cb9cf | ||
|
|
09b2a32c7e | ||
|
|
faf359760e | ||
|
|
d1c2a2cce6 | ||
|
|
f10acb48dd | ||
|
|
97b2e2b7c9 | ||
|
|
421bebb294 | ||
|
|
b77bf97acd | ||
|
|
b671040deb | ||
|
|
86e66ede1d | ||
|
|
c113fd0bbc | ||
|
|
54f8e6b157 | ||
|
|
be44be878c | ||
|
|
1700fbe251 | ||
|
|
b760bbdf3e | ||
|
|
8c609f5515 | ||
|
|
ff31a3b737 | ||
|
|
123285107d | ||
|
|
3d13569146 | ||
|
|
e9bc6f5246 | ||
|
|
5c662bae69 | ||
|
|
eece21742c | ||
|
|
ee126cf60c | ||
|
|
db28863295 | ||
|
|
223a4ea6b5 | ||
|
|
e6ee948355 | ||
|
|
2662567576 | ||
|
|
309038bb4a | ||
|
|
3b019df919 | ||
|
|
1cf21ddb98 | ||
|
|
0aeb48fe2f | ||
|
|
70c7ee79b0 | ||
|
|
62937901c2 | ||
|
|
4e5a2b4d27 | ||
|
|
ab9a8d7160 | ||
|
|
e080a976a6 | ||
|
|
252a7b23aa | ||
|
|
0a4d9c4452 | ||
|
|
6939823646 | ||
|
|
60503e87ed | ||
|
|
2f732b6dcc | ||
|
|
1f999d1c3c | ||
|
|
3f5b36a878 | ||
|
|
f1c905f5dd | ||
|
|
d83069f300 | ||
|
|
092ad56487 | ||
|
|
cfedd1e091 | ||
|
|
7bf14e4f10 | ||
|
|
1521795dd8 | ||
|
|
645569dc97 | ||
|
|
113b6b678e | ||
|
|
512d8257fd | ||
|
|
db7680861e | ||
|
|
8623771537 | ||
|
|
4199210593 | ||
|
|
3c9432d1f3 | ||
|
|
fa76db456f | ||
|
|
b434ce505b | ||
|
|
2d3ffcbd42 | ||
|
|
c4c0bf5270 | ||
|
|
8736114213 | ||
|
|
075ac41e2a | ||
|
|
c7dc12f4bb | ||
|
|
3a7f23577a | ||
|
|
02725264fd | ||
|
|
ef25f64dcd | ||
|
|
47e8a82c41 | ||
|
|
5be16e5544 | ||
|
|
91ad05ab89 | ||
|
|
e9116631d8 | ||
|
|
330099049a | ||
|
|
06dca856ad | ||
|
|
b042f5ac8e | ||
|
|
4ba2fce7cf | ||
|
|
3c66cce5dd | ||
|
|
50ae72364c | ||
|
|
490520775f | ||
|
|
8231301a53 | ||
|
|
2e8e8fb440 | ||
|
|
ff1928a09f | ||
|
|
1ff85a3a26 | ||
|
|
6b723e1776 | ||
|
|
8aacebad42 | ||
|
|
d388307b85 | ||
|
|
e04ec220e3 | ||
|
|
6ff94a3848 | ||
|
|
1f885bbd1c | ||
|
|
e99af0bc2b | ||
|
|
2f86d79697 | ||
|
|
0e72cce51f | ||
|
|
2b7b095419 | ||
|
|
bb828fd0eb | ||
|
|
d957c4d873 | ||
|
|
613da613c4 | ||
|
|
9c5e4ad69b | ||
|
|
8e448d6c57 | ||
|
|
31eb8abddf | ||
|
|
6acb07ed4e | ||
|
|
02133f0692 | ||
|
|
6543f2ce6c | ||
|
|
e7b49898df | ||
|
|
99c7d0e2c6 | ||
|
|
a46995b833 | ||
|
|
1a73bc2b25 | ||
|
|
f15b5c36da | ||
|
|
ac6aed6aa4 | ||
|
|
c0905a30f0 | ||
|
|
8555fae94a | ||
|
|
a4575ccf18 | ||
|
|
abc9f19ac3 | ||
|
|
5e40ec15af | ||
|
|
aa9ddceb06 | ||
|
|
8f58693ef5 | ||
|
|
fd12d6508f |
No files matched your search
+24
-14
@@ -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 }}
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
github: davidclaeysquinones
|
||||||
@@ -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}}
|
||||||
|
|||||||
+21
-10
@@ -1,8 +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 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
|
||||||
@@ -22,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"
|
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
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 David Claeys
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -32,19 +38,34 @@ You can do this by creating a mapping in the `/config` folder.
|
|||||||
#### Custom fixes
|
#### Custom fixes
|
||||||
|
|
||||||
Through the `ENABLE_FIXES` variable custom provider fixes can be applied to the container.
|
Through the `ENABLE_FIXES` variable custom provider fixes can be applied to the container.
|
||||||
By default some fixes are available. If you have suggestions or a problem with them please submit an issue.
|
By default some fixes are available. These fixes have been validated before being added to this repo.
|
||||||
|
However this option is disabled by default since you might only want to run the unmodified source.
|
||||||
|
If you have suggestions or a problem with them please submit an issue.
|
||||||
|
|
||||||
|
This the list of the provided custom fixes :
|
||||||
|
|
||||||
|
| Provider | Author(s) | Status |
|
||||||
|
|--------------------|------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| movistarplus.es | | |
|
||||||
|
| orangetv.orange.es | | |
|
||||||
|
| pickx.be | [davidclaeysquinones](https://github.com/davidclaeysquinones) | In testing |
|
||||||
|
| telenet.tv | | |
|
||||||
|
| 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>
|
||||||
It is recommended that you take existing provider code as a base for your customisations.
|
It is recommended that you take existing provider code as a base for your customisations.
|
||||||
|
|
||||||
### Environment Variables
|
### Environment Variables
|
||||||
|
|
||||||
| Variable | Description | Default |
|
| Variable | Description | Default |
|
||||||
|-------------------------------|----------------------------------------------------------------------------|------------------|
|
|-------------------------------|----------------------------------------------------------------------------|----------------------------------|
|
||||||
| 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 |
|
||||||
| MAX_CONNECTIONS | The maximum amount of parallel connections that can be established | 10 |
|
| DELAY | Delay between requests in milliseconds | 0 |
|
||||||
|
| 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` |
|
||||||
|
|
||||||
### Compose file
|
### Compose file
|
||||||
|
|
||||||
@@ -72,25 +93,205 @@ services:
|
|||||||
|
|
||||||
This image is bound to the content of the [iptv-org/epg](https://github.com/iptv-org/epg) repository. In the underlying list you can see to which commit each version of the docker image is bound.
|
This image is bound to the content of the [iptv-org/epg](https://github.com/iptv-org/epg) repository. In the underlying list you can see to which commit each version of the docker image is bound.
|
||||||
|
|
||||||
Normally when a change is made in the source repository the documention is updated and a new tag is created in this repository. This is completely normal since the source repository is only cloned during the build process of the docker image.
|
Normally when a change is made in the source repository the documentation is updated and a new tag is created in this repository. This is completely normal since the source repository is only cloned during the build process of the docker image.
|
||||||
|
|
||||||
Sometimes a new version of this image will be bound to the same source commit. This will happen when improvements are made to the image.
|
Sometimes a new version of this image will be bound to the same source commit. This will happen when improvements are made to the image.
|
||||||
|
|
||||||
- 1.0.0
|
- 1.0.0
|
||||||
[08-01-2024](https://github.com/iptv-org/epg/commit/793c74ca397504fc2afc8fbfa998e0b8e4ca45d9)
|
[08-01-2024](https://github.com/iptv-org/epg/commit/793c74ca397504fc2afc8fbfa998e0b8e4ca45d9)
|
||||||
- 1.0.1
|
- 1.0.1
|
||||||
[08-14-2024](https://github.com/iptv-org/epg/commit/270e85cfae6f0f691c2e6ab7ce511d60fd687565)
|
[08-14-2024](https://github.com/iptv-org/epg/commit/270e85cfae6f0f691c2e6ab7ce511d60fd687565)
|
||||||
- 1.0.2
|
- 1.0.2
|
||||||
[09-07-2024](https://github.com/iptv-org/epg/commit/4e3b06a86e225cdd1b9362a683e6770fb68ff28f)
|
[09-07-2024](https://github.com/iptv-org/epg/commit/4e3b06a86e225cdd1b9362a683e6770fb68ff28f)
|
||||||
- 1.0.3
|
- 1.0.3
|
||||||
[09-14-2024](https://github.com/iptv-org/epg/commit/c69f3c93b1123ddf0fecc62c7067fced59ae4e99)
|
[09-14-2024](https://github.com/iptv-org/epg/commit/c69f3c93b1123ddf0fecc62c7067fced59ae4e99)
|
||||||
- 1.0.4
|
- 1.0.4
|
||||||
[09-30-2024](https://github.com/iptv-org/epg/commit/d90c7a54b941238cb92391b33d80a75e746d3002)
|
[09-30-2024](https://github.com/iptv-org/epg/commit/d90c7a54b941238cb92391b33d80a75e746d3002)
|
||||||
- 1.0.5
|
- 1.0.5
|
||||||
[10-02-2024](https://github.com/iptv-org/epg/commit/713dbf60a1cb9623ffcab6ab370ee9a78b32102b)
|
[10-02-2024](https://github.com/iptv-org/epg/commit/713dbf60a1cb9623ffcab6ab370ee9a78b32102b)
|
||||||
- 1.0.6
|
- 1.0.6
|
||||||
[10-02-2024](https://github.com/iptv-org/epg/commit/713dbf60a1cb9623ffcab6ab370ee9a78b32102b)<br>Adds possibility to enable custom fixes
|
[10-02-2024](https://github.com/iptv-org/epg/commit/713dbf60a1cb9623ffcab6ab370ee9a78b32102b)<br>Adds possibility to enable custom fixes
|
||||||
- 1.0.7
|
- 1.0.7
|
||||||
[10-02-2024](https://github.com/iptv-org/epg/commit/713dbf60a1cb9623ffcab6ab370ee9a78b32102b)<br>Adds improvement to the docker image size
|
[10-02-2024](https://github.com/iptv-org/epg/commit/713dbf60a1cb9623ffcab6ab370ee9a78b32102b)<br>Adds improvement to the docker image size
|
||||||
- 1.0.8
|
- 1.0.8
|
||||||
[10-10-2024](https://github.com/iptv-org/epg/commit/2241bc261fd37b8b16e036a0b61167030a5ce2e6)
|
[10-10-2024](https://github.com/iptv-org/epg/commit/2241bc261fd37b8b16e036a0b61167030a5ce2e6)
|
||||||
|
- 1.0.9
|
||||||
|
[10-12-2024](https://github.com/iptv-org/epg/commit/fd382db08da7a96150928b8dcfef115e29e661d3)
|
||||||
|
- 1.0.10
|
||||||
|
[10-14-2024 12:50](https://github.com/iptv-org/epg/commit/a3e7661f95103cbee4bcb78bd483396680e9abfc)
|
||||||
|
- 1.0.11
|
||||||
|
[10-14-2024 17:34](https://github.com/iptv-org/epg/commit/7610f7b9f5cc1ccab8d17f3408a95d31b36ace7c)
|
||||||
|
- 1.0.12
|
||||||
|
[10-14-2024](https://github.com/iptv-org/epg/commit/7610f7b9f5cc1ccab8d17f3408a95d31b36ace7c)<br>Fix Pickx.be url
|
||||||
|
- 1.0.13
|
||||||
|
[10-14-2024](https://github.com/iptv-org/epg/commit/7610f7b9f5cc1ccab8d17f3408a95d31b36ace7c)<br>Add custom fix for web.magentatv.de
|
||||||
|
- 1.0.14
|
||||||
|
[10-14-2024](https://github.com/iptv-org/epg/commit/7610f7b9f5cc1ccab8d17f3408a95d31b36ace7c)<br>Change fix for movistarplus.es in order to work with new API
|
||||||
|
- 1.0.15
|
||||||
|
[11-26-2024](https://github.com/iptv-org/epg/commit/d15911006e163262c0c7f267deae28160c0d7a8f)<br>Add option to customize channel endpoint
|
||||||
|
- 1.0.16
|
||||||
|
[11-26-2024](https://github.com/iptv-org/epg/commit/d15911006e163262c0c7f267deae28160c0d7a8f)<br>Fix icons for movistarplus.es
|
||||||
|
- 1.0.17
|
||||||
|
[11-26-2024](https://github.com/iptv-org/epg/commit/d15911006e163262c0c7f267deae28160c0d7a8f)<br>Update fix for pickx.be
|
||||||
|
- 1.0.18
|
||||||
|
[11-27-2024 01:51](https://github.com/iptv-org/epg/commit/78dad4cfb4fc16f078c3b44b5534779c7c645b6b)
|
||||||
|
- 1.0.19
|
||||||
|
[11-27-2024 15:43](https://github.com/iptv-org/epg/commit/e5f0850b3b2e35ed394f00ac68b699eaabc4f0e4)
|
||||||
|
- 1.0.20
|
||||||
|
[11-28-2024](https://github.com/iptv-org/epg/commit/da18b70ddb1c3950e5a315411fd9aeaf60b6092c)
|
||||||
|
- 1.0.21
|
||||||
|
[11-28-2024](https://github.com/iptv-org/epg/commit/da18b70ddb1c3950e5a315411fd9aeaf60b6092c)<br>Add orangetv.es
|
||||||
|
- 1.0.22
|
||||||
|
[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
@@ -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>
|
||||||
@@ -1,74 +1,120 @@
|
|||||||
const { DateTime } = require('luxon')
|
//https://github.com/iptv-org/epg/blob/master/sites/movistarplus.es/movistarplus.es.config.js
|
||||||
|
|
||||||
const API_PROD_ENDPOINT = 'https://www.movistarplus.es/programacion-tv'
|
const axios = require('axios')
|
||||||
const API_IMAGE_ENDPOINT = 'https://www.movistarplus.es/recorte/n/caratulaH/';
|
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 ({ date }) {
|
url({ channel, date }) {
|
||||||
return `${API_PROD_ENDPOINT}/${date.format('YYYY-MM-DD')}?v=json`
|
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`
|
||||||
},
|
},
|
||||||
parser({ content, channel, date }) {
|
request: {
|
||||||
|
headers: {
|
||||||
|
'User-Agent':
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||||
|
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',
|
||||||
|
Referer: 'https://www.movistarplus.es/programacion-tv'
|
||||||
|
},
|
||||||
|
maxRedirects: 5
|
||||||
|
},
|
||||||
|
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
|
||||||
let guideDate = date
|
|
||||||
|
|
||||||
items.forEach(item => {
|
items.forEach(el => {
|
||||||
let startTime = DateTime.fromFormat(
|
|
||||||
`${guideDate.format('YYYY-MM-DD')} ${item.HORA_INICIO}`,
|
|
||||||
'yyyy-MM-dd HH:mm',
|
|
||||||
{
|
|
||||||
zone: 'Europe/Madrid'
|
|
||||||
}
|
|
||||||
).toUTC()
|
|
||||||
let stopTime = DateTime.fromFormat(
|
|
||||||
`${guideDate.format('YYYY-MM-DD')} ${item.HORA_FIN}`,
|
|
||||||
'yyyy-MM-dd HH:mm',
|
|
||||||
{
|
|
||||||
zone: 'Europe/Madrid'
|
|
||||||
}
|
|
||||||
).toUTC()
|
|
||||||
if (stopTime < startTime) {
|
|
||||||
guideDate = guideDate.add(1, 'd')
|
|
||||||
stopTime = stopTime.plus({ days: 1 })
|
|
||||||
}
|
|
||||||
programs.push({
|
programs.push({
|
||||||
title: item.TITULO,
|
title: el.title,
|
||||||
icon: parseIcon(item, channel),
|
description: el.description,
|
||||||
category: item.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() {
|
async channels() {
|
||||||
const axios = require('axios')
|
const json = await axios
|
||||||
const dayjs = require('dayjs')
|
.get(
|
||||||
const data = await axios
|
'https://ottcache.dof6.com/movistarplus/webplayer/OTT/contents/channels?mdrm=true&tlsstream=true&demarcation=18&version=8'
|
||||||
.get(`${API_PROD_ENDPOINT}/${dayjs().format('YYYY-MM-DD')}?v=json`)
|
)
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
|
|
||||||
return Object.values(data.data).map(item => {
|
// Load JSON, CodCadenaTv is the closest to the old MVSTR site ch. ID
|
||||||
|
return json.map(channel => {
|
||||||
return {
|
return {
|
||||||
lang: 'es',
|
lang: 'es',
|
||||||
site_id: item.DATOS_CADENA.CODIGO,
|
site_id: channel.CodCadenaTv,
|
||||||
name: item.DATOS_CADENA.NOMBRE
|
name: channel.Nombre,
|
||||||
|
logo: channel.Logo || channel.Logos?.[0]?.uri || null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseIcon(item, channel) {
|
function parseImages(images) {
|
||||||
return `${API_IMAGE_ENDPOINT}/M${channel.site_id}P${item.ELEMENTO}`;
|
return images.filter(image => image.id === 'watch2tgr-end').map(image => image.uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(content, channel) {
|
async function parseItems(content) {
|
||||||
const json = typeof content === 'string' ? JSON.parse(content) : content
|
try {
|
||||||
if (!(`${channel.site_id}-CODE` in json.data)) return []
|
const data = JSON.parse(content)
|
||||||
const data = json.data[`${channel.site_id}-CODE`]
|
const programs = Array.isArray(data) ? data : [data]
|
||||||
return data ? data.PROGRAMAS : []
|
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 []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -0,0 +1,412 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<channels>
|
||||||
|
<channel site="pickx.be" site_id="1143" lang="fr" xmltv_id="MaghrebTV.be@SD">Maghreb TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1043" lang="en" xmltv_id="">Netflix</channel>
|
||||||
|
<channel site="pickx.be" site_id="1058" lang="fr" xmltv_id="NationalGeographicWild.fr@SD">National Geographic Wild F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1190" lang="nl" xmltv_id="NationalGeographicWild.nl@SD">National Geographic Wild N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1130" lang="de" xmltv_id="DasErste.de@SD">Das Erste</channel>
|
||||||
|
<channel site="pickx.be" site_id="1093" lang="fr" xmltv_id="TipikVision.be@SD">TIPIK vision</channel>
|
||||||
|
<channel site="pickx.be" site_id="1131" lang="de" xmltv_id="ZDF.de@SD">ZDF</channel>
|
||||||
|
<channel site="pickx.be" site_id="1195" lang="nl" xmltv_id="DobbitTV.be@NL">Dobbit TV N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1149" lang="nl" xmltv_id="VTM2.be@HD">VTM 2 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1011" lang="fr" xmltv_id="PickxPlus.be@FR">Pickx+ F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1155" lang="nl" xmltv_id="PickxPlus.be@NL">Pickx+ N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1065" lang="fr" xmltv_id="DobbitTV.be@FR">Dobbit TV F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1001" lang="fr" xmltv_id="Tipik.be@HD">TIPIK HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1201" lang="nl" xmltv_id="PlattelandsTV.be@SD">Plattelands</channel>
|
||||||
|
<channel site="pickx.be" site_id="1174" lang="nl" xmltv_id="DisneyJunior.nl@SD">Disney Jr. N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1036" lang="fr" xmltv_id="PickxPlus.be@FRHD">Pickx+ F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1182" lang="nl" xmltv_id="PickxPlus.be@NLHD">Pickx+ N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1016" lang="fr" xmltv_id="AB3.be@HD">AB3 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1054" lang="fr" xmltv_id="DiscoveryChannel.fr@SD">Discovery F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1054" lang="fr" xmltv_id="DiscoveryChannel.fr@HD">Disc HD F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1098" lang="fr" xmltv_id="MezzoLive.fr@SD">MezzoLive</channel>
|
||||||
|
<channel site="pickx.be" site_id="1002" lang="fr" xmltv_id="RTLTVI.be@HD">RTL tvi HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1004" lang="fr" xmltv_id="RTLPlug.be@HD">RTL plug HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1110" lang="fr" xmltv_id="Telesambre.be@SD">Télé Sambre</channel>
|
||||||
|
<channel site="pickx.be" site_id="1113" lang="fr" xmltv_id="Vedia.be@SD">Védia</channel>
|
||||||
|
<channel site="pickx.be" site_id="1111" lang="fr" xmltv_id="">TV Com</channel>
|
||||||
|
<channel site="pickx.be" site_id="1112" lang="fr" xmltv_id="TVLux.be@SD">TV Lux</channel>
|
||||||
|
<channel site="pickx.be" site_id="1106" lang="fr" xmltv_id="Matele.be@SD">MaTélé</channel>
|
||||||
|
<channel site="pickx.be" site_id="1044" lang="fr" xmltv_id="">Disney+</channel>
|
||||||
|
<channel site="pickx.be" site_id="1167" lang="nl" xmltv_id="BBCFirst.uk@Benelux">BBC First</channel>
|
||||||
|
<channel site="pickx.be" site_id="1171" lang="nl" xmltv_id="Nickelodeon.nl@HD">nick N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1157" lang="nl" xmltv_id="Play6.be@SD">Play6</channel>
|
||||||
|
<channel site="pickx.be" site_id="1157" lang="nl" xmltv_id="Play6.be@HD">Play6 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1129" lang="fr" xmltv_id="France24.fr@FrenchHD">France 24 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1128" lang="fr" xmltv_id="EuronewsFrench.fr@SD">Euronews F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1150" lang="nl" xmltv_id="VTM3.be@HD">VTM 3 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1063" lang="fr" xmltv_id="CrimeDistrict.fr@SD">Crime District</channel>
|
||||||
|
<channel site="pickx.be" site_id="1092" lang="fr" xmltv_id="BelRTL.be@HD">bel RTL HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1196" lang="nl" xmltv_id="EclipsTV.be@SD">Eclips</channel>
|
||||||
|
<channel site="pickx.be" site_id="1017" lang="fr" xmltv_id="ABXplore.be@HD">ABXPLO HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1194" lang="nl" xmltv_id="Njam.be@HD">Njam! HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1194" lang="nl" xmltv_id="Njam.be@SD">Njam!</channel>
|
||||||
|
<channel site="pickx.be" site_id="1020" lang="fr" xmltv_id="arte.fr@HD">arte HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1187" lang="nl" xmltv_id="AnimalPlanet.nl@HD">Animal Pl HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1154" lang="nl" xmltv_id="Ketnet.be@HD">Ketnet HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1161" lang="nl" xmltv_id="NPO1.nl@HD">NPO 1 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1162" lang="nl" xmltv_id="NPO2.nl@HD">NPO 2 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1163" lang="nl" xmltv_id="NPO3.nl@HD">NPO 3 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1037" lang="fr" xmltv_id="Be1.be@SD">Be1</channel>
|
||||||
|
<channel site="pickx.be" site_id="1039" lang="fr" xmltv_id="BeCine.be@SD">Be Ciné</channel>
|
||||||
|
<channel site="pickx.be" site_id="1038" lang="fr" xmltv_id="BeSeries.be@SD">Be Séries</channel>
|
||||||
|
<channel site="pickx.be" site_id="1040" lang="fr" xmltv_id="CinePlusOCS.fr@SD">Ciné+OCS</channel>
|
||||||
|
<channel site="pickx.be" site_id="1041" lang="fr" xmltv_id="CinePlusFrisson.fr@SD">Ciné+Frisson</channel>
|
||||||
|
<channel site="pickx.be" site_id="1042" lang="fr" xmltv_id="CinePlusClassic.be@SD">Ciné+Classic</channel>
|
||||||
|
<channel site="pickx.be" site_id="1200" lang="nl" xmltv_id="OUTtv.nl@SD">OUT tv</channel>
|
||||||
|
<channel site="pickx.be" site_id="1007" lang="fr" xmltv_id="France3.fr@HD">France 3 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1018" lang="fr" xmltv_id="France4.fr@HD">France 4 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1019" lang="fr" xmltv_id="France5.fr@HD">France 5 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1015" lang="fr" xmltv_id="LN24.be@SD">LN24</channel>
|
||||||
|
<channel site="pickx.be" site_id="1160" lang="nl" xmltv_id="VTMGold.be@SD">VTM Gold</channel>
|
||||||
|
<channel site="pickx.be" site_id="1227" lang="en" xmltv_id="PenthouseGold.us@SD">Penthouse Gold</channel>
|
||||||
|
<channel site="pickx.be" site_id="1204" lang="nl" xmltv_id="PickxPlusSports1.be@NL">Pickx+ Sports 1 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1205" lang="nl" xmltv_id="PickxPlusSports2.be@NL">Pickx+ Sports 2 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1206" lang="nl" xmltv_id="PickxPlusSports3.be@NL">Pickx+ Sports 3 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1207" lang="nl" xmltv_id="PickxPlusSports4.be@NL">Pickx+ Sports 4 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1208" lang="nl" xmltv_id="PickxPlusSports5.be@NL">Pickx+ Sports 5 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1209" lang="nl" xmltv_id="PickxPlusSports6.be@NL">Pickx+ Sports 6 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1211" lang="nl" xmltv_id="PickxPlusSports8.be@NLHD">Pickx+ Sports 8 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1212" lang="nl" xmltv_id="PickxPlusSports9.be@NLHD">Pickx+ Sports 9 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1228" lang="en" xmltv_id="DuskTV.nl@SD">Dusk</channel>
|
||||||
|
<channel site="pickx.be" site_id="1203" lang="nl" xmltv_id="PickxLive.be@NLHD">Pickx Sports Pop-up N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1156" lang="nl" xmltv_id="PickxPlusSports1.be@NLHD">Pickx+ Sports 1 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1205" lang="nl" xmltv_id="PickxPlusSports2.be@NLHD">Pickx+ Sports 2 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1206" lang="nl" xmltv_id="PickxPlusSports3.be@NLHD">Pickx+ Sports 3 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1207" lang="nl" xmltv_id="PickxPlusSports4.be@NLHD">Pickx+ Sports 4 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1208" lang="nl" xmltv_id="PickxPlusSports5.be@NLHD">Pickx+ Sports 5 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1209" lang="nl" xmltv_id="PickxPlusSports6.be@NLHD">Pickx+ Sports 6 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1084" lang="fr" xmltv_id="DAZN1.uk@France">DAZN 1 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1217" lang="nl" xmltv_id="DAZN1.uk@Netherlands">DAZN 1 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1085" lang="fr" xmltv_id="DAZN2.uk@France">DAZN 2 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1218" lang="nl" xmltv_id="DAZN2.uk@Netherlands">DAZN 2 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1084" lang="fr" xmltv_id="DAZN1.uk@FranceHD">DAZN 1 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1217" lang="nl" xmltv_id="DAZN1.uk@NetherlandsHD">DAZN 1 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1085" lang="fr" xmltv_id="DAZN2.uk@FranceHD">DAZN 2 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1218" lang="nl" xmltv_id="DAZN2.uk@NetherlandsHD">DAZN 2 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1071" lang="fr" xmltv_id="PickxPlusSports2.be@FR">Pickx+ Sports 1 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1073" lang="fr" xmltv_id="PickxPlusSports3.be@FR">Pickx+ Sports 3 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1074" lang="fr" xmltv_id="PickxPlusSports4.be@FR">Pickx+ Sports 4 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1075" lang="fr" xmltv_id="PickxPlusSports5.be@FR">Pickx+ Sports 5 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1076" lang="fr" xmltv_id="PickxPlusSports6.be@FR">Pickx+ Sports 6 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1078" lang="fr" xmltv_id="PickxPlusSports8.be@FRHD">Pickx+ Sports 8 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1079" lang="fr" xmltv_id="PickxPlusSports9.be@FRHD">Pickx+ Sports 9 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1080" lang="fr" xmltv_id="PickxPlusSports10.be@FRHD">Pickx+ Sports 10 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1010" lang="fr" xmltv_id="PickxLive.be@FRHD">Pickx Sports Pop-up F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1012" lang="fr" xmltv_id="PickxPlusSports1.be@FRHD">Pickx+ Sports 1 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1072" lang="fr" xmltv_id="PickxPlusSports2.be@FRHD">Pickx+ Sports 2 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1073" lang="fr" xmltv_id="PickxPlusSports3.be@FRHD">Pickx+ Sports 3 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1074" lang="fr" xmltv_id="PickxPlusSports4.be@FRHD">Pickx+ Sports 4 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1075" lang="fr" xmltv_id="PickxPlusSports5.be@FRHD">Pickx+ Sports 5 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1076" lang="fr" xmltv_id="PickxPlusSports6.be@FRHD">Pickx+ Sports 6 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1213" lang="nl" xmltv_id="PickxPlusSports10.be@NLHD">Pickx+ Sports 10 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1236" lang="nl" xmltv_id="StuBru.be@SD">StuBru</channel>
|
||||||
|
<channel site="pickx.be" site_id="1256" lang="fr" xmltv_id="PromiusPickxInfoChannel.be@SD">InfoChannel</channel>
|
||||||
|
<channel site="pickx.be" site_id="1114" lang="nl" xmltv_id="VlaamsParlementTV.be@SD">Vlaamsparlement.tv</channel>
|
||||||
|
<channel site="pickx.be" site_id="1064" lang="fr" xmltv_id="E.fr@HD">E! HD F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1197" lang="nl" xmltv_id="EEurope.nl@HD">E! HD N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1024" lang="fr" xmltv_id="DisneyChannel.fr@HD">Disn Ch HD F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1173" lang="nl" xmltv_id="DisneyChannel.nl@HD">Disn Ch HD N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1140" lang="fr" xmltv_id="2MMonde.ma@SD">2M Monde</channel>
|
||||||
|
<channel site="pickx.be" site_id="1172" lang="nl" xmltv_id="VTMLife.be@HD">VTM Life HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1159" lang="nl" xmltv_id="KanaalZ.be@HD">Kanaal Z HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1014" lang="fr" xmltv_id="CanalZ.be@HD">Canal Z HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1046" lang="fr" xmltv_id="TVBreizh.fr@HD">TV Breizh HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1049" lang="fr" xmltv_id="TCMCinema.fr@HD">TCM Cinéma HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1048" lang="fr" xmltv_id="Syfy.fr@HD">SyFy HD F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1047" lang="fr" xmltv_id="13emeRue.fr@HD">13è Rue HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1045" lang="fr" xmltv_id="Action.fr@HD">Action HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1222" lang="nl" xmltv_id="Sport10.be@SD">Sport 10</channel>
|
||||||
|
<channel site="pickx.be" site_id="1034" lang="fr" xmltv_id="Gulli.fr@HD">Gulli HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1186" lang="nl" xmltv_id="NationalGeographic.nl@HD">NGC HD N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1089" lang="en" xmltv_id="Motorvision.de@SD">Motorvision+</channel>
|
||||||
|
<channel site="pickx.be" site_id="1021" lang="fr" xmltv_id="TV5MondeFranceBelgiumSwitzerlandMonaco.fr@HD">TV5 Monde HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1089" lang="en" xmltv_id="Motorvision.de@HD">Motorvision+ HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1050" lang="fr" xmltv_id="ComedyCentral.fr@SD">Comedy Central F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1030" lang="fr" xmltv_id="NickelodeonJunior.fr@SD">nick jr F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1151" lang="nl" xmltv_id="VTM4.be@HD">VTM 4 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1203" lang="nl" xmltv_id="PickxLive.be@NL">Pickx Showcase N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1147" lang="nl" xmltv_id="Play4.be@HD">Play4 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1148" lang="nl" xmltv_id="Play5.be@HD">Play5 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1081" lang="fr" xmltv_id="DAZNProLeague1.uk@FranceHD">DAZN Pro League 1 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1081" lang="fr" xmltv_id="DAZNProLeague1.uk@France">DAZN Pro League 1 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1193" lang="nl" xmltv_id="TLC.nl@SD">TLC</channel>
|
||||||
|
<channel site="pickx.be" site_id="1172" lang="nl" xmltv_id="VTMLife.be@SD">VTM Life</channel>
|
||||||
|
<channel site="pickx.be" site_id="1056" lang="fr" xmltv_id="Trek.fr@HD">TREK HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1214" lang="nl" xmltv_id="DAZNProLeague1.uk@NetherlandsHD">DAZN Pro League 1 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1214" lang="nl" xmltv_id="DAZNProLeague1.uk@Netherlands">DAZN Pro League 1 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1082" lang="fr" xmltv_id="DAZNProLeague2.uk@FranceHD">DAZN Pro League 2 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1082" lang="fr" xmltv_id="DAZNProLeague2.uk@France">DAZN Pro League 2 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1215" lang="nl" xmltv_id="DAZNProLeague2.uk@NetherlandsHD">DAZN Pro League 2 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1215" lang="nl" xmltv_id="DAZNProLeague2.uk@Netherlands">DAZN Pro League 2 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1132" lang="de" xmltv_id="RTL.de@SD">RTL</channel>
|
||||||
|
<channel site="pickx.be" site_id="1051" lang="fr" xmltv_id="TMC.fr@HD">TMC HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1158" lang="nl" xmltv_id="Play7.be@HD">Play7 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1068" lang="fr" xmltv_id="MyZenTV.fr@SD">MyZen.tv</channel>
|
||||||
|
<channel site="pickx.be" site_id="1057" lang="fr" xmltv_id="MuseumTVFrench.fr@SD">Museum TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1103" lang="fr" xmltv_id="ACTV.be@HD">Antenne Centre HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1115" lang="nl" xmltv_id="ATV.be@HD">ATV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1116" lang="nl" xmltv_id="AVS.be@HD">AVS HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1013" lang="nl" xmltv_id="Bruzz.be@HD">BRUZZ HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1009" lang="fr" xmltv_id="BX1.be@HD">bx1 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1104" lang="fr" xmltv_id="Bouke.be@HD">Bouké HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1105" lang="fr" xmltv_id="CanalZoom.be@HD">Canal Zoom HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1117" lang="nl" xmltv_id="FocusTV.be@HD">Focus TV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1106" lang="fr" xmltv_id="Matele.be@HD">MaTélé HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1107" lang="fr" xmltv_id="Notele.be@HD">No Télé HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1118" lang="nl" xmltv_id="RingTV.be@HD">Ring TV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1119" lang="nl" xmltv_id="ROBTV.be@HD">ROBTV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1108" lang="fr" xmltv_id="QU4TRELiegeMedia.be@HD">Quatre HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1120" lang="nl" xmltv_id="RTVKempen.be@HD">RTV Kempen HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1121" lang="nl" xmltv_id="RTVMech.be@HD">RTV Mech HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1109" lang="fr" xmltv_id="TeleMB.be@HD">Télé MB HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1110" lang="fr" xmltv_id="Telesambre.be@HD">Télé Sambre HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1122" lang="nl" xmltv_id="TVLimburg.be@HD">TV Limburg HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1112" lang="fr" xmltv_id="TVLux.be@HD">TV Lux HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1123" lang="nl" xmltv_id="TVOost.be@HD">TV Oost HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1113" lang="fr" xmltv_id="Vedia.be@HD">Védia HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1124" lang="nl" xmltv_id="WTV.be@HD">WTV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1224" lang="nl" xmltv_id="MentTV.be@HD">Ment TV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1192" lang="nl" xmltv_id="InsightTV.nl@SD">INPLUS</channel>
|
||||||
|
<channel site="pickx.be" site_id="1053" lang="fr" xmltv_id="TF1SeriesFilms.fr@SD">TF1 Séries Films</channel>
|
||||||
|
<channel site="pickx.be" site_id="1223" lang="nl" xmltv_id="QMusic.be@SD">Q-Music Kijk Live</channel>
|
||||||
|
<channel site="pickx.be" site_id="1165" lang="en" xmltv_id="BBCTwo.uk@HD">BBC Two HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1221" lang="nl" xmltv_id="Eurosport2.fr@NetherlandsHD">Eurosp2 HD N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1029" lang="fr" xmltv_id="Boomerang.fr@HD">Boom F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1180" lang="nl" xmltv_id="Cartoonito.uk@HD">Cartoonito HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1026" lang="fr" xmltv_id="CartoonNetworkCEE.uk@FranceHD">Cartoon F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1176" lang="nl" xmltv_id="CartoonNetworkWesternEurope.uk@NetherlandsHD">Cartoon N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1188" lang="nl" xmltv_id="InvestigationDiscovery.nl@HD">Inv Disc HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1271" lang="en" xmltv_id="WSport.za@SD">W Sports</channel>
|
||||||
|
<channel site="pickx.be" site_id="1025" lang="fr" xmltv_id="DisneyJr.fr@HD">Disney Jr. F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1059" lang="fr" xmltv_id="ScienceVieTV.fr@HD">Sc et Vie TV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1060" lang="fr" xmltv_id="HistoireTV.fr@HD">Histoire HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1189" lang="nl" xmltv_id="History.nl@HD">History HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1136" lang="fr" xmltv_id="Rai1.it@HD">RAI Uno HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1137" lang="fr" xmltv_id="Rai2.it@HD">RAI Due HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1138" lang="fr" xmltv_id="Rai3.it@HD">RAI Tre HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1195" lang="nl" xmltv_id="DobbitTV.be@NLHD">Dobbit N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1130" lang="de" xmltv_id="DasErste.de@HD">Das Erste HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1183" lang="nl" xmltv_id="ComedyCentral.nl@HD">Comedy Central N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1127" lang="fr" xmltv_id="LCI.fr@HD">LCI HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1033" lang="fr" xmltv_id="Mangas.fr@HD">Mangas HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1131" lang="de" xmltv_id="ZDF.de@HD">ZDF HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1226" lang="en" xmltv_id="DorcelXXX.nl@HD">Dorcel XXX HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1225" lang="nl" xmltv_id="PassieXXX.nl@HD">Passie XXX HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1229" lang="en" xmltv_id="PinkX.fr@HD">Pink HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1031" lang="fr" xmltv_id="TiJi.fr@HD">Tiji HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1096" lang="fr" xmltv_id="TraceUrban.fr@HD">Trace HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1032" lang="fr" xmltv_id="CanalJ.fr@HD">Canal J HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1198" lang="en" xmltv_id="FashionTVEurope.fr@HD">Fashion TV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1102" lang="fr" xmltv_id="Melody.fr@HD">Melody.tv HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1199" lang="nl" xmltv_id="MTV.nl@HD">MTV N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1141" lang="fr" xmltv_id="AlAoula.ma@HD">Al Aoula HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1142" lang="fr" xmltv_id="AlJazeera.qa@EnglishHD">Al Jazeera HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1090" lang="fr" xmltv_id="Automotolachaine.fr@HD">AUTOMOTO HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1095" lang="fr" xmltv_id="RFMTV.fr@HD">RFM TV HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1132" lang="de" xmltv_id="RTL.de@HD">RTL Deutschland HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1134" lang="fr" xmltv_id="TVEInternacionalEuropeAsia.es@HD">TVE International HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1062" lang="fr" xmltv_id="Animaux.fr@HD">Animaux HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1126" lang="en" xmltv_id="EuronewsEnglish.fr@HD">Euronews E HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1128" lang="fr" xmltv_id="EuronewsFrench.fr@HD">Euronews F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1295" lang="nl" xmltv_id="HGTV.be@SD">HGTV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1046" lang="fr" xmltv_id="TVBreizh.fr@SD">TV Breizh</channel>
|
||||||
|
<channel site="pickx.be" site_id="1060" lang="fr" xmltv_id="HistoireTV.fr@SD">Histoire</channel>
|
||||||
|
<channel site="pickx.be" site_id="1094" lang="fr" xmltv_id="RadioContact.be@SD">ContactV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1137" lang="fr" xmltv_id="Rai2.it@SD">RAI Due</channel>
|
||||||
|
<channel site="pickx.be" site_id="1185" lang="nl" xmltv_id="DiscoveryChannel.nl@SD">Discovery N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1020" lang="fr" xmltv_id="arte.fr@SD">Arte</channel>
|
||||||
|
<channel site="pickx.be" site_id="1045" lang="fr" xmltv_id="Action.fr@SD">Action</channel>
|
||||||
|
<channel site="pickx.be" site_id="1026" lang="fr" xmltv_id="CartoonNetworkCEE.uk@France">Cartoon F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1176" lang="nl" xmltv_id="CartoonNetworkWesternEurope.uk@Netherlands">Cartoon N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1056" lang="fr" xmltv_id="Trek.fr@SD">TREK</channel>
|
||||||
|
<channel site="pickx.be" site_id="1024" lang="fr" xmltv_id="DisneyChannel.fr@SD">Disn Ch F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1061" lang="fr" xmltv_id="UshuaiaTV.fr@SD">Ushuaïa</channel>
|
||||||
|
<channel site="pickx.be" site_id="1004" lang="fr" xmltv_id="RTLPlug.be@SD">RTL plug</channel>
|
||||||
|
<channel site="pickx.be" site_id="1134" lang="fr" xmltv_id="TVEInternacionalEuropeAsia.es@SD">TVE Int</channel>
|
||||||
|
<channel site="pickx.be" site_id="1096" lang="fr" xmltv_id="TraceUrban.fr@SD">TraceUrban</channel>
|
||||||
|
<channel site="pickx.be" site_id="1191" lang="nl" xmltv_id="DiscoveryScienceEurope.uk@Netherlands">Discovery Science</channel>
|
||||||
|
<channel site="pickx.be" site_id="1021" lang="fr" xmltv_id="TV5MondeFranceBelgiumSwitzerlandMonaco.fr@SD">TV5 Monde</channel>
|
||||||
|
<channel site="pickx.be" site_id="1198" lang="en" xmltv_id="FashionTVEurope.fr@SD">FashionTV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1125" lang="en" xmltv_id="CNNInternational.us@MENA">CNN</channel>
|
||||||
|
<channel site="pickx.be" site_id="1159" lang="nl" xmltv_id="KanaalZ.be@SD">Kanaal Z</channel>
|
||||||
|
<channel site="pickx.be" site_id="1014" lang="fr" xmltv_id="CanalZ.be@SD">Canal Z</channel>
|
||||||
|
<channel site="pickx.be" site_id="1144" lang="nl" xmltv_id="VRT1.be@SD">VRT 1</channel>
|
||||||
|
<channel site="pickx.be" site_id="1019" lang="fr" xmltv_id="France5.fr@SD">France 5</channel>
|
||||||
|
<channel site="pickx.be" site_id="1171" lang="nl" xmltv_id="Nickelodeon.nl@SD">nickelodeon N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1146" lang="nl" xmltv_id="VTM.be@SD">VTM</channel>
|
||||||
|
<channel site="pickx.be" site_id="1017" lang="fr" xmltv_id="ABXplore.be@SD">ABXPLORE</channel>
|
||||||
|
<channel site="pickx.be" site_id="1095" lang="fr" xmltv_id="RFMTV.fr@SD">RFM TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1149" lang="nl" xmltv_id="VTM2.be@SD">VTM 2</channel>
|
||||||
|
<channel site="pickx.be" site_id="1033" lang="fr" xmltv_id="Mangas.fr@SD">Mangas</channel>
|
||||||
|
<channel site="pickx.be" site_id="1161" lang="nl" xmltv_id="NPO1.nl@SD">NPO 1</channel>
|
||||||
|
<channel site="pickx.be" site_id="1136" lang="fr" xmltv_id="Rai1.it@SD">RAI Uno</channel>
|
||||||
|
<channel site="pickx.be" site_id="1062" lang="fr" xmltv_id="Animaux.fr@SD">Animaux</channel>
|
||||||
|
<channel site="pickx.be" site_id="1032" lang="fr" xmltv_id="CanalJ.fr@SD">Canal J</channel>
|
||||||
|
<channel site="pickx.be" site_id="1016" lang="fr" xmltv_id="AB3.be@SD">AB3</channel>
|
||||||
|
<channel site="pickx.be" site_id="1001" lang="fr" xmltv_id="Tipik.be@SD">RTBF TIPIK</channel>
|
||||||
|
<channel site="pickx.be" site_id="1000" lang="fr" xmltv_id="LaUne.be@SD">RTBF La Une</channel>
|
||||||
|
<channel site="pickx.be" site_id="1048" lang="fr" xmltv_id="Syfy.fr@SD">SyFy F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1055" lang="fr" xmltv_id="NationalGeographic.fr@SD">National Geographic F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1148" lang="nl" xmltv_id="Play5.be@SD">Play5</channel>
|
||||||
|
<channel site="pickx.be" site_id="1127" lang="fr" xmltv_id="LCI.fr@SD">LCI</channel>
|
||||||
|
<channel site="pickx.be" site_id="1005" lang="fr" xmltv_id="TF1.fr@SD">TF1</channel>
|
||||||
|
<channel site="pickx.be" site_id="1166" lang="en" xmltv_id="BBCNews.uk@Europe">BBC News</channel>
|
||||||
|
<channel site="pickx.be" site_id="1003" lang="fr" xmltv_id="RTLClub.be@SD">RTL club</channel>
|
||||||
|
<channel site="pickx.be" site_id="1164" lang="en" xmltv_id="BBCOne.uk@London">BBC One</channel>
|
||||||
|
<channel site="pickx.be" site_id="1002" lang="fr" xmltv_id="RTLTVI.be@SD">RTL tvi</channel>
|
||||||
|
<channel site="pickx.be" site_id="1129" lang="fr" xmltv_id="France24.fr@French">France 24 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1009" lang="fr" xmltv_id="BX1.be@SD">bx1</channel>
|
||||||
|
<channel site="pickx.be" site_id="1087" lang="fr" xmltv_id="Eurosport1.fr@France">Eurosport F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1163" lang="nl" xmltv_id="NPO3.nl@SD">NPO 3</channel>
|
||||||
|
<channel site="pickx.be" site_id="1162" lang="nl" xmltv_id="NPO2.nl@SD">NPO 2</channel>
|
||||||
|
<channel site="pickx.be" site_id="1018" lang="fr" xmltv_id="France4.fr@SD">France 4</channel>
|
||||||
|
<channel site="pickx.be" site_id="1150" lang="nl" xmltv_id="VTM3.be@SD">VTM 3</channel>
|
||||||
|
<channel site="pickx.be" site_id="1147" lang="nl" xmltv_id="Play4.be@SD">Play4</channel>
|
||||||
|
<channel site="pickx.be" site_id="1145" lang="nl" xmltv_id="VRTCanvas.be@SD">VRT Canvas</channel>
|
||||||
|
<channel site="pickx.be" site_id="1126" lang="en" xmltv_id="EuronewsEnglish.fr@SD">Euronews E</channel>
|
||||||
|
<channel site="pickx.be" site_id="1186" lang="nl" xmltv_id="NationalGeographic.nl@SD">National Geographic N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1006" lang="fr" xmltv_id="France2.fr@SD">France 2</channel>
|
||||||
|
<channel site="pickx.be" site_id="1007" lang="fr" xmltv_id="France3.fr@SD">France 3</channel>
|
||||||
|
<channel site="pickx.be" site_id="1088" lang="fr" xmltv_id="Eurosport2.fr@France">Eurosp2 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1187" lang="nl" xmltv_id="AnimalPlanet.nl@SD">Animal Planet</channel>
|
||||||
|
<channel site="pickx.be" site_id="1220" lang="nl" xmltv_id="Eurosport1.fr@Netherlands">Eurosport N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1031" lang="fr" xmltv_id="TiJi.fr@SD">Tiji</channel>
|
||||||
|
<channel site="pickx.be" site_id="1049" lang="fr" xmltv_id="TCMCinema.fr@SD">TCM Cinéma</channel>
|
||||||
|
<channel site="pickx.be" site_id="1226" lang="fr" xmltv_id="DorcelXXX.nl@SD">Dorcel XXX</channel>
|
||||||
|
<channel site="pickx.be" site_id="1059" lang="fr" xmltv_id="ScienceVieTV.fr@SD">Science et Vie TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1029" lang="fr" xmltv_id="Boomerang.fr@SD">Boomerang F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1064" lang="fr" xmltv_id="E.fr@SD">E! F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1047" lang="fr" xmltv_id="13emeRue.fr@SD">13è Rue</channel>
|
||||||
|
<channel site="pickx.be" site_id="1090" lang="fr" xmltv_id="Automotolachaine.fr@SD">AUTOMOTO</channel>
|
||||||
|
<channel site="pickx.be" site_id="1070" lang="fr" xmltv_id="PickxLive.be@FR">Pickx Showcase F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1124" lang="nl" xmltv_id="WTV.be@SD">WTV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1117" lang="nl" xmltv_id="FocusTV.be@SD">Focus TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1115" lang="nl" xmltv_id="ATV.be@SD">ATV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1122" lang="nl" xmltv_id="TVLimburg.be@SD">TV Limburg</channel>
|
||||||
|
<channel site="pickx.be" site_id="1119" lang="nl" xmltv_id="ROBTV.be@SD">ROBTV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1197" lang="nl" xmltv_id="EEurope.nl@SD">E! N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1123" lang="nl" xmltv_id="TVOost.be@SD">TV Oost</channel>
|
||||||
|
<channel site="pickx.be" site_id="1013" lang="nl" xmltv_id="Bruzz.be@SD">BRUZZ</channel>
|
||||||
|
<channel site="pickx.be" site_id="1120" lang="nl" xmltv_id="RTVKempen.be@SD">RTV Kempen O</channel>
|
||||||
|
<channel site="pickx.be" site_id="1121" lang="nl" xmltv_id="RTVMech.be@SD">RTV Mech</channel>
|
||||||
|
<channel site="pickx.be" site_id="1118" lang="nl" xmltv_id="RingTV.be@SD">Ring TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1107" lang="fr" xmltv_id="Notele.be@SD">No Télé</channel>
|
||||||
|
<channel site="pickx.be" site_id="1025" lang="fr" xmltv_id="DisneyJr.fr@SD">Disney Jr. F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1109" lang="fr" xmltv_id="TeleMB.be@SD">Télé MB</channel>
|
||||||
|
<channel site="pickx.be" site_id="1141" lang="fr" xmltv_id="AlAoula.ma@SD">Al Aoula</channel>
|
||||||
|
<channel site="pickx.be" site_id="1067" lang="fr" xmltv_id="MTV.fr@SD">MTV F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1199" lang="nl" xmltv_id="MTV.nl@SD">MTV N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1183" lang="nl" xmltv_id="ComedyCentral.nl@SD">Comedy Central N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1104" lang="fr" xmltv_id="Bouke.be@SD">Bouké</channel>
|
||||||
|
<channel site="pickx.be" site_id="1105" lang="fr" xmltv_id="CanalZoom.be@SD">Canal Zoom</channel>
|
||||||
|
<channel site="pickx.be" site_id="1103" lang="fr" xmltv_id="ACTV.be@SD">Antenne C</channel>
|
||||||
|
<channel site="pickx.be" site_id="1225" lang="nl" xmltv_id="PassieXXX.nl@SD">Passie XXX</channel>
|
||||||
|
<channel site="pickx.be" site_id="1178" lang="nl" xmltv_id="NickJr.nl@SD">nick jr N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1189" lang="nl" xmltv_id="History.nl@SD">History</channel>
|
||||||
|
<channel site="pickx.be" site_id="1102" lang="fr" xmltv_id="Melody.fr@SD">Melody.tv</channel>
|
||||||
|
<channel site="pickx.be" site_id="1142" lang="fr" xmltv_id="AlJazeera.qa@English">Al Jazeera</channel>
|
||||||
|
<channel site="pickx.be" site_id="1135" lang="fr" xmltv_id="KTO.fr@SD">KTO</channel>
|
||||||
|
<channel site="pickx.be" site_id="1179" lang="nl" xmltv_id="Nicktoons.nl@SD">nick Toons</channel>
|
||||||
|
<channel site="pickx.be" site_id="1005" lang="fr" xmltv_id="TF1.fr@HD">TF1 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1229" lang="fr" xmltv_id="PinkX.fr@SD">Pink</channel>
|
||||||
|
<channel site="pickx.be" site_id="1061" lang="fr" xmltv_id="UshuaiaTV.fr@HD">Ushuaïa HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1097" lang="nl" xmltv_id="StingrayClassica.ca@SD">Classica</channel>
|
||||||
|
<channel site="pickx.be" site_id="1185" lang="nl" xmltv_id="DiscoveryChannel.nl@HD">Disc HD N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1222" lang="nl" xmltv_id="Sport10.be@HD">Sport 10 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1055" lang="fr" xmltv_id="NationalGeographic.fr@HD">NGC HD F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1144" lang="nl" xmltv_id="VRT1.be@HD">VRT 1 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1003" lang="fr" xmltv_id="RTLClub.be@HD">RTL club HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1220" lang="nl" xmltv_id="Eurosport1.fr@NetherlandsHD">Eurosp HD N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1006" lang="fr" xmltv_id="France2.fr@HD">France 2 HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1210" lang="nl" xmltv_id="PickxPlusSports7.be@NL">Pickx+ Sports 7 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1188" lang="nl" xmltv_id="InvestigationDiscovery.nl@SD">Inv Disc</channel>
|
||||||
|
<channel site="pickx.be" site_id="1212" lang="nl" xmltv_id="PickxPlusSports9.be@NL">Pickx+ Sports 9 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1213" lang="nl" xmltv_id="PickxPlusSports10.be@NL">Pickx+ Sports 10 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1211" lang="nl" xmltv_id="PickxPlusSports8.be@NL">Pickx+ Sports 8 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1080" lang="fr" xmltv_id="PickxPlusSports10.be@FR">Pickx+ Sports 10 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1077" lang="fr" xmltv_id="PickxPlusSports7.be@FR">Pickx+ Sports 7 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1078" lang="fr" xmltv_id="PickxPlusSports8.be@FR">Pickx+ Sports 8 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1079" lang="fr" xmltv_id="PickxPlusSports9.be@FR">Pickx+ Sports 9 F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1221" lang="nl" xmltv_id="Eurosport2.fr@Netherlands">Eurosp2 N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1077" lang="fr" xmltv_id="PickxPlusSports7.be@FRHD">Pickx+ Sports 7 F HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1210" lang="nl" xmltv_id="PickxPlusSports7.be@NLHD">Pickx+ Sports 7 N HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1165" lang="en" xmltv_id="BBCTwo.uk@England">BBC Two</channel>
|
||||||
|
<channel site="pickx.be" site_id="1146" lang="nl" xmltv_id="VTM.be@HD">VTM HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1151" lang="nl" xmltv_id="VTM4.be@SD">VTM 4</channel>
|
||||||
|
<channel site="pickx.be" site_id="1008" lang="fr" xmltv_id="LaTrois.be@SD">La Trois</channel>
|
||||||
|
<channel site="pickx.be" site_id="1180" lang="nl" xmltv_id="Cartoonito.uk@SD">Cartoonito</channel>
|
||||||
|
<channel site="pickx.be" site_id="1145" lang="nl" xmltv_id="VRTCanvas.be@HD">VRT Canvas HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1170" lang="nl" xmltv_id="Ketnet.be@SD">Ketnet</channel>
|
||||||
|
<channel site="pickx.be" site_id="1023" lang="fr" xmltv_id="Nickelodeon.fr@SD">nick F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1224" lang="nl" xmltv_id="MentTV.be@SD">Ment TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1000" lang="fr" xmltv_id="LaUne.be@HD">La Une HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1173" lang="nl" xmltv_id="DisneyChannel.nl@SD">Disn Ch N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1008" lang="fr" xmltv_id="LaTrois.be@HD">La Trois HD</channel>
|
||||||
|
<channel site="pickx.be" site_id="1108" lang="fr" xmltv_id="QU4TRELiegeMedia.be@SD">Quatre</channel>
|
||||||
|
<channel site="pickx.be" site_id="1133" lang="de" xmltv_id="">BRF Fernsehen</channel>
|
||||||
|
<channel site="pickx.be" site_id="1245" lang="de" xmltv_id="">BRF 1</channel>
|
||||||
|
<channel site="pickx.be" site_id="1261" lang="en" xmltv_id="">Test VRT ENG</channel>
|
||||||
|
<channel site="pickx.be" site_id="1265" lang="en" xmltv_id="">Test 977</channel>
|
||||||
|
<channel site="pickx.be" site_id="1266" lang="en" xmltv_id="">Test RTBF ENG</channel>
|
||||||
|
<channel site="pickx.be" site_id="1267" lang="en" xmltv_id="">Test RTL ENG</channel>
|
||||||
|
<channel site="pickx.be" site_id="1268" lang="en" xmltv_id="">Test DPG ENG</channel>
|
||||||
|
<channel site="pickx.be" site_id="1277" lang="en" xmltv_id="">Test 998</channel>
|
||||||
|
<channel site="pickx.be" site_id="1302" lang="en" xmltv_id="">Horse and Country</channel>
|
||||||
|
<channel site="pickx.be" site_id="2000" lang="en" xmltv_id="">Sanity Check Live 01</channel>
|
||||||
|
<channel site="pickx.be" site_id="1069" lang="fr" xmltv_id="">Pickx+ F</channel>
|
||||||
|
<channel site="pickx.be" site_id="1246" lang="fr" xmltv_id="">RTBF La Prem1ère</channel>
|
||||||
|
<channel site="pickx.be" site_id="1247" lang="fr" xmltv_id="">RTBF VivaCité</channel>
|
||||||
|
<channel site="pickx.be" site_id="1248" lang="fr" xmltv_id="">RTBF Musiq'3</channel>
|
||||||
|
<channel site="pickx.be" site_id="1249" lang="fr" xmltv_id="">RTBF Classic21</channel>
|
||||||
|
<channel site="pickx.be" site_id="1250" lang="fr" xmltv_id="">RTBF Tipik Radio</channel>
|
||||||
|
<channel site="pickx.be" site_id="1251" lang="fr" xmltv_id="">bel RTL</channel>
|
||||||
|
<channel site="pickx.be" site_id="1252" lang="fr" xmltv_id="">MINT</channel>
|
||||||
|
<channel site="pickx.be" site_id="1253" lang="fr" xmltv_id="">Contact</channel>
|
||||||
|
<channel site="pickx.be" site_id="1254" lang="fr" xmltv_id="">Nostalgie</channel>
|
||||||
|
<channel site="pickx.be" site_id="1255" lang="fr" xmltv_id="">LN Radio</channel>
|
||||||
|
<channel site="pickx.be" site_id="1294" lang="fr" xmltv_id="">Test 984</channel>
|
||||||
|
<channel site="pickx.be" site_id="1296" lang="fr" xmltv_id="">RTL district</channel>
|
||||||
|
<channel site="pickx.be" site_id="2001" lang="fr" xmltv_id="">Sanity Check Radio</channel>
|
||||||
|
<channel site="pickx.be" site_id="2002" lang="fr" xmltv_id="">Sanity Check Live 02</channel>
|
||||||
|
<channel site="pickx.be" site_id="2003" lang="fr" xmltv_id="">Sanity Check Live 03</channel>
|
||||||
|
<channel site="pickx.be" site_id="2004" lang="fr" xmltv_id="">Sanity Check Live 04</channel>
|
||||||
|
<channel site="pickx.be" site_id="2005" lang="fr" xmltv_id="">Sanity Check Live 05</channel>
|
||||||
|
<channel site="pickx.be" site_id="2006" lang="fr" xmltv_id="">Sanity Check Live 06</channel>
|
||||||
|
<channel site="pickx.be" site_id="2007" lang="fr" xmltv_id="">Sanity Check Live 07</channel>
|
||||||
|
<channel site="pickx.be" site_id="2008" lang="fr" xmltv_id="">Sanity Check Live 08</channel>
|
||||||
|
<channel site="pickx.be" site_id="2009" lang="fr" xmltv_id="">Sanity Check Live 09</channel>
|
||||||
|
<channel site="pickx.be" site_id="2010" lang="fr" xmltv_id="">Sanity Check Live 10</channel>
|
||||||
|
<channel site="pickx.be" site_id="2011" lang="fr" xmltv_id="">Sanity Check Live 11</channel>
|
||||||
|
<channel site="pickx.be" site_id="2012" lang="fr" xmltv_id="">Sanity Check Live 12</channel>
|
||||||
|
<channel site="pickx.be" site_id="2020" lang="fr" xmltv_id="">Sanity Check Live 20</channel>
|
||||||
|
<channel site="pickx.be" site_id="3350" lang="fr" xmltv_id="">NTVBE Test 11</channel>
|
||||||
|
<channel site="pickx.be" site_id="3351" lang="fr" xmltv_id="">NTVBE Test 12</channel>
|
||||||
|
<channel site="pickx.be" site_id="3352" lang="fr" xmltv_id="">NTVBE Test 13</channel>
|
||||||
|
<channel site="pickx.be" site_id="3353" lang="fr" xmltv_id="">NTVBE Test 14</channel>
|
||||||
|
<channel site="pickx.be" site_id="3354" lang="fr" xmltv_id="">NTVBE Test 15</channel>
|
||||||
|
<channel site="pickx.be" site_id="1139" lang="it" xmltv_id="">Mediaset Italia</channel>
|
||||||
|
<channel site="pickx.be" site_id="1152" lang="nl" xmltv_id="">Studio 100 TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1153" lang="nl" xmltv_id="">Proximus Showcase N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1169" lang="nl" xmltv_id="">Studio 100 TV</channel>
|
||||||
|
<channel site="pickx.be" site_id="1184" lang="nl" xmltv_id="">STAR Channel</channel>
|
||||||
|
<channel site="pickx.be" site_id="1202" lang="nl" xmltv_id="">Pickx+ N</channel>
|
||||||
|
<channel site="pickx.be" site_id="1230" lang="nl" xmltv_id="">Radio 1</channel>
|
||||||
|
<channel site="pickx.be" site_id="1231" lang="nl" xmltv_id="">Radio 2 Antwerpen</channel>
|
||||||
|
<channel site="pickx.be" site_id="1232" lang="nl" xmltv_id="">Radio 2 Limburg</channel>
|
||||||
|
<channel site="pickx.be" site_id="1233" lang="nl" xmltv_id="">Radio 2 Oost-Vlaanderen</channel>
|
||||||
|
<channel site="pickx.be" site_id="1234" lang="nl" xmltv_id="">Radio 2 Vlaam-Brabant</channel>
|
||||||
|
<channel site="pickx.be" site_id="1235" lang="nl" xmltv_id="">Radio 2 West-Vlaanderen</channel>
|
||||||
|
<channel site="pickx.be" site_id="1237" lang="nl" xmltv_id="">MNM</channel>
|
||||||
|
<channel site="pickx.be" site_id="1238" lang="nl" xmltv_id="">MNM Hits</channel>
|
||||||
|
<channel site="pickx.be" site_id="1239" lang="nl" xmltv_id="">Klara</channel>
|
||||||
|
<channel site="pickx.be" site_id="1240" lang="nl" xmltv_id="">Klara Continuo</channel>
|
||||||
|
<channel site="pickx.be" site_id="1241" lang="nl" xmltv_id="">Radio Bene</channel>
|
||||||
|
<channel site="pickx.be" site_id="1242" lang="nl" xmltv_id="">De Tijdloze</channel>
|
||||||
|
<channel site="pickx.be" site_id="1243" lang="nl" xmltv_id="">Qmusic</channel>
|
||||||
|
<channel site="pickx.be" site_id="1244" lang="nl" xmltv_id="">JOE</channel>
|
||||||
|
<channel site="pickx.be" site_id="1278" lang="nl" xmltv_id="">Play Crime</channel>
|
||||||
|
<channel site="pickx.be" site_id="1284" lang="nl" xmltv_id="">Frame</channel>
|
||||||
|
<channel site="pickx.be" site_id="1301" lang="nl" xmltv_id="">Pickx Crime</channel>
|
||||||
|
</channels>
|
||||||
+125
-153
@@ -1,178 +1,150 @@
|
|||||||
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 {
|
|
||||||
// https://px-epg.azureedge.net/version is deprecated
|
|
||||||
// probably the version url will be changed around over time
|
|
||||||
|
|
||||||
//history of used version urls
|
const items = data.containers || []
|
||||||
//const versionUrl = 'https://www.pickx.be/api/s-3b36540f3cef64510112f3f95c2c0cdca321997ed2b1042ad778523235e155eb'
|
items.forEach(item => {
|
||||||
//const versionUrl = 'https://www.pickx.be/api/s-671f172425e1bc74cd0440fd67aaa6cbe68b582f3f401186c2f46ae97e80516b'
|
const metadata = item.metadata
|
||||||
//const versionUrl = 'https://www.pickx.be/api/s-a6b4b4fefaa20e438523a6167e63b8504d96b9df8303473349763c4418cffe30'
|
if (!metadata) return
|
||||||
//const versionUrl = 'https://www.pickx.be/api/s-8546c5fd136241d42aab714d2fe3ccc5671fd899035efae07cd0b8f4eb23994e'
|
|
||||||
//const versionUrl = 'https://www.pickx.be/api/s-64464ad9a3bc117af5dca620027216ecade6a51c230135a0f134c0ee042ff407';
|
|
||||||
//const versionUrl = 'https://www.pickx.be/api/s-626d8fdabfb1d44e5a614cd69f4b45d6843fdb63566fc80ea4f97f40e4ea3152';
|
|
||||||
//const versionUrl = 'https://www.pickx.be/api/s-cefaf96e249e53648c4895c279e7a621233c50b4357d62b0bdf6bff45f31b5c0';
|
|
||||||
//const versionUrl = 'https://www.pickx.be/api/s-7fa35253080e9665f9c7d9d85e707d6fb1d1bf07ede11965e859fcb57c723949';
|
|
||||||
//the new strategy to break the provider is to leave old version url's available and to return invalid results on those endpoints
|
|
||||||
|
|
||||||
const versionUrl = 'https://www.pickx.be/api/s-0e58be3938175b6b900dfb5233bd5cfc0bcf915b633fe57b935f7ce8dbe5f6eb';
|
channels.push({
|
||||||
|
lang: LANGUAGES[metadata.channelLanguage] || 'fr',
|
||||||
|
site_id: String(metadata.channelId),
|
||||||
const response = await axios.get(versionUrl, {
|
name: metadata.channelName
|
||||||
headers: {
|
})
|
||||||
Origin: 'https://www.pickx.be',
|
|
||||||
Referer: 'https://www.pickx.be/'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (response.status === 200) {
|
if (!items.length || channels.length >= data.total) break
|
||||||
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 fetching API version:', error.message)
|
|
||||||
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 []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,20 @@
|
|||||||
|
//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',
|
||||||
@@ -13,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
|
||||||
@@ -92,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) {
|
||||||
@@ -111,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
|
||||||
@@ -133,6 +191,73 @@ function parseEpisode(detail) {
|
|||||||
return detail.episodeNumber
|
return detail.episodeNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseIcon(item) {
|
function parseYear(detail) {
|
||||||
return `${API_IMAGE_ENDPOINT}/intent/${item.id}/posterTile`;
|
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) {
|
||||||
|
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),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,215 @@
|
|||||||
|
//https://github.com/iptv-org/epg/blob/master/sites/web.magentatv.de/web.magentatv.de.config.js
|
||||||
|
|
||||||
|
const axios = require('axios')
|
||||||
|
const dayjs = require('dayjs')
|
||||||
|
const utc = require('dayjs/plugin/utc')
|
||||||
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
|
|
||||||
|
let X_CSRFTOKEN
|
||||||
|
let Cookie
|
||||||
|
const cookiesToExtract = ['JSESSIONID', 'CSESSIONID', 'CSRFSESSION']
|
||||||
|
|
||||||
|
dayjs.extend(utc)
|
||||||
|
dayjs.extend(customParseFormat)
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
site: 'web.magentatv.de',
|
||||||
|
days: 2,
|
||||||
|
url: 'https://api.prod.sngtv.magentatv.de/EPG/JSON/PlayBillList',
|
||||||
|
request: {
|
||||||
|
method: 'POST',
|
||||||
|
async headers() {
|
||||||
|
return await setHeaders()
|
||||||
|
},
|
||||||
|
data({ channel, date }) {
|
||||||
|
return {
|
||||||
|
count: -1,
|
||||||
|
isFillProgram: 1,
|
||||||
|
offset: 0,
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
include:
|
||||||
|
'endtime,genres,id,name,starttime,channelid,pictures,introduce,subName,seasonNum,subNum,cast,country,producedate,externalIds',
|
||||||
|
name: 'playbill'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
type: 2,
|
||||||
|
begintime: date.format('YYYYMMDD000000'),
|
||||||
|
channelid: channel.site_id,
|
||||||
|
endtime: date.add(1, 'd').format('YYYYMMDD000000')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
parser({ content }) {
|
||||||
|
const programs = []
|
||||||
|
const items = parseItems(content)
|
||||||
|
items.forEach(item => {
|
||||||
|
programs.push({
|
||||||
|
title: item.name,
|
||||||
|
description: item.introduce,
|
||||||
|
image: parseImage(item),
|
||||||
|
icon: parseImage(item),
|
||||||
|
category: parseCategory(item),
|
||||||
|
start: parseStart(item),
|
||||||
|
stop: parseStop(item),
|
||||||
|
sub_title: item.subName,
|
||||||
|
season: item.seasonNum,
|
||||||
|
episode: item.subNum,
|
||||||
|
directors: parseDirectors(item),
|
||||||
|
producers: parseProducers(item),
|
||||||
|
adapters: parseAdapters(item),
|
||||||
|
country: item.country?.toUpperCase(),
|
||||||
|
date: item.producedate,
|
||||||
|
urls: parseUrls(item)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return programs
|
||||||
|
},
|
||||||
|
async channels() {
|
||||||
|
const url = 'https://api.prod.sngtv.magentatv.de/EPG/JSON/AllChannel'
|
||||||
|
const body = {
|
||||||
|
channelNamespace: 2,
|
||||||
|
filterlist: [
|
||||||
|
{
|
||||||
|
key: 'IsHide',
|
||||||
|
value: '-1'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
metaDataVer: 'Channel/1.1',
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
include: '/channellist/logicalChannel/contentId,/channellist/logicalChannel/name',
|
||||||
|
name: 'logicalChannel'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returnSatChannel: 0
|
||||||
|
}
|
||||||
|
const params = {
|
||||||
|
headers: await setHeaders()
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await axios
|
||||||
|
.post(url, body, params)
|
||||||
|
.then(r => r.data)
|
||||||
|
.catch(console.log)
|
||||||
|
|
||||||
|
return data.channellist.map(item => {
|
||||||
|
return {
|
||||||
|
lang: 'de',
|
||||||
|
site_id: item.contentId,
|
||||||
|
name: item.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCategory(item) {
|
||||||
|
return item.genres
|
||||||
|
? item.genres
|
||||||
|
.replace('und', ',')
|
||||||
|
.split(',')
|
||||||
|
.map(i => i.trim())
|
||||||
|
: []
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseDirectors(item) {
|
||||||
|
if (!item.cast || !item.cast.director) return []
|
||||||
|
return item.cast.director
|
||||||
|
.replace('und', ',')
|
||||||
|
.split(',')
|
||||||
|
.map(i => i.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseProducers(item) {
|
||||||
|
if (!item.cast || !item.cast.producer) return []
|
||||||
|
return item.cast.producer
|
||||||
|
.replace('und', ',')
|
||||||
|
.split(',')
|
||||||
|
.map(i => i.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseAdapters(item) {
|
||||||
|
if (!item.cast || !item.cast.adaptor) return []
|
||||||
|
return item.cast.adaptor
|
||||||
|
.replace('und', ',')
|
||||||
|
.split(',')
|
||||||
|
.map(i => i.trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseUrls(item) {
|
||||||
|
// currently only a imdb id is returned by the api, thus we can construct the url here
|
||||||
|
if (!item.externalIds) return []
|
||||||
|
return JSON.parse(item.externalIds)
|
||||||
|
.filter(externalId => externalId.type === 'imdb' && externalId.id)
|
||||||
|
.map(externalId => ({ system: 'imdb', value: `https://www.imdb.com/title/${externalId.id}` }))
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseImage(item) {
|
||||||
|
if (!Array.isArray(item.pictures) || !item.pictures.length) return null
|
||||||
|
|
||||||
|
return item.pictures[0].href
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseStart(item) {
|
||||||
|
return dayjs.utc(item.starttime, 'YYYY-MM-DD HH:mm:ss')
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseStop(item) {
|
||||||
|
return dayjs.utc(item.endtime, 'YYYY-MM-DD HH:mm:ss')
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseItems(content) {
|
||||||
|
const data = JSON.parse(content)
|
||||||
|
if (!data || !Array.isArray(data.playbilllist)) return []
|
||||||
|
|
||||||
|
return data.playbilllist
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchCookieAndToken() {
|
||||||
|
// Only fetch the cookies and csrfToken if they are not already set
|
||||||
|
if (X_CSRFTOKEN && Cookie) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.request({
|
||||||
|
url: 'https://api.prod.sngtv.magentatv.de/EPG/JSON/Authenticate',
|
||||||
|
params: {
|
||||||
|
SID: 'firstup',
|
||||||
|
T: 'Windows_chrome_118'
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
data: '{"terminalid":"00:00:00:00:00:00","mac":"00:00:00:00:00:00","terminaltype":"WEBTV","utcEnable":1,"timezone":"Etc/GMT0","userType":3,"terminalvendor":"Unknown"}'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Extract the cookies specified in cookiesToExtract
|
||||||
|
const setCookieHeader = response.headers['set-cookie'] || []
|
||||||
|
const extractedCookies = []
|
||||||
|
cookiesToExtract.forEach(cookieName => {
|
||||||
|
const regex = new RegExp(`${cookieName}=(.+?)(;|$)`)
|
||||||
|
const match = setCookieHeader.find(header => regex.test(header))
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
const cookieString = regex.exec(match)[0]
|
||||||
|
extractedCookies.push(cookieString)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// check if we recieved a csrfToken only then store the values
|
||||||
|
if (!response.data.csrfToken) {
|
||||||
|
console.log('csrfToken not found in the response.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
X_CSRFTOKEN = response.data.csrfToken
|
||||||
|
Cookie = extractedCookies.join(' ')
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setHeaders() {
|
||||||
|
await fetchCookieAndToken()
|
||||||
|
|
||||||
|
return { X_CSRFTOKEN, Cookie }
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -6,8 +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#*=}" ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -15,15 +17,16 @@ 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}"
|
||||||
|
|
||||||
if [ "$enable_fixes" = true ] ; then
|
if [ "$enable_fixes" = true ] ; then
|
||||||
cp -R /fixes/* /bin/epg/sites/
|
cp -R /fixes/* /bin/epg/sites/
|
||||||
fi
|
fi
|
||||||
|
|
||||||
pm2 --name epg start npm -- run serve
|
sed -i -E "s/(https:\x2f\x2fiptv-org.github.io\x2fapi$\123filename\125)/$api_url$\123filename\125/g" $work_dir/scripts/core/apiClient.ts
|
||||||
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"
|
||||||
Reference in new issue
Block a user