Replace LF with CRLF

This commit is contained in:
freearhey
2025-10-09 03:20:46 +03:00
parent 4861c60b74
commit 60fde4cc8c
30 changed files with 3590 additions and 3588 deletions

View File

@@ -1,85 +1,85 @@
{"type":"raw","filepath":"raw/ad.m3u","count":4}
{"type":"raw","filepath":"raw/ca.m3u","count":2}
{"type":"raw","filepath":"raw/in.m3u","count":1}
{"type":"raw","filepath":"raw/kg.m3u","count":1}
{"type":"raw","filepath":"raw/uk.m3u","count":1}
{"type":"raw","filepath":"raw/unsorted.m3u","count":4}
{"type":"category","filepath":"categories/auto.m3u","count":0}
{"type":"category","filepath":"categories/animation.m3u","count":0}
{"type":"category","filepath":"categories/classic.m3u","count":0}
{"type":"category","filepath":"categories/comedy.m3u","count":0}
{"type":"category","filepath":"categories/culture.m3u","count":0}
{"type":"category","filepath":"categories/documentary.m3u","count":0}
{"type":"category","filepath":"categories/business.m3u","count":0}
{"type":"category","filepath":"categories/cooking.m3u","count":0}
{"type":"category","filepath":"categories/education.m3u","count":0}
{"type":"category","filepath":"categories/family.m3u","count":0}
{"type":"category","filepath":"categories/legislative.m3u","count":0}
{"type":"category","filepath":"categories/news.m3u","count":1}
{"type":"category","filepath":"categories/kids.m3u","count":0}
{"type":"category","filepath":"categories/lifestyle.m3u","count":0}
{"type":"category","filepath":"categories/movies.m3u","count":0}
{"type":"category","filepath":"categories/religious.m3u","count":0}
{"type":"category","filepath":"categories/outdoor.m3u","count":0}
{"type":"category","filepath":"categories/general.m3u","count":3}
{"type":"category","filepath":"categories/relax.m3u","count":0}
{"type":"category","filepath":"categories/music.m3u","count":0}
{"type":"category","filepath":"categories/series.m3u","count":0}
{"type":"category","filepath":"categories/travel.m3u","count":0}
{"type":"category","filepath":"categories/sports.m3u","count":0}
{"type":"category","filepath":"categories/science.m3u","count":0}
{"type":"category","filepath":"categories/weather.m3u","count":1}
{"type":"category","filepath":"categories/shop.m3u","count":0}
{"type":"category","filepath":"categories/xxx.m3u","count":1}
{"type":"category","filepath":"categories/undefined.m3u","count":7}
{"type":"category","filepath":"categories/entertainment.m3u","count":0}
{"type":"language","filepath":"languages/cat.m3u","count":1}
{"type":"language","filepath":"languages/eng.m3u","count":1}
{"type":"language","filepath":"languages/undefined.m3u","count":8}
{"type":"language","filepath":"languages/rus.m3u","count":1}
{"type":"country","filepath":"countries/ad.m3u","count":1}
{"type":"country","filepath":"countries/ru.m3u","count":1}
{"type":"country","filepath":"countries/ca.m3u","count":2}
{"type":"country","filepath":"countries/int.m3u","count":4}
{"type":"country","filepath":"countries/undefined.m3u","count":4}
{"type":"subdivision","filepath":"subdivisions/ad-02.m3u","count":1}
{"type":"city","filepath":"cities/adcan.m3u","count":1}
{"type":"region","filepath":"regions/afr.m3u","count":2}
{"type":"source","filepath":"sources/in.m3u","count":1}
{"type":"subdivision","filepath":"subdivisions/ad-07.m3u","count":1}
{"type":"subdivision","filepath":"subdivisions/ca-on.m3u","count":1}
{"type":"region","filepath":"regions/amer.m3u","count":5}
{"type":"region","filepath":"regions/apac.m3u","count":2}
{"type":"region","filepath":"regions/cas.m3u","count":3}
{"type":"region","filepath":"regions/asean.m3u","count":2}
{"type":"region","filepath":"regions/cis.m3u","count":4}
{"type":"region","filepath":"regions/carib.m3u","count":2}
{"type":"region","filepath":"regions/arab.m3u","count":2}
{"type":"region","filepath":"regions/emea.m3u","count":5}
{"type":"region","filepath":"regions/asia.m3u","count":4}
{"type":"region","filepath":"regions/cenamer.m3u","count":2}
{"type":"region","filepath":"regions/ww.m3u","count":7}
{"type":"region","filepath":"regions/eur.m3u","count":5}
{"type":"region","filepath":"regions/lac.m3u","count":2}
{"type":"region","filepath":"regions/maghreb.m3u","count":2}
{"type":"region","filepath":"regions/latam.m3u","count":2}
{"type":"region","filepath":"regions/hispam.m3u","count":2}
{"type":"region","filepath":"regions/mena.m3u","count":2}
{"type":"region","filepath":"regions/mideast.m3u","count":2}
{"type":"region","filepath":"regions/nam.m3u","count":5}
{"type":"region","filepath":"regions/oce.m3u","count":2}
{"type":"region","filepath":"regions/nord.m3u","count":2}
{"type":"region","filepath":"regions/southam.m3u","count":2}
{"type":"region","filepath":"regions/noram.m3u","count":5}
{"type":"region","filepath":"regions/wafr.m3u","count":2}
{"type":"region","filepath":"regions/sas.m3u","count":2}
{"type":"region","filepath":"regions/ssa.m3u","count":2}
{"type":"source","filepath":"sources/unsorted.m3u","count":4}
{"type":"source","filepath":"sources/ca.m3u","count":2}
{"type":"source","filepath":"sources/ad.m3u","count":3}
{"type":"source","filepath":"sources/uk.m3u","count":1}
{"type":"source","filepath":"sources/kg.m3u","count":1}
{"type":"index","filepath":"index.m3u","count":11}
{"type":"index","filepath":"index.category.m3u","count":12}
{"type":"index","filepath":"index.country.m3u","count":12}
{"type":"index","filepath":"index.language.m3u","count":11}
{"type":"raw","filepath":"raw/ad.m3u","count":4}
{"type":"raw","filepath":"raw/ca.m3u","count":2}
{"type":"raw","filepath":"raw/in.m3u","count":1}
{"type":"raw","filepath":"raw/kg.m3u","count":1}
{"type":"raw","filepath":"raw/uk.m3u","count":1}
{"type":"raw","filepath":"raw/unsorted.m3u","count":4}
{"type":"category","filepath":"categories/auto.m3u","count":0}
{"type":"category","filepath":"categories/animation.m3u","count":0}
{"type":"category","filepath":"categories/classic.m3u","count":0}
{"type":"category","filepath":"categories/comedy.m3u","count":0}
{"type":"category","filepath":"categories/culture.m3u","count":0}
{"type":"category","filepath":"categories/documentary.m3u","count":0}
{"type":"category","filepath":"categories/business.m3u","count":0}
{"type":"category","filepath":"categories/cooking.m3u","count":0}
{"type":"category","filepath":"categories/education.m3u","count":0}
{"type":"category","filepath":"categories/family.m3u","count":0}
{"type":"category","filepath":"categories/legislative.m3u","count":0}
{"type":"category","filepath":"categories/news.m3u","count":1}
{"type":"category","filepath":"categories/kids.m3u","count":0}
{"type":"category","filepath":"categories/lifestyle.m3u","count":0}
{"type":"category","filepath":"categories/movies.m3u","count":0}
{"type":"category","filepath":"categories/religious.m3u","count":0}
{"type":"category","filepath":"categories/outdoor.m3u","count":0}
{"type":"category","filepath":"categories/general.m3u","count":3}
{"type":"category","filepath":"categories/relax.m3u","count":0}
{"type":"category","filepath":"categories/music.m3u","count":0}
{"type":"category","filepath":"categories/series.m3u","count":0}
{"type":"category","filepath":"categories/travel.m3u","count":0}
{"type":"category","filepath":"categories/sports.m3u","count":0}
{"type":"category","filepath":"categories/science.m3u","count":0}
{"type":"category","filepath":"categories/weather.m3u","count":1}
{"type":"category","filepath":"categories/shop.m3u","count":0}
{"type":"category","filepath":"categories/xxx.m3u","count":1}
{"type":"category","filepath":"categories/undefined.m3u","count":7}
{"type":"category","filepath":"categories/entertainment.m3u","count":0}
{"type":"language","filepath":"languages/cat.m3u","count":1}
{"type":"language","filepath":"languages/eng.m3u","count":1}
{"type":"language","filepath":"languages/undefined.m3u","count":8}
{"type":"language","filepath":"languages/rus.m3u","count":1}
{"type":"country","filepath":"countries/ad.m3u","count":1}
{"type":"country","filepath":"countries/ru.m3u","count":1}
{"type":"country","filepath":"countries/ca.m3u","count":2}
{"type":"country","filepath":"countries/int.m3u","count":4}
{"type":"country","filepath":"countries/undefined.m3u","count":4}
{"type":"subdivision","filepath":"subdivisions/ad-02.m3u","count":1}
{"type":"city","filepath":"cities/adcan.m3u","count":1}
{"type":"region","filepath":"regions/afr.m3u","count":2}
{"type":"source","filepath":"sources/in.m3u","count":1}
{"type":"subdivision","filepath":"subdivisions/ad-07.m3u","count":1}
{"type":"subdivision","filepath":"subdivisions/ca-on.m3u","count":1}
{"type":"region","filepath":"regions/amer.m3u","count":5}
{"type":"region","filepath":"regions/apac.m3u","count":2}
{"type":"region","filepath":"regions/cas.m3u","count":3}
{"type":"region","filepath":"regions/asean.m3u","count":2}
{"type":"region","filepath":"regions/cis.m3u","count":4}
{"type":"region","filepath":"regions/carib.m3u","count":2}
{"type":"region","filepath":"regions/arab.m3u","count":2}
{"type":"region","filepath":"regions/emea.m3u","count":5}
{"type":"region","filepath":"regions/asia.m3u","count":4}
{"type":"region","filepath":"regions/cenamer.m3u","count":2}
{"type":"region","filepath":"regions/ww.m3u","count":7}
{"type":"region","filepath":"regions/eur.m3u","count":5}
{"type":"region","filepath":"regions/lac.m3u","count":2}
{"type":"region","filepath":"regions/maghreb.m3u","count":2}
{"type":"region","filepath":"regions/latam.m3u","count":2}
{"type":"region","filepath":"regions/hispam.m3u","count":2}
{"type":"region","filepath":"regions/mena.m3u","count":2}
{"type":"region","filepath":"regions/mideast.m3u","count":2}
{"type":"region","filepath":"regions/nam.m3u","count":5}
{"type":"region","filepath":"regions/oce.m3u","count":2}
{"type":"region","filepath":"regions/nord.m3u","count":2}
{"type":"region","filepath":"regions/southam.m3u","count":2}
{"type":"region","filepath":"regions/noram.m3u","count":5}
{"type":"region","filepath":"regions/wafr.m3u","count":2}
{"type":"region","filepath":"regions/sas.m3u","count":2}
{"type":"region","filepath":"regions/ssa.m3u","count":2}
{"type":"source","filepath":"sources/unsorted.m3u","count":4}
{"type":"source","filepath":"sources/ca.m3u","count":2}
{"type":"source","filepath":"sources/ad.m3u","count":3}
{"type":"source","filepath":"sources/uk.m3u","count":1}
{"type":"source","filepath":"sources/kg.m3u","count":1}
{"type":"index","filepath":"index.m3u","count":11}
{"type":"index","filepath":"index.category.m3u","count":12}
{"type":"index","filepath":"index.country.m3u","count":12}
{"type":"index","filepath":"index.language.m3u","count":11}

