Compare commits
103 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 |
@@ -21,6 +21,64 @@ jobs:
|
|||||||
echo "Docker installation not found. Docker will be installed"
|
echo "Docker installation not found. Docker will be installed"
|
||||||
curl -fsSL https://get.docker.com | sh
|
curl -fsSL https://get.docker.com | sh
|
||||||
fi
|
fi
|
||||||
|
- name: Install npm dependencies
|
||||||
|
run: |
|
||||||
|
echo "Installing fetch"
|
||||||
|
install_node=$false
|
||||||
|
if ! command -v node &> /dev/null; then
|
||||||
|
echo "No version of NodeJS detected"
|
||||||
|
install_node=true
|
||||||
|
else
|
||||||
|
node_version=$(node -v)
|
||||||
|
node_version=${node_version:1} # Remove 'v' at the beginning
|
||||||
|
node_version=${node_version%\.*} # Remove trailing ".*".
|
||||||
|
node_version=${node_version%\.*} # Remove trailing ".*".
|
||||||
|
node_version=$(($node_version)) # Convert the NodeJS version number from a string to an integer.
|
||||||
|
if [ $node_version -lt 24 ]; then
|
||||||
|
echo "node version : " $node_version
|
||||||
|
echo $"removing outdated npm version"
|
||||||
|
install_node=true
|
||||||
|
apt-get remove nodejs npm
|
||||||
|
apt-get purge nodejs
|
||||||
|
rm -rf /usr/local/bin/npm
|
||||||
|
rm -rf /usr/local/share/man/man1/node*
|
||||||
|
rm -rf /usr/local/lib/dtrace/node.d
|
||||||
|
rm -rf ~/.npm
|
||||||
|
rm -rf ~/.node-gyp
|
||||||
|
rm -rf /opt/local/bin/node
|
||||||
|
rm -rf opt/local/include/node
|
||||||
|
rm -rf /opt/local/lib/node_modules
|
||||||
|
rm -rf /usr/local/lib/node*
|
||||||
|
rm -rf /usr/local/include/node*
|
||||||
|
rm -rf /usr/local/bin/node*
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if $install_node; then
|
||||||
|
NODE_MAJOR=24
|
||||||
|
echo "Installing node ${NODE_MAJOR}"
|
||||||
|
if test -f /etc/apt/keyrings/nodesource.gpg; then
|
||||||
|
rm /etc/apt/keyrings/nodesource.gpg
|
||||||
|
fi
|
||||||
|
if test -f /etc/apt/sources.list.d/nodesource.list; then
|
||||||
|
rm /etc/apt/sources.list.d/nodesource.list
|
||||||
|
fi
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y -q ca-certificates curl gnupg
|
||||||
|
mkdir -p /etc/apt/keyrings
|
||||||
|
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
||||||
|
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y -q nodejs
|
||||||
|
npm install npm --global
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "node version : " $(node -v)
|
||||||
|
|
||||||
|
package='node-fetch'
|
||||||
|
if [ `npm list -g | grep -c $package` -eq 0 ]; then
|
||||||
|
npm install -g $package
|
||||||
|
fi
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: https://github.com/docker/setup-buildx-action@v3
|
uses: https://github.com/docker/setup-buildx-action@v3
|
||||||
- name: Login to Gitea container registry
|
- name: Login to Gitea container registry
|
||||||
@@ -38,12 +96,23 @@ 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://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
|
||||||
tags: |
|
tags: |
|
||||||
type=semver,pattern={{raw}}
|
type=semver,pattern={{raw}}
|
||||||
type=sha
|
type=sha
|
||||||
|
- name: Update docker Hub Description
|
||||||
|
uses: https://github.com/peter-evans/dockerhub-description@v5
|
||||||
|
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 +120,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 }}
|
||||||
|
|
||||||
|
|||||||
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
github: davidclaeysquinones
|
||||||
5
.github/workflows/action.yml
vendored
5
.github/workflows/action.yml
vendored
@@ -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}}
|
||||||
|
|||||||
15
Dockerfile
15
Dockerfile
@@ -1,8 +1,10 @@
|
|||||||
FROM node:21-alpine
|
FROM node:22-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,7 +24,8 @@ 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 .gitignore \
|
||||||
@@ -40,14 +43,20 @@ RUN apk update \
|
|||||||
&& 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
|
||||||
9
LICENSE
Normal file
9
LICENSE
Normal file
@@ -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.
|
||||||
183
README.md
183
README.md
@@ -11,7 +11,7 @@ A public mirror is available at https://github.com/davidclaeysquinones/epg-info-
|
|||||||
[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:22-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,7 +32,20 @@ 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 | [davidclaeysquinones](https://github.com/davidclaeysquinones) | [PR](https://github.com/iptv-org/epg/pull/2440) pending approval |
|
||||||
|
| orangetv.orange.es | [fraudiay79](https://github.com/fraudiay79) and [davidclaeysquinones](https://github.com/davidclaeysquinones) | [PR](https://github.com/iptv-org/epg/pull/2485) merged since commit [8a8262e](https://github.com/iptv-org/epg/commit/8a8262eacb46b2d35df7eb11f46de22263eab053) |
|
||||||
|
| pickx.be | [davidclaeysquinones](https://github.com/davidclaeysquinones) and [BellezaEmporium](https://github.com/BellezaEmporium) | [PR](https://github.com/iptv-org/epg/pull/2525) merged since commit [fd91a9c](https://github.com/iptv-org/epg/commit/fd91a9c532b476f6e192a564371d30e766b762ab) |
|
||||||
|
| telenet.tv | [davidclaeysquinones](https://github.com/davidclaeysquinones) | [PR](https://github.com/iptv-org/epg/pull/2429) merged since commit [fd382db](https://github.com/iptv-org/epg/commit/fd382db08da7a96150928b8dcfef115e29e661d3) |
|
||||||
|
| web.magentatv.de | [klausellus-wallace](https://github.com/klausellus-wallace) | [PR](https://github.com/iptv-org/epg/pull/2458) merged since commit [61afe09](https://github.com/iptv-org/epg/commit/61afe090b6e7892cc5426457d960e9452222f885) |
|
||||||
|
|
||||||
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.
|
||||||
@@ -40,11 +53,13 @@ It is recommended that you take existing provider code as a base for your custom
|
|||||||
### 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 |
|
||||||
|
| DELAY | Delay between requests in milliseconds | 0 |
|
||||||
| MAX_CONNECTIONS | The maximum amount of parallel connections that can be established | 10 |
|
| MAX_CONNECTIONS | The maximum amount of parallel connections that can be established | 10 |
|
||||||
| ENABLE_FIXES | Some fixes to providers take a long time to be merged into the main branch.<br>When this option is enabled some of these fixes will also be included.<br>The source code for these fixes can be seen under the `fixes` folder.<br> Recreate the container when changing this variable in order for it to take effect | false |
|
| ENABLE_FIXES | Some fixes to providers take a long time to be merged into the main branch.<br>When this option is enabled some of these fixes will also be included.<br>The source code for these fixes can be seen under the `fixes` folder.<br> Recreate the container when changing this variable in order for it to take effect | false |
|
||||||
|
| API_URL | The endpoint where channel information will be grabbed | `https://iptv-org.github.io/api` |
|
||||||
|
|
||||||
### Compose file
|
### Compose file
|
||||||
|
|
||||||
@@ -72,29 +87,167 @@ 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
|
- 1.0.9
|
||||||
[10-12-2024](https://github.com/iptv-org/epg/commit/fd382db08da7a96150928b8dcfef115e29e661d3)
|
[10-12-2024](https://github.com/iptv-org/epg/commit/fd382db08da7a96150928b8dcfef115e29e661d3)
|
||||||
- 1.0.10
|
- 1.0.10
|
||||||
[10-14-2024](https://github.com/iptv-org/epg/commit/a3e7661f95103cbee4bcb78bd483396680e9abfc)
|
[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,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,146 @@
|
|||||||
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 cheerio = require('cheerio')
|
||||||
|
const dayjs = require('dayjs')
|
||||||
|
const utc = require('dayjs/plugin/utc')
|
||||||
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
|
|
||||||
|
dayjs.extend(utc)
|
||||||
|
dayjs.extend(timezone)
|
||||||
|
|
||||||
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://www.movistarplus.es/programacion-tv/${channel.site_id}/${date.format('YYYY-MM-DD')}`
|
||||||
},
|
},
|
||||||
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, date }) {
|
||||||
let programs = []
|
let programs = []
|
||||||
let items = parseItems(content, channel)
|
const $ = cheerio.load(content)
|
||||||
if (!items.length) return programs
|
|
||||||
let guideDate = date
|
|
||||||
|
|
||||||
items.forEach(item => {
|
const programDivs = $('div[id^="ele-"]').toArray()
|
||||||
let startTime = DateTime.fromFormat(
|
|
||||||
`${guideDate.format('YYYY-MM-DD')} ${item.HORA_INICIO}`,
|
for (let i = 0; i < programDivs.length; i++) {
|
||||||
'yyyy-MM-dd HH:mm',
|
const el = $(programDivs[i])
|
||||||
{
|
|
||||||
zone: 'Europe/Madrid'
|
const title = el.find('li.title').text().trim()
|
||||||
|
if (!title) continue
|
||||||
|
|
||||||
|
const timeText = el.find('li.time').text().trim()
|
||||||
|
if (!timeText) continue
|
||||||
|
|
||||||
|
const [hours, minutes] = timeText.split(':').map(h => parseInt(h, 10))
|
||||||
|
|
||||||
|
// Parse time in Spain timezone (Europe/Madrid)
|
||||||
|
let startDate = dayjs.tz(
|
||||||
|
`${date.format('YYYY-MM-DD')} ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`,
|
||||||
|
'YYYY-MM-DD HH:mm',
|
||||||
|
'Europe/Madrid'
|
||||||
|
)
|
||||||
|
|
||||||
|
// If the time is in early morning (before 5 AM), it's the next day
|
||||||
|
if (hours < 5) {
|
||||||
|
startDate = startDate.add(1, 'day')
|
||||||
}
|
}
|
||||||
).toUTC()
|
|
||||||
let stopTime = DateTime.fromFormat(
|
// Calculate end time from next program's start time
|
||||||
`${guideDate.format('YYYY-MM-DD')} ${item.HORA_FIN}`,
|
let endDate
|
||||||
'yyyy-MM-dd HH:mm',
|
if (i < programDivs.length - 1) {
|
||||||
{
|
const nextEl = $(programDivs[i + 1])
|
||||||
zone: 'Europe/Madrid'
|
const nextTimeText = nextEl.find('li.time').text().trim()
|
||||||
|
if (nextTimeText) {
|
||||||
|
const [nextHours, nextMinutes] = nextTimeText.split(':').map(h => parseInt(h, 10))
|
||||||
|
endDate = dayjs.tz(
|
||||||
|
`${date.format('YYYY-MM-DD')} ${nextHours.toString().padStart(2, '0')}:${nextMinutes.toString().padStart(2, '0')}`,
|
||||||
|
'YYYY-MM-DD HH:mm',
|
||||||
|
'Europe/Madrid'
|
||||||
|
)
|
||||||
|
|
||||||
|
// If the next time is in early morning (before 5 AM), it's the next day
|
||||||
|
if (nextHours < 5) {
|
||||||
|
endDate = endDate.add(1, 'day')
|
||||||
}
|
}
|
||||||
).toUTC()
|
|
||||||
if (stopTime < startTime) {
|
// If end time is still before or same as start time, add another day
|
||||||
guideDate = guideDate.add(1, 'd')
|
if (endDate.isBefore(startDate) || endDate.isSame(startDate)) {
|
||||||
stopTime = stopTime.plus({ days: 1 })
|
endDate = endDate.add(1, 'day')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no end time, use start of next day
|
||||||
|
if (!endDate) {
|
||||||
|
endDate = startDate.add(1, 'day').startOf('day')
|
||||||
|
}
|
||||||
|
|
||||||
|
const programLink = el.find('a').attr('href')
|
||||||
|
let description = null
|
||||||
|
|
||||||
|
if (programLink) {
|
||||||
|
description = await getProgramDescription(programLink).catch(() => null)
|
||||||
|
}
|
||||||
|
|
||||||
programs.push({
|
programs.push({
|
||||||
title: item.TITULO,
|
title,
|
||||||
icon: parseIcon(item, channel),
|
description,
|
||||||
category: item.GENERO,
|
start: startDate,
|
||||||
start: startTime,
|
stop: endDate
|
||||||
stop: stopTime
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels() {
|
async channels() {
|
||||||
const axios = require('axios')
|
const html = await axios
|
||||||
const dayjs = require('dayjs')
|
.get('https://www.movistarplus.es/programacion-tv', {
|
||||||
const data = await axios
|
headers: {
|
||||||
.get(`${API_PROD_ENDPOINT}/${dayjs().format('YYYY-MM-DD')}?v=json`)
|
'User-Agent':
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||||
|
Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'
|
||||||
|
}
|
||||||
|
})
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.log)
|
.catch(console.log)
|
||||||
|
|
||||||
return Object.values(data.data).map(item => {
|
const $ = cheerio.load(html)
|
||||||
|
let scheme = $('script:contains(ItemList)').html()
|
||||||
|
scheme = JSON.parse(scheme)
|
||||||
|
|
||||||
|
return scheme.itemListElement.map(el => {
|
||||||
|
const urlParts = el.item.url.split('/')
|
||||||
|
const site_id = urlParts.pop().toLowerCase()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
lang: 'es',
|
lang: 'es',
|
||||||
site_id: item.DATOS_CADENA.CODIGO,
|
name: el.item.name,
|
||||||
name: item.DATOS_CADENA.NOMBRE
|
site_id
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseIcon(item, channel) {
|
async function getProgramDescription(programUrl) {
|
||||||
return `${API_IMAGE_ENDPOINT}/M${channel.site_id}P${item.ELEMENTO}`;
|
const response = await axios.get(programUrl, {
|
||||||
|
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',
|
||||||
|
Referer: 'https://www.movistarplus.es/programacion-tv/'
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
function parseItems(content, channel) {
|
const $ = cheerio.load(response.data)
|
||||||
const json = typeof content === 'string' ? JSON.parse(content) : content
|
const description = $('.show-content .text p').first().text().trim() || null
|
||||||
if (!(`${channel.site_id}-CODE` in json.data)) return []
|
|
||||||
const data = json.data[`${channel.site_id}-CODE`]
|
return description
|
||||||
return data ? data.PROGRAMAS : []
|
|
||||||
}
|
}
|
||||||
104
fixes/orangetv.orange.es/orangetv.orange.es.config.js
Normal file
104
fixes/orangetv.orange.es/orangetv.orange.es.config.js
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
//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/Smartphone_Android/1_PRO'
|
||||||
|
const API_CHANNEL_ENDPOINT =
|
||||||
|
'https://pc.orangetv.orange.es/pc/api/rtv/v1/GetChannelList?bouquet_id=1&model_external_id=PC&filter_unsupported_channels=false&client=json'
|
||||||
|
const API_IMAGE_ENDPOINT = 'https://pc.orangetv.orange.es/pc/api/rtv/v1/images'
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
site: 'orangetv.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: function({ date, segment = 1 }) {
|
||||||
|
return `${API_PROGRAM_ENDPOINT}/${date.format('YYYYMMDD')}_8h_${segment}.json`
|
||||||
|
},
|
||||||
|
async parser({ content, channel, date }) {
|
||||||
|
const programs = []
|
||||||
|
const items = parseItems(content, channel)
|
||||||
|
if (items.length) {
|
||||||
|
const queues = [
|
||||||
|
module.exports.url({ date, segment: 2 }),
|
||||||
|
module.exports.url({ date, segment: 3 })
|
||||||
|
]
|
||||||
|
await doFetch(queues, (url, res) => {
|
||||||
|
items.push(...parseItems(res, channel))
|
||||||
|
})
|
||||||
|
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 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 => i.channelExternalId === channel.site_id)
|
||||||
|
.forEach(i => {
|
||||||
|
result.push(...i.programs)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -1,32 +1,18 @@
|
|||||||
|
//https://github.com/iptv-org/epg/blob/e4f92bb2a2768dcba3dbbd52b19d78d96bebc31e/sites/pickx.be/pickx.be.config.js
|
||||||
|
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
|
||||||
|
|
||||||
let apiVersion
|
let apiVersion
|
||||||
let isApiVersionFetched = false
|
|
||||||
|
|
||||||
;(async () => {
|
|
||||||
try {
|
|
||||||
await fetchApiVersion()
|
|
||||||
isApiVersionFetched = true
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error during script initialization:', error)
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
|
|
||||||
dayjs.extend(utc)
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'pickx.be',
|
site: 'pickx.be',
|
||||||
days: 2,
|
days: 2,
|
||||||
apiVersion: function () {
|
async url({ channel, date }) {
|
||||||
return apiVersion
|
if (!apiVersion) {
|
||||||
},
|
await fetchApiVersion()
|
||||||
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(
|
return `https://px-epg.azureedge.net/airings/${apiVersion}/${date.format(
|
||||||
'YYYY-MM-DD'
|
'YYYY-MM-DD'
|
||||||
)}/channel/${channel.site_id}?timezone=Europe%2FBrussels`
|
)}/channel/${channel.site_id}?timezone=Europe%2FBrussels`
|
||||||
@@ -50,25 +36,27 @@ module.exports = {
|
|||||||
? item.program.translatedCategory[channel.lang]
|
? item.program.translatedCategory[channel.lang]
|
||||||
: item.program.category.split('.')[1],
|
: item.program.category.split('.')[1],
|
||||||
image: item.program.posterFileName
|
image: item.program.posterFileName
|
||||||
? `https://experience-cache.proximustv.be/posterserver/poster/EPG/w-166_h-110/${item.program.posterFileName}`
|
? `https://experience-cache.cdi.streaming.proximustv.be/posterserver/poster/EPG/${item.program.posterFileName}`
|
||||||
: null,
|
: null,
|
||||||
season: item.program.seasonNumber,
|
season: item.program.seasonNumber,
|
||||||
episode: item.program.episodeNumber,
|
episode: item.program.episodeNumber,
|
||||||
actors: item.program.actors,
|
actors: item.program.actors,
|
||||||
director: item.program.director ? [item.program.director] : null,
|
director: item.program.director ? [item.program.director] : null,
|
||||||
start: dayjs.utc(item.programScheduleStart),
|
start: dayjs(item.programScheduleStart),
|
||||||
stop: dayjs.utc(item.programScheduleEnd)
|
stop: dayjs(item.programScheduleEnd)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels({ lang = '' }) {
|
async channels() {
|
||||||
|
let channels = []
|
||||||
|
|
||||||
const query = {
|
const query = {
|
||||||
operationName: 'getChannels',
|
operationName: 'getChannels',
|
||||||
variables: {
|
variables: {
|
||||||
language: lang,
|
language: 'fr',
|
||||||
queryParams: {},
|
queryParams: {},
|
||||||
id: '0',
|
id: '0',
|
||||||
params: {
|
params: {
|
||||||
@@ -78,84 +66,49 @@ module.exports = {
|
|||||||
query: `query getChannels($language: String!, $queryParams: ChannelQueryParams, $id: String, $params: ChannelParams) {
|
query: `query getChannels($language: String!, $queryParams: ChannelQueryParams, $id: String, $params: ChannelParams) {
|
||||||
channels(language: $language, queryParams: $queryParams, id: $id, params: $params) {
|
channels(language: $language, queryParams: $queryParams, id: $id, params: $params) {
|
||||||
id
|
id
|
||||||
channelReferenceNumber
|
|
||||||
name
|
name
|
||||||
callLetter
|
|
||||||
number
|
|
||||||
logo {
|
|
||||||
key
|
|
||||||
url
|
|
||||||
__typename
|
|
||||||
}
|
|
||||||
language
|
language
|
||||||
hd
|
|
||||||
radio
|
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)
|
const data = await axios
|
||||||
|
.post('https://api.proximusmwc.be/tiams/v3/graphql', query)
|
||||||
.then(r => r.data)
|
.then(r => r.data)
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
|
|
||||||
return (
|
data.data.channels.forEach(channel => {
|
||||||
result?.data?.channels
|
let lang = channel.language || 'fr'
|
||||||
.filter(
|
if (channel.language === 'ger') lang = 'de'
|
||||||
channel =>
|
|
||||||
!channel.radio && (!lang || channel.language === (lang === 'de' ? 'ger' : lang))
|
channels.push({
|
||||||
)
|
lang,
|
||||||
.map(channel => {
|
|
||||||
return {
|
|
||||||
lang: channel.language === 'ger' ? 'de' : channel.language,
|
|
||||||
site_id: channel.id,
|
site_id: channel.id,
|
||||||
name: channel.name
|
name: channel.name
|
||||||
}
|
})
|
||||||
}) || []
|
})
|
||||||
)
|
|
||||||
|
return channels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 versionUrl = 'https://www.pickx.be/api/s-3b36540f3cef64510112f3f95c2c0cdca321997ed2b1042ad778523235e155eb'
|
|
||||||
//const versionUrl = 'https://www.pickx.be/api/s-671f172425e1bc74cd0440fd67aaa6cbe68b582f3f401186c2f46ae97e80516b'
|
|
||||||
//const versionUrl = 'https://www.pickx.be/api/s-a6b4b4fefaa20e438523a6167e63b8504d96b9df8303473349763c4418cffe30'
|
|
||||||
//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';
|
|
||||||
|
|
||||||
|
async function fetchApiVersion() {
|
||||||
|
const hashUrl = 'https://www.pickx.be/nl/televisie/tv-gids'
|
||||||
|
const hashData = await axios
|
||||||
|
.get(hashUrl)
|
||||||
|
.then(r => {
|
||||||
|
const re = /"hashes":\["(.*)"\]/
|
||||||
|
const match = r.data.match(re)
|
||||||
|
if (match && match[1]) {
|
||||||
|
return match[1]
|
||||||
|
} else {
|
||||||
|
throw new Error('React app version hash not found')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(console.error)
|
||||||
|
|
||||||
|
const versionUrl = `https://www.pickx.be/api/s-${hashData}`
|
||||||
const response = await axios.get(versionUrl, {
|
const response = await axios.get(versionUrl, {
|
||||||
headers: {
|
headers: {
|
||||||
Origin: 'https://www.pickx.be',
|
Origin: 'https://www.pickx.be',
|
||||||
@@ -163,6 +116,8 @@ function fetchApiVersion() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
apiVersion = response.data.version
|
apiVersion = response.data.version
|
||||||
resolve()
|
resolve()
|
||||||
@@ -171,7 +126,7 @@ function fetchApiVersion() {
|
|||||||
reject(`Failed to fetch API version. Status: ${response.status}`)
|
reject(`Failed to fetch API version. Status: ${response.status}`)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching API version:', error.message)
|
console.error('Error during fetchApiVersion:', error)
|
||||||
reject(error)
|
reject(error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
//https://github.com/iptv-org/epg/blob/e4f92bb2a2768dcba3dbbd52b19d78d96bebc31e/sites/telenet.tv/telenet.tv.config.js
|
||||||
|
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
|
|
||||||
const API_STATIC_ENDPOINT = 'https://static.spark.telenet.tv/eng/web/epg-service-lite/be'
|
const API_STATIC_ENDPOINT = 'https://static.spark.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'
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'telenet.tv',
|
site: 'telenet.tv',
|
||||||
@@ -14,7 +16,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
url: function ({ date, channel }) {
|
url: function ({ date, channel }) {
|
||||||
return `${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date.format('YYYYMMDDHHmmss')}`
|
return `${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date.format('YYYYMMDD')}000000`
|
||||||
},
|
},
|
||||||
async parser({ content, channel, date }) {
|
async parser({ content, channel, date }) {
|
||||||
let programs = []
|
let programs = []
|
||||||
@@ -22,25 +24,19 @@ module.exports = {
|
|||||||
if (!items.length) return programs
|
if (!items.length) return programs
|
||||||
const promises = [
|
const promises = [
|
||||||
axios.get(
|
axios.get(
|
||||||
`${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date
|
`${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date.format('YYYYMMDD')}060000`,
|
||||||
.add(6, 'h')
|
|
||||||
.format('YYYYMMDDHHmmss')}`,
|
|
||||||
{
|
{
|
||||||
responseType: 'arraybuffer'
|
responseType: 'arraybuffer'
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
axios.get(
|
axios.get(
|
||||||
`${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date
|
`${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date.format('YYYYMMDD')}120000`,
|
||||||
.add(12, 'h')
|
|
||||||
.format('YYYYMMDDHHmmss')}`,
|
|
||||||
{
|
{
|
||||||
responseType: 'arraybuffer'
|
responseType: 'arraybuffer'
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
axios.get(
|
axios.get(
|
||||||
`${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date
|
`${API_STATIC_ENDPOINT}/${channel.lang}/events/segments/${date.format('YYYYMMDD')}180000`,
|
||||||
.add(18, 'h')
|
|
||||||
.format('YYYYMMDDHHmmss')}`,
|
|
||||||
{
|
{
|
||||||
responseType: 'arraybuffer'
|
responseType: 'arraybuffer'
|
||||||
}
|
}
|
||||||
@@ -63,6 +59,7 @@ module.exports = {
|
|||||||
const detail = await loadProgramDetails(item, channel)
|
const detail = await loadProgramDetails(item, channel)
|
||||||
programs.push({
|
programs.push({
|
||||||
title: item.title,
|
title: item.title,
|
||||||
|
subTitle: detail.episodeName,
|
||||||
icon: parseIcon(item),
|
icon: parseIcon(item),
|
||||||
description: detail.longDescription,
|
description: detail.longDescription,
|
||||||
category: detail.genres,
|
category: detail.genres,
|
||||||
@@ -134,5 +131,5 @@ function parseEpisode(detail) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function parseIcon(item) {
|
function parseIcon(item) {
|
||||||
return `${API_IMAGE_ENDPOINT}/intent/${item.id}/posterTile`;
|
return `${API_IMAGE_ENDPOINT}/intent/${item.id}/posterTile`
|
||||||
}
|
}
|
||||||
215
fixes/web.magentatv.de/web.magentatv.de.config.js
Normal file
215
fixes/web.magentatv.de/web.magentatv.de.config.js
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
// https://github.com/iptv-org/epg/blob/e4f92bb2a2768dcba3dbbd52b19d78d96bebc31e/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),
|
||||||
|
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 }
|
||||||
|
}
|
||||||
23
pm2.config.js
Normal file
23
pm2.config.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
module.exports = {
|
||||||
|
apps: [
|
||||||
|
{
|
||||||
|
name: 'serve',
|
||||||
|
script: 'npx serve -- public',
|
||||||
|
instances: 1,
|
||||||
|
watch: false,
|
||||||
|
autorestart: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'grab',
|
||||||
|
script: process.env.SITE
|
||||||
|
? `npm run grab -- --site=${process.env.SITE} ${
|
||||||
|
process.env.CLANG ? `--lang=${process.env.CLANG}` : ''
|
||||||
|
} --output=public/guide.xml`
|
||||||
|
: `npm run grab -- --gzip --channels=channels.xml --output=public/guide.xml`,
|
||||||
|
cron_restart: process.env.CRON_SCHEDULE || null,
|
||||||
|
instances: 1,
|
||||||
|
watch: false,
|
||||||
|
autorestart: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
9
start.sh
9
start.sh
@@ -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