` command.
- `channels:validate`: checks the description of channels for errors.
- `sites:init`: creates a new site config from the template.
- `sites:update`: updates the list of sites and their status in [SITES.md](SITES.md).
+- `guides:update`: updates the list of guides and their status in [GUIDES.md](GUIDES.md).
- `grab`: downloads a program from a specified source.
- `serve`: starts the [web server](https://github.com/vercel/serve).
- `lint`: сhecks the scripts for syntax errors.
diff --git a/GUIDES.md b/GUIDES.md
new file mode 100644
index 000000000..46c58a37d
--- /dev/null
+++ b/GUIDES.md
@@ -0,0 +1,12 @@
+# Guides
+
+
+
+ | Host | Status | Channels | Last Updated | Links |
+
+
+ | worker-9dd4.onrender.com | 🟢 | 1 | a day ago | channels.xml guide.xml |
+
+
+
+[How can I add my server to the list?](CONTRIBUTING.md#how-to-add-my-server-to-the-guides-md)
diff --git a/README.md b/README.md
index 06a8bf352..d6aeecd9a 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ Tools for downloading the EPG (Electronic Program Guide) for thousands of TV cha
- 🚀 [Usage](#usage)
- 💫 [Update](#update)
- 🐋 [Docker](#docker)
-- 📺 [Playlists](#playlists)
+- 📅 [Guides](#guides)
- 🗄 [Database](#database)
- 👨💻 [API](#api)
- 📚 [Resources](#resources)
@@ -155,7 +155,7 @@ docker pull ghcr.io/iptv-org/epg:master
### Create and run container
```sh
-docker run -p 3000:3000 -v /path/to/channels.xml:/epg/channels.xml ghcr.io/iptv-org/epg:master
+docker run -p 3000:3000 -v /path/to/channels.xml:/epg/public/channels.xml ghcr.io/iptv-org/epg:master
```
By default, the guide will be downloaded every day at 00:00 UTC and saved to the `/epg/public/guide.xml` file inside the container.
@@ -179,7 +179,7 @@ To fine-tune the execution, you can pass environment variables to the container
```sh
docker run \
-p 5000:3000 \
--v /path/to/channels.xml:/epg/channels.xml \
+-v /path/to/channels.xml:/epg/public/channels.xml \
-e CRON_SCHEDULE="0 0,12 * * *" \
-e MAX_CONNECTIONS=10 \
-e GZIP=true \
@@ -203,6 +203,10 @@ ghcr.io/iptv-org/epg:master
| DELAY | Delay between request in milliseconds (default: 0) |
| RUN_AT_STARTUP | Run grab on container startup (default: true) |
+## Guides
+
+Any user can share the guides they have created with the rest of the community. A complete list of these guides and their current status can be found in the [GUIDES.md](GUIDES.md) file.
+
## Database
All channel data is taken from the [iptv-org/database](https://github.com/iptv-org/database) repository. If you find any errors please open a new [issue](https://github.com/iptv-org/database/issues) there.
@@ -236,4 +240,3 @@ And thank you to everyone who has already contributed!
## License
[](LICENSE)
-
diff --git a/SITES.md b/SITES.md
index c3a569249..c2da69e56 100644
--- a/SITES.md
+++ b/SITES.md
@@ -59,7 +59,7 @@
| foxsports.com.au | 7 | 7 | 🟢 | |
| foxtel.com.au | 99 | 60 | 🟢 | |
| freetv.tv | 7 | 7 | 🟢 | |
- | freeview.co.uk | 167 | 98 | 🟢 | |
+ | freeview.co.uk | 166 | 104 | 🟢 | |
| frikanalen.no | 1 | 1 | 🟢 | |
| galamtv.kz | 27 | 22 | 🟢 | |
| gatotv.com | 475 | 360 | 🟢 | |
@@ -91,7 +91,7 @@
| mediaklikk.hu | 8 | 8 | 🟢 | |
| mediasetinfinity.mediaset.it | 13 | 13 | 🟢 | |
| melita.com | 127 | 110 | 🟢 | |
- | meo.pt | 217 | 189 | 🟢 | |
+ | meo.pt | 211 | 185 | 🟢 | |
| meuguia.tv | 102 | 96 | 🟢 | |
| mewatch.sg | 25 | 24 | 🟢 | |
| mi.tv | 2084 | 614 | 🟢 | |
@@ -99,10 +99,10 @@
| moji.id | 1 | 1 | 🟢 | |
| mojmaxtv.hrvatskitelekom.hr | 243 | 0 | 🟢 | |
| mon-programme-tv.be | 111 | 94 | 🟢 | |
- | movistarplus.es | 178 | 0 | 🔴 | https://github.com/iptv-org/epg/issues/2865 |
+ | movistarplus.es | 178 | 0 | 🟢 | |
| mtel.ba | 501 | 0 | 🟢 | |
| mts.rs | 457 | 0 | 🟢 | |
- | mujtvprogram.cz | 216 | 202 | 🟢 | |
+ | mujtvprogram.cz | 213 | 190 | 🟢 | |
| musor.tv | 181 | 142 | 🟢 | |
| mysky.com.ph | 115 | 43 | 🟢 | |
| mytelly.co.uk | 488 | 387 | 🟢 | https://github.com/iptv-org/epg/issues/2985 |
@@ -110,16 +110,16 @@
| neo.io | 337 | 230 | 🟢 | |
| nhkworldpremium.com | 2 | 2 | 🟢 | |
| nhl.com | 1 | 1 | 🟢 | |
- | nostv.pt | 169 | 152 | 🟢 | |
+ | nostv.pt | 167 | 151 | 🟢 | |
| novacyprus.com | 29 | 24 | 🟢 | |
| novasports.gr | 16 | 16 | 🟢 | |
| nowplayer.now.com | 288 | 227 | 🟢 | |
| nuevosiglo.com.uy | 173 | 46 | 🟢 | |
| nzxmltv.com | 532 | 118 | 🟢 | |
- | ontvtonight.com | 5177 | 528 | 🟢 | |
+ | ontvtonight.com | 5177 | 528 | 🟢 | https://github.com/iptv-org/epg/issues/3014 |
| opto.sic.pt | 4 | 4 | 🟢 | |
| orangetv.orange.es | 273 | 151 | 🟢 | |
- | osn.com | 118 | 98 | 🟢 | |
+ | osn.com | 134 | 86 | 🟢 | |
| passie.nl | 1 | 1 | 🟢 | |
| pbsguam.org | 1 | 1 | 🟢 | |
| pickx.be | 404 | 375 | 🟢 | |
@@ -185,7 +185,7 @@
| tv.lv | 137 | 49 | 🟢 | |
| tv.magenta.at | 307 | 219 | 🟢 | |
| tv.mail.ru | 664 | 632 | 🟢 | |
- | tv.movistar.com.pe | 282 | 39 | 🟢 | |
+ | tv.movistar.com.pe | 262 | 31 | 🟢 | |
| tv.nu | 199 | 180 | 🟢 | |
| tv.post.lu | 332 | 241 | 🟢 | |
| tv.sfr.fr | 489 | 438 | 🟢 | https://github.com/iptv-org/epg/issues/2998 |
@@ -222,7 +222,7 @@
| virgintvgo.virginmedia.com | 238 | 181 | 🟢 | |
| visionplus.id | 250 | 224 | 🟢 | |
| vivoplay.com.br | 397 | 0 | 🟢 | |
- | vodafone.pt | 147 | 135 | 🟢 | |
+ | vodafone.pt | 146 | 135 | 🟢 | |
| vtm.be | 7 | 6 | 🟢 | |
| walesi.com.fj | 9 | 8 | 🟢 | |
| watch.sportsnet.ca | 8 | 8 | 🟢 | |
diff --git a/package-lock.json b/package-lock.json
index dc7fa85f4..352f9b8b4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -41,6 +41,7 @@
"@typescript-eslint/parser": "^8.38.0",
"axios": "^1.11.0",
"axios-cookiejar-support": "^6.0.4",
+ "axios-mock-adapter": "^2.1.0",
"chalk": "^5.4.1",
"cheerio": "^1.1.2",
"cli-progress": "^3.12.0",
@@ -52,7 +53,7 @@
"cwait": "^1.1.2",
"dayjs": "^1.11.13",
"epg-grabber": "^0.46.1",
- "epg-parser": "^0.3.1",
+ "epg-parser": "^0.5.0",
"eslint": "^9.32.0",
"eslint-config-prettier": "^10.1.8",
"form-data": "^4.0.4",
@@ -1091,9 +1092,9 @@
}
},
"node_modules/@eslint/eslintrc/node_modules/js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+ "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"dependencies": {
"argparse": "^2.0.1"
},
@@ -1610,27 +1611,6 @@
"node": ">=16.0.0"
}
},
- "node_modules/@isaacs/balanced-match": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
- "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
- "license": "MIT",
- "engines": {
- "node": "20 || >=22"
- }
- },
- "node_modules/@isaacs/brace-expansion": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
- "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
- "license": "MIT",
- "dependencies": {
- "@isaacs/balanced-match": "^4.0.1"
- },
- "engines": {
- "node": "20 || >=22"
- }
- },
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
@@ -2228,9 +2208,10 @@
}
},
"node_modules/@jest/reporters/node_modules/glob": {
- "version": "10.4.5",
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
- "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^3.1.2",
@@ -2845,6 +2826,17 @@
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"license": "ISC"
},
+ "node_modules/@pm2/blessed": {
+ "version": "0.1.81",
+ "resolved": "https://registry.npmjs.org/@pm2/blessed/-/blessed-0.1.81.tgz",
+ "integrity": "sha512-ZcNHqQjMuNRcQ7Z1zJbFIQZO/BDKV3KbiTckWdfbUaYhj7uNmUwb+FbdDWSCkvxNr9dBJQwvV17o6QBkAvgO0g==",
+ "bin": {
+ "blessed": "bin/tput.js"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
"node_modules/@pm2/io": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@pm2/io/-/io-6.1.0.tgz",
@@ -4206,23 +4198,25 @@
}
},
"node_modules/axios": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
- "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
+ "version": "1.13.5",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
+ "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==",
"dependencies": {
- "follow-redirects": "^1.15.6",
- "form-data": "^4.0.4",
+ "follow-redirects": "^1.15.11",
+ "form-data": "^4.0.5",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/axios-cache-interceptor": {
- "version": "1.8.3",
- "resolved": "https://registry.npmjs.org/axios-cache-interceptor/-/axios-cache-interceptor-1.8.3.tgz",
- "integrity": "sha512-ifuSBoCEkVaiugg1UTjVuTdK+SjSOJ35pdv2OrzhRT3wDMr52QiayQxUqs7jd7GDsfPOjMcw3T3ek0TysbyZZw==",
+ "version": "1.11.4",
+ "resolved": "https://registry.npmjs.org/axios-cache-interceptor/-/axios-cache-interceptor-1.11.4.tgz",
+ "integrity": "sha512-xZ4OZUxdpcFUpZjrqfYlGK0VglpPRKKSoE3vMHrstxolixQNs/MrbMezOAO5uS454hIEcWpnk75RZK26WkPW/g==",
"dependencies": {
- "cache-parser": "1.2.5",
- "fast-defer": "1.1.8",
- "object-code": "1.3.3"
+ "cache-parser": "^1.2.6",
+ "fast-defer": "^1.1.9",
+ "http-vary": "^1.0.3",
+ "object-code": "^2.0.0",
+ "try": "^1.0.3"
},
"engines": {
"node": ">=12"
@@ -4398,17 +4392,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/blessed": {
- "version": "0.1.81",
- "resolved": "https://registry.npmjs.org/blessed/-/blessed-0.1.81.tgz",
- "integrity": "sha512-LoF5gae+hlmfORcG1M5+5XZi4LBmvlXTzwJWzUlPryN/SJdSflZvROM2TwkT0GMpq7oqT48NRd4GS7BiVBc5OQ==",
- "bin": {
- "blessed": "bin/tput.js"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
"node_modules/bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@@ -4614,9 +4597,9 @@
}
},
"node_modules/cache-parser": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/cache-parser/-/cache-parser-1.2.5.tgz",
- "integrity": "sha512-Md/4VhAHByQ9frQ15WD6LrMNiVw9AEl/J7vWIXw+sxT6fSOpbtt6LHTp76vy8+bOESPBO94117Hm2bIjlI7XjA=="
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/cache-parser/-/cache-parser-1.2.6.tgz",
+ "integrity": "sha512-SjjnKlWgrhDrAWKUxAvmZLRGDa6JExMfjSu59/pvpNoI6mEHYSLcLKUw2RtECEOINvf6dxJo35fY+T/scA0SUA=="
},
"node_modules/call-bind": {
"version": "1.0.8",
@@ -5238,9 +5221,9 @@
}
},
"node_modules/dayjs": {
- "version": "1.11.18",
- "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz",
- "integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA=="
+ "version": "1.11.19",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
+ "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="
},
"node_modules/debug": {
"version": "4.3.4",
@@ -5538,12 +5521,12 @@
}
},
"node_modules/epg-parser": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/epg-parser/-/epg-parser-0.3.1.tgz",
- "integrity": "sha512-y131hXfDthUdSeKbN0Ru1wiFF5er4t/TLT+IaAnHF2CYB0cnygHTJteQMDYIlHWHDsGj+z9ejm1cU3saFNF3nQ==",
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/epg-parser/-/epg-parser-0.5.0.tgz",
+ "integrity": "sha512-NK9vSev/KkCVcKilJd35PmB9tP4+tN45dhcsSxHagVoUTINh8KLZ1yvgtoPDVYr0IaSPJXIIIZWcu1JPjS5HMw==",
"dependencies": {
- "dayjs": "^1.11.6",
- "lodash": "^4.17.21",
+ "dayjs": "^1.11.19",
+ "lodash.groupby": "^4.6.0",
"xml-js": "^1.6.11"
}
},
@@ -6022,9 +6005,9 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"node_modules/fast-defer": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/fast-defer/-/fast-defer-1.1.8.tgz",
- "integrity": "sha512-lEJeOH5VL5R09j6AA0D4Uvq7AgsHw0dAImQQ+F3iSyHZuAxyQfWobsagGpTcOPvJr3urmKRHrs+Gs9hV+/Qm/Q=="
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/fast-defer/-/fast-defer-1.1.9.tgz",
+ "integrity": "sha512-JP7Xm9HuePSeTT1DI78NeE9eAQvgNb9qNP2jlyQrcx4jiWM189omV6oyd0xaUPWHPlKmvDzz6H1FfPWIDU+xfg=="
},
"node_modules/fast-glob": {
"version": "3.3.3",
@@ -6152,9 +6135,9 @@
"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="
},
"node_modules/follow-redirects": {
- "version": "1.15.6",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
- "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
+ "version": "1.15.11",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
+ "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
"funding": [
{
"type": "individual",
@@ -6214,9 +6197,9 @@
}
},
"node_modules/form-data": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
- "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
+ "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
@@ -6377,14 +6360,14 @@
"integrity": "sha512-2e/nZezdVlyCopOCYHeW0onkbZg7xP1Ad6pndPy1rCygeRykefUS6r7oA5cJRGEFvseiaz5a/qUHFVX1dd6Isg=="
},
"node_modules/glob": {
- "version": "11.0.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz",
- "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==",
- "license": "ISC",
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz",
+ "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
"dependencies": {
"foreground-child": "^3.3.1",
"jackspeak": "^4.1.1",
- "minimatch": "^10.0.3",
+ "minimatch": "^10.1.1",
"minipass": "^7.1.2",
"package-json-from-dist": "^1.0.0",
"path-scurry": "^2.0.0"
@@ -6410,13 +6393,34 @@
"node": ">=10.13.0"
}
},
- "node_modules/glob/node_modules/minimatch": {
- "version": "10.0.3",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz",
- "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==",
- "license": "ISC",
+ "node_modules/glob/node_modules/balanced-match": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.2.tgz",
+ "integrity": "sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==",
"dependencies": {
- "@isaacs/brace-expansion": "^5.0.0"
+ "jackspeak": "^4.2.3"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/glob/node_modules/brace-expansion": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz",
+ "integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/glob/node_modules/minimatch": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.0.tgz",
+ "integrity": "sha512-ugkC31VaVg9cF0DFVoADH12k6061zNZkZON+aX8AWsR9GhPcErkcMBceb6znR8wLERM2AkkOxy2nWRLpT9Jq5w==",
+ "dependencies": {
+ "brace-expansion": "^5.0.2"
},
"engines": {
"node": "20 || >=22"
@@ -6590,6 +6594,11 @@
"node": ">= 14"
}
},
+ "node_modules/http-vary": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/http-vary/-/http-vary-1.0.3.tgz",
+ "integrity": "sha512-sx7Y8YTqF3o0mFJJvF66n8dbaE8v3liV1RgCz46XP5xK7dnzyZHvwMWRA115q5kjbCPBV65/nOMlgW54WLyiag=="
+ },
"node_modules/https-proxy-agent": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
@@ -7059,12 +7068,11 @@
}
},
"node_modules/jackspeak": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz",
- "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==",
- "license": "BlueOak-1.0.0",
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz",
+ "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==",
"dependencies": {
- "@isaacs/cliui": "^8.0.2"
+ "@isaacs/cliui": "^9.0.0"
},
"engines": {
"node": "20 || >=22"
@@ -7073,6 +7081,14 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/jackspeak/node_modules/@isaacs/cliui": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz",
+ "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/jest": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/jest/-/jest-30.0.5.tgz",
@@ -7360,9 +7376,10 @@
}
},
"node_modules/jest-config/node_modules/glob": {
- "version": "10.4.5",
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
- "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^3.1.2",
@@ -8046,9 +8063,10 @@
}
},
"node_modules/jest-runtime/node_modules/glob": {
- "version": "10.4.5",
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
- "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^3.1.2",
@@ -8690,9 +8708,14 @@
}
},
"node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ "version": "4.17.23",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
+ "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="
+ },
+ "node_modules/lodash.groupby": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz",
+ "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw=="
},
"node_modules/lodash.merge": {
"version": "4.6.2",
@@ -9088,9 +9111,9 @@
}
},
"node_modules/object-code": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/object-code/-/object-code-1.3.3.tgz",
- "integrity": "sha512-/Ds4Xd5xzrtUOJ+xJQ57iAy0BZsZltOHssnDgcZ8DOhgh41q1YJCnTPnWdWSLkNGNnxYzhYChjc5dgC9mEERCA=="
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/object-code/-/object-code-2.0.0.tgz",
+ "integrity": "sha512-qOwMF43O/VAD51nJAB7MKsf1yWksql6O1i0DHRo1yaOQM6xJQH0NAE9UKJzYB7lyKw1jnpeb2BmB8qakjxiYZA=="
},
"node_modules/object-treeify": {
"version": "2.1.1",
@@ -9533,36 +9556,36 @@
}
},
"node_modules/pm2": {
- "version": "6.0.10",
- "resolved": "https://registry.npmjs.org/pm2/-/pm2-6.0.10.tgz",
- "integrity": "sha512-sbk4HsnhtJMx1wJlhFQhYfDRzHtVK+cvdrIezbjM9WjSyc7kLtQ4nZ5K7JLOdLe3AevytmRcTiOa3VvAQrve2A==",
+ "version": "6.0.14",
+ "resolved": "https://registry.npmjs.org/pm2/-/pm2-6.0.14.tgz",
+ "integrity": "sha512-wX1FiFkzuT2H/UUEA8QNXDAA9MMHDsK/3UHj6Dkd5U7kxyigKDA5gyDw78ycTQZAuGCLWyUX5FiXEuVQWafukA==",
"dependencies": {
"@pm2/agent": "~2.1.1",
+ "@pm2/blessed": "0.1.81",
"@pm2/io": "~6.1.0",
"@pm2/js-api": "~0.8.0",
- "@pm2/pm2-version-check": "latest",
+ "@pm2/pm2-version-check": "^1.0.4",
"ansis": "4.0.0-node10",
- "async": "~3.2.6",
- "blessed": "0.1.81",
- "chokidar": "^3.5.3",
- "cli-tableau": "^2.0.0",
+ "async": "3.2.6",
+ "chokidar": "3.6.0",
+ "cli-tableau": "2.0.1",
"commander": "2.15.1",
- "croner": "~4.1.92",
- "dayjs": "~1.11.13",
- "debug": "^4.3.7",
+ "croner": "4.1.97",
+ "dayjs": "1.11.15",
+ "debug": "4.4.3",
"enquirer": "2.3.6",
"eventemitter2": "5.0.1",
"fclone": "1.0.11",
- "js-yaml": "~4.1.0",
+ "js-yaml": "4.1.1",
"mkdirp": "1.0.4",
"needle": "2.4.0",
- "pidusage": "~3.0",
+ "pidusage": "3.0.2",
"pm2-axon": "~4.0.1",
"pm2-axon-rpc": "~0.7.1",
"pm2-deploy": "~1.0.2",
"pm2-multimeter": "^0.1.2",
- "promptly": "^2",
- "semver": "^7.6.2",
+ "promptly": "2.2.0",
+ "semver": "7.7.2",
"source-map-support": "0.5.21",
"sprintf-js": "1.1.2",
"vizion": "~2.2.1"
@@ -9674,11 +9697,15 @@
"resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag=="
},
+ "node_modules/pm2/node_modules/dayjs": {
+ "version": "1.11.15",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.15.tgz",
+ "integrity": "sha512-MC+DfnSWiM9APs7fpiurHGCoeIx0Gdl6QZBy+5lu8MbYKN5FZEXqOgrundfibdfhGZ15o9hzmZ2xJjZnbvgKXQ=="
+ },
"node_modules/pm2/node_modules/debug": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
- "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
- "license": "MIT",
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dependencies": {
"ms": "^2.1.3"
},
@@ -9692,9 +9719,9 @@
}
},
"node_modules/pm2/node_modules/js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+ "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"dependencies": {
"argparse": "^2.0.1"
},
@@ -10643,9 +10670,9 @@
}
},
"node_modules/systeminformation": {
- "version": "5.25.11",
- "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.25.11.tgz",
- "integrity": "sha512-jI01fn/t47rrLTQB0FTlMCC+5dYx8o0RRF+R4BPiUNsvg5OdY0s9DKMFmJGrx5SwMZQ4cag0Gl6v8oycso9b/g==",
+ "version": "5.30.7",
+ "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.30.7.tgz",
+ "integrity": "sha512-33B/cftpaWdpvH+Ho9U1b08ss8GQuLxrWHelbJT1yw4M48Taj8W3ezcPuaLoIHZz5V6tVHuQPr5BprEfnBLBMw==",
"optional": true,
"os": [
"darwin",
@@ -10800,6 +10827,14 @@
"node": ">= 14.0.0"
}
},
+ "node_modules/try": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/try/-/try-1.0.3.tgz",
+ "integrity": "sha512-AHA8khVCII6zKyRkyPo6pRwoR9v5jb7QFw6e5avtaVSkxVfaEucYIo06xnwB+pJaEarfYNbs7W3Vq+LZLZiWyA==",
+ "funding": {
+ "url": "https://github.com/arthurfiorette/try?sponsor=1"
+ }
+ },
"node_modules/ts-api-utils": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
@@ -10896,9 +10931,9 @@
}
},
"node_modules/undici": {
- "version": "7.12.0",
- "resolved": "https://registry.npmjs.org/undici/-/undici-7.12.0.tgz",
- "integrity": "sha512-GrKEsc3ughskmGA9jevVlIOPMiiAHJ4OFUtaAH+NhfTUSiZ1wMPIQqQvAJUrJspFXJt3EBWgpAeoHEDVT1IBug==",
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.21.0.tgz",
+ "integrity": "sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==",
"engines": {
"node": ">=20.18.1"
}
@@ -12001,9 +12036,9 @@
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="
},
"js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+ "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"requires": {
"argparse": "^2.0.1"
}
@@ -12310,19 +12345,6 @@
}
}
},
- "@isaacs/balanced-match": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
- "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="
- },
- "@isaacs/brace-expansion": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
- "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
- "requires": {
- "@isaacs/balanced-match": "^4.0.1"
- }
- },
"@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
@@ -12760,9 +12782,9 @@
}
},
"glob": {
- "version": "10.4.5",
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
- "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
"requires": {
"foreground-child": "^3.1.0",
"jackspeak": "^3.1.2",
@@ -13226,6 +13248,11 @@
}
}
},
+ "@pm2/blessed": {
+ "version": "0.1.81",
+ "resolved": "https://registry.npmjs.org/@pm2/blessed/-/blessed-0.1.81.tgz",
+ "integrity": "sha512-ZcNHqQjMuNRcQ7Z1zJbFIQZO/BDKV3KbiTckWdfbUaYhj7uNmUwb+FbdDWSCkvxNr9dBJQwvV17o6QBkAvgO0g=="
+ },
"@pm2/io": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@pm2/io/-/io-6.1.0.tgz",
@@ -14130,23 +14157,25 @@
}
},
"axios": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
- "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
+ "version": "1.13.5",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
+ "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==",
"requires": {
- "follow-redirects": "^1.15.6",
- "form-data": "^4.0.4",
+ "follow-redirects": "^1.15.11",
+ "form-data": "^4.0.5",
"proxy-from-env": "^1.1.0"
}
},
"axios-cache-interceptor": {
- "version": "1.8.3",
- "resolved": "https://registry.npmjs.org/axios-cache-interceptor/-/axios-cache-interceptor-1.8.3.tgz",
- "integrity": "sha512-ifuSBoCEkVaiugg1UTjVuTdK+SjSOJ35pdv2OrzhRT3wDMr52QiayQxUqs7jd7GDsfPOjMcw3T3ek0TysbyZZw==",
+ "version": "1.11.4",
+ "resolved": "https://registry.npmjs.org/axios-cache-interceptor/-/axios-cache-interceptor-1.11.4.tgz",
+ "integrity": "sha512-xZ4OZUxdpcFUpZjrqfYlGK0VglpPRKKSoE3vMHrstxolixQNs/MrbMezOAO5uS454hIEcWpnk75RZK26WkPW/g==",
"requires": {
- "cache-parser": "1.2.5",
- "fast-defer": "1.1.8",
- "object-code": "1.3.3"
+ "cache-parser": "^1.2.6",
+ "fast-defer": "^1.1.9",
+ "http-vary": "^1.0.3",
+ "object-code": "^2.0.0",
+ "try": "^1.0.3"
}
},
"axios-cookiejar-support": {
@@ -14264,11 +14293,6 @@
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="
},
- "blessed": {
- "version": "0.1.81",
- "resolved": "https://registry.npmjs.org/blessed/-/blessed-0.1.81.tgz",
- "integrity": "sha512-LoF5gae+hlmfORcG1M5+5XZi4LBmvlXTzwJWzUlPryN/SJdSflZvROM2TwkT0GMpq7oqT48NRd4GS7BiVBc5OQ=="
- },
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@@ -14401,9 +14425,9 @@
"integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw=="
},
"cache-parser": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/cache-parser/-/cache-parser-1.2.5.tgz",
- "integrity": "sha512-Md/4VhAHByQ9frQ15WD6LrMNiVw9AEl/J7vWIXw+sxT6fSOpbtt6LHTp76vy8+bOESPBO94117Hm2bIjlI7XjA=="
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/cache-parser/-/cache-parser-1.2.6.tgz",
+ "integrity": "sha512-SjjnKlWgrhDrAWKUxAvmZLRGDa6JExMfjSu59/pvpNoI6mEHYSLcLKUw2RtECEOINvf6dxJo35fY+T/scA0SUA=="
},
"call-bind": {
"version": "1.0.8",
@@ -14838,9 +14862,9 @@
"integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw=="
},
"dayjs": {
- "version": "1.11.18",
- "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz",
- "integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA=="
+ "version": "1.11.19",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
+ "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="
},
"debug": {
"version": "4.3.4",
@@ -15056,12 +15080,12 @@
}
},
"epg-parser": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/epg-parser/-/epg-parser-0.3.1.tgz",
- "integrity": "sha512-y131hXfDthUdSeKbN0Ru1wiFF5er4t/TLT+IaAnHF2CYB0cnygHTJteQMDYIlHWHDsGj+z9ejm1cU3saFNF3nQ==",
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/epg-parser/-/epg-parser-0.5.0.tgz",
+ "integrity": "sha512-NK9vSev/KkCVcKilJd35PmB9tP4+tN45dhcsSxHagVoUTINh8KLZ1yvgtoPDVYr0IaSPJXIIIZWcu1JPjS5HMw==",
"requires": {
- "dayjs": "^1.11.6",
- "lodash": "^4.17.21",
+ "dayjs": "^1.11.19",
+ "lodash.groupby": "^4.6.0",
"xml-js": "^1.6.11"
}
},
@@ -15369,9 +15393,9 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"fast-defer": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/fast-defer/-/fast-defer-1.1.8.tgz",
- "integrity": "sha512-lEJeOH5VL5R09j6AA0D4Uvq7AgsHw0dAImQQ+F3iSyHZuAxyQfWobsagGpTcOPvJr3urmKRHrs+Gs9hV+/Qm/Q=="
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/fast-defer/-/fast-defer-1.1.9.tgz",
+ "integrity": "sha512-JP7Xm9HuePSeTT1DI78NeE9eAQvgNb9qNP2jlyQrcx4jiWM189omV6oyd0xaUPWHPlKmvDzz6H1FfPWIDU+xfg=="
},
"fast-glob": {
"version": "3.3.3",
@@ -15481,9 +15505,9 @@
"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="
},
"follow-redirects": {
- "version": "1.15.6",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
- "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA=="
+ "version": "1.15.11",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
+ "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="
},
"for-each": {
"version": "0.3.5",
@@ -15510,9 +15534,9 @@
}
},
"form-data": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
- "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
+ "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
@@ -15622,24 +15646,40 @@
"integrity": "sha512-2e/nZezdVlyCopOCYHeW0onkbZg7xP1Ad6pndPy1rCygeRykefUS6r7oA5cJRGEFvseiaz5a/qUHFVX1dd6Isg=="
},
"glob": {
- "version": "11.0.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz",
- "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==",
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz",
+ "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==",
"requires": {
"foreground-child": "^3.3.1",
"jackspeak": "^4.1.1",
- "minimatch": "^10.0.3",
+ "minimatch": "^10.1.1",
"minipass": "^7.1.2",
"package-json-from-dist": "^1.0.0",
"path-scurry": "^2.0.0"
},
"dependencies": {
- "minimatch": {
- "version": "10.0.3",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz",
- "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==",
+ "balanced-match": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.2.tgz",
+ "integrity": "sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==",
"requires": {
- "@isaacs/brace-expansion": "^5.0.0"
+ "jackspeak": "^4.2.3"
+ }
+ },
+ "brace-expansion": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz",
+ "integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==",
+ "requires": {
+ "balanced-match": "^4.0.2"
+ }
+ },
+ "minimatch": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.0.tgz",
+ "integrity": "sha512-ugkC31VaVg9cF0DFVoADH12k6061zNZkZON+aX8AWsR9GhPcErkcMBceb6znR8wLERM2AkkOxy2nWRLpT9Jq5w==",
+ "requires": {
+ "brace-expansion": "^5.0.2"
}
}
}
@@ -15746,6 +15786,11 @@
"debug": "^4.3.4"
}
},
+ "http-vary": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/http-vary/-/http-vary-1.0.3.tgz",
+ "integrity": "sha512-sx7Y8YTqF3o0mFJJvF66n8dbaE8v3liV1RgCz46XP5xK7dnzyZHvwMWRA115q5kjbCPBV65/nOMlgW54WLyiag=="
+ },
"https-proxy-agent": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
@@ -16042,11 +16087,18 @@
}
},
"jackspeak": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz",
- "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==",
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz",
+ "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==",
"requires": {
- "@isaacs/cliui": "^8.0.2"
+ "@isaacs/cliui": "^9.0.0"
+ },
+ "dependencies": {
+ "@isaacs/cliui": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz",
+ "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg=="
+ }
}
},
"jest": {
@@ -16284,9 +16336,9 @@
}
},
"glob": {
- "version": "10.4.5",
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
- "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
"requires": {
"foreground-child": "^3.1.0",
"jackspeak": "^3.1.2",
@@ -16810,9 +16862,9 @@
}
},
"glob": {
- "version": "10.4.5",
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
- "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
"requires": {
"foreground-child": "^3.1.0",
"jackspeak": "^3.1.2",
@@ -17279,9 +17331,14 @@
}
},
"lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ "version": "4.17.23",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
+ "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="
+ },
+ "lodash.groupby": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz",
+ "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw=="
},
"lodash.merge": {
"version": "4.6.2",
@@ -17573,9 +17630,9 @@
"integrity": "sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA=="
},
"object-code": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/object-code/-/object-code-1.3.3.tgz",
- "integrity": "sha512-/Ds4Xd5xzrtUOJ+xJQ57iAy0BZsZltOHssnDgcZ8DOhgh41q1YJCnTPnWdWSLkNGNnxYzhYChjc5dgC9mEERCA=="
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/object-code/-/object-code-2.0.0.tgz",
+ "integrity": "sha512-qOwMF43O/VAD51nJAB7MKsf1yWksql6O1i0DHRo1yaOQM6xJQH0NAE9UKJzYB7lyKw1jnpeb2BmB8qakjxiYZA=="
},
"object-treeify": {
"version": "2.1.1",
@@ -17896,37 +17953,37 @@
}
},
"pm2": {
- "version": "6.0.10",
- "resolved": "https://registry.npmjs.org/pm2/-/pm2-6.0.10.tgz",
- "integrity": "sha512-sbk4HsnhtJMx1wJlhFQhYfDRzHtVK+cvdrIezbjM9WjSyc7kLtQ4nZ5K7JLOdLe3AevytmRcTiOa3VvAQrve2A==",
+ "version": "6.0.14",
+ "resolved": "https://registry.npmjs.org/pm2/-/pm2-6.0.14.tgz",
+ "integrity": "sha512-wX1FiFkzuT2H/UUEA8QNXDAA9MMHDsK/3UHj6Dkd5U7kxyigKDA5gyDw78ycTQZAuGCLWyUX5FiXEuVQWafukA==",
"requires": {
"@pm2/agent": "~2.1.1",
+ "@pm2/blessed": "0.1.81",
"@pm2/io": "~6.1.0",
"@pm2/js-api": "~0.8.0",
- "@pm2/pm2-version-check": "latest",
+ "@pm2/pm2-version-check": "^1.0.4",
"ansis": "4.0.0-node10",
- "async": "~3.2.6",
- "blessed": "0.1.81",
- "chokidar": "^3.5.3",
- "cli-tableau": "^2.0.0",
+ "async": "3.2.6",
+ "chokidar": "3.6.0",
+ "cli-tableau": "2.0.1",
"commander": "2.15.1",
- "croner": "~4.1.92",
- "dayjs": "~1.11.13",
- "debug": "^4.3.7",
+ "croner": "4.1.97",
+ "dayjs": "1.11.15",
+ "debug": "4.4.3",
"enquirer": "2.3.6",
"eventemitter2": "5.0.1",
"fclone": "1.0.11",
- "js-yaml": "~4.1.0",
+ "js-yaml": "4.1.1",
"mkdirp": "1.0.4",
"needle": "2.4.0",
- "pidusage": "~3.0",
+ "pidusage": "3.0.2",
"pm2-axon": "~4.0.1",
"pm2-axon-rpc": "~0.7.1",
"pm2-deploy": "~1.0.2",
"pm2-multimeter": "^0.1.2",
"pm2-sysmonit": "^1.2.8",
- "promptly": "^2",
- "semver": "^7.6.2",
+ "promptly": "2.2.0",
+ "semver": "7.7.2",
"source-map-support": "0.5.21",
"sprintf-js": "1.1.2",
"vizion": "~2.2.1"
@@ -17942,18 +17999,23 @@
"resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag=="
},
+ "dayjs": {
+ "version": "1.11.15",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.15.tgz",
+ "integrity": "sha512-MC+DfnSWiM9APs7fpiurHGCoeIx0Gdl6QZBy+5lu8MbYKN5FZEXqOgrundfibdfhGZ15o9hzmZ2xJjZnbvgKXQ=="
+ },
"debug": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
- "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"requires": {
"ms": "^2.1.3"
}
},
"js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+ "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"requires": {
"argparse": "^2.0.1"
}
@@ -18664,9 +18726,9 @@
}
},
"systeminformation": {
- "version": "5.25.11",
- "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.25.11.tgz",
- "integrity": "sha512-jI01fn/t47rrLTQB0FTlMCC+5dYx8o0RRF+R4BPiUNsvg5OdY0s9DKMFmJGrx5SwMZQ4cag0Gl6v8oycso9b/g==",
+ "version": "5.30.7",
+ "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.30.7.tgz",
+ "integrity": "sha512-33B/cftpaWdpvH+Ho9U1b08ss8GQuLxrWHelbJT1yw4M48Taj8W3ezcPuaLoIHZz5V6tVHuQPr5BprEfnBLBMw==",
"optional": true
},
"table2array": {
@@ -18767,6 +18829,11 @@
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
"integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg=="
},
+ "try": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/try/-/try-1.0.3.tgz",
+ "integrity": "sha512-AHA8khVCII6zKyRkyPo6pRwoR9v5jb7QFw6e5avtaVSkxVfaEucYIo06xnwB+pJaEarfYNbs7W3Vq+LZLZiWyA=="
+ },
"ts-api-utils": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
@@ -18826,9 +18893,9 @@
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="
},
"undici": {
- "version": "7.12.0",
- "resolved": "https://registry.npmjs.org/undici/-/undici-7.12.0.tgz",
- "integrity": "sha512-GrKEsc3ughskmGA9jevVlIOPMiiAHJ4OFUtaAH+NhfTUSiZ1wMPIQqQvAJUrJspFXJt3EBWgpAeoHEDVT1IBug=="
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.21.0.tgz",
+ "integrity": "sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg=="
},
"undici-types": {
"version": "7.8.0",
diff --git a/package.json b/package.json
index 6c6d8aa59..4f2be8a44 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"channels:validate": "tsx scripts/commands/channels/validate.ts",
"sites:init": "tsx scripts/commands/sites/init.ts",
"sites:update": "tsx scripts/commands/sites/update.ts",
+ "guides:update": "tsx scripts/commands/guides/update.ts",
"grab": "tsx scripts/commands/epg/grab.ts",
"lint": "npx eslint \"{scripts,tests,sites}/**/*.{ts,mts,js}\"",
"test": "cross-env TZ=Pacific/Nauru npx jest --runInBand",
@@ -71,6 +72,7 @@
"@typescript-eslint/parser": "^8.38.0",
"axios": "^1.11.0",
"axios-cookiejar-support": "^6.0.4",
+ "axios-mock-adapter": "^2.1.0",
"chalk": "^5.4.1",
"cheerio": "^1.1.2",
"cli-progress": "^3.12.0",
@@ -82,7 +84,7 @@
"cwait": "^1.1.2",
"dayjs": "^1.11.13",
"epg-grabber": "^0.46.1",
- "epg-parser": "^0.3.1",
+ "epg-parser": "^0.5.0",
"eslint": "^9.32.0",
"eslint-config-prettier": "^10.1.8",
"form-data": "^4.0.4",
diff --git a/pm2.config.js b/pm2.config.js
index f1f901166..d06556d3b 100644
--- a/pm2.config.js
+++ b/pm2.config.js
@@ -1,35 +1,35 @@
-const grab = process.env.SITE
- ? `npm run grab -- --site=${process.env.SITE} ${process.env.CLANG ? `--lang=${process.env.CLANG}` : ''
- } --output=public/guide.xml`
- : 'npm run grab -- --channels=channels.xml --output=public/guide.xml'
-
-
-const apps = [
- {
- name: 'serve',
- script: 'npx serve -- public',
- instances: 1,
- watch: false,
- autorestart: true
- },
- {
- name: 'grab',
- script: `npx chronos -e "${grab}" -p "${process.env.CRON_SCHEDULE}" -l`,
- instances: 1,
- watch: false,
- autorestart: true
- }
-];
-
-if (process.env.RUN_AT_STARTUP === 'true') {
- apps.push({
- name: 'grab-at-startup',
- script: grab,
- instances: 1,
- autorestart: false,
- watch: false,
- max_restarts: 1
- });
-}
-
-module.exports = { apps };
\ No newline at end of file
+const grab = process.env.SITE
+ ? `npm run grab -- --site=${process.env.SITE} ${
+ process.env.CLANG ? `--lang=${process.env.CLANG}` : ''
+ } --output=public/guide.xml`
+ : 'npm run grab -- --channels=public/channels.xml --output=public/guide.xml'
+
+const apps = [
+ {
+ name: 'serve',
+ script: 'npx serve -- public',
+ instances: 1,
+ watch: false,
+ autorestart: true
+ },
+ {
+ name: 'grab',
+ script: `npx chronos -e "${grab}" -p "${process.env.CRON_SCHEDULE}" -l`,
+ instances: 1,
+ watch: false,
+ autorestart: true
+ }
+]
+
+if (process.env.RUN_AT_STARTUP === 'true') {
+ apps.push({
+ name: 'grab-at-startup',
+ script: grab,
+ instances: 1,
+ autorestart: false,
+ watch: false,
+ max_restarts: 1
+ })
+}
+
+module.exports = { apps }
diff --git a/scripts/commands/guides/update.ts b/scripts/commands/guides/update.ts
new file mode 100644
index 000000000..f43b96b6c
--- /dev/null
+++ b/scripts/commands/guides/update.ts
@@ -0,0 +1,144 @@
+import { HTMLTableRow, HTMLTableDataItem, HTMLTableColumn } from '../../types/htmlTable'
+import epgGrabber, { EPGGrabber } from 'epg-grabber'
+import AxiosMockAdapter from 'axios-mock-adapter'
+import { Storage } from '@freearhey/storage-js'
+import { Channel, Worker } from '../../models'
+import { Collection } from '@freearhey/core'
+import { ROOT_DIR } from '../../constants'
+import { Logger } from '@freearhey/core'
+import { HTMLTable } from '../../core'
+import epgParser from 'epg-parser'
+import axios from 'axios'
+
+async function main() {
+ const logger = new Logger({ level: process.env.NODE_ENV === 'test' ? -999 : 3 })
+ const rootStorage = new Storage(ROOT_DIR)
+ const workers = new Map()
+
+ logger.info('loading workers.txt...')
+ const workersTxt = await rootStorage.load('workers.txt')
+
+ workersTxt.split('\r\n').forEach((host: string) => {
+ if (!host) return
+
+ const worker = new Worker({ host })
+
+ workers.set(host, worker)
+ })
+
+ for (const worker of workers.values()) {
+ logger.info(`processing "${worker.host}"...`)
+
+ const client = axios.create({
+ baseURL: worker.getBaseUrl(),
+ timeout: 60000
+ })
+
+ if (process.env.NODE_ENV === 'test') {
+ const mock = new AxiosMockAdapter(client)
+ if (worker.host === 'example.com') {
+ mock.onGet('worker.json').reply(404)
+ } else {
+ const testStorage = new Storage('tests/__data__/input/guides_update')
+ mock.onGet('worker.json').reply(200, await testStorage.load('worker.json'))
+ mock.onGet('channels.xml').reply(200, await testStorage.load('channels.xml'))
+ mock.onGet('guide.xml').reply(200, await testStorage.load('guide.xml'))
+ }
+ }
+
+ const workerJson = await client
+ .get('worker.json')
+ .then(res => res.data)
+ .catch(err => {
+ worker.status = err.status
+ logger.error(err.message)
+ })
+
+ if (!workerJson) {
+ worker.status = 'MISSING_WORKER_CONFIG'
+ logger.error('Unable to load "workers.json"')
+ continue
+ }
+
+ worker.channelsPath = workerJson.channels
+ worker.guidePath = workerJson.guide
+
+ if (!worker.channelsPath) {
+ worker.status = 'MISSING_CHANNELS_PATH'
+ logger.error('The "channels" property is missing from the workers config')
+ continue
+ }
+
+ if (!worker.guidePath) {
+ worker.status = 'MISSING_GUIDE_PATH'
+ logger.error('The "guide" property is missing from the workers config')
+ continue
+ }
+
+ const channelsXml = await client
+ .get(worker.channelsPath)
+ .then(res => res.data)
+ .catch(err => {
+ worker.status = err.status
+ logger.error(err.message)
+ })
+
+ if (!channelsXml) continue
+
+ const parsedChannels = EPGGrabber.parseChannelsXML(channelsXml)
+ worker.channels = new Collection(parsedChannels).map(
+ (channel: epgGrabber.Channel) => new Channel(channel.toObject())
+ )
+
+ const guideXml = await client
+ .get(worker.guidePath)
+ .then(res => res.data)
+ .catch(err => {
+ worker.status = err.status
+ logger.error(err.message)
+ })
+
+ if (!guideXml) continue
+
+ const parsedGuide = epgParser.parse(guideXml)
+ worker.lastUpdated = parsedGuide.date
+
+ worker.status = 'OK'
+ }
+
+ logger.info('creating guides table...')
+ const rows = new Collection()
+ workers.forEach((worker: Worker) => {
+ rows.add(
+ new Collection([
+ { value: worker.host },
+ { value: worker.getStatusEmoji(), align: 'center' },
+ { value: worker.getChannelsCount().toString(), align: 'right' },
+ { value: worker.getLastUpdated(), align: 'left' },
+ {
+ value:
+ worker.status === 'OK'
+ ? `${worker.channelsPath}
${worker.guidePath}`
+ : ''
+ }
+ ])
+ )
+ })
+
+ logger.info('updating guides.md...')
+ const table = new HTMLTable(
+ rows,
+ new Collection([
+ { name: 'Host', align: 'left' },
+ { name: 'Status', align: 'left' },
+ { name: 'Channels', align: 'left' },
+ { name: 'Last Updated', align: 'left' },
+ { name: 'Links', align: 'left' }
+ ])
+ )
+ const guidesTemplate = await new Storage().load('scripts/templates/_guides.md')
+ const guidesContent = guidesTemplate.replace('_TABLE_', table.toString())
+ await rootStorage.save('GUIDES.md', guidesContent)
+}
+
+main()
diff --git a/scripts/models/index.ts b/scripts/models/index.ts
index a05f13a89..c891f01bf 100644
--- a/scripts/models/index.ts
+++ b/scripts/models/index.ts
@@ -3,3 +3,4 @@ export * from './issue'
export * from './site'
export * from './channel'
export * from './program'
+export * from './worker'
diff --git a/scripts/models/worker.ts b/scripts/models/worker.ts
new file mode 100644
index 000000000..94b94dfcb
--- /dev/null
+++ b/scripts/models/worker.ts
@@ -0,0 +1,73 @@
+import relativeTime from 'dayjs/plugin/relativeTime'
+import { Collection } from '@freearhey/core'
+import { Channel } from './channel'
+import utc from 'dayjs/plugin/utc'
+import dayjs from 'dayjs'
+
+dayjs.extend(relativeTime)
+dayjs.extend(utc)
+
+export interface WorkerData {
+ host: string
+}
+
+export class Worker {
+ host: string
+ channelsPath?: string
+ guidePath?: string
+ channels?: Collection
+ status?: string
+ lastUpdated?: string
+
+ constructor(data: WorkerData) {
+ this.host = data.host
+ }
+
+ getBaseUrl(): string {
+ return `https://${this.host}`
+ }
+
+ getConfigUrl(): string {
+ const url = new URL('worker.json', this.getBaseUrl())
+
+ return url.href
+ }
+
+ getChannelsUrl(): string {
+ if (!this.channelsPath) return ''
+
+ const url = new URL(this.channelsPath, this.getBaseUrl())
+
+ return url.href
+ }
+
+ getGuideUrl(): string {
+ if (!this.guidePath) return ''
+
+ const url = new URL(this.guidePath, this.getBaseUrl())
+
+ return url.href
+ }
+
+ getStatusEmoji(): string {
+ if (!this.status) return '⚪'
+ if (this.status === 'OK') return '🟢'
+
+ return '🔴'
+ }
+
+ getChannelsCount(): number {
+ if (!this.channels) return 0
+
+ return this.channels.count()
+ }
+
+ getLastUpdated(): string {
+ if (!this.lastUpdated) return '-'
+
+ let now = dayjs()
+ if (process.env.NODE_ENV === 'test') now = dayjs.utc('2026-02-13')
+
+ return dayjs.utc(this.lastUpdated).from(now)
+ }
+}
diff --git a/scripts/templates/_guides.md b/scripts/templates/_guides.md
new file mode 100644
index 000000000..d643a4637
--- /dev/null
+++ b/scripts/templates/_guides.md
@@ -0,0 +1,5 @@
+# Guides
+
+_TABLE_
+
+[How can I add my server to the list?](CONTRIBUTING.md#how-to-add-my-server-to-the-guides-md)
diff --git a/sites/artonline.tv/artonline.tv.config.js b/sites/artonline.tv/artonline.tv.config.js
index 2b9fe78c4..b5abb1346 100644
--- a/sites/artonline.tv/artonline.tv.config.js
+++ b/sites/artonline.tv/artonline.tv.config.js
@@ -34,6 +34,7 @@ module.exports = {
const programs = []
if (!content) return programs
const items = JSON.parse(content)
+ if (!Array.isArray(items)) return programs
items.forEach(item => {
const image = parseImage(item)
const start = parseStart(item)
@@ -60,9 +61,9 @@ function parseStart(item) {
}
function parseDuration(item) {
- const [, HH, mm, ss] = item.duration.match(/(\d+):(\d+):(\d+)/)
+ const [, HH, mm, ss] = item.duration.match(/(\d+):(\d+)(?::(\d+))?/)
- return parseInt(HH) * 3600 + parseInt(mm) * 60 + parseInt(ss)
+ return parseInt(HH) * 3600 + parseInt(mm) * 60 + parseInt(ss || 0)
}
function parseImage(item) {
diff --git a/sites/freeview.co.uk/freeview.co.uk.channels.xml b/sites/freeview.co.uk/freeview.co.uk.channels.xml
index 10e9fec90..eee24034c 100644
--- a/sites/freeview.co.uk/freeview.co.uk.channels.xml
+++ b/sites/freeview.co.uk/freeview.co.uk.channels.xml
@@ -1,14 +1,6 @@
- BBC ONE Lon
- BBC TWO
- BBC THREE
- BBC NEWS
BBC Red Button
- BBC FOUR
- CBBC
- CBeebies
- BBC Parliament
BBC R5L
BBC 5SX
BBC 6 Music
@@ -25,146 +17,153 @@
BBC Radio 2
BBC Radio 3
BBC Radio 4
- BBC RB 1
- ITV1
- ITV3
- ITV2
- ITV4
- ITV Quiz
- ITV1+1
- Channel 4
- Film4
- More 4
- E4
- Channel 4+1
- E4+1
- 4seven
- 5
That's TV 3
- 5STAR
- YAAAS!
- 5USA
- U&DaveJaVu
- 5 +1
- QVC
- MBC
- Blaze
- Blaze+1
- QVC2
- TRUE CRIME
- TRUE CRIME XTRA
- WildEarth
- LEGEND
Sonlife
On Demand 365
Channelbox
- UK RADIO PORTAL
- Great! Action
- Great! Movies
- TJC
That's Oldies
- ITV4+1
- ITV2+1
- ITV3+1
- 5ACTION
CNA Originals
GIGS
EuroNews
Trailblazer
Odyssey TV
- Ketchup TV
- U&Drama
Ketchup Too
ROK
- Revelation TV
- God TV
- Nolly Africa
- Alaraby Network
- POP Max
- Al Jazeera English
- Tiny Pop
- Al Jazeera Arabic
Global Arabic +
- NHK WORLD
- Newsmax
Amazing Facts
New Media TV
- Together TV
- FRANCE 24
Nosey
Shop On TV
Purpose Media
- Talk
- BBC TWO HD
- BBC ONE Lon HD
- ITV1 HD
- Channel 4 HD
- 5 HD
- BBC THREE HD
- BBC FOUR HD
- CBBC HD
- CBeebies HD
- U&Eden
LEGEND XTRA
- TBN UK
- 5SELECT
- Sky News
- Sky Arts
- Sky Mix
- Challenge
- U&Dave
- U&Drama+1
- E4 Extra
- Film4+1
- talkSPORT
RNIB Connect
Heart
Capital
Classic FM
LBC
- Food Network
That's TV 2
SonLife
Must Have Ideas
- Really
- Quest Red
- QUEST+1
- Gems TV
- U&Yesterday
- Ideal World
+ That's 80s
Smooth Radio
- Great! TV
- Jewellery Maker
Hobbycraft TV
- Great! Christmas
- QUEST
- GB News
- Together TV+1
- POP UP
- DMAX
Rewind TV
- POP
Together TV IP
- HobbyMaker
- Great! Mystery
- That's TV (UK)
- PBS America
- HGTV
That's Melody
- U&W
Premier Radio
- TalkingPictures TV
Great! Player
- GREAT! romance mix
- London TV
- 3ABN
+ Great! Romance Mix
India Today
- TRACE UK
- Pop Player
+ MBC Group
wedotv movies
It Is Written TV
OUTflix Proud
High Street TV
+ Cartoon Classics
+ wedotv Movies UK
+ Nolly Africa
+ 4seven
+ 5ACTION
+ 5SELECT
+ 5STAR
+ 5USA
AL ARABIYA
+ Alaraby Network
+ Al Jazeera Arabic
+ Al Jazeera English
ASHARQ NEWS
+ BBC FOUR HD
+ BBC FOUR
+ BBC NEWS
+ BBC ONE Lon
+ BBC ONE Lon HD
+ BBC Parliament
+ BBC RB 1
+ BBC THREE HD
+ BBC THREE
+ BBC TWO
+ BBC TWO HD
+ Blaze+1
+ Blaze
+ CBBC HD
+ CBBC
+ CBeebies HD
+ CBeebies
+ Challenge
+ Channel 4 HD
+ Channel 4+1
+ Channel 4
+ 5 HD
+ 5 +1
+ 5
+ DMAX
+ E4+1
+ E4
+ E4 Extra
+ Film4+1
+ Film4
+ Food Network
+ FRANCE 24
+ GB News
+ Gemporia
+ God TV
+ Great! Action
+ Great! Mystery
+ Great! Movies
+ Great! Romance
+ Great! TV
+ HGTV
+ HobbyMaker
+ Ideal World
+ ITV1 HD
+ ITV1
+ ITV1+1
+ ITV2+1
+ ITV2
+ ITV3+1
+ ITV3
+ ITV4+1
+ ITV4
+ ITV Quiz
+ Jewellery Maker
+ Ketchup TV
+ LEGEND
+ London TV
+ MBC
+ More 4
+ Newsmax
+ NHK WORLD
+ PBS America
+ POP
+ POP UP
+ QUEST+1
+ QUEST
+ Quest Red
+ QVC2
+ QVC
+ Really
+ Revelation TV
+ Sky Arts
+ Sky Mix
+ Sky News
+ TalkingPictures TV
+ talkSPORT
+ Talk
+ TBN UK
+ That's TV (UK)
+ Tiny Pop
+ TJC
+ Together TV+1
+ Together TV
+ TRUE CRIME
+ TRUE CRIME XTRA
+ U&Dave
+ U&DaveJaVu
+ U&Drama+1
+ U&Drama
+ U&Eden
+ U&W
+ U&Yesterday
+ WildEarth
+ YAAAS!
diff --git a/sites/meo.pt/__data__/content.json b/sites/meo.pt/__data__/content.json
index 66e68008a..7dd23d0f6 100644
--- a/sites/meo.pt/__data__/content.json
+++ b/sites/meo.pt/__data__/content.json
@@ -1 +1,26 @@
-{"d":{"__type":"Ptsi.Isites.GridTv.CanaisService.GridTV","ExtensionData":{},"services":[],"channels":[{"__type":"Ptsi.Isites.GridTv.CanaisService.Channels","ExtensionData":{},"id":100,"name":"RTP MEMÓRIA","sigla":"RTPM","friendlyUrlName":"RTP_Memoria","url":"https://meogo.meo.pt/direto?canalUrl=RTP_Memoria","meogo":true,"logo":"https://www.meo.pt/PublishingImages/canais/rtp-memoria.png","isAdult":false,"categories":[{"ExtensionData":{},"id":4,"name":"Entretenimento"}],"types":[{"ExtensionData":{},"id":0,"name":"Gravações Automáticas"},{"ExtensionData":{},"id":1,"name":"Restart TV"}],"programs":[{"ExtensionData":{},"date":"1-12-2022","timeIni":"23:35","timeEnd":"00:17","number":15992358,"uniqueId":"27621378","name":"Walker, O Ranger Do Texas T6 - Ep. 14","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"103787"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"00:17","timeEnd":"01:07","number":17690651,"uniqueId":"27621379","name":"O Barco Do Amor T7 - Ep. 21","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"117870"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"01:07","timeEnd":"01:57","number":17690652,"uniqueId":"27621380","name":"Um Anjo Na Terra T3 - Ep. 22","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"117869"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"01:57","timeEnd":"02:39","number":15992358,"uniqueId":"27621381","name":"Walker, O Ranger Do Texas T6 - Ep. 14","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"103787"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"02:39","timeEnd":"03:42","number":17690659,"uniqueId":"27621382","name":"5 Para A Meia-Noite T7 - Ep. 29","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"118268"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"03:42","timeEnd":"04:33","number":13223378,"uniqueId":"27621383","name":"O Conde D´Abranhos - Ep. 9","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"1367"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"04:33","timeEnd":"05:02","number":17690660,"uniqueId":"27621384","name":"Quebra-Cabeças T4 - Ep. 60","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"91370"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"05:02","timeEnd":"05:19","number":17690661,"uniqueId":"27621385","name":"As Aventuras De Eva - Ep. 9","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"118559"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"05:19","timeEnd":"06:02","number":13338966,"uniqueId":"27621386","name":"Bem-Vindos A Beirais T4 - Ep. 36","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"80897"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"06:02","timeEnd":"06:29","number":12414718,"uniqueId":"27621387","name":"Horizontes Da Memória T6 - Ep. 19","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"74413"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"06:29","timeEnd":"06:56","number":13492284,"uniqueId":"27621388","name":"SMS - Ser Mais Sabedor T1 - Ep. 49","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"81681"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"06:56","timeEnd":"07:00","number":17733452,"uniqueId":"27621389","name":"A Música Portuguesa A Gostar Dela Própria T1 - Ep. 103","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"87775"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"07:00","timeEnd":"07:45","number":13290499,"uniqueId":"27564192","name":"Vila Faia - Ep. 47","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"47671"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"07:45","timeEnd":"08:15","number":17690662,"uniqueId":"27564176","name":"Palavras Cruzadas - Ep. 16","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"71429"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"08:15","timeEnd":"09:00","number":12441944,"uniqueId":"27564188","name":"Portugueses Pelo Mundo T5 - Ep. 24","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"72818"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"09:00","timeEnd":"09:50","number":12663593,"uniqueId":"27564181","name":"Gente Fina É Outra Coisa - Ep. 9","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"76694"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"09:50","timeEnd":"10:35","number":17690663,"uniqueId":"27636531","name":"Só Visto! T1 - Ep. 24","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"116128"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"10:35","timeEnd":"11:00","number":17690670,"uniqueId":"27636532","name":"A Essência","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"961481536"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"11:00","timeEnd":"11:43","number":17690671,"uniqueId":"27636533","name":"Patrulha Da Noite T2 - Ep. 9","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"118560"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"11:43","timeEnd":"12:35","number":17690664,"uniqueId":"27636534","name":"Terra Mãe - Ep. 93","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"71427"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"12:35","timeEnd":"13:00","number":17647748,"uniqueId":"27564194","name":"As Aventuras De Eva - Ep. 5","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"118559"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"13:00","timeEnd":"14:00","number":17690665,"uniqueId":"27564168","name":"Em Mouriscas Acontece","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":""},{"ExtensionData":{},"date":"2-12-2022","timeIni":"14:00","timeEnd":"14:51","number":13732638,"uniqueId":"27564162","name":"Donos Disto Tudo T2 - Ep. 15","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"85899"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"14:51","timeEnd":"15:00","number":17621219,"uniqueId":"27636535","name":"Fragmentos - Ep. 43","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"116736"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"15:00","timeEnd":"15:45","number":12723927,"uniqueId":"27564197","name":"Bem-Vindos A Beirais T3 - Ep. 124","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"71872"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"15:45","timeEnd":"16:00","number":17690673,"uniqueId":"27564159","name":"A Cidade Na Ponta Dos Dedos T2 - Ep. 43","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"116737"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"16:00","timeEnd":"17:00","number":12852209,"uniqueId":"27564209","name":"As Grandes Batalhas De Portugal - Ep. 1","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"74660"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"17:00","timeEnd":"17:33","number":12939074,"uniqueId":"27573164","name":"Na Paz Dos Anjos - Ep. 137","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"72967"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"17:33","timeEnd":"18:18","number":17690666,"uniqueId":"27636536","name":"Filhos Do Vento - Ep. 138","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"47657"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"18:18","timeEnd":"18:43","number":10334871,"uniqueId":"27636537","name":"Telerural T3 - Ep. 6","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"51886"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"18:43","timeEnd":"19:40","number":8319968,"uniqueId":"27636538","name":"Herman Enciclopédia T2 - Ep. 5","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"39546"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"19:40","timeEnd":"20:09","number":17690667,"uniqueId":"27636539","name":"Sim, Chef! T2 - Ep. 1","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"119065"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"20:09","timeEnd":"21:00","number":12414714,"uniqueId":"27636540","name":"Mulheres De Abril - Ep. 5","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"74937"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"21:00","timeEnd":"21:45","number":12723927,"uniqueId":"27573170","name":"Bem-Vindos A Beirais T3 - Ep. 124","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"71872"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"21:45","timeEnd":"22:36","number":17690668,"uniqueId":"27636541","name":"O Barco Do Amor T7 - Ep. 22","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"117870"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"22:36","timeEnd":"23:25","number":17690669,"uniqueId":"27636542","name":"Um Anjo Na Terra T3 - Ep. 23","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"117869"},{"ExtensionData":{},"date":"2-12-2022","timeIni":"23:25","timeEnd":"00:08","number":16036114,"uniqueId":"27573173","name":"Walker, O Ranger Do Texas T6 - Ep. 15","synopse":null,"imageM":null,"imageL":null,"imageXL":null,"recordType":0,"recordingDefinitionID":"00000000-0000-0000-0000-000000000000","recordingProgramID":"00000000-0000-0000-0000-000000000000","seriesID":"103787"}],"moreInfo":{"ExtensionData":{},"Label":"","Link":""},"programacaoCanal":{"ExtensionData":{},"Label":"Programação","Link":"canal=RTPM"}}],"filters":{"ExtensionData":{},"types":[{"ExtensionData":{},"id":0,"name":"Gravações Automáticas"},{"ExtensionData":{},"id":1,"name":"Restart TV"}],"categories":[{"ExtensionData":{},"id":4,"name":"Entretenimento"}]}}}
\ No newline at end of file
+{
+ "Status": "OK",
+ "StatusCode": 200,
+ "Result": [
+ {
+ "CallLetter": "RTP1",
+ "EndDate": "2026-01-23T00:04:00",
+ "Id": 42314383,
+ "IsAdultContent": false,
+ "ProgramId": 22604754,
+ "StartDate": "2026-01-22T23:40:00",
+ "Synopsis": "'Barman' é uma série de comédia dramática sobre um jovem comediante que começa a trabalhar como Barman porque precisa de arranjar dinheiro depressa, pelo caminho é obrigado a lidar com a vida noturna e conciliar duas realidades diferentes.",
+ "Title": "Barman - Ep. 4"
+ },
+ {
+ "CallLetter": "RTP1",
+ "EndDate": "2026-01-23T00:30:00",
+ "Id": 42314384,
+ "IsAdultContent": false,
+ "ProgramId": 22604763,
+ "StartDate": "2026-01-23T00:04:00",
+ "Synopsis": "'Barman' é uma série de comédia dramática sobre um jovem comediante que começa a trabalhar como Barman porque precisa de arranjar dinheiro depressa, pelo caminho é obrigado a lidar com a vida noturna e conciliar duas realidades diferentes.",
+ "Title": "Barman - Ep. 5"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/sites/meo.pt/meo.pt.channels.xml b/sites/meo.pt/meo.pt.channels.xml
index 58d7164e8..1f6cc070b 100644
--- a/sites/meo.pt/meo.pt.channels.xml
+++ b/sites/meo.pt/meo.pt.channels.xml
@@ -48,7 +48,7 @@
CNN
CNN Portugal
Canção Nova
- Conta Lá
+ Conta Lá
Cubavision
DAZN 1
DAZN 2
@@ -66,7 +66,6 @@
DORCEL TV
Duck TV
DEUTSCHE WELLE
- E! Entertainment
English Club TV
Eurosport 1
Euronews
@@ -112,9 +111,6 @@
MCM Top
Mezzo Live
Mezzo
- MTV 00s
- MTV Live
- MTV Portugal
NBA TV
NEW Brasil
News Now
@@ -185,8 +181,6 @@
Telesur
TLC
TPA Notícias
- Trace Brasil
- Trace Toca
Trace Urban
Travelxp HD
Travelxp 4K HDR
@@ -217,4 +211,4 @@
ZDFNEO
ZEE CINEMA
ZEE TV
-
+
\ No newline at end of file
diff --git a/sites/meo.pt/meo.pt.config.js b/sites/meo.pt/meo.pt.config.js
index e5c9f2b0f..82d5f1cf9 100644
--- a/sites/meo.pt/meo.pt.config.js
+++ b/sites/meo.pt/meo.pt.config.js
@@ -3,65 +3,55 @@ const { DateTime } = require('luxon')
module.exports = {
site: 'meo.pt',
days: 2,
- url: 'https://authservice.apps.meo.pt/Services/GridTv/GridTvMng.svc/getProgramsFromChannels',
+ url: function ({ channel, date }) {
+ return `https://meogouser.apps.meo.pt/Services/GridTv/GridTv.svc/GetLiveChannelProgramsByDate?callLetter=${channel.site_id}&date=${date.format('YYYY-MM-DD')}&userAgent=IPTV_OFR_GTV`
+ },
request: {
- method: 'POST',
+ method: 'GET',
headers: {
- Origin: 'https://www.meo.pt',
- 'User-Agent': 'Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; en-US Trident/4.0)'
- },
- data: function ({ channel, date }) {
- return {
- service: 'channelsguide',
- channels: [channel.site_id],
- dateStart: date.format('YYYY-MM-DDT00:00:00-00:00'),
- dateEnd: date.add(1, 'd').format('YYYY-MM-DDT00:00:00-00:00'),
- accountID: ''
- }
+ 'accept': '*/*',
+ 'accept-language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7,pt;q=0.6,cs;q=0.5',
+ 'cache-control': 'no-cache',
+ 'origin': 'https://www.meo.pt',
+ 'pragma': 'no-cache',
+ 'priority': 'u=1, i',
+ 'referer': 'https://www.meo.pt/',
+ 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"',
+ 'sec-ch-ua-mobile': '?1',
+ 'sec-ch-ua-platform': '"Android"',
+ 'sec-fetch-dest': 'empty',
+ 'sec-fetch-mode': 'cors',
+ 'sec-fetch-site': 'same-site',
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Mobile Safari/537.36'
}
},
- async parser({ content }) {
- const axios = require('axios')
+ async parser({ content, channel }) {
let programs = []
const items = parseItems(content)
if (!items.length) return programs
- // simple per-run in-memory cache
- const detailsCache = new Map()
-
for (const item of items) {
- const start = parseStart(item)
- let stop = parseStop(item)
- if (stop < start) {
- stop = stop.plus({ days: 1 })
- }
-
- let description = ''
- let image = ''
-
- const programID = item.uniqueId || null
- if (programID) {
- let details = detailsCache.get(programID)
- if (!details) {
- details = await fetchProgramDetails(programID, axios).catch(() => null)
- if (details) detailsCache.set(programID, details)
- }
- if (details) {
- description = details.description || description
- image = details.image || image
- }
- }
+ const start = DateTime.fromISO(item.StartDate, { zone: 'Europe/Lisbon' }).toUTC()
+ const stop = DateTime.fromISO(item.EndDate, { zone: 'Europe/Lisbon' }).toUTC()
const prog = {
- title: item.name || 'Sem título',
+ title: item.Title || 'Sem título',
start,
stop
}
- if (description) prog.description = description
- if (image) {
+
+ if (item.Synopsis) {
+ prog.description = item.Synopsis
+ }
+
+ // Construct image URL using the same logic as before if possible
+ if (item.Title && channel.site_id) {
+ const encodedTitle = encodeURIComponent(item.Title)
+ const image = `https://proxycache.online.meo.pt/eemstb/ImageHandler.ashx?evTitle=${encodedTitle}&chCallLetter=${channel.site_id}&profile=16_9&width=600`
prog.icon = { src: image }
prog.image = image
}
+
programs.push(prog)
}
@@ -70,84 +60,45 @@ module.exports = {
async channels() {
const axios = require('axios')
const data = await axios
- .post('https://authservice.apps.meo.pt/Services/GridTv/GridTvMng.svc/getGridAnon', null, {
+ .get('https://meogouser.apps.meo.pt/Services/GridTv/GridTv.svc/GetContentsForChannels?userAgent=IPTV_OFR_GTV', {
headers: {
- Origin: 'https://www.meo.pt',
- 'User-Agent': 'Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; en-US Trident/4.0)'
+ 'accept': '*/*',
+ 'accept-language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7,pt;q=0.6,cs;q=0.5',
+ 'cache-control': 'no-cache',
+ 'origin': 'https://www.meo.pt',
+ 'pragma': 'no-cache',
+ 'priority': 'u=1, i',
+ 'referer': 'https://www.meo.pt/',
+ 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"',
+ 'sec-ch-ua-mobile': '?1',
+ 'sec-ch-ua-platform': '"Android"',
+ 'sec-fetch-dest': 'empty',
+ 'sec-fetch-mode': 'cors',
+ 'sec-fetch-site': 'same-site',
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Mobile Safari/537.36'
}
})
.then(r => r.data)
.catch(console.log)
- // channel logo at data.d.channels.logo
-
- return data.d.channels
+ return data.Result
.map(item => {
return {
lang: 'pt',
- site_id: item.sigla,
- name: item.name
+ site_id: item.CallLetter,
+ name: item.Title
}
})
.filter(channel => channel.site_id)
}
}
-function parseStart(item) {
- return DateTime.fromFormat(`${item.date} ${item.timeIni}`, 'd-M-yyyy HH:mm', {
- zone: 'Europe/Lisbon'
- }).toUTC()
-}
-
-function parseStop(item) {
- return DateTime.fromFormat(`${item.date} ${item.timeEnd}`, 'd-M-yyyy HH:mm', {
- zone: 'Europe/Lisbon'
- }).toUTC()
-}
-
function parseItems(content) {
if (!content) return []
- const data = JSON.parse(content)
- const programs = data?.d?.channels?.[0]?.programs
-
- return Array.isArray(programs) ? programs : []
-}
-
-async function fetchProgramDetails(programID, axiosInstance) {
try {
- const response = await axiosInstance.post(
- 'https://authservice.apps.meo.pt/Services/GridTv/GridTvMng.svc/getProgramDetails',
- {
- service: 'programdetail',
- programID: String(programID),
- accountID: ''
- },
- {
- headers: {
- Origin: 'https://www.meo.pt',
- 'User-Agent': 'Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; en-US Trident/4.0)'
- },
- timeout: 10000
- }
- )
-
- const data = response.data
- // Response structure has program data directly in data.d
- const program = data?.d
- if (!program || typeof program !== 'object') return null
-
- // Build image URL using MEO's image handler
- let image = null
- if (program.progName && program.channelSigla) {
- const encodedTitle = encodeURIComponent(program.progName)
- image = `https://proxycache.online.meo.pt/eemstb/ImageHandler.ashx?evTitle=${encodedTitle}&chCallLetter=${program.channelSigla}&profile=16_9&width=600`
- }
-
- const description = program.description || null
-
- return { description, image }
+ const data = typeof content === 'string' ? JSON.parse(content) : content
+ return Array.isArray(data.Result) ? data.Result : []
} catch {
- // Silent fail returning null so parser continues
- return null
+ return []
}
}
diff --git a/sites/meo.pt/meo.pt.test.js b/sites/meo.pt/meo.pt.test.js
index d86e9d2d9..26b5ce0f5 100644
--- a/sites/meo.pt/meo.pt.test.js
+++ b/sites/meo.pt/meo.pt.test.js
@@ -18,37 +18,28 @@ const channel = {
}
it('can generate valid url', () => {
- expect(url).toBe(
- 'https://authservice.apps.meo.pt/Services/GridTv/GridTvMng.svc/getProgramsFromChannels'
+ expect(url({ channel, date })).toBe(
+ 'https://meogouser.apps.meo.pt/Services/GridTv/GridTv.svc/GetLiveChannelProgramsByDate?callLetter=RTPM&date=2022-12-02&userAgent=IPTV_OFR_GTV'
)
})
it('can generate valid request method', () => {
- expect(request.method).toBe('POST')
+ expect(request.method).toBe('GET')
})
it('can generate valid request headers', () => {
expect(request.headers).toMatchObject({
- Origin: 'https://www.meo.pt'
- })
-})
-
-it('can generate valid request method', () => {
- expect(request.data({ channel, date })).toMatchObject({
- service: 'channelsguide',
- channels: ['RTPM'],
- dateStart: '2022-12-02T00:00:00-00:00',
- dateEnd: '2022-12-03T00:00:00-00:00',
- accountID: ''
+ 'origin': 'https://www.meo.pt',
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Mobile Safari/537.36'
})
})
it('can parse response', async () => {
- const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
+ const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'), 'utf-8')
- axios.post.mockResolvedValue({ data: {} })
+ axios.get.mockResolvedValue({ data: {} })
- let results = await parser({ content })
+ let results = await parser({ content, channel })
results = results.map(p => {
p.start = p.start.toJSON()
p.stop = p.stop.toJSON()
@@ -56,9 +47,13 @@ it('can parse response', async () => {
})
expect(results[0]).toMatchObject({
- start: '2022-12-01T23:35:00.000Z',
- stop: '2022-12-02T00:17:00.000Z',
- title: 'Walker, O Ranger Do Texas T6 - Ep. 14'
+ start: '2026-01-22T23:40:00.000Z',
+ stop: '2026-01-23T00:04:00.000Z',
+ title: 'Barman - Ep. 4',
+ description: "'Barman' é uma série de comédia dramática sobre um jovem comediante que começa a trabalhar como Barman porque precisa de arranjar dinheiro depressa, pelo caminho é obrigado a lidar com a vida noturna e conciliar duas realidades diferentes.",
+ icon: {
+ src: 'https://proxycache.online.meo.pt/eemstb/ImageHandler.ashx?evTitle=Barman%20-%20Ep.%204&chCallLetter=RTPM&profile=16_9&width=600'
+ }
})
})
diff --git a/sites/mujtvprogram.cz/mujtvprogram.cz.channels.xml b/sites/mujtvprogram.cz/mujtvprogram.cz.channels.xml
index 0c8143117..ad0cf9a3e 100644
--- a/sites/mujtvprogram.cz/mujtvprogram.cz.channels.xml
+++ b/sites/mujtvprogram.cz/mujtvprogram.cz.channels.xml
@@ -1,219 +1,216 @@
- ČT1
- ČT2
- Nova
- Prima
- HBO
- HBO2
- Cinemax
AXN
- Spektrum
- Animal Planet
- Discovery
- Viasat Explorer
- Viasat History
- CS Film
- Eurosport 1
- Nova Sport 1
- ČT sport
- ÓČKO
- MTV Europe
- National Geographic
- CNN
- ČT24
- Eurosport 2
- TV Paprika
- Spektrum Home
- Disney Channel
- Minimax
- TVP 1
- TVP 2
- Polsat
- ORF1
- ORF2
- ARD
- 3SAT
- ARTE
- RTL
- RTL2
- SAT1
- VOX
- Kabel1
- Sport 1
- Film+
- FilmBox
- FilmBox Plus
- MTV 00s
- Mezzo
- Hustler
- Cartoonito
- Private TV
- TV Noe
- JimJam
- Nova Cinema
- National Geographic Wild
- Extreme Sports Channel
- TV Barrandov
- Prima COOL
- Sport 2
- BBC World News
- Fishing & Hunting
- Playboy
- Travel Channel
- MTV 80s
- Baby TV
- Ducktv
- Stingray CMusic
- Cinemax 2
- Euronews
- Fashion TV
- FilmBox Extra HD
- France 24 (FR)
- History Channel
- LEO TV
- Club MTV
- Music Box
- RT
- Sky News
- TV5 Monde
- Blue Hustler
MTV Europe CZ
- DMAX
- CNBC Europe
- MTV 90s
- MTV Hits
- Deutsche Welle
- PRO7
- Dvojka
- Jednotka
- Doma
- Markíza
- PLUS
- JOJ
- Spectrum
- TA3
- Retro
- Viasat Nature
National Geographic HD
- ZDF NEO
- Al Jazeera English
- Golf Channel
- Prima Love
- MTV Live HD
- Stingray Classica
- Stingray iConcerts
- Deluxe Music
- Duna (SK)
- RTL
- TV 8
- FilmBox Family
- Film Europe
- TLC
- Bloomberg
+ Auto Motor Sport HD
+ CANAL+ Sport
+ Canal+ Action
+ Story 4
+ Canal+ Sport 2
+ Nova Sport 5
+ Nova Sport 6
+ Warner TV
+ Viasat True Crime
+ DVTV Extra
+ 3SAT
Canal 24 Horas
A11
- Erox HD
- FightBox HD
- SUPER RTL
- TV Lux
- M1
- Dajto
- RELAX
- DocuBox
- CBS Reality
- Cartoon Network
- EroXXX HD
- Prima ZOOM
- FashionBox HD
- Arena Sport 1
- WAU
- ÓČKO STAR
- KiKA
- Disney Junior
- M2
- ČT :D
- ČT art
- Duna (H)
- RTL
- Senzi
- Rebel
- Cool TV
- 360TuneBox
- Crime & Investigation
+ AMC
+ Animal Planet
+ ARTE
AXN Black
AXN White
- ÓČKO EXPRES
- Ginx eSports TV
- Brazzers TV Europe
- Arena Sport 2
- Mezzo Live HD
- Investigation Discovery
- ZDF
- AMC
- France 24 (EN)
- FilmBox Premium
- Jojko
- HTV1
- HTV2
- Fast&FunBox HD
- English Club TV
- SAT.1 Gold
- E! Entertainment
- Mňam TV
- Auto Motor Sport HD
- Kino Barrandov
Barrandov Krimi
- JOJ Cinema
- Nova Sport 2
- Food Network
- Prima MAX
- Paramount Network
- Nova International
- Markíza International
- HBO3
- Premier Sport
- JOJ Family
- Dorcel TV
- Prima PLUS
- Nova Action
- Nova Gold
- Nova Fun
- Mňau TV
- Travelxp HD
- Epic Drama
- Televize Seznam
- Prim KRIMI
- Nick Jr. Czech
- Nickelodeon
- Power TV
- Skylink 7
- Óčko Black HD
- LALA TV
+ Cartoon Network
+ Cinemax 2
+ Cinemax
+ CNBC Europe
+ CNN Prim NEWS
+ Crime & Investigation
+ CS Film
CS History
CS Horror
CS Mystery
- Nicktoons
- Dorcel XXX
- Love Nature HD
+ ČT1
+ ČT2
+ ČT24
+ ČT art
+ ČT :D
+ ČT sport
+ ARD
+ Discovery
+ Disney Channel
+ Duna (SK)
+ E! Entertainment
+ Epic Drama
+ Eurosport 1
+ Eurosport 2
+ FashionBox HD
+ FilmBox
+ FilmBox Extra HD
+ FilmBox Family
+ FilmBox Premium
+ FilmBox Plus
+ Film Europe
Film Europe + HD
- CNN Prima News
- Šlágr Premium
- Vixen
- Prima STAR
- Premier Sport 2
+ Film+
+ Food Network
+ Golf Channel
+ HBO2
+ HBO3
+ HBO
+ History Channel
+ HTV1
+ HTV2
+ Investigation Discovery
+ JimJam
+ Kabel1
+ Kino Barrandov
+ LALA TV
+ LEO TV
+ M1
+ M2
+ Minimax
+ Mňam TV
+ Mňau TV
+ MTV Europe
+ National Geographic
+ National Geographic Wild
+ Nickelodeon
+ Nick Jr. Czech
+ Nicktoons
+ Nova Action
+ Nova Cinema
+ Nova Fun
+ Nova Krimi
+ Nova International
+ Nova Lady
+ Nova Sport 1
+ Nova Sport 2
Nova Sport 3
Nova Sport 4
- Nova Lady
- Prima Show
- JOJ Šport
- RTVS Šport
- RTVS 24
+ ÓČKO
+ Óčko Black HD
+ ÓČKO EXPRES
+ ÓČKO STAR
+ ORF1
+ ORF2
+ Polsat
+ Power TV
+ Premier Sport 2
+ Prima
+ Prima COOL
+ Prim KRIMI
+ Prim LOVE
+ Prima MAX
+ Prim SHOW
+ Prima STAR
+ Prima ZOOM
+ PRO7
+ Rebel
+ Retro
+ RTL
+ RTL
+ RTL2
+ SAT1
+ SAT.1 Gold
+ Šlágr Premium
+ Spektrum
+ Spektrum Home
+ Sport 1
+ Sport 2
+ Televize Seznam
+ Fishing & Hunting
+ TLC
+ Travel Channel
+ Travelxp HD
+ TV Barrandov
+ TV Noe
+ Nova
+ TVP 1
+ TVP 2
+ TV Paprika
+ Viasat Explorer
+ Viasat History
+ Viasat Nature
+ VOX
+ ZDF
+ SUPER RTL
+ DMAX
+ KiKA
+ ZDF NEO
+ Music Box
+ 360TuneBox
+ Al Jazeera English
+ Baby TV
+ BBC World News
+ Bloomberg
+ Blue Hustler
+ Brazzers TV Europe
+ Cartoonito
+ CNN
+ Deluxe Music
+ Disney Junior
+ DocuBox
+ Dorcel TV
+ Dorcel XXX
+ Deutsche Welle
+ English Club TV
+ Erox HD
+ EroXXX HD
+ Euronews
+ Extreme Sports Channel
+ Fashion TV
+ Fast&FunBox HD
+ FightBox HD
+ France 24 (EN)
+ Ginx eSports TV
+ Hustler
+ Love Nature HD
+ Playboy
+ Private TV
+ RT
+ Sky News
+ Stingray Classica
+ Stingray CMusic
+ Stingray iConcerts
+ Vixen
+ France 24 (FR)
+ Mezzo
+ Mezzo Live HD
+ TV5 Monde
+ Cool TV
+ Duna (H)
+ RTL
+ Spectrum
+ ST24
Markíza Krimi
- CANAL+ Sport
JOJ 24
- Canal+ Action
- Story 4
TV Spark
JOJ Svet
+ JOJ Šport
+ Markíza KLASIK
+ JOJ Šport 2
+ Arena Sport 1
+ Arena Sport 2
+ ducktv
+ ST2
+ ST1
+ JOJ Cinema
+ JOJ Family
+ Jojko
+ PLUS
+ WAU
+ Markíza
+ Dajto
+ Doma
+ Markíza International
+ Prima SK
+ Senzi
+ RTVS Šport
+ TA3
+ TV 8
+ JOJ
+ TV Lux
diff --git a/sites/nostv.pt/__data__/data.json b/sites/nostv.pt/__data__/data.json
index 205e57974..6725777c5 100644
--- a/sites/nostv.pt/__data__/data.json
+++ b/sites/nostv.pt/__data__/data.json
@@ -1 +1,67 @@
-[{"CoreId":"2023121151009543","AssetId":"EPGE2023121151009543","ContentId":"epg@2023121151009543","ProgramId":"3011502","AggregatorId":"2967456","DateFullEventId":"2023121151009543","GridItemsLink":"/v2/browse/epg@2023121151009543/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121151009543/PlayListTray/items","UtcDateTimeStart":"2023-12-11T16:30:00Z","UtcDateTimeEnd":"2023-12-11T17:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Village Vets","SubTitle":"","RatingDisplay":"NC","GenreDisplay":"Reality TV","SeriesId":"142241","Description":"A história de dois melhores amigos veterinários e o seu extraordinário trabalho na Austrália.","ReleaseYear":"2014","Rating":0,"Season":1,"Episode":12,"Duration":30,"ProgramId":3011502,"AggregatorId":2967456,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"8329ed1aec5d4c0faa2056972256ff9f","Url":"http://vip.pam.local.internal/PAM.Images/Store/8329ed1aec5d4c0faa2056972256ff9f","Type":1}]},{"CoreId":"2023121151009544","AssetId":"EPGE2023121151009544","ContentId":"epg@2023121151009544","ProgramId":"3161537","AggregatorId":"2165665","DateFullEventId":"2023121151009544","GridItemsLink":"/v2/browse/epg@2023121151009544/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121151009544/PlayListTray/items","UtcDateTimeStart":"2023-12-11T17:00:00Z","UtcDateTimeEnd":"2023-12-11T18:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Histórias Clínicas","SubTitle":"Associações","RatingDisplay":"M12","GenreDisplay":"Saúde","SeriesId":"102905","Description":"Processo de Decisão Clínica.","ReleaseYear":"2018","Rating":80,"Season":7,"Episode":13,"Duration":60,"ProgramId":3161537,"AggregatorId":2165665,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"818dba4817a7464f9e8433620270b01d","Url":"http://vip.pam.local.internal/PAM.Images/Store/818dba4817a7464f9e8433620270b01d","Type":1}]},{"CoreId":"2023121151009545","AssetId":"EPGE2023121151009545","ContentId":"epg@2023121151009545","ProgramId":"3357379","AggregatorId":"2182966","DateFullEventId":"2023121151009545","GridItemsLink":"/v2/browse/epg@2023121151009545/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121151009545/PlayListTray/items","UtcDateTimeStart":"2023-12-11T18:00:00Z","UtcDateTimeEnd":"2023-12-11T19:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Corpo Clínico","SubTitle":"","RatingDisplay":"Todos","GenreDisplay":"Saúde","SeriesId":"103390","Description":"Farmacovigilância.","ReleaseYear":"2018","Rating":1,"Season":12,"Episode":5,"Duration":60,"ProgramId":3357379,"AggregatorId":2182966,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"a060ca5930444d3a864ad20615e7df33","Url":"http://vip.pam.local.internal/PAM.Images/Store/a060ca5930444d3a864ad20615e7df33","Type":1}]},{"CoreId":"2023121151009546","AssetId":"EPGE2023121151009546","ContentId":"epg@2023121151009546","ProgramId":"3364579","AggregatorId":"3161534","DateFullEventId":"2023121151009546","GridItemsLink":"/v2/browse/epg@2023121151009546/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121151009546/PlayListTray/items","UtcDateTimeStart":"2023-12-11T19:00:00Z","UtcDateTimeEnd":"2023-12-11T20:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Caixa de Pandora","SubTitle":"","RatingDisplay":"M12","GenreDisplay":"Talk-Show","SeriesId":"152921","Description":"Programa de 45 minutos, em estúdio, que reúne 4 mulheres de diversas idades e backgrounds que conversam todas as semanas sobre temas ligados à saúde e bem-estar, mas também à sexualidade, vida em família, ao trabalho, etc. É uma tertúlia no feminino.","ReleaseYear":"2023","Rating":80,"Season":4,"Episode":13,"Duration":60,"ProgramId":3364579,"AggregatorId":3161534,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"0ba7dccc8d1d459083c90666a2250776","Url":"http://vip.pam.local.internal/PAM.Images/Store/0ba7dccc8d1d459083c90666a2250776","Type":1}]},{"CoreId":"2023121151009547","AssetId":"EPGE2023121151009547","ContentId":"epg@2023121151009547","ProgramId":"3161541","AggregatorId":"2166905","DateFullEventId":"2023121151009547","GridItemsLink":"/v2/browse/epg@2023121151009547/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121151009547/PlayListTray/items","UtcDateTimeStart":"2023-12-11T20:00:00Z","UtcDateTimeEnd":"2023-12-11T21:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Anatomia De Vénus","SubTitle":"","RatingDisplay":"M12","GenreDisplay":"Entrevista","SeriesId":"102934","Description":"Sexualidade e Deficiência.","ReleaseYear":"2018","Rating":80,"Season":7,"Episode":13,"Duration":60,"ProgramId":3161541,"AggregatorId":2166905,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"5a9c92a158084235901d63e0cda418df","Url":"http://vip.pam.local.internal/PAM.Images/Store/5a9c92a158084235901d63e0cda418df","Type":1}]},{"CoreId":"2023121151009548","AssetId":"EPGE2023121151009548","ContentId":"epg@2023121151009548","ProgramId":"3072059","AggregatorId":"3066918","DateFullEventId":"2023121151009548","GridItemsLink":"/v2/browse/epg@2023121151009548/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121151009548/PlayListTray/items","UtcDateTimeStart":"2023-12-11T21:00:00Z","UtcDateTimeEnd":"2023-12-11T22:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Heart Transplant: A Chance To Live","SubTitle":"","RatingDisplay":"NC","GenreDisplay":"Saúde","SeriesId":"146850","Description":"Acompanhamos a vida de sete doentes criticos à espera para fazerem transplantes de coração.","ReleaseYear":"2018","Rating":0,"Season":1,"Episode":2,"Duration":60,"ProgramId":3072059,"AggregatorId":3066918,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"aba563a9ff3748de8a3551633f3bd1cb","Url":"http://vip.pam.local.internal/PAM.Images/Store/aba563a9ff3748de8a3551633f3bd1cb","Type":1}]},{"CoreId":"2023121151009549","AssetId":"EPGE2023121151009549","ContentId":"epg@2023121151009549","ProgramId":"3361332","AggregatorId":"3103070","DateFullEventId":"2023121151009549","GridItemsLink":"/v2/browse/epg@2023121151009549/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121151009549/PlayListTray/items","UtcDateTimeStart":"2023-12-11T22:00:00Z","UtcDateTimeEnd":"2023-12-11T22:30:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Entre Turnos","SubTitle":"","RatingDisplay":"M12","GenreDisplay":"Saúde","SeriesId":"149976","Description":"Vasco Lança (jogador de basquetebol e estudante de medicina).","ReleaseYear":"2022","Rating":80,"Season":1,"Episode":11,"Duration":30,"ProgramId":3361332,"AggregatorId":3103070,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"2e0fa1bc7d36404ab52dafcf450137d2","Url":"http://vip.pam.local.internal/PAM.Images/Store/2e0fa1bc7d36404ab52dafcf450137d2","Type":1}]},{"CoreId":"2023121151009550","AssetId":"EPGE2023121151009550","ContentId":"epg@2023121151009550","ProgramId":"3367957","AggregatorId":"3333429","DateFullEventId":"2023121151009550","GridItemsLink":"/v2/browse/epg@2023121151009550/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121151009550/PlayListTray/items","UtcDateTimeStart":"2023-12-11T22:30:00Z","UtcDateTimeEnd":"2023-12-11T23:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Fact Check","SubTitle":"","RatingDisplay":"Todos","GenreDisplay":"Entretenimento","SeriesId":"164520","Description":"Ouviu dizer que não deve misturar melancia e vinho na mesma refeição? Contaram-lhe que aquecer refeições no micro-ondas provoca cancro? No outro dia, viu nas redes sociais alguém afirmar que só vai ao psiquiatra quem tem doenças graves?","ReleaseYear":"2023","Rating":1,"Season":1,"Episode":11,"Duration":30,"ProgramId":3367957,"AggregatorId":3333429,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"6b08d78551e745899ff8db0fea2b8680","Url":"http://vip.pam.local.internal/PAM.Images/Store/6b08d78551e745899ff8db0fea2b8680","Type":1}]},{"CoreId":"2023121151009551","AssetId":"EPGE2023121151009551","ContentId":"epg@2023121151009551","ProgramId":"3365804","AggregatorId":"2165712","DateFullEventId":"2023121151009551","GridItemsLink":"/v2/browse/epg@2023121151009551/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121151009551/PlayListTray/items","UtcDateTimeStart":"2023-12-11T23:00:00Z","UtcDateTimeEnd":"2023-12-12T00:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Check Up","SubTitle":"","RatingDisplay":"Todos","GenreDisplay":"Debate","SeriesId":"102906","Description":"Para debater o futuro da saúde em Portugal, todas as semanas abrimos antena a “Check up”. O programa promete reunir os principais protagonistas do setor para discutirem em conjunto os grandes temas que preocupam este universo.","ReleaseYear":"2018","Rating":1,"Season":10,"Episode":14,"Duration":60,"ProgramId":3365804,"AggregatorId":2165712,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"5bf507f275934d369ceb7a790251bd1e","Url":"http://vip.pam.local.internal/PAM.Images/Store/5bf507f275934d369ceb7a790251bd1e","Type":1}]},{"CoreId":"2023121251009807","AssetId":"EPGE2023121251009807","ContentId":"epg@2023121251009807","ProgramId":"3364404","AggregatorId":"2460399","DateFullEventId":"2023121251009807","GridItemsLink":"/v2/browse/epg@2023121251009807/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009807/PlayListTray/items","UtcDateTimeStart":"2023-12-12T00:00:00Z","UtcDateTimeEnd":"2023-12-12T00:30:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Doutor Ajuda","SubTitle":"","RatingDisplay":"Todos","GenreDisplay":"Saúde","SeriesId":"112361","Description":"O que é a toxina botulínica e suas utilizações.","ReleaseYear":"2023","Rating":1,"Season":3,"Episode":9,"Duration":30,"ProgramId":3364404,"AggregatorId":2460399,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"dfc67678e6de4a2baf23cd16a039684b","Url":"http://vip.pam.local.internal/PAM.Images/Store/dfc67678e6de4a2baf23cd16a039684b","Type":1}]},{"CoreId":"2023121251009808","AssetId":"EPGE2023121251009808","ContentId":"epg@2023121251009808","ProgramId":"2207459","AggregatorId":"2165669","DateFullEventId":"2023121251009808","GridItemsLink":"/v2/browse/epg@2023121251009808/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009808/PlayListTray/items","UtcDateTimeStart":"2023-12-12T00:30:00Z","UtcDateTimeEnd":"2023-12-12T01:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Atendimento Permanente","SubTitle":"","RatingDisplay":"Todos","GenreDisplay":"Reality TV","SeriesId":"102919","Description":"No Atendimento Permanente desta semana vamos conhecer o dia a dia de um fisiatra.","ReleaseYear":"2018","Rating":1,"Season":1,"Episode":6,"Duration":30,"ProgramId":2207459,"AggregatorId":2165669,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"7973715e80b449afaeea3a23aa830fa0","Url":"http://vip.pam.local.internal/PAM.Images/Store/7973715e80b449afaeea3a23aa830fa0","Type":1}]},{"CoreId":"2023121251009809","AssetId":"EPGE2023121251009809","ContentId":"epg@2023121251009809","ProgramId":"3161541","AggregatorId":"2166905","DateFullEventId":"2023121251009809","GridItemsLink":"/v2/browse/epg@2023121251009809/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009809/PlayListTray/items","UtcDateTimeStart":"2023-12-12T01:00:00Z","UtcDateTimeEnd":"2023-12-12T02:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Anatomia De Vénus","SubTitle":"","RatingDisplay":"M12","GenreDisplay":"Entrevista","SeriesId":"102934","Description":"Sexualidade e Deficiência.","ReleaseYear":"2018","Rating":80,"Season":7,"Episode":13,"Duration":60,"ProgramId":3161541,"AggregatorId":2166905,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"5a9c92a158084235901d63e0cda418df","Url":"http://vip.pam.local.internal/PAM.Images/Store/5a9c92a158084235901d63e0cda418df","Type":1}]},{"CoreId":"2023121251009810","AssetId":"EPGE2023121251009810","ContentId":"epg@2023121251009810","ProgramId":"3047405","AggregatorId":"140870","DateFullEventId":"2023121251009810","GridItemsLink":"/v2/browse/epg@2023121251009810/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009810/PlayListTray/items","UtcDateTimeStart":"2023-12-12T02:00:00Z","UtcDateTimeEnd":"2023-12-12T03:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Sete Vidas","SubTitle":"","RatingDisplay":"Todos","GenreDisplay":"Entrevista","SeriesId":"116562","Description":"Anorexia, perturbação bipolar, depressão, comportamentos aditivos, dor crónica ou comportamento obsessivo-compulsivo são patologias psicológicas que a conhecida psicóloga clínica Joana Amaral Dias vai retratar através de uma conversa com uma figura pública que tenha vivenciado e superado o problema.","ReleaseYear":"2022","Rating":1,"Season":3,"Episode":8,"Duration":60,"ProgramId":3047405,"AggregatorId":140870,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"245f7c92250d443dbfa923d4a7cdda30","Url":"http://vip.pam.local.internal/PAM.Images/Store/245f7c92250d443dbfa923d4a7cdda30","Type":1}]},{"CoreId":"2023121251009811","AssetId":"EPGE2023121251009811","ContentId":"epg@2023121251009811","ProgramId":"2602834","AggregatorId":"2597243","DateFullEventId":"2023121251009811","GridItemsLink":"/v2/browse/epg@2023121251009811/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009811/PlayListTray/items","UtcDateTimeStart":"2023-12-12T03:00:00Z","UtcDateTimeEnd":"2023-12-12T04:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Histórias Clínicas: Dra. Sofia Braga","SubTitle":"","RatingDisplay":"M12","GenreDisplay":"Talk-Show","SeriesId":"120596","Description":"Rastreio cancro prostata.","ReleaseYear":"2020","Rating":80,"Season":6,"Episode":5,"Duration":60,"ProgramId":2602834,"AggregatorId":2597243,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"818dba4817a7464f9e8433620270b01d","Url":"http://vip.pam.local.internal/PAM.Images/Store/818dba4817a7464f9e8433620270b01d","Type":1}]},{"CoreId":"2023121251009812","AssetId":"EPGE2023121251009812","ContentId":"epg@2023121251009812","ProgramId":"2554643","AggregatorId":"1059808","DateFullEventId":"2023121251009812","GridItemsLink":"/v2/browse/epg@2023121251009812/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009812/PlayListTray/items","UtcDateTimeStart":"2023-12-12T04:00:00Z","UtcDateTimeEnd":"2023-12-12T05:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Pura Vida","SubTitle":"","RatingDisplay":"Todos","GenreDisplay":"Entrevista","SeriesId":"102883","Description":"João Paulo Freitas.","ReleaseYear":"2018","Rating":1,"Season":5,"Episode":9,"Duration":60,"ProgramId":2554643,"AggregatorId":1059808,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"c59c07b60101435a846e546633137b54","Url":"http://vip.pam.local.internal/PAM.Images/Store/c59c07b60101435a846e546633137b54","Type":1}]},{"CoreId":"2023121251009813","AssetId":"EPGE2023121251009813","ContentId":"epg@2023121251009813","ProgramId":"2581668","AggregatorId":"2527677","DateFullEventId":"2023121251009813","GridItemsLink":"/v2/browse/epg@2023121251009813/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009813/PlayListTray/items","UtcDateTimeStart":"2023-12-12T05:00:00Z","UtcDateTimeEnd":"2023-12-12T05:30:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Casos Singulares","SubTitle":"","RatingDisplay":"Todos","GenreDisplay":"Entrevista","SeriesId":"116606","Description":"No mundo foram reconhecidas entre 5 a 8 mil doenças raras que afetam o próprio e quem está ao redor. O peso social do problema, o acesso às terapêuticas quando existem, a forma de lidar com o problema, são aspetos a abordar no programa, que apresenta patologias e histórias de vida diferentes.","ReleaseYear":"2019","Rating":1,"Season":1,"Episode":13,"Duration":30,"ProgramId":2581668,"AggregatorId":2527677,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"42a228cd013742ffa58e302d4706b401","Url":"http://vip.pam.local.internal/PAM.Images/Store/42a228cd013742ffa58e302d4706b401","Type":1}]},{"CoreId":"2023121251009814","AssetId":"EPGE2023121251009814","ContentId":"epg@2023121251009814","ProgramId":"2312607","AggregatorId":"2176405","DateFullEventId":"2023121251009814","GridItemsLink":"/v2/browse/epg@2023121251009814/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009814/PlayListTray/items","UtcDateTimeStart":"2023-12-12T05:30:00Z","UtcDateTimeEnd":"2023-12-12T06:30:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Histórias Clínicas: Dra. Rita Gama","SubTitle":"","RatingDisplay":"M12","GenreDisplay":"Talk-Show","SeriesId":"103212","Description":"Prematuridade e doenças pulmonares crónicas obstrutivas.","ReleaseYear":"2018","Rating":80,"Season":2,"Episode":3,"Duration":60,"ProgramId":2312607,"AggregatorId":2176405,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"818dba4817a7464f9e8433620270b01d","Url":"http://vip.pam.local.internal/PAM.Images/Store/818dba4817a7464f9e8433620270b01d","Type":1}]},{"CoreId":"2023121251009815","AssetId":"EPGE2023121251009815","ContentId":"epg@2023121251009815","ProgramId":"2944028","AggregatorId":"2165663","DateFullEventId":"2023121251009815","GridItemsLink":"/v2/browse/epg@2023121251009815/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009815/PlayListTray/items","UtcDateTimeStart":"2023-12-12T06:30:00Z","UtcDateTimeEnd":"2023-12-12T07:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Ajudar Quem Ajuda","SubTitle":"","RatingDisplay":"Todos","GenreDisplay":"Entrevista","SeriesId":"102898","Description":"Hoje apresentamos a Associação Careca Power.","ReleaseYear":"2018","Rating":1,"Season":7,"Episode":11,"Duration":30,"ProgramId":2944028,"AggregatorId":2165663,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"a655dbeb67b745418e40096827581a69","Url":"http://vip.pam.local.internal/PAM.Images/Store/a655dbeb67b745418e40096827581a69","Type":1}]},{"CoreId":"2023121251009816","AssetId":"EPGE2023121251009816","ContentId":"epg@2023121251009816","ProgramId":"2554639","AggregatorId":"2165680","DateFullEventId":"2023121251009816","GridItemsLink":"/v2/browse/epg@2023121251009816/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009816/PlayListTray/items","UtcDateTimeStart":"2023-12-12T07:00:00Z","UtcDateTimeEnd":"2023-12-12T08:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Tenho um bebé. E agora?","SubTitle":"","RatingDisplay":"Todos","GenreDisplay":"Magazine","SeriesId":"102886","Description":"Obesidade Infantil - Estratégias de combate em casa e na escola.","ReleaseYear":"2018","Rating":1,"Season":5,"Episode":9,"Duration":60,"ProgramId":2554639,"AggregatorId":2165680,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"293d91056a424619b904d93cd60e8db5","Url":"http://vip.pam.local.internal/PAM.Images/Store/293d91056a424619b904d93cd60e8db5","Type":1}]},{"CoreId":"2023121251009817","AssetId":"EPGE2023121251009817","ContentId":"epg@2023121251009817","ProgramId":"2383511","AggregatorId":"2303539","DateFullEventId":"2023121251009817","GridItemsLink":"/v2/browse/epg@2023121251009817/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009817/PlayListTray/items","UtcDateTimeStart":"2023-12-12T08:00:00Z","UtcDateTimeEnd":"2023-12-12T09:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Histórias Clínicas: Dr. Luis Sousa","SubTitle":"","RatingDisplay":"M12","GenreDisplay":"Talk-Show","SeriesId":"106734","Description":"Medicina Dentária em Portugal.","ReleaseYear":"2018","Rating":80,"Season":3,"Episode":1,"Duration":60,"ProgramId":2383511,"AggregatorId":2303539,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"818dba4817a7464f9e8433620270b01d","Url":"http://vip.pam.local.internal/PAM.Images/Store/818dba4817a7464f9e8433620270b01d","Type":1}]},{"CoreId":"2023121251009818","AssetId":"EPGE2023121251009818","ContentId":"epg@2023121251009818","ProgramId":"3364579","AggregatorId":"3161534","DateFullEventId":"2023121251009818","GridItemsLink":"/v2/browse/epg@2023121251009818/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009818/PlayListTray/items","UtcDateTimeStart":"2023-12-12T09:00:00Z","UtcDateTimeEnd":"2023-12-12T10:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Caixa de Pandora","SubTitle":"","RatingDisplay":"M12","GenreDisplay":"Talk-Show","SeriesId":"152921","Description":"Programa de 45 minutos, em estúdio, que reúne 4 mulheres de diversas idades e backgrounds que conversam todas as semanas sobre temas ligados à saúde e bem-estar, mas também à sexualidade, vida em família, ao trabalho, etc. É uma tertúlia no feminino.","ReleaseYear":"2023","Rating":80,"Season":4,"Episode":13,"Duration":60,"ProgramId":3364579,"AggregatorId":3161534,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"0ba7dccc8d1d459083c90666a2250776","Url":"http://vip.pam.local.internal/PAM.Images/Store/0ba7dccc8d1d459083c90666a2250776","Type":1}]},{"CoreId":"2023121251009819","AssetId":"EPGE2023121251009819","ContentId":"epg@2023121251009819","ProgramId":"3357379","AggregatorId":"2182966","DateFullEventId":"2023121251009819","GridItemsLink":"/v2/browse/epg@2023121251009819/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009819/PlayListTray/items","UtcDateTimeStart":"2023-12-12T10:00:00Z","UtcDateTimeEnd":"2023-12-12T11:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Corpo Clínico","SubTitle":"","RatingDisplay":"Todos","GenreDisplay":"Saúde","SeriesId":"103390","Description":"Farmacovigilância.","ReleaseYear":"2018","Rating":1,"Season":12,"Episode":5,"Duration":60,"ProgramId":3357379,"AggregatorId":2182966,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"a060ca5930444d3a864ad20615e7df33","Url":"http://vip.pam.local.internal/PAM.Images/Store/a060ca5930444d3a864ad20615e7df33","Type":1}]},{"CoreId":"2023121251009820","AssetId":"EPGE2023121251009820","ContentId":"epg@2023121251009820","ProgramId":"3365186","AggregatorId":"3120338","DateFullEventId":"2023121251009820","GridItemsLink":"/v2/browse/epg@2023121251009820/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009820/PlayListTray/items","UtcDateTimeStart":"2023-12-12T11:00:00Z","UtcDateTimeEnd":"2023-12-12T12:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Tenho Um Adolescente. E Agora?","SubTitle":"","RatingDisplay":"M12","GenreDisplay":"Saúde","SeriesId":"150432","Description":"Como lidar com a rejeição.","ReleaseYear":"2022","Rating":80,"Season":2,"Episode":3,"Duration":60,"ProgramId":3365186,"AggregatorId":3120338,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"d0b53e8f6f644939a11be96ac28aae07","Url":"http://vip.pam.local.internal/PAM.Images/Store/d0b53e8f6f644939a11be96ac28aae07","Type":1}]},{"CoreId":"2023121251009821","AssetId":"EPGE2023121251009821","ContentId":"epg@2023121251009821","ProgramId":"3031742","AggregatorId":"2967454","DateFullEventId":"2023121251009821","GridItemsLink":"/v2/browse/epg@2023121251009821/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009821/PlayListTray/items","UtcDateTimeStart":"2023-12-12T12:00:00Z","UtcDateTimeEnd":"2023-12-12T13:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"One Born Every Minute","SubTitle":"","RatingDisplay":"NC","GenreDisplay":"Saúde","SeriesId":"142171","Description":"Saiba quais os segredos de uma boa relação.","ReleaseYear":"2018","Rating":0,"Season":9,"Episode":5,"Duration":60,"ProgramId":3031742,"AggregatorId":2967454,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"746a4552819c485aba07aed59fcca49d","Url":"http://vip.pam.local.internal/PAM.Images/Store/746a4552819c485aba07aed59fcca49d","Type":1}]},{"CoreId":"2023121251009822","AssetId":"EPGE2023121251009822","ContentId":"epg@2023121251009822","ProgramId":"3361332","AggregatorId":"3103070","DateFullEventId":"2023121251009822","GridItemsLink":"/v2/browse/epg@2023121251009822/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009822/PlayListTray/items","UtcDateTimeStart":"2023-12-12T13:00:00Z","UtcDateTimeEnd":"2023-12-12T13:30:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Entre Turnos","SubTitle":"","RatingDisplay":"M12","GenreDisplay":"Saúde","SeriesId":"149976","Description":"Vasco Lança (jogador de basquetebol e estudante de medicina).","ReleaseYear":"2022","Rating":80,"Season":1,"Episode":11,"Duration":30,"ProgramId":3361332,"AggregatorId":3103070,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"2e0fa1bc7d36404ab52dafcf450137d2","Url":"http://vip.pam.local.internal/PAM.Images/Store/2e0fa1bc7d36404ab52dafcf450137d2","Type":1}]},{"CoreId":"2023121251009823","AssetId":"EPGE2023121251009823","ContentId":"epg@2023121251009823","ProgramId":"3367957","AggregatorId":"3333429","DateFullEventId":"2023121251009823","GridItemsLink":"/v2/browse/epg@2023121251009823/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009823/PlayListTray/items","UtcDateTimeStart":"2023-12-12T13:30:00Z","UtcDateTimeEnd":"2023-12-12T14:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Fact Check","SubTitle":"","RatingDisplay":"Todos","GenreDisplay":"Entretenimento","SeriesId":"164520","Description":"Ouviu dizer que não deve misturar melancia e vinho na mesma refeição? Contaram-lhe que aquecer refeições no micro-ondas provoca cancro? No outro dia, viu nas redes sociais alguém afirmar que só vai ao psiquiatra quem tem doenças graves?","ReleaseYear":"2023","Rating":1,"Season":1,"Episode":11,"Duration":30,"ProgramId":3367957,"AggregatorId":3333429,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"6b08d78551e745899ff8db0fea2b8680","Url":"http://vip.pam.local.internal/PAM.Images/Store/6b08d78551e745899ff8db0fea2b8680","Type":1}]},{"CoreId":"2023121251009824","AssetId":"EPGE2023121251009824","ContentId":"epg@2023121251009824","ProgramId":"3206760","AggregatorId":"3161538","DateFullEventId":"2023121251009824","GridItemsLink":"/v2/browse/epg@2023121251009824/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009824/PlayListTray/items","UtcDateTimeStart":"2023-12-12T14:00:00Z","UtcDateTimeEnd":"2023-12-12T15:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Guia da Vida Saudável","SubTitle":"","RatingDisplay":"M12","GenreDisplay":"Magazine","SeriesId":"152938","Description":"Programa de estúdio de 45 minutos, onde vamos mostrar exemplos e práticas que podem determinar uma vida mais saudável. Queremos condensar toda a informação disponível. O objetivo do programa é “prevenir primeiro, para não ter que remediar depois”.","ReleaseYear":"2023","Rating":80,"Season":1,"Episode":12,"Duration":60,"ProgramId":3206760,"AggregatorId":3161538,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"0082754b26bb4bc4978b9e324cccd8f6","Url":"http://vip.pam.local.internal/PAM.Images/Store/0082754b26bb4bc4978b9e324cccd8f6","Type":1}]},{"CoreId":"2023121251009825","AssetId":"EPGE2023121251009825","ContentId":"epg@2023121251009825","ProgramId":"3365804","AggregatorId":"2165712","DateFullEventId":"2023121251009825","GridItemsLink":"/v2/browse/epg@2023121251009825/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009825/PlayListTray/items","UtcDateTimeStart":"2023-12-12T15:00:00Z","UtcDateTimeEnd":"2023-12-12T16:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Check Up","SubTitle":"","RatingDisplay":"Todos","GenreDisplay":"Debate","SeriesId":"102906","Description":"Para debater o futuro da saúde em Portugal, todas as semanas abrimos antena a “Check up”. O programa promete reunir os principais protagonistas do setor para discutirem em conjunto os grandes temas que preocupam este universo.","ReleaseYear":"2018","Rating":1,"Season":10,"Episode":14,"Duration":60,"ProgramId":3365804,"AggregatorId":2165712,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"5bf507f275934d369ceb7a790251bd1e","Url":"http://vip.pam.local.internal/PAM.Images/Store/5bf507f275934d369ceb7a790251bd1e","Type":1}]},{"CoreId":"2023121251009826","AssetId":"EPGE2023121251009826","ContentId":"epg@2023121251009826","ProgramId":"3161537","AggregatorId":"2165665","DateFullEventId":"2023121251009826","GridItemsLink":"/v2/browse/epg@2023121251009826/grid/items","PlayListTrayItemLink":"/v1/contents/epg@2023121251009826/PlayListTray/items","UtcDateTimeStart":"2023-12-12T16:00:00Z","UtcDateTimeEnd":"2023-12-12T17:00:00Z","Type":4,"IsAdult":false,"AiringChannel":{"IsOnline":true,"IsTimeWarpable":true,"IsRestartable":true,"ServiceId":"510","ChannelId":"510","AssetId":"EPGC510","Name":"S+ HD","RatingDisplay":"M3","DvbLocator":"dvb://36.4C.835","Rating":20,"Position":129,"QualityVersion":2,"Images":[{"ImageId":"SAUDEMAIS.png","Url":"http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/SAUDEMAIS.png","Type":16}]},"Metadata":{"Title":"Histórias Clínicas","SubTitle":"Associações","RatingDisplay":"M12","GenreDisplay":"Saúde","SeriesId":"102905","Description":"Processo de Decisão Clínica.","ReleaseYear":"2018","Rating":80,"Season":7,"Episode":13,"Duration":60,"ProgramId":3161537,"AggregatorId":2165665,"IsNPVR":true,"IsStartOver":true},"Images":[{"ImageId":"818dba4817a7464f9e8433620270b01d","Url":"http://vip.pam.local.internal/PAM.Images/Store/818dba4817a7464f9e8433620270b01d","Type":1}]}]
\ No newline at end of file
+[
+ {
+ "CoreId": "2026012313905035",
+ "AssetId": "EPGE2026012313905035",
+ "ContentId": "epg@2026012313905035",
+ "ProgramId": "3805166",
+ "AggregatorId": "2649043",
+ "DateFullEventId": "2026012313905035",
+ "GridItemsLink": "/v2/browse/epg@2026012313905035/grid/items",
+ "PlayListTrayItemLink": "/v1/contents/epg@2026012313905035/PlayListTray/items",
+ "DetailNodeItemNavLink": "/nodeitems/epg@2026012313905035/detail?context=schedule",
+ "UtcDateTimeStart": "2026-01-23T22:39:00Z",
+ "UtcDateTimeEnd": "2026-01-24T00:23:00Z",
+ "Type": 4,
+ "IsAdult": false,
+ "AiringChannel": {
+ "IsOnline": true,
+ "IsTimeWarpable": true,
+ "IsRestartable": true,
+ "ServiceId": "139",
+ "ChannelId": "5",
+ "AssetId": "EPGC139",
+ "Name": "RTP 1 HD",
+ "RatingDisplay": "M3",
+ "DvbLocator": "dvb://36.4E.1E79",
+ "Rating": 20,
+ "Position": 1,
+ "QualityVersion": 2,
+ "Images": [
+ {
+ "ImageId": "RTPHD.png",
+ "Type": 16,
+ "Url": "http://vip.repositories.local.internal/Repositories.EPG/OttChannelIcons/RTPHD.png"
+ }
+ ]
+ },
+ "Metadata": {
+ "Title": "Em Casa d'Amália",
+ "SubTitle": "",
+ "RatingDisplay": "M6",
+ "GenreDisplay": "Talk-Show",
+ "SeriesId": "124075",
+ "Description": "Que mais poderíamos pedir para o regresso deste programa, do que receber um dos poetas de Amália? Manuel Alegre, autor do icónico \"Trova do Vento que Passa\", estará connosco. A este raro momento, juntam-se também ilustres convidados: Paulo de Carvalho e o seu filho Agir, Rita Guerra e André Amaro...",
+ "ReleaseYear": "2025",
+ "Rating": 60,
+ "Season": 9,
+ "Episode": 15,
+ "Duration": 104,
+ "ProgramId": 3805166,
+ "AggregatorId": 2649043,
+ "IsNPVR": true,
+ "IsStartOver": true
+ },
+ "Images": [
+ {
+ "ImageId": "901d96a8f1534749b076212c296d821e",
+ "Type": 1,
+ "Url": "http://vip.pam.local.internal/PAM.Images/Store/901d96a8f1534749b076212c296d821e"
+ },
+ {
+ "ImageId": "4de2fbd7177c4e7c8cc9faf703b119b5",
+ "Type": 38,
+ "Url": "http://vip.pam.local.internal/PAM.Images/Store/4de2fbd7177c4e7c8cc9faf703b119b5"
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/sites/nostv.pt/nostv.pt.channels.xml b/sites/nostv.pt/nostv.pt.channels.xml
index 378f158c1..0eb5ba713 100644
--- a/sites/nostv.pt/nostv.pt.channels.xml
+++ b/sites/nostv.pt/nostv.pt.channels.xml
@@ -12,7 +12,6 @@
Record News
TeleSUR
MCM Top
- MTV 00s
M6
Sky News
RTL
@@ -142,7 +141,6 @@
TVI HD
RTP Noticias HD
CNN Portugal HD
- MTV Live
Discovery HD
Eurosport 2 HD
Canal 11 HD
@@ -168,5 +166,5 @@
Dizi
Now
Sport TV 7 HD
- Conta Lá
-
+ Conta Lá
+
\ No newline at end of file
diff --git a/sites/nostv.pt/nostv.pt.config.js b/sites/nostv.pt/nostv.pt.config.js
index ffeb7a6eb..88db91de0 100644
--- a/sites/nostv.pt/nostv.pt.config.js
+++ b/sites/nostv.pt/nostv.pt.config.js
@@ -5,24 +5,33 @@ const utc = require('dayjs/plugin/utc')
dayjs.extend(utc)
const headers = {
- 'X-Apikey': 'xe1dgrShwdR1DVOKGmsj8Ut4QLlGyOFI',
- 'X-Core-Appversion': '2.20.0.3',
- 'X-Core-Contentratinglimit': '0',
- 'X-Core-Deviceid': '',
- 'X-Core-Devicetype': 'web',
- Origin: 'https://nostv.pt',
- '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': 'application/json, text/plain, */*',
+ 'accept-language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7,pt;q=0.6,cs;q=0.5',
+ 'cache-control': 'no-cache',
+ 'origin': 'https://nostv.pt',
+ 'pragma': 'no-cache',
+ 'priority': 'u=1, i',
+ 'referer': 'https://nostv.pt/',
+ 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"',
+ 'sec-ch-ua-mobile': '?1',
+ 'sec-ch-ua-platform': '"Android"',
+ 'sec-fetch-dest': 'empty',
+ 'sec-fetch-mode': 'cors',
+ 'sec-fetch-site': 'cross-site',
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Mobile Safari/537.36',
+ 'x-apikey': 'xe1dgrShwdR1DVOKGmsj8Ut4QLlGyOFI',
+ 'x-core-appversion': '2.20.2.2',
+ 'x-core-contentratinglimit': '0',
+ 'x-core-deviceid': '',
+ 'x-core-devicetype': 'web',
+ 'x-core-timezoneoffset': '3600000'
}
module.exports = {
site: 'nostv.pt',
days: 2,
url({ channel, date }) {
- return `https://api.clg.nos.pt/nostv/ott/schedule/range/contents/guest?channels=${channel.site_id
- }&minDate=${date.format('YYYY-MM-DD')}T00:00:00Z&maxDate=${date.format(
- 'YYYY-MM-DD'
- )}T23:59:59Z&isDateInclusive=true&client_id=${headers['X-Apikey']}`
+ return `https://api.clg.nos.pt/nostv/ott/schedule/range/contents/guest?channels=${channel.site_id}&minDate=${date.format('YYYY-MM-DD')}T00:00:00Z&maxDate=${date.format('YYYY-MM-DD')}T23:59:59Z&isDateInclusive=true&client_id=${headers['x-apikey']}`
},
request: { headers },
parser({ content }) {
@@ -31,7 +40,7 @@ module.exports = {
const items = Array.isArray(content) ? content : JSON.parse(content)
items.forEach(item => {
const image = item.Images
- ? `https://mage.stream.nos.pt/mage/v1/Images?sourceUri=${item.Images[0].Url}&profile=ott_1_452x340&client_id=${headers['X-Apikey']}`
+ ? `https://mage.stream.nos.pt/mage/v1/Images?sourceUri=${item.Images[0].Url}&profile=ott_1_452x340&client_id=${headers['x-apikey']}`
: null
programs.push({
title: item.Metadata?.Title,
@@ -54,7 +63,7 @@ module.exports = {
async channels() {
const result = await axios
.get(
- `https://api.clg.nos.pt/nostv/ott/channels/guest?client_id=${headers['X-Apikey']}`,
+ `https://api.clg.nos.pt/nostv/ott/channels/guest?client_id=${headers['x-apikey']}`,
{ headers }
)
.then(r => r.data)
diff --git a/sites/nostv.pt/nostv.pt.test.js b/sites/nostv.pt/nostv.pt.test.js
index 939b8aadc..e20132c20 100644
--- a/sites/nostv.pt/nostv.pt.test.js
+++ b/sites/nostv.pt/nostv.pt.test.js
@@ -28,20 +28,17 @@ it('can parse response', () => {
return p
})
- const image = 'https://mage.stream.nos.pt/mage/v1/Images?sourceUri=http://vip.pam.local.internal/PAM.Images/Store/8329ed1aec5d4c0faa2056972256ff9f&profile=ott_1_452x340&client_id=xe1dgrShwdR1DVOKGmsj8Ut4QLlGyOFI'
-
expect(results[0]).toMatchObject({
- start: '2023-12-11T16:30:00.000Z',
- stop: '2023-12-11T17:00:00.000Z',
- title: 'Village Vets',
- description:
- 'A história de dois melhores amigos veterinários e o seu extraordinário trabalho na Austrália.',
- season: 1,
- episode: 12,
+ start: '2026-01-23T22:39:00.000Z',
+ stop: '2026-01-24T00:23:00.000Z',
+ title: 'Em Casa d\'Amália',
+ description: 'Que mais poderíamos pedir para o regresso deste programa, do que receber um dos poetas de Amália? Manuel Alegre, autor do icónico "Trova do Vento que Passa", estará connosco. A este raro momento, juntam-se também ilustres convidados: Paulo de Carvalho e o seu filho Agir, Rita Guerra e André Amaro...',
+ season: 9,
+ episode: 15,
icon: {
- src: image
+ src: 'https://mage.stream.nos.pt/mage/v1/Images?sourceUri=http://vip.pam.local.internal/PAM.Images/Store/901d96a8f1534749b076212c296d821e&profile=ott_1_452x340&client_id=xe1dgrShwdR1DVOKGmsj8Ut4QLlGyOFI'
},
- image
+ image: 'https://mage.stream.nos.pt/mage/v1/Images?sourceUri=http://vip.pam.local.internal/PAM.Images/Store/901d96a8f1534749b076212c296d821e&profile=ott_1_452x340&client_id=xe1dgrShwdR1DVOKGmsj8Ut4QLlGyOFI'
})
})
diff --git a/sites/osn.com/osn.com_ar.channels.xml b/sites/osn.com/osn.com_ar.channels.xml
index 98df113fc..30aeeee39 100644
--- a/sites/osn.com/osn.com_ar.channels.xml
+++ b/sites/osn.com/osn.com_ar.channels.xml
@@ -1,62 +1,70 @@
- OSN TV Movies Action
- Kapatid TV5
- ANC
Animal Planet
+ Blippi and Friends
+ Bloomberg Originals HD
+ OSN TV Documentary
+ DWRR 101.9
+ eClutch LIVE 2
+ eClutch Access
+ eClutch LIVE 1
+ eClutch Arabic
+ Esport 24
+ Gametoon
+ Ginx
+ MCM Top
+ Motorvision
+ OSNtv Crime
+ OSNtv Movies Horror
+ OSNtv Movies Family
+ OSNtv Now
+ OSNtv Movies Comedy
+ OSNtv Showcase Classics
+ OSNtv One
+ Padeltime
+ OSNtv Pop up Love story
+ RFM TV
+ Kapatid TV5
+ Alfa Series Channel
+ Alfa Series +2
+ Al Safwa
+ Alfa Al Yawm
+ ANC
Bloomberg
- Crime & Investigation Network
- Cine Mo
+ Cartoon Network
Alfa Cinema 1
Alfa Cinema 2
- CNBC
- CNN
Cinema One Global
- Discovery ID
+ Cine Mo
+ CNN
+ Crime & Investigation Network
Discovery HD
- DWRR 101.9
- DZMM Teleradyo
- E! Entertainment
Alfa Fann
Fatafeat
- GMA Pinoy TV
GMA Life TV
GMA News TV
+ GMA Pinoy TV
H2 HD
History HD
- OSN TV Kidzone
+ Discovery ID
Moonbug Kids
- MTV Live HD
+ Music Now
Myx
Nickelodeon HD
Nick Jr
NickToons HD
- Music Now
- OSN TV Crime
- OSNtv Movies Horror
- OSN TV Comedy
- OSN TV Showcase
- OSN TV Movies Family
- OSN TV Now
- OSN TV Movies Premiere
- OSN TV Movies Comedy
- OSN TV Kids
- OSN TV Mezze
- OSN TV News
- OSN TV Movies Hollywood
- OSN TV Showcase Classics
- OSN TV One
- OSN TV Yahala Bil Arabi
- OSN TV Yahala Aflam
- OSN TV Yahala
+ OSNtv Comedy
+ OSNtv Kids
+ OSNtv Mezze
+ OSNtv Movies Action
+ OSNtv Movies Hollywood
+ OSNtv Movies Premiere
+ OSNtv Showcase
+ OSNtv Yahala
+ OSNtv Yahala Aflam
+ OSNtv Yahala Bil Arabi
PBA Rush
- Al Safwa
- Alfa Series +2
- Alfa Series Channel
- Sky News HD
- Cartoon Network
+ DZMM Teleradyo
TFC
TLC HD
- MTV 00s
- Alfa Al Yawm
diff --git a/sites/osn.com/osn.com_en.channels.xml b/sites/osn.com/osn.com_en.channels.xml
index 462de041b..1a008dce2 100644
--- a/sites/osn.com/osn.com_en.channels.xml
+++ b/sites/osn.com/osn.com_en.channels.xml
@@ -1,62 +1,70 @@
- OSN TV Movies Action
- Kapatid TV5
- ANC
Animal Planet
+ Blippi and Friends
+ Bloomberg Originals HD
+ OSN TV Documentary
+ DWRR 101.9
+ eClutch LIVE 2
+ eClutch Access
+ eClutch LIVE 1
+ eClutch Arabic
+ Esport 24
+ Gametoon
+ Ginx
+ MCM Top
+ Motorvision
+ OSNtv Crime
+ OSNtv Movies Horror
+ OSNtv Movies Family
+ OSNtv Now
+ OSNtv Movies Comedy
+ OSNtv Showcase Classics
+ OSNtv One
+ Padeltime
+ OSNtv Pop up Love story
+ RFM TV
+ Kapatid TV5
+ Alfa Series Channel
+ Alfa Series +2
+ Al Safwa
+ Alfa Al Yawm
+ ANC
Bloomberg
- Crime & Investigation Network
- Cine Mo
+ Cartoon Network
Alfa Cinema 1
Alfa Cinema 2
- CNBC
- CNN
Cinema One Global
- Discovery ID
+ Cine Mo
+ CNN
+ Crime & Investigation Network
Discovery HD
- DWRR 101.9
- DZMM Teleradyo
- E! Entertainment
Alfa Fann
Fatafeat
- GMA Pinoy TV
GMA Life TV
GMA News TV
+ GMA Pinoy TV
H2 HD
History HD
- OSN TV Kidzone
+ Discovery ID
Moonbug Kids
- MTV Live HD
+ Music Now
Myx
Nickelodeon HD
Nick Jr
NickToons HD
- Music Now
- OSN TV Crime
- OSNtv Movies Horror
- OSN TV Comedy
- OSN TV Showcase
- OSN TV Movies Family
- OSN TV Now
- OSN TV Movies Premiere
- OSN TV Movies Comedy
- OSN TV Kids
- OSN TV Mezze
- OSN TV News
- OSN TV Movies Hollywood
- OSN TV Showcase Classics
- OSN TV One
- OSN TV Yahala Bil Arabi
- OSN TV Yahala Aflam
- OSN TV Yahala
+ OSNtv Comedy
+ OSNtv Kids
+ OSNtv Mezze
+ OSNtv Movies Action
+ OSNtv Movies Hollywood
+ OSNtv Movies Premiere
+ OSNtv Showcase
+ OSNtv Yahala
+ OSNtv Yahala Aflam
+ OSNtv Yahala Bil Arabi
PBA Rush
- Al Safwa
- Alfa Series +2
- Alfa Series Channel
- Sky News HD
- Cartoon Network
+ DZMM Teleradyo
TFC
TLC HD
- MTV 00s
- Alfa Al Yawm
diff --git a/sites/tv.movistar.com.pe/tv.movistar.com.pe.channels.xml b/sites/tv.movistar.com.pe/tv.movistar.com.pe.channels.xml
index 889c09310..d2491aa59 100644
--- a/sites/tv.movistar.com.pe/tv.movistar.com.pe.channels.xml
+++ b/sites/tv.movistar.com.pe/tv.movistar.com.pe.channels.xml
@@ -1,43 +1,27 @@
- CANAL N
ESPN INTERNACIONAL
ESPN 3
Cartoon Network HD
- TNT HD OTT
+ TNT HD
LATINA HD
AMERICA TELEVISION HD
PANAMERICANA TELEVISION HD
TV PERU HD
ATV HD
- LATINA
- AMERICA TELEVISION
- PANAMERICANA TELEVISION
- TV PERU
- ATV
- RPP TV
- TV PERU 7.3
GLOBAL
LA TELE PERU
- WILLAX
- ATV+
TNT
TNT SERIES
TNT SERIES HD
- SONY
WARNER CHANNEL
STAR CHANNEL
- AXN
- UNIVERSAL CHANNEL
FX
INVESTIGATION DISCOVERY
TRU TV
TCM
SPACE
- PARAMOUNT
- I-SAT
STUDIO UNIVERSAL
- EUROCHANNEL
CINECANAL
CINEMAX
HBO
@@ -48,14 +32,12 @@
HBO PLUS ESTE
HBO XTREME
DISCOVERY CHANNEL
- HISTORY CHANNEL
NAT GEO
HISTORY 2
DISCOVERY SCIENCE
DISCOVERY TURBO
TLC
HOME & HEALTH
- GLITZ
CARTOON NETWORK
DISCOVERY KIDS
CARTOONITO
@@ -63,58 +45,46 @@
ANIMAL PLANET
DISNEY JUNIOR
FOX SPORTS PREMIUM
- FOX SPORTS 2
- FOX SPORTS 3
+ ESPN 7
+ ESPN 6
ESPN 2
- GOL TV
GOLF CHANNEL
- JCP
- TOROS TV
+ JOCKEY CLUB
WOBI
CNN ESPAÑOL
CNN INTERNACIONAL
FOX NEWS
- PODER JUDICIAL
CAPITAL TV
ENLACE TBN
- ORBE 21
MTV
- MTV HITS
HTV
CANAL N HD
- GOLPERU HD
STAR CHANNEL HD
WARNER CHANNEL HD
FX HD
- ID HD - INVESTIGATION DISCOVERY HD
+ INV.DISCOVERY HD
COMEDY CENTRAL HD
SPACE HD
- PARAMOUNT HD
CINECANAL HD
CINEMAX HD
- ESPN 4
- FOX SPORTS 2 HD
- FOX SPORTS 3 HD
- GOL TV HD
+ ESPN 5 HD
+ ESPN 7 HD
+ ESPN 6 HD
DISCOVERY THEATER HD
DISCOVERY HD
NAT GEO HD
- TRU TV HD
+ LATINA
FASHION ONE HD
- ATRES SERIES HD
DISCOVERY WORLD HD
HOME & HEALTH HD
DISCOVERY KIDS HD
DISNEY CHANNEL HD
NICK HD
MTV HD
- MTV 00S
GLOBO TV
TELEFE
EL TRECE
- TV CHILE
TELESUR
- NUESTRA TELE
TVE
ANTENA3
DEUTSCHE WELLE
@@ -122,34 +92,23 @@
TV5
NHK
CCTV
- ARTV
VOA
PLAYBOY
- VENUS
- SEXTREME
PLAYBOY HD
CONGRESO
- A&E
- GOLPERU
- ESPN 2 HD
RPP HD
HBO HD
- QUALITY CHANNEL
BABY TV
- EL GOURMET HD
BBC WORLD NEWS
ESPN HD
ESPN 3 HD
- SPACE REGIONAL DTH LIVE
- GOL PERU
- ESPN EXTRA HD
+ SPACE HD
+ ESPN 4 HD
ANIMAL PLANET HD
TNT HD
- M PLUS HD
+ PLUS LIFE
M DEPORTES HD
M DEPORTES
- M PLUS
- NICK JR OTT
CABLE NOTICIAS
HBO PLUS ESTE HD
HBO SIGNATURE HD
@@ -158,30 +117,23 @@
NAT GEO HD
TEST01
TEST02
- CANAL J
- ESPN 2
- KANAL D DRAMA
- ZEE MUNDO
+ Juntos TV
+ ESPN 2 HD
DISCOVERY HOME & GARDEN
FOOD NETWORK
- USMP TV
- MOVISTAR EVENTOS 2
MOVISTAR EVENTOS
Food Network HD
Exitosa TV
Exitosa TV
INFO STAR PREMIUM
- AZ CORAZON
VE PLUS TV
HGTV
- AZ MUNDO
NICKELODEON
DISNEY
PX SPORTS
FRANCE24
JUSTICIA TV
EWTN
- PAXTV
MOVISTAR EVENTOS HD
TV PERÚ 7.3 HD
WILLAX TV HD
@@ -189,51 +141,24 @@
HGTV HD
CARTOONITO HD
CANAL J HD
- RUSIA TODAY HD
TVN CHILE
- RUSIA TODAY
CLOVER
UCL
TOONCAST
- LOLLY KIDS
- QUIALITY CHANNEL
+ KIDS STARS
CLOVER
CLOVER
DISNEY JUNIOR
- TOONCAST
- LOLLY KIDS
- Alianza Lima TV
- Alianza Lima TV
- Universitario TV
- Universitario TV
UCL
- UCL
- EL TIEMPO
- Alianza TV
+ Movistar Te Informa
U TV
TV PERU HD
- CANAL J
- AMC HD
Star TVE HD
- Pasiones HD
- Film & Arts HD
- Love Nature HD
Via X Esports HD
- Mas Chic HD
- Europa Europa HD
EWTN
- EUROCHANNEL
- RAI ITALIA
- ANTENA 3
- PX SPORTS
TVE
- K-DRAMA
- I-SAT
- GLITZ
HTV
TV5
- WOBI
- NUESTRA TELE
FRANCE24
TV GLOBO
TVN CHILE
@@ -241,9 +166,6 @@
Telefe Internacional
ATV+
BABY TV
- GLOBAL TV
- CONGRESO
- EXITOSA TV
JUSTICIA TV
ADULT SWIM
ENLACE TBN
@@ -251,9 +173,7 @@
IPe
VIVA TV
La Tele
- JCP-JNE
SOL TV
- QUALITY TV
JN19 TELEJUAN
NUEVO TIEMPO
PAXTV
@@ -282,4 +202,64 @@
YouTube
Youtube Kids
Star+
+ ATRES SERIES HD
+ CLAN HD
+ TVLIBERTAD
+ DAYSTAR HD
+ MOVISTAR EVENTOS 2
+ AMERICA TELEVISION AREQUIPA
+ AMERICA TELEVISION CUSCO
+ AMERICA TELEVISION TRUJILLO
+ AMERICA TELEVISION CHICLAYO
+ AMERICA TELEVISION PIURA
+ PANAMERICANA TELEVISION AREQUIPA
+ PANAMERICANA TELEVISION CUSCO
+ PANAMERICANA TELEVISION TRUJILLO
+ PANAMERICANA TELEVISION CHICLAYO
+ PANAMERICANA TELEVISION PIURA
+ ALACOCINA TV
+ TOP LATINO
+ LATINA NOTICIAS
+ PBO
+ BBC WORLD NEWS
+ PLIM PLIM
+ TRIVU
+ OVACION
+ JNE TV
+ CRISTOVISION
+ NICK JR
+ L1MAX
+ L1
+ AMERICA TELEVISION
+ ANTENA 3
+ ATV
+ ATV+
+ CANAL J
+ CANAL N
+ CONGRESO
+ EL TIEMPO
+ EXITOSA TV
+ GLOBAL TV
+ PODER JUDICIAL
+ KANAL D DRAMA
+ K-DRAMA
+ LATINA
+ LOLLY KIDS
+ Love Nature HD
+ M PLUS
+ PANAMERICANA TELEVISION
+ Pasiones HD
+ PAXTV
+ PX SPORTS
+ RPP TV
+ TOONCAST
+ TV CHILE
+ TV PERU
+ TV PERU 7.3
+ UCL
+ USMP TV
+ VENUS
+ WILLAX
+ ZEE MUNDO
+ RAI ITALIA
diff --git a/sites/vodafone.pt/vodafone.pt.channels.xml b/sites/vodafone.pt/vodafone.pt.channels.xml
index 7f2c332d8..092a70ba8 100644
--- a/sites/vodafone.pt/vodafone.pt.channels.xml
+++ b/sites/vodafone.pt/vodafone.pt.channels.xml
@@ -33,7 +33,6 @@
24h
CNBC
TPA
- MTV 00s
Pro TV International
Bloomberg
Mezzo
@@ -146,5 +145,5 @@
BabyTV
História
W-Sport
- Conta Lá
+ Conta Lá
diff --git a/sites/webtv.sk/__data__/content.json b/sites/webtv.sk/__data__/content.json
new file mode 100644
index 000000000..817661fd5
--- /dev/null
+++ b/sites/webtv.sk/__data__/content.json
@@ -0,0 +1 @@
+{"id":"golf_channel","content":[{"ChannelTitle":"Golf Channel","Start":"2026-02-17T00:00:00+01:00","Stop":"2026-02-17T05:00:00+01:00","Title":"Qatar Masters","Subtitle":"","Description":"Fin\u00e1lov\u00e9 kolo turnaje DP World Tour. Doha, Qatar., (\u0161port)","Icon":"","SeriesID":"dc1ad829a6c42cde31b0f84657eb90bb","Genres":["\u0161port"],"Score":0},{"ChannelTitle":"Golf Channel","Start":"2026-02-17T05:00:00+01:00","Stop":"2026-02-17T07:00:00+01:00","Title":"The Bay vs Los Angeles","Subtitle":"","Description":"Tomorrow's Golf League. SoFi Center, Palm Beach State College, USA., (\u0161port)","Icon":"","SeriesID":"39eb4a8d024da076ce509b24c17e1a75","Genres":["\u0161port"],"Score":0},{"ChannelTitle":"Golf Channel","Start":"2026-02-17T07:00:00+01:00","Stop":"2026-02-17T12:00:00+01:00","Title":"LIV Golf Adelaide","Subtitle":"","Description":"Fin\u00e1lov\u00e9 kolo turnaje LIV Golf. The Grange Golf Club, Australia., (\u0161port)","Icon":"","SeriesID":"735549e083f0cb5495881ee0f2530f16","Genres":["\u0161port"],"Score":0},{"ChannelTitle":"Golf Channel","Start":"2026-02-17T12:00:00+01:00","Stop":"2026-02-17T12:25:00+01:00","Title":"The Golf Fix","Subtitle":"","Description":"Jak kontrolovat d\u00e9lku ran wedgemi. Kontrola vzd\u00e1lenosti je p\u0159edev\u0161\u00edm u ran wedgemi naprosto kl\u00ed\u010dov\u00fd p\u0159edpoklad golfov\u00e9ho \u00fasp\u011bchu. Zn\u00e1m\u00fd tren\u00e9r Devan Bonebrake v\u00e1m v dal\u0161\u00edm d\u00edlu po\u0159adu Golf Fix nab\u00eddne skv\u011bl\u00e9 tipy a cvi\u010den\u00ed pro zlep\u0161en\u00ed v t\u00e9to oblasti.., (\u0161port)","Icon":"\/channel\/golf_channel\/programme\/2026-02-17T12:00:00+01:00\/icon\/8793bfb65b85be90d64adfdb7163c022","SeriesID":"8793bfb65b85be90d64adfdb7163c022","Genres":["\u0161port"],"Score":0},{"ChannelTitle":"Golf Channel","Start":"2026-02-17T12:25:00+01:00","Stop":"2026-02-17T12:30:00+01:00","Title":"Cestov\u00e1n\u00ed za golfem 2025","Subtitle":"","Description":"Profesion\u00e1ln\u00ed turnaje. B\u011bhem deseti d\u00edl\u016f s\u00e9rie Cestov\u00e1n\u00ed za golfem se spole\u010dn\u011b pod\u00edv\u00e1me jak na m\u00edsta, kam golfist\u00e9 v roce 2025 cestuj\u00ed nej\u010dast\u011bji, tak zav\u00edt\u00e1me do destinac\u00ed, kter\u00e1 si o sv\u00e9 slovo teprve \u0159\u00edkaj\u00ed.., (\u0161port)","Icon":"\/channel\/golf_channel\/programme\/2026-02-17T12:25:00+01:00\/icon\/724f5af276123ee230befad2a27fa7fd","SeriesID":"724f5af276123ee230befad2a27fa7fd","Genres":["\u0161port"],"Score":0},{"ChannelTitle":"Golf Channel","Start":"2026-02-17T12:30:00+01:00","Stop":"2026-02-17T14:30:00+01:00","Title":"The Bay vs Los Angeles","Subtitle":"","Description":"(\u0161port)","Icon":"","SeriesID":"39eb4a8d024da076ce509b24c17e1a75","Genres":["\u0161port"],"Score":0},{"ChannelTitle":"Golf Channel","Start":"2026-02-17T14:30:00+01:00","Stop":"2026-02-17T15:00:00+01:00","Title":"The Golf Fix","Subtitle":"","Description":"Um\u011bn\u00ed kr\u00e1tk\u00e9 hry. Nikdo nem\u00e1 r\u00e1d tr\u00e1pen\u00ed okolo greenu. P\u0159itom dobr\u00e1 kr\u00e1tk\u00e1 hra m\u016f\u017ee v\u00fdrazn\u011b pomoci sn\u00ed\u017eit sk\u00f3re. Pokud m\u00e1te probl\u00e9my s kr\u00e1tkou hrou, \u0159e\u0161en\u00ed nab\u00edz\u00ed v dal\u0161\u00edm d\u00edlu Golf Fix pr\u016fvodce Devan Bonebrake.., (\u0161port)","Icon":"\/channel\/golf_channel\/programme\/2026-02-17T14:30:00+01:00\/icon\/8793bfb65b85be90d64adfdb7163c022","SeriesID":"8793bfb65b85be90d64adfdb7163c022","Genres":["\u0161port"],"Score":0},{"ChannelTitle":"Golf Channel","Start":"2026-02-17T15:00:00+01:00","Stop":"2026-02-17T20:00:00+01:00","Title":"LIV Golf Adelaide","Subtitle":"","Description":"Fin\u00e1lov\u00e9 kolo turnaje LIV Golf. The Grange Golf Club, Australia., (\u0161port)","Icon":"","SeriesID":"735549e083f0cb5495881ee0f2530f16","Genres":["\u0161port"],"Score":0},{"ChannelTitle":"Golf Channel","Start":"2026-02-17T20:00:00+01:00","Stop":"2026-02-17T21:00:00+01:00","Title":"Sn\u011bhul\u00e1k","Subtitle":"","Description":"Romana Pavelkov\u00e1, (\u0161port)","Icon":"\/channel\/golf_channel\/programme\/2026-02-17T20:00:00+01:00\/icon\/782cd01f689e432d695a5c482dcbeee0","SeriesID":"782cd01f689e432d695a5c482dcbeee0","Genres":["\u0161port"],"Score":0},{"ChannelTitle":"Golf Channel","Start":"2026-02-17T21:00:00+01:00","Stop":"2026-02-17T21:30:00+01:00","Title":"The Golf Fix","Subtitle":"","Description":"Jak potopit v\u00edc putt\u016f. M\u00edjet kr\u00e1tk\u00e9 putty m\u016f\u017ee znamenat pro celkov\u00e9 sk\u00f3re pohromu. Devan Bonebrake v\u00e1s v dal\u0161\u00edm pokra\u010dov\u00e1n\u00ed po\u0159adu Golf Fix provede v\u0161emi z\u00e1ludnostmi spojen\u00fdmi s puttov\u00e1n\u00edm.., (\u0161port)","Icon":"\/channel\/golf_channel\/programme\/2026-02-17T21:00:00+01:00\/icon\/8793bfb65b85be90d64adfdb7163c022","SeriesID":"8793bfb65b85be90d64adfdb7163c022","Genres":["\u0161port"],"Score":0},{"ChannelTitle":"Golf Channel","Start":"2026-02-17T21:30:00+01:00","Stop":"2026-02-17T23:30:00+01:00","Title":"The Bay vs Los Angeles","Subtitle":"","Description":"(\u0161port)","Icon":"","SeriesID":"39eb4a8d024da076ce509b24c17e1a75","Genres":["\u0161port"],"Score":0},{"ChannelTitle":"Golf Channel","Start":"2026-02-17T23:30:00+01:00","Stop":"2026-02-18T00:00:00+01:00","Title":"The Golf Fix","Subtitle":"","Description":"Jak v golfu pracovat se spinem. Spin neboli zp\u011btn\u00e1 rotace m\u00ed\u010dku je jedn\u00edm z nejd\u016fle\u017eit\u011bj\u0161\u00edch faktor\u016f v golfu. Jak s n\u00edm pracovat a jak ho m\u00edt pod kontrolou v\u00e1s v dal\u0161\u00edm pokra\u010dov\u00e1n\u00ed po\u0159adu Golf Fix nau\u010d\u00ed Devan Bonebrake.., (\u0161port)","Icon":"\/channel\/golf_channel\/programme\/2026-02-17T23:30:00+01:00\/icon\/8793bfb65b85be90d64adfdb7163c022","SeriesID":"8793bfb65b85be90d64adfdb7163c022","Genres":["\u0161port"],"Score":0}]}
\ No newline at end of file
diff --git a/sites/webtv.sk/readme.md b/sites/webtv.sk/readme.md
new file mode 100644
index 000000000..70cd24252
--- /dev/null
+++ b/sites/webtv.sk/readme.md
@@ -0,0 +1,21 @@
+# webtv.sk
+
+https://webtv.sk/archive
+
+### Download the guide
+
+```sh
+npm run grab --- --site=webtv.sk
+```
+
+### Update channel list
+
+```sh
+npm run channels:parse --- --config=./sites/webtv.sk/webtv.sk.config.js --output=./sites/webtv.sk/webtv.sk.channels.xml
+```
+
+### Test
+
+```sh
+npm test --- webtv.sk
+```
diff --git a/sites/webtv.sk/webtv.sk.channels.xml b/sites/webtv.sk/webtv.sk.channels.xml
new file mode 100644
index 000000000..058822546
--- /dev/null
+++ b/sites/webtv.sk/webtv.sk.channels.xml
@@ -0,0 +1,189 @@
+
+
+ 360 TuneBox
+ Al Jazeera
+ Al Jazeera English
+ AMC
+ Animal Planet
+ Arena Sport 1
+ Arena Sport 2
+ Arirang TV
+ Armenia 1 TV
+ ATV Žiar
+ Auto Motor und Sport
+ AXN
+ AXN Black
+ AXN White
+ Barrandov
+ Barrandov Krimi
+ BTV
+ CETV
+ CGTN
+ CGTN Documentary
+ Cinemax
+ Cinemax 2
+ HaHa TV
+ Crime & Investigation
+ ČSRTV
+ ČT1
+ ČT2
+ ČT24
+ ČT :D - ČT art
+ Current Time
+ DajTo
+ Discovery
+ Disney Channel
+ Disney Junior
+ DocuBox
+ Doktor TV
+ Doma
+ Duck TV
+ Duck TV Plus
+ eClutch 1
+ eClutch 2
+ English Club TV
+ Espreso TV
+ Euronews
+ Eurosport 1
+ Eurosport 2
+ Fashion TV Czech & Slovak
+ FashionBox
+ Fast and Funbox
+ FightBox
+ Film +
+ FilmBox
+ Filmbox Arthouse
+ FilmBox Extra
+ FilmBox Family
+ FilmBox Stars
+ FilmBox Premium
+ Fishing&Hunting
+ Folklorika
+ Food Network
+ France 24
+ France 24 English
+ Golf Channel
+ GTTV
+ HBO
+ HBO 2
+ HBO 3
+ HGTV
+ History 2
+ History Channel
+ HN TV
+ Antik Info TV
+ ID
+ JimJam
+ JOJ
+ JOJ 24
+ JOJ Cinema
+ JOJ Cinema +1
+ JOJ Plus
+ JOJ +1
+ JOJ Šport
+ JOJ Šport 2
+ JOJ Svet
+ Kino Barrandov
+ Kitchen TV
+ LALA TV
+ LangLab
+ Life TV
+ Lingo Toons
+ TV LocAll
+ Love Nature
+ TV LUX
+ Markíza
+ Markíza Klasik
+ Markíza Krimi
+ Markíza +1
+ Mestská Televízia Trnava
+ Mestská Tv Košice
+ Mestská Televízia Partizánske
+ Miestna TV Trebišov
+ Minimax
+ TV Mistral
+ Moldava TV
+ National Geographic Channel
+ National Geographic Wild
+ NHK World Japan
+ Nick Jr
+ Nickelodeon
+ Nicktoons
+ NOE
+ Nova International
+ Nova Sport 1
+ Nova Sport 2
+ tv NRSR
+ Óčko
+ Óčko Black
+ Óčko Expres
+ Óčko Star
+ Padel Time
+ PARK TV
+ Rebel
+ Relax
+ Polar TV
+ Prima Cool SK
+ Prima Krimi SK
+ Prima Love SK
+ CNN Prima News
+ Prima SK
+ Rai Tre
+ Rai Uno
+ Régió TV
+ A11
+ Retro Music Television
+ RiK TV
+ Jojko
+ RVTV
+ Senzi
+ Seznam.cz TV
+ Skvelé TV
+ Sky News
+ PREMIUM
+ Šláger Muzika
+ Šláger Originál
+ Spektrum
+ Spektrum Home
+ Sport 1
+ Sport 2
+ STINGRAY iConcerts
+ Jednotka
+ Dvojka
+ :24
+ :Šport
+ SuperYacht TV
+ TA3
+ Tanečné súťaže
+ TLC
+ Travel Channel
+ TRT World
+ Turbo TV
+ TV7
+ TV 9
+ TV8
+ TV Bratislava
+ TV Nitrička
+ TV Nové Zámky
+ TV Panoráma
+ TV Paprika
+ TV Piánko
+ TV Poprad
+ TV Považie
+ TV RAJ
+ TV Reduta
+ TV Romana
+ TV Ružinov
+ TV SEN
+ TV Kežmarok
+ Tv Vega
+ Godzone TV
+ TV Zemplín
+ TVP Info
+ TVP Polonia
+ TVP World
+ UA TV
+ Kanal1
+ WAU
+ Televízia Slovensko
+
diff --git a/sites/webtv.sk/webtv.sk.config.js b/sites/webtv.sk/webtv.sk.config.js
new file mode 100644
index 000000000..dc7045a28
--- /dev/null
+++ b/sites/webtv.sk/webtv.sk.config.js
@@ -0,0 +1,74 @@
+const axios = require('axios')
+const dayjs = require('dayjs')
+const utc = require('dayjs/plugin/utc')
+
+dayjs.extend(utc)
+
+module.exports = {
+ site: 'webtv.sk',
+ days: 2,
+ delay: 1000,
+ url: 'https://api.webtv.sk/epg/channel',
+ request: {
+ method: 'POST',
+ headers: {
+ 'content-type': 'application/json'
+ },
+ data({ channel, date }) {
+ return {
+ channel_id: channel.site_id,
+ date: dayjs.utc(date).toJSON()
+ }
+ }
+ },
+ parser({ content }) {
+ return parseItems(content).map(item => {
+ return {
+ title: item.Title,
+ subtitle: item.Subtitle,
+ description: item.Description,
+ categories: item.Genres,
+ start: dayjs(item.Start),
+ stop: dayjs(item.Stop)
+ }
+ })
+ },
+ async channels() {
+ const data = await axios
+ .post(
+ 'https://api.webtv.sk/channels',
+ { type: 'TV', channels_content: null },
+ {
+ headers: {
+ 'content-type': 'application/json'
+ }
+ }
+ )
+ .then(r => r.data)
+ .catch(console.error)
+
+ let channels = []
+ for (const site_id in data.data) {
+ const channel = data.data[site_id]
+
+ channels.push({
+ site_id,
+ name: channel.name,
+ lang: 'sk'
+ })
+ }
+
+ return channels
+ }
+}
+
+function parseItems(content) {
+ try {
+ const data = JSON.parse(content)
+ if (!data || !Array.isArray(data.content)) return []
+
+ return data.content
+ } catch {
+ return []
+ }
+}
diff --git a/sites/webtv.sk/webtv.sk.test.js b/sites/webtv.sk/webtv.sk.test.js
new file mode 100644
index 000000000..b3b42d56a
--- /dev/null
+++ b/sites/webtv.sk/webtv.sk.test.js
@@ -0,0 +1,68 @@
+const { parser, url, request } = require('./webtv.sk.config.js')
+const fs = require('fs')
+const path = require('path')
+const dayjs = require('dayjs')
+const utc = require('dayjs/plugin/utc')
+const customParseFormat = require('dayjs/plugin/customParseFormat')
+dayjs.extend(customParseFormat)
+dayjs.extend(utc)
+
+const date = dayjs.utc('2026-02-17', 'YYYY-MM-DD').startOf('d')
+const channel = { site_id: 'golf_channel' }
+
+it('can generate valid url', () => {
+ expect(url).toBe('https://api.webtv.sk/epg/channel')
+})
+
+it('can generate valid request method', () => {
+ expect(request.method).toBe('POST')
+})
+
+it('can generate valid request headers', () => {
+ expect(request.headers).toMatchObject({
+ 'content-type': 'application/json'
+ })
+})
+
+it('can generate valid request data', () => {
+ expect(request.data({ channel, date })).toMatchObject({
+ channel_id: 'golf_channel',
+ date: '2026-02-17T00:00:00.000Z'
+ })
+})
+
+it('can parse response', () => {
+ const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
+
+ const results = parser({ content }).map(p => {
+ p.start = p.start.toJSON()
+ p.stop = p.stop.toJSON()
+
+ return p
+ })
+
+ expect(results.length).toBe(12)
+ expect(results[0]).toMatchObject({
+ title: 'Qatar Masters',
+ subtitle: '',
+ description: 'Finálové kolo turnaje DP World Tour. Doha, Qatar., (šport)',
+ categories: ['šport'],
+ start: '2026-02-16T23:00:00.000Z',
+ stop: '2026-02-17T04:00:00.000Z'
+ })
+ expect(results[11]).toMatchObject({
+ title: 'The Golf Fix',
+ subtitle: '',
+ description:
+ 'Jak v golfu pracovat se spinem. Spin neboli zpětná rotace míčku je jedním z nejdůležitějších faktorů v golfu. Jak s ním pracovat a jak ho mít pod kontrolou vás v dalším pokračování pořadu Golf Fix naučí Devan Bonebrake.., (šport)',
+ categories: ['šport'],
+ start: '2026-02-17T22:30:00.000Z',
+ stop: '2026-02-17T23:00:00.000Z'
+ })
+})
+
+it('can handle empty guide', () => {
+ const results = parser({ content: '' })
+
+ expect(results).toMatchObject([])
+})
diff --git a/tests/__data__/expected/guides_update/GUIDES.md b/tests/__data__/expected/guides_update/GUIDES.md
new file mode 100644
index 000000000..f6e86cfc8
--- /dev/null
+++ b/tests/__data__/expected/guides_update/GUIDES.md
@@ -0,0 +1,13 @@
+# Guides
+
+
+
+ | Host | Status | Channels | Last Updated | Links |
+
+
+ | example.com | 🔴 | 0 | - | |
+ | worker-9dd4.onrender.com | 🟢 | 1 | a day ago | channels.xml guide.xml |
+
+
+
+[How can I add my server to the list?](CONTRIBUTING.md#how-to-add-my-server-to-the-guides-md)
diff --git a/tests/__data__/input/guides_update/channels.xml b/tests/__data__/input/guides_update/channels.xml
new file mode 100644
index 000000000..46c1b2e93
--- /dev/null
+++ b/tests/__data__/input/guides_update/channels.xml
@@ -0,0 +1,4 @@
+
+
+ ANT1 Europe
+
\ No newline at end of file
diff --git a/tests/__data__/input/guides_update/guide.xml b/tests/__data__/input/guides_update/guide.xml
new file mode 100644
index 000000000..ed17438ed
--- /dev/null
+++ b/tests/__data__/input/guides_update/guide.xml
@@ -0,0 +1,30 @@
+
+ANT1 Europehttps://antennaeurope.gr
+ΚΑΛΗΜΕΡΑ ΕΛΛΑΔΑ
+ΤΟ ΠΡΩΙΝΟ
+ANT1 NEWS
+ΑΠΟΚΑΛΥΨΕΙΣ
+ΡΟΥΚ ΖΟΥΚ
+5 X 5
+ANT1 NEWS
+ΠΟΙΟΣ ΘΕΛΕΙ ΝΑ ΓΙΝΕΙ ΕΚΑΤΟΜΜΥΡΙΟΥΧΟΣ
+GRAND HOTEL
+ΓΙΑΤΙ ΡΕ ΠΑΤΕΡΑ ;
+THE ROADSHOW - BEST OF
+ΕΝΩΠΙΟΣ ΕΝΩΠΙΩ
+5 X 5
+ΤΟ ΠΡΩΙΝΟ
+ΚΑΛΗΜΕΡΑ ΕΛΛΑΔΑ
+ΤΟ ΠΡΩΙΝΟ
+ANT1 NEWS
+ΑΠΟΚΑΛΥΨΕΙΣ
+ΡΟΥΚ ΖΟΥΚ
+5 X 5
+ANT1 NEWS
+ΠΟΙΟΣ ΘΕΛΕΙ ΝΑ ΓΙΝΕΙ ΕΚΑΤΟΜΜΥΡΙΟΥΧΟΣ
+DON'T FORGET THE LYRICS
+VIΠ
+ΠΕΦΤΕΙ Η ΝΥΧΤΑ ΜΕ... ΡΥΘΜΟ
+5 X 5
+ΤΟ ΠΡΩΙΝΟ
+
\ No newline at end of file
diff --git a/tests/__data__/input/guides_update/worker.json b/tests/__data__/input/guides_update/worker.json
new file mode 100644
index 000000000..371feec07
--- /dev/null
+++ b/tests/__data__/input/guides_update/worker.json
@@ -0,0 +1,4 @@
+{
+ "channels": "channels.xml",
+ "guide": "guide.xml"
+}
\ No newline at end of file
diff --git a/tests/__data__/input/guides_update/workers.txt b/tests/__data__/input/guides_update/workers.txt
new file mode 100644
index 000000000..02ca158a1
--- /dev/null
+++ b/tests/__data__/input/guides_update/workers.txt
@@ -0,0 +1,2 @@
+example.com
+worker-9dd4.onrender.com
\ No newline at end of file
diff --git a/tests/commands/guides/update.test.ts b/tests/commands/guides/update.test.ts
new file mode 100644
index 000000000..4f3d0f6ef
--- /dev/null
+++ b/tests/commands/guides/update.test.ts
@@ -0,0 +1,29 @@
+import { execSync } from 'child_process'
+import { pathToFileURL } from 'node:url'
+import fs from 'fs-extra'
+
+const ENV_VAR = 'cross-env ROOT_DIR=tests/__data__/output'
+
+beforeEach(() => {
+ fs.emptyDirSync('tests/__data__/output')
+ fs.copySync('tests/__data__/input/guides_update/workers.txt', 'tests/__data__/output/workers.txt')
+})
+
+it('can update GUIDES.md', () => {
+ const cmd = `${ENV_VAR} npm run guides:update`
+
+ const stdout = execSync(cmd, { encoding: 'utf8' })
+ if (process.env.DEBUG === 'true') console.log(cmd, stdout)
+
+ expect(content('tests/__data__/output/GUIDES.md')).toEqual(
+ content('tests/__data__/expected/guides_update/GUIDES.md')
+ )
+})
+
+function content(filepath: string) {
+ const data = fs.readFileSync(pathToFileURL(filepath), {
+ encoding: 'utf8'
+ })
+
+ return JSON.stringify(data)
+}
diff --git a/workers.txt b/workers.txt
new file mode 100644
index 000000000..d43ab81c3
--- /dev/null
+++ b/workers.txt
@@ -0,0 +1 @@
+worker-9dd4.onrender.com
\ No newline at end of file