View File

@@ -1,177 +1,177 @@
## Playlists
There are several versions of playlists that differ in the way they are grouped. As of January 30th, 2024, we have stopped distributing NSFW channels. For more information, please look at [this issue](https://github.com/iptv-org/iptv/issues/15723).
### Grouped by category
Playlists in which channels are grouped by category.
<details>
<summary>Expand</summary>
<br>
```
https://iptv-org.github.io/iptv/index.category.m3u
```
Same thing, but split up into separate files:
<!-- prettier-ignore -->
<table>
<thead>
<tr><th align="left">Category</th><th align="left">Channels</th><th align="left">Playlist</th></tr>
</thead>
<tbody>
<tr><td>Animation</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/animation.m3u</code></td></tr>
<tr><td>Auto</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/auto.m3u</code></td></tr>
<tr><td>Business</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/business.m3u</code></td></tr>
<tr><td>Classic</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/classic.m3u</code></td></tr>
<tr><td>Comedy</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/comedy.m3u</code></td></tr>
<tr><td>Cooking</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/cooking.m3u</code></td></tr>
<tr><td>Culture</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/culture.m3u</code></td></tr>
<tr><td>Documentary</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/documentary.m3u</code></td></tr>
<tr><td>Education</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/education.m3u</code></td></tr>
<tr><td>Entertainment</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/entertainment.m3u</code></td></tr>
<tr><td>Family</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/family.m3u</code></td></tr>
<tr><td>General</td><td align="right">2</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/general.m3u</code></td></tr>
<tr><td>Kids</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/kids.m3u</code></td></tr>
<tr><td>Legislative</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/legislative.m3u</code></td></tr>
<tr><td>Lifestyle</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/lifestyle.m3u</code></td></tr>
<tr><td>Movies</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/movies.m3u</code></td></tr>
<tr><td>Music</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/music.m3u</code></td></tr>
<tr><td>News</td><td align="right">1</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/news.m3u</code></td></tr>
<tr><td>Outdoor</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/outdoor.m3u</code></td></tr>
<tr><td>Relax</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/relax.m3u</code></td></tr>
<tr><td>Religious</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/religious.m3u</code></td></tr>
<tr><td>Science</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/science.m3u</code></td></tr>
<tr><td>Series</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/series.m3u</code></td></tr>
<tr><td>Shop</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/shop.m3u</code></td></tr>
<tr><td>Sports</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/sports.m3u</code></td></tr>
<tr><td>Travel</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/travel.m3u</code></td></tr>
<tr><td>Weather</td><td align="right">1</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/weather.m3u</code></td></tr>
<tr><td>XXX</td><td align="right">1</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/xxx.m3u</code></td></tr>
<tr><td>Undefined</td><td align="right">3</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/undefined.m3u</code></td></tr>
</tbody>
</table>
</details>
### Grouped by language
Playlists in which channels are grouped by the language in which they are broadcast.
<details>
<summary>Expand</summary>
<br>
```
https://iptv-org.github.io/iptv/index.language.m3u
```
Same thing, but split up into separate files:
<!-- prettier-ignore -->
<table>
<thead>
<tr><th align="left">Language</th><th align="left">Channels</th><th align="left">Playlist</th></tr>
</thead>
<tbody>
<tr><td align="left">Catalan</td><td align="right">1</td><td align="left" nowrap><code>https://iptv-org.github.io/iptv/languages/cat.m3u</code></td></tr>
<tr><td align="left">English</td><td align="right">1</td><td align="left" nowrap><code>https://iptv-org.github.io/iptv/languages/eng.m3u</code></td></tr>
<tr><td align="left">French</td><td align="right">1</td><td align="left" nowrap><code>https://iptv-org.github.io/iptv/languages/fra.m3u</code></td></tr>
<tr><td align="left">Russian</td><td align="right">1</td><td align="left" nowrap><code>https://iptv-org.github.io/iptv/languages/rus.m3u</code></td></tr>
<tr><td align="left">Undefined</td><td align="right">2</td><td align="left" nowrap><code>https://iptv-org.github.io/iptv/languages/undefined.m3u</code></td></tr>
</tbody>
</table>
</details>
### Grouped by broadcast area
Playlists in which channels are grouped by broadcast area.
<details>
<summary>Expand</summary>
#### Countries
```
https://iptv-org.github.io/iptv/index.country.m3u
```
Same thing, but split up into separate files:
<!-- prettier-ignore -->
- 🇦🇩 Andorra <code>https://iptv-org.github.io/iptv/countries/ad.m3u</code>
- Canillo <code>https://iptv-org.github.io/iptv/subdivisions/ad-02.m3u</code>
- Canillo <code>https://iptv-org.github.io/iptv/cities/adcan.m3u</code>
- 🇨🇲 Cameroon <code>https://iptv-org.github.io/iptv/countries/cm.m3u</code>
- 🇨🇦 Canada <code>https://iptv-org.github.io/iptv/countries/ca.m3u</code>
- Ontario <code>https://iptv-org.github.io/iptv/subdivisions/ca-on.m3u</code>
- 🇨🇻 Cape Verde <code>https://iptv-org.github.io/iptv/countries/cv.m3u</code>
- 🇭🇰 Hong Kong <code>https://iptv-org.github.io/iptv/countries/hk.m3u</code>
- Sai Kung <code>https://iptv-org.github.io/iptv/cities/hk9sk.m3u</code>
- 🇨🇬 Republic of the Congo <code>https://iptv-org.github.io/iptv/countries/cg.m3u</code>
- 🇷🇪 Réunion <code>https://iptv-org.github.io/iptv/countries/re.m3u</code>
- 🇷🇴 Romania <code>https://iptv-org.github.io/iptv/countries/ro.m3u</code>
- 🇷🇺 Russia <code>https://iptv-org.github.io/iptv/countries/ru.m3u</code>
- 🇷🇼 Rwanda <code>https://iptv-org.github.io/iptv/countries/rw.m3u</code>
- 🇧🇱 Saint Barthélemy <code>https://iptv-org.github.io/iptv/countries/bl.m3u</code>
- 🇸🇭 Saint Helena <code>https://iptv-org.github.io/iptv/countries/sh.m3u</code>
- 🇰🇳 Saint Kitts and Nevis <code>https://iptv-org.github.io/iptv/countries/kn.m3u</code>
- 🌐 International <code>https://iptv-org.github.io/iptv/countries/int.m3u</code>
- Undefined <code>https://iptv-org.github.io/iptv/countries/undefined.m3u</code>
#### Regions
<!-- prettier-ignore -->
- Africa <code>https://iptv-org.github.io/iptv/regions/afr.m3u</code>
- Americas <code>https://iptv-org.github.io/iptv/regions/amer.m3u</code>
- Arab world <code>https://iptv-org.github.io/iptv/regions/arab.m3u</code>
- Asia <code>https://iptv-org.github.io/iptv/regions/asia.m3u</code>
- Asia-Pacific <code>https://iptv-org.github.io/iptv/regions/apac.m3u</code>
- Association of Southeast Asian Nations <code>https://iptv-org.github.io/iptv/regions/asean.m3u</code>
- Caribbean <code>https://iptv-org.github.io/iptv/regions/carib.m3u</code>
- Central America <code>https://iptv-org.github.io/iptv/regions/cenamer.m3u</code>
- Central Asia <code>https://iptv-org.github.io/iptv/regions/cas.m3u</code>
- Commonwealth of Independent States <code>https://iptv-org.github.io/iptv/regions/cis.m3u</code>
- Europe <code>https://iptv-org.github.io/iptv/regions/eur.m3u</code>
- Europe, the Middle East and Africa <code>https://iptv-org.github.io/iptv/regions/emea.m3u</code>
- Hispanic America <code>https://iptv-org.github.io/iptv/regions/hispam.m3u</code>
- Latin America <code>https://iptv-org.github.io/iptv/regions/latam.m3u</code>
- Latin America and the Caribbean <code>https://iptv-org.github.io/iptv/regions/lac.m3u</code>
- Maghreb <code>https://iptv-org.github.io/iptv/regions/maghreb.m3u</code>
- Middle East <code>https://iptv-org.github.io/iptv/regions/mideast.m3u</code>
- Middle East and North Africa <code>https://iptv-org.github.io/iptv/regions/mena.m3u</code>
- Nordics <code>https://iptv-org.github.io/iptv/regions/nord.m3u</code>
- North America <code>https://iptv-org.github.io/iptv/regions/noram.m3u</code>
- Northern America <code>https://iptv-org.github.io/iptv/regions/nam.m3u</code>
- Oceania <code>https://iptv-org.github.io/iptv/regions/oce.m3u</code>
- South America <code>https://iptv-org.github.io/iptv/regions/southam.m3u</code>
- South Asia <code>https://iptv-org.github.io/iptv/regions/sas.m3u</code>
- Sub-Saharan Africa <code>https://iptv-org.github.io/iptv/regions/ssa.m3u</code>
- West Africa <code>https://iptv-org.github.io/iptv/regions/wafr.m3u</code>
</details>
### Grouped by sources
Playlists in which channels are grouped by broadcast source.
<details>
<summary>Expand</summary>
<br>
To use the playlist, simply replace `<FILENAME>` in the link below with the name of one of the files in the [streams](streams) folder.
```
https://iptv-org.github.io/iptv/sources/<FILENAME>.m3u
```
</details>
Also, any of our internal playlists are available in raw form (without any filtering or sorting) at this link:
```
https://iptv-org.github.io/iptv/raw/<FILENAME>.m3u
```
## Playlists
There are several versions of playlists that differ in the way they are grouped. As of January 30th, 2024, we have stopped distributing NSFW channels. For more information, please look at [this issue](https://github.com/iptv-org/iptv/issues/15723).
### Grouped by category
Playlists in which channels are grouped by category.
<details>
<summary>Expand</summary>
<br>
```
https://iptv-org.github.io/iptv/index.category.m3u
```
Same thing, but split up into separate files:
<!-- prettier-ignore -->
<table>
<thead>
<tr><th align="left">Category</th><th align="left">Channels</th><th align="left">Playlist</th></tr>
</thead>
<tbody>
<tr><td>Animation</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/animation.m3u</code></td></tr>
<tr><td>Auto</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/auto.m3u</code></td></tr>
<tr><td>Business</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/business.m3u</code></td></tr>
<tr><td>Classic</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/classic.m3u</code></td></tr>
<tr><td>Comedy</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/comedy.m3u</code></td></tr>
<tr><td>Cooking</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/cooking.m3u</code></td></tr>
<tr><td>Culture</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/culture.m3u</code></td></tr>
<tr><td>Documentary</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/documentary.m3u</code></td></tr>
<tr><td>Education</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/education.m3u</code></td></tr>
<tr><td>Entertainment</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/entertainment.m3u</code></td></tr>
<tr><td>Family</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/family.m3u</code></td></tr>
<tr><td>General</td><td align="right">2</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/general.m3u</code></td></tr>
<tr><td>Kids</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/kids.m3u</code></td></tr>
<tr><td>Legislative</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/legislative.m3u</code></td></tr>
<tr><td>Lifestyle</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/lifestyle.m3u</code></td></tr>
<tr><td>Movies</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/movies.m3u</code></td></tr>
<tr><td>Music</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/music.m3u</code></td></tr>
<tr><td>News</td><td align="right">1</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/news.m3u</code></td></tr>
<tr><td>Outdoor</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/outdoor.m3u</code></td></tr>
<tr><td>Relax</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/relax.m3u</code></td></tr>
<tr><td>Religious</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/religious.m3u</code></td></tr>
<tr><td>Science</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/science.m3u</code></td></tr>
<tr><td>Series</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/series.m3u</code></td></tr>
<tr><td>Shop</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/shop.m3u</code></td></tr>
<tr><td>Sports</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/sports.m3u</code></td></tr>
<tr><td>Travel</td><td align="right">0</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/travel.m3u</code></td></tr>
<tr><td>Weather</td><td align="right">1</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/weather.m3u</code></td></tr>
<tr><td>XXX</td><td align="right">1</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/xxx.m3u</code></td></tr>
<tr><td>Undefined</td><td align="right">3</td><td nowrap><code>https://iptv-org.github.io/iptv/categories/undefined.m3u</code></td></tr>
</tbody>
</table>
</details>
### Grouped by language
Playlists in which channels are grouped by the language in which they are broadcast.
<details>
<summary>Expand</summary>
<br>
```
https://iptv-org.github.io/iptv/index.language.m3u
```
Same thing, but split up into separate files:
<!-- prettier-ignore -->
<table>
<thead>
<tr><th align="left">Language</th><th align="left">Channels</th><th align="left">Playlist</th></tr>
</thead>
<tbody>
<tr><td align="left">Catalan</td><td align="right">1</td><td align="left" nowrap><code>https://iptv-org.github.io/iptv/languages/cat.m3u</code></td></tr>
<tr><td align="left">English</td><td align="right">1</td><td align="left" nowrap><code>https://iptv-org.github.io/iptv/languages/eng.m3u</code></td></tr>
<tr><td align="left">French</td><td align="right">1</td><td align="left" nowrap><code>https://iptv-org.github.io/iptv/languages/fra.m3u</code></td></tr>
<tr><td align="left">Russian</td><td align="right">1</td><td align="left" nowrap><code>https://iptv-org.github.io/iptv/languages/rus.m3u</code></td></tr>
<tr><td align="left">Undefined</td><td align="right">2</td><td align="left" nowrap><code>https://iptv-org.github.io/iptv/languages/undefined.m3u</code></td></tr>
</tbody>
</table>
</details>
### Grouped by broadcast area
Playlists in which channels are grouped by broadcast area.
<details>
<summary>Expand</summary>
#### Countries
```
https://iptv-org.github.io/iptv/index.country.m3u
```
Same thing, but split up into separate files:
<!-- prettier-ignore -->
- 🇦🇩 Andorra <code>https://iptv-org.github.io/iptv/countries/ad.m3u</code>
- Canillo <code>https://iptv-org.github.io/iptv/subdivisions/ad-02.m3u</code>
- Canillo <code>https://iptv-org.github.io/iptv/cities/adcan.m3u</code>
- 🇨🇲 Cameroon <code>https://iptv-org.github.io/iptv/countries/cm.m3u</code>
- 🇨🇦 Canada <code>https://iptv-org.github.io/iptv/countries/ca.m3u</code>
- Ontario <code>https://iptv-org.github.io/iptv/subdivisions/ca-on.m3u</code>
- 🇨🇻 Cape Verde <code>https://iptv-org.github.io/iptv/countries/cv.m3u</code>
- 🇭🇰 Hong Kong <code>https://iptv-org.github.io/iptv/countries/hk.m3u</code>
- Sai Kung <code>https://iptv-org.github.io/iptv/cities/hk9sk.m3u</code>
- 🇨🇬 Republic of the Congo <code>https://iptv-org.github.io/iptv/countries/cg.m3u</code>
- 🇷🇪 Réunion <code>https://iptv-org.github.io/iptv/countries/re.m3u</code>
- 🇷🇴 Romania <code>https://iptv-org.github.io/iptv/countries/ro.m3u</code>
- 🇷🇺 Russia <code>https://iptv-org.github.io/iptv/countries/ru.m3u</code>
- 🇷🇼 Rwanda <code>https://iptv-org.github.io/iptv/countries/rw.m3u</code>
- 🇧🇱 Saint Barthélemy <code>https://iptv-org.github.io/iptv/countries/bl.m3u</code>
- 🇸🇭 Saint Helena <code>https://iptv-org.github.io/iptv/countries/sh.m3u</code>
- 🇰🇳 Saint Kitts and Nevis <code>https://iptv-org.github.io/iptv/countries/kn.m3u</code>
- 🌐 International <code>https://iptv-org.github.io/iptv/countries/int.m3u</code>
- Undefined <code>https://iptv-org.github.io/iptv/countries/undefined.m3u</code>
#### Regions
<!-- prettier-ignore -->
- Africa <code>https://iptv-org.github.io/iptv/regions/afr.m3u</code>
- Americas <code>https://iptv-org.github.io/iptv/regions/amer.m3u</code>
- Arab world <code>https://iptv-org.github.io/iptv/regions/arab.m3u</code>
- Asia <code>https://iptv-org.github.io/iptv/regions/asia.m3u</code>
- Asia-Pacific <code>https://iptv-org.github.io/iptv/regions/apac.m3u</code>
- Association of Southeast Asian Nations <code>https://iptv-org.github.io/iptv/regions/asean.m3u</code>
- Caribbean <code>https://iptv-org.github.io/iptv/regions/carib.m3u</code>
- Central America <code>https://iptv-org.github.io/iptv/regions/cenamer.m3u</code>
- Central Asia <code>https://iptv-org.github.io/iptv/regions/cas.m3u</code>
- Commonwealth of Independent States <code>https://iptv-org.github.io/iptv/regions/cis.m3u</code>
- Europe <code>https://iptv-org.github.io/iptv/regions/eur.m3u</code>
- Europe, the Middle East and Africa <code>https://iptv-org.github.io/iptv/regions/emea.m3u</code>
- Hispanic America <code>https://iptv-org.github.io/iptv/regions/hispam.m3u</code>
- Latin America <code>https://iptv-org.github.io/iptv/regions/latam.m3u</code>
- Latin America and the Caribbean <code>https://iptv-org.github.io/iptv/regions/lac.m3u</code>
- Maghreb <code>https://iptv-org.github.io/iptv/regions/maghreb.m3u</code>
- Middle East <code>https://iptv-org.github.io/iptv/regions/mideast.m3u</code>
- Middle East and North Africa <code>https://iptv-org.github.io/iptv/regions/mena.m3u</code>
- Nordics <code>https://iptv-org.github.io/iptv/regions/nord.m3u</code>
- North America <code>https://iptv-org.github.io/iptv/regions/noram.m3u</code>
- Northern America <code>https://iptv-org.github.io/iptv/regions/nam.m3u</code>
- Oceania <code>https://iptv-org.github.io/iptv/regions/oce.m3u</code>
- South America <code>https://iptv-org.github.io/iptv/regions/southam.m3u</code>
- South Asia <code>https://iptv-org.github.io/iptv/regions/sas.m3u</code>
- Sub-Saharan Africa <code>https://iptv-org.github.io/iptv/regions/ssa.m3u</code>
- West Africa <code>https://iptv-org.github.io/iptv/regions/wafr.m3u</code>
</details>
### Grouped by sources
Playlists in which channels are grouped by broadcast source.
<details>
<summary>Expand</summary>
<br>
To use the playlist, simply replace `<FILENAME>` in the link below with the name of one of the files in the [streams](streams) folder.
```
https://iptv-org.github.io/iptv/sources/<FILENAME>.m3u
```
</details>
Also, any of our internal playlists are available in raw form (without any filtering or sorting) at this link:
```
https://iptv-org.github.io/iptv/raw/<FILENAME>.m3u
```

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,14 @@
module.exports = {
'https://query-streamlink.herokuapp.com/iptv-query?streaming-ip=https://www.twitch.tv/absliveantigua3':
{
url: 'https://query-streamlink.herokuapp.com/iptv-query?streaming-ip=https://www.twitch.tv/absliveantigua3',
http: { referrer: '', 'user-agent': '' },
status: { ok: false, code: 'HTTP_NOT_FOUND', message: 'HTTP 404 Not Found' }
},
'https://tego-cdn2a.sibercdn.com/Live_TV-ABSTV-10/tracks-v3a1/rewind-7200.m3u8?token=e5f61e7be8363eb781b4bdfe591bf917dd529c1a-SjY3NzRTbDZQNnFQVkZaNkZja2RxV3JKc1VBa05zQkdMNStJakRGV0VTTzNrOEVGVUlIQmxta1NLV0o3bzdVdQ-1736094545-1736008145':
{
url: 'https://tego-cdn2a.sibercdn.com/Live_TV-ABSTV-10/tracks-v3a1/rewind-7200.m3u8?token=e5f61e7be8363eb781b4bdfe591bf917dd529c1a-SjY3NzRTbDZQNnFQVkZaNkZja2RxV3JKc1VBa05zQkdMNStJakRGV0VTTzNrOEVGVUlIQmxta1NLV0o3bzdVdQ-1736094545-1736008145',
http: { referrer: '', 'user-agent': '' },
status: { ok: false, code: 'HTTP_FORBIDDEN', message: 'HTTP 403 Forbidden' }
}
}
module.exports = {
'https://query-streamlink.herokuapp.com/iptv-query?streaming-ip=https://www.twitch.tv/absliveantigua3':
{
url: 'https://query-streamlink.herokuapp.com/iptv-query?streaming-ip=https://www.twitch.tv/absliveantigua3',
http: { referrer: '', 'user-agent': '' },
status: { ok: false, code: 'HTTP_NOT_FOUND', message: 'HTTP 404 Not Found' }
},
'https://tego-cdn2a.sibercdn.com/Live_TV-ABSTV-10/tracks-v3a1/rewind-7200.m3u8?token=e5f61e7be8363eb781b4bdfe591bf917dd529c1a-SjY3NzRTbDZQNnFQVkZaNkZja2RxV3JKc1VBa05zQkdMNStJakRGV0VTTzNrOEVGVUlIQmxta1NLV0o3bzdVdQ-1736094545-1736008145':
{
url: 'https://tego-cdn2a.sibercdn.com/Live_TV-ABSTV-10/tracks-v3a1/rewind-7200.m3u8?token=e5f61e7be8363eb781b4bdfe591bf917dd529c1a-SjY3NzRTbDZQNnFQVkZaNkZja2RxV3JKc1VBa05zQkdMNStJakRGV0VTTzNrOEVGVUlIQmxta1NLV0o3bzdVdQ-1736094545-1736008145',
http: { referrer: '', 'user-agent': '' },
status: { ok: false, code: 'HTTP_FORBIDDEN', message: 'HTTP 403 Forbidden' }
}
}

View File

@@ -1,26 +1,26 @@
import { pathToFileURL } from 'node:url'
import { execSync } from 'child_process'
import fs from 'fs-extra'
const ENV_VAR =
'cross-env DATA_DIR=tests/__data__/input/data STREAMS_DIR=tests/__data__/input/api_generate API_DIR=tests/__data__/output/.api'
beforeEach(() => {
fs.emptyDirSync('tests/__data__/output')
})
describe('api:generate', () => {
it('can create streams.json', () => {
const cmd = `${ENV_VAR} npm run api:generate`
const stdout = execSync(cmd, { encoding: 'utf8' })
if (process.env.DEBUG === 'true') console.log(cmd, stdout)
expect(content('tests/__data__/output/.api/streams.json')).toMatchObject(
content('tests/__data__/expected/api_generate/.api/streams.json')
)
})
})
function content(filepath: string) {
return JSON.parse(fs.readFileSync(pathToFileURL(filepath), { encoding: 'utf8' }))
}
import { pathToFileURL } from 'node:url'
import { execSync } from 'child_process'
import fs from 'fs-extra'
const ENV_VAR =
'cross-env DATA_DIR=tests/__data__/input/data STREAMS_DIR=tests/__data__/input/api_generate API_DIR=tests/__data__/output/.api'
beforeEach(() => {
fs.emptyDirSync('tests/__data__/output')
})
describe('api:generate', () => {
it('can create streams.json', () => {
const cmd = `${ENV_VAR} npm run api:generate`
const stdout = execSync(cmd, { encoding: 'utf8' })
if (process.env.DEBUG === 'true') console.log(cmd, stdout)
expect(content('tests/__data__/output/.api/streams.json')).toMatchObject(
content('tests/__data__/expected/api_generate/.api/streams.json')
)
})
})
function content(filepath: string) {
return JSON.parse(fs.readFileSync(pathToFileURL(filepath), { encoding: 'utf8' }))
}

View File

@@ -1,38 +1,38 @@
import { execSync } from 'child_process'
import fs from 'fs-extra'
type ExecError = {
status: number
stdout: string
}
const ENV_VAR = 'cross-env DATA_DIR=tests/__data__/input/data'
beforeEach(() => {
fs.emptyDirSync('tests/__data__/output')
fs.copySync(
'tests/__data__/input/playlist_edit/playlist.m3u',
'tests/__data__/output/playlist.m3u'
)
})
describe('playlist:edit', () => {
it('shows list of options for a streams', () => {
const cmd = `${ENV_VAR} npm run playlist:edit --- tests/__data__/output/playlist.m3u`
try {
const stdout = execSync(cmd, { encoding: 'utf8' })
if (process.env.DEBUG === 'true') console.log(cmd, stdout)
checkStdout(stdout)
} catch (error) {
// NOTE: for Windows only
if (process.env.DEBUG === 'true') console.log(cmd, error)
checkStdout((error as ExecError).stdout)
}
})
})
function checkStdout(stdout: string) {
expect(stdout).toContain('TF1.fr (TF1, Télévision française 1)')
expect(stdout).toContain('Type...')
expect(stdout).toContain('Skip')
}
import { execSync } from 'child_process'
import fs from 'fs-extra'
type ExecError = {
status: number
stdout: string
}
const ENV_VAR = 'cross-env DATA_DIR=tests/__data__/input/data'
beforeEach(() => {
fs.emptyDirSync('tests/__data__/output')
fs.copySync(
'tests/__data__/input/playlist_edit/playlist.m3u',
'tests/__data__/output/playlist.m3u'
)
})
describe('playlist:edit', () => {
it('shows list of options for a streams', () => {
const cmd = `${ENV_VAR} npm run playlist:edit --- tests/__data__/output/playlist.m3u`
try {
const stdout = execSync(cmd, { encoding: 'utf8' })
if (process.env.DEBUG === 'true') console.log(cmd, stdout)
checkStdout(stdout)
} catch (error) {
// NOTE: for Windows only
if (process.env.DEBUG === 'true') console.log(cmd, error)
checkStdout((error as ExecError).stdout)
}
})
})
function checkStdout(stdout: string) {
expect(stdout).toContain('TF1.fr (TF1, Télévision française 1)')
expect(stdout).toContain('Type...')
expect(stdout).toContain('Skip')
}

View File

@@ -1,36 +1,37 @@
import { pathToFileURL } from 'node:url'
import { execSync } from 'child_process'
import * as fs from 'fs-extra'
import { glob } from 'glob'
const ENV_VAR = 'cross-env STREAMS_DIR=tests/__data__/output/streams DATA_DIR=tests/__data__/input/data'
beforeEach(() => {
fs.emptyDirSync('tests/__data__/output')
fs.copySync('tests/__data__/input/playlist_format', 'tests/__data__/output/streams')
})
describe('playlist:format', () => {
it('can format playlists', () => {
const cmd = `${ENV_VAR} npm run playlist:format`
const stdout = execSync(cmd, { encoding: 'utf8' })
if (process.env.DEBUG === 'true') console.log(cmd, stdout)
const files = glob.sync('tests/__data__/expected/playlist_format/*.m3u').map(filepath => {
const fileUrl = pathToFileURL(filepath).toString()
const pathToRemove = pathToFileURL('tests/__data__/expected/playlist_format/').toString()
return fileUrl.replace(pathToRemove, '')
})
files.forEach(filepath => {
expect(content(`tests/__data__/output/streams/${filepath}`)).toBe(
content(`tests/__data__/expected/playlist_format/${filepath}`)
)
})
})
})
function content(filepath: string) {
return fs.readFileSync(pathToFileURL(filepath), { encoding: 'utf8' })
}
import { pathToFileURL } from 'node:url'
import { execSync } from 'child_process'
import * as fs from 'fs-extra'
import { glob } from 'glob'
const ENV_VAR =
'cross-env STREAMS_DIR=tests/__data__/output/streams DATA_DIR=tests/__data__/input/data'
beforeEach(() => {
fs.emptyDirSync('tests/__data__/output')
fs.copySync('tests/__data__/input/playlist_format', 'tests/__data__/output/streams')
})
describe('playlist:format', () => {
it('can format playlists', () => {
const cmd = `${ENV_VAR} npm run playlist:format`
const stdout = execSync(cmd, { encoding: 'utf8' })
if (process.env.DEBUG === 'true') console.log(cmd, stdout)
const files = glob.sync('tests/__data__/expected/playlist_format/*.m3u').map(filepath => {
const fileUrl = pathToFileURL(filepath).toString()
const pathToRemove = pathToFileURL('tests/__data__/expected/playlist_format/').toString()
return fileUrl.replace(pathToRemove, '')
})
files.forEach(filepath => {
expect(content(`tests/__data__/output/streams/${filepath}`)).toBe(
content(`tests/__data__/expected/playlist_format/${filepath}`)
)
})
})
})
function content(filepath: string) {
return fs.readFileSync(pathToFileURL(filepath), { encoding: 'utf8' })
}

View File

@@ -1,43 +1,43 @@
import { pathToFileURL } from 'node:url'
import { execSync } from 'child_process'
import { EOL } from 'node:os'
import * as fs from 'fs-extra'
import * as glob from 'glob'
const ENV_VAR =
'cross-env STREAMS_DIR=tests/__data__/input/playlist_generate DATA_DIR=tests/__data__/input/data PUBLIC_DIR=tests/__data__/output/.gh-pages LOGS_DIR=tests/__data__/output/logs'
beforeEach(() => {
fs.emptyDirSync('tests/__data__/output')
})
describe('playlist:generate', () => {
it('can generate playlists and logs', () => {
const cmd = `${ENV_VAR} npm run playlist:generate`
const stdout = execSync(cmd, { encoding: 'utf8' })
if (process.env.DEBUG === 'true') console.log(cmd, stdout)
const playlists = glob
.sync('tests/__data__/expected/playlist_generate/.gh-pages/**/*.m3u')
.map(filepath => {
const fileUrl = pathToFileURL(filepath).toString()
const pathToRemove = pathToFileURL('tests/__data__/expected/playlist_generate/').toString()
return fileUrl.replace(pathToRemove, '')
})
playlists.forEach((filepath: string) => {
expect(content(`tests/__data__/output/${filepath}`), filepath).toBe(
content(`tests/__data__/expected/playlist_generate/${filepath}`)
)
})
expect(content('tests/__data__/output/logs/generators.log').split(EOL).sort()).toStrictEqual(
content('tests/__data__/expected/playlist_generate/logs/generators.log').split(EOL).sort()
)
})
})
function content(filepath: string) {
return fs.readFileSync(pathToFileURL(filepath), { encoding: 'utf8' })
}
import { pathToFileURL } from 'node:url'
import { execSync } from 'child_process'
import { EOL } from 'node:os'
import * as fs from 'fs-extra'
import * as glob from 'glob'
const ENV_VAR =
'cross-env STREAMS_DIR=tests/__data__/input/playlist_generate DATA_DIR=tests/__data__/input/data PUBLIC_DIR=tests/__data__/output/.gh-pages LOGS_DIR=tests/__data__/output/logs'
beforeEach(() => {
fs.emptyDirSync('tests/__data__/output')
})
describe('playlist:generate', () => {
it('can generate playlists and logs', () => {
const cmd = `${ENV_VAR} npm run playlist:generate`
const stdout = execSync(cmd, { encoding: 'utf8' })
if (process.env.DEBUG === 'true') console.log(cmd, stdout)
const playlists = glob
.sync('tests/__data__/expected/playlist_generate/.gh-pages/**/*.m3u')
.map(filepath => {
const fileUrl = pathToFileURL(filepath).toString()
const pathToRemove = pathToFileURL('tests/__data__/expected/playlist_generate/').toString()
return fileUrl.replace(pathToRemove, '')
})
playlists.forEach((filepath: string) => {
expect(content(`tests/__data__/output/${filepath}`), filepath).toBe(
content(`tests/__data__/expected/playlist_generate/${filepath}`)
)
})
expect(content('tests/__data__/output/logs/generators.log').split(EOL).sort()).toStrictEqual(
content('tests/__data__/expected/playlist_generate/logs/generators.log').split(EOL).sort()
)
})
})
function content(filepath: string) {
return fs.readFileSync(pathToFileURL(filepath), { encoding: 'utf8' })
}

View File

@@ -1,21 +1,21 @@
import { execSync } from 'child_process'
type ExecError = {
status: number
stdout: string
}
const ENV_VAR = 'cross-env ROOT_DIR=tests/__data__/input DATA_DIR=tests/__data__/input/data'
describe('playlist:test', () => {
it('shows an error if the playlist contains a broken link', () => {
const cmd = `${ENV_VAR} npm run playlist:test playlist_test/ag.m3u`
try {
execSync(cmd, { encoding: 'utf8' })
} catch (error) {
if (process.env.DEBUG === 'true') console.log(cmd, error)
expect((error as ExecError).stdout).toContain('playlist_test/ag.m3u')
expect((error as ExecError).stdout).toContain('2 problems (1 errors, 1 warnings)')
}
})
})
import { execSync } from 'child_process'
type ExecError = {
status: number
stdout: string
}
const ENV_VAR = 'cross-env ROOT_DIR=tests/__data__/input DATA_DIR=tests/__data__/input/data'
describe('playlist:test', () => {
it('shows an error if the playlist contains a broken link', () => {
const cmd = `${ENV_VAR} npm run playlist:test playlist_test/ag.m3u`
try {
execSync(cmd, { encoding: 'utf8' })
} catch (error) {
if (process.env.DEBUG === 'true') console.log(cmd, error)
expect((error as ExecError).stdout).toContain('playlist_test/ag.m3u')
expect((error as ExecError).stdout).toContain('2 problems (1 errors, 1 warnings)')
}
})
})

View File

@@ -1,44 +1,45 @@
import { execSync } from 'child_process'
type ExecError = {
status: number
stdout: string
}
const ENV_VAR = 'cross-env DATA_DIR=tests/__data__/input/data ROOT_DIR=tests/__data__/input/playlist_validate'
describe('playlist:validate', () => {
it('show an error if channel id in the blocklist', () => {
const cmd = `${ENV_VAR} npm run playlist:validate -- us_blocked.m3u`
try {
execSync(cmd, { encoding: 'utf8' })
} catch (error) {
if (process.env.DEBUG === 'true') console.log(cmd, error)
expect((error as ExecError).stdout).toContain('us_blocked.m3u')
expect((error as ExecError).stdout).toContain(
'2 error "FoxSports2.us" is on the blocklist due to claims of copyright holders (https://github.com/iptv-org/iptv/issues/0002)'
)
expect((error as ExecError).stdout).toContain(
'4 error "TVN.pl" is on the blocklist due to NSFW content (https://github.com/iptv-org/iptv/issues/0003)'
)
expect((error as ExecError).stdout).toContain('2 problems (2 errors, 0 warnings)')
}
})
it('show a warning if channel has wrong id', () => {
const cmd = `${ENV_VAR} npm run playlist:validate -- wrong_id.m3u`
try {
execSync(cmd, { encoding: 'utf8' })
} catch (error) {
if (process.env.DEBUG === 'true') console.log(cmd, error)
expect((error as ExecError).stdout).toContain(
'wrong_id.m3u\n 2 warning "qib22lAq1L.us" is not in the database\n\n1 problems (0 errors, 1 warnings)\n'
)
}
})
it('skip the file if it does not exist', () => {
const cmd = `${ENV_VAR} npm run playlist:validate -- missing.m3u`
execSync(cmd, { encoding: 'utf8' })
})
})
import { execSync } from 'child_process'
type ExecError = {
status: number
stdout: string
}
const ENV_VAR =
'cross-env DATA_DIR=tests/__data__/input/data ROOT_DIR=tests/__data__/input/playlist_validate'
describe('playlist:validate', () => {
it('show an error if channel id in the blocklist', () => {
const cmd = `${ENV_VAR} npm run playlist:validate -- us_blocked.m3u`
try {
execSync(cmd, { encoding: 'utf8' })
} catch (error) {
if (process.env.DEBUG === 'true') console.log(cmd, error)
expect((error as ExecError).stdout).toContain('us_blocked.m3u')
expect((error as ExecError).stdout).toContain(
'2 error "FoxSports2.us" is on the blocklist due to claims of copyright holders (https://github.com/iptv-org/iptv/issues/0002)'
)
expect((error as ExecError).stdout).toContain(
'4 error "TVN.pl" is on the blocklist due to NSFW content (https://github.com/iptv-org/iptv/issues/0003)'
)
expect((error as ExecError).stdout).toContain('2 problems (2 errors, 0 warnings)')
}
})
it('show a warning if channel has wrong id', () => {
const cmd = `${ENV_VAR} npm run playlist:validate -- wrong_id.m3u`
try {
execSync(cmd, { encoding: 'utf8' })
} catch (error) {
if (process.env.DEBUG === 'true') console.log(cmd, error)
expect((error as ExecError).stdout).toContain(
'wrong_id.m3u\n 2 warning "qib22lAq1L.us" is not in the database\n\n1 problems (0 errors, 1 warnings)\n'
)
}
})
it('skip the file if it does not exist', () => {
const cmd = `${ENV_VAR} npm run playlist:validate -- missing.m3u`
execSync(cmd, { encoding: 'utf8' })
})
})

View File

@@ -1,26 +1,26 @@
import { pathToFileURL } from 'node:url'
import { execSync } from 'child_process'
import fs from 'fs-extra'
const ENV_VAR =
'cross-env DATA_DIR=tests/__data__/input/data LOGS_DIR=tests/__data__/input/readme_update ROOT_DIR=tests/__data__/output'
beforeEach(() => {
fs.emptyDirSync('tests/__data__/output')
})
describe('readme:update', () => {
it('can update readme.md', () => {
const cmd = `${ENV_VAR} npm run readme:update`
const stdout = execSync(cmd, { encoding: 'utf8' })
if (process.env.DEBUG === 'true') console.log(cmd, stdout)
expect(content('tests/__data__/output/PLAYLISTS.md')).toEqual(
content('tests/__data__/expected/readme_update/playlists.md')
)
})
})
function content(filepath: string) {
return JSON.stringify(fs.readFileSync(pathToFileURL(filepath), { encoding: 'utf8' }))
}
import { pathToFileURL } from 'node:url'
import { execSync } from 'child_process'
import fs from 'fs-extra'
const ENV_VAR =
'cross-env DATA_DIR=tests/__data__/input/data LOGS_DIR=tests/__data__/input/readme_update ROOT_DIR=tests/__data__/output'
beforeEach(() => {
fs.emptyDirSync('tests/__data__/output')
})
describe('readme:update', () => {
it('can update readme.md', () => {
const cmd = `${ENV_VAR} npm run readme:update`
const stdout = execSync(cmd, { encoding: 'utf8' })
if (process.env.DEBUG === 'true') console.log(cmd, stdout)
expect(content('tests/__data__/output/PLAYLISTS.md')).toEqual(
content('tests/__data__/expected/readme_update/playlists.md')
)
})
})
function content(filepath: string) {
return JSON.stringify(fs.readFileSync(pathToFileURL(filepath), { encoding: 'utf8' }))
}