Compare commits

...

17 Commits

Author SHA1 Message Date
Baleshevich Srdjan 11e910b6ea
Merge 4b35106ba2 into bce5e4ff6b 2026-04-08 20:11:08 +02:00
PlaylistBot 4b35106ba2 Update Playlist (GitHub Actions) 2026-04-08 18:11:03 +00:00
Baleshevich Srdjan a69802bcc6
Merge branch 'master' into master 2026-04-08 20:10:49 +02:00
PlaylistBot bce5e4ff6b Update Playlist (GitHub Actions) 2026-03-08 20:06:27 +00:00
Aasav Chauhan e619e82306
Add four India IPTV Hindi news channels to India list (#877)
Added Aaj Tak, India TV, TV9 Bharatvarsh, and Republic Bharat with YouTube live links, logos, and official sites to the India channels table.
2026-03-08 21:06:19 +01:00
PlaylistBot 946dc0fc85 Update Playlist (GitHub Actions) 2026-03-08 20:04:59 +00:00
Un Féfé Sauvage dd3138c41a
Removed RT-France from french channel list (#868) 2026-03-08 21:04:51 +01:00
cantonbrayton-commits 8e1efe4f27
Update france.md (#856) 2026-03-08 20:53:05 +01:00
PlaylistBot 148bc990ba Update Playlist (GitHub Actions) 2026-03-08 19:41:17 +00:00
KAMI 1b0fff3d4d
Fix no-dash linting errors in Russian channel names (#991)
Replace dashes with colons in Smotrim channel names.

Co-authored-by: Kálmán „KAMI” Szalai <kami911gmail.com>
2026-03-08 20:41:10 +01:00
KAMI 43b8dced11
Add tvg-country attribute to M3U8 playlist entries (#990)
Add ISO 3166-1 alpha-2 country codes via tvg-country attribute
to all #EXTINF lines, enabling IPTV players to filter and display
channels by country.

Co-authored-by: Kálmán „KAMI” Szalai <kami911gmail.com>
2026-03-08 09:29:23 +01:00
KAMI 8a67a85d1a
Improve make_playlist.py code quality and fix bugs (#989)
* Improve make_playlist.py code quality and fix bugs

- Fix group name bug: replace underscores with spaces before title()
  so filenames like north_korea.md produce "North Korea" not "North_Korea"
- Fix resource leaks: use context managers for all file handles including
  EPG list and per-country playlist files
- Remove os.chdir() global side effect: use absolute paths derived from
  the script location instead
- Avoid calling to_m3u_line() twice per channel by caching the result
- Fix redundant trailing colon in filename[:-3:] slice
- Consistent use of write() for headers instead of mixing print/write
- Strip blank lines from EPG URL list when reading

* Skip commit and push when playlist has no changes

Prevents the workflow from failing with exit code 1 when the generated
playlist is identical to the previous run and there is nothing to commit.

* Use current branch instead of hardcoded master for push

Replace hardcoded origin/master reference with @{u} (upstream of current
branch) for the diff check, and use HEAD for the push target so the
workflow works correctly on any branch.

---------

Co-authored-by: Kálmán „KAMI” Szalai <kami911gmail.com>
2026-03-08 07:40:47 +01:00
PlaylistBot 3608712580 Update Playlist (GitHub Actions) 2026-01-22 12:23:01 +00:00
Baleshevich Srdjan 799c03ef76 Updated the Bosnia & Herzegovina, Serbia & Montenegro playlist and list
Updated the link of one TV stations in Bosnia and Herzegovina, and remarked a non-HD channel on that list.
Updated all the links of TV stations from Montenegro, marked some of the links with GeoIP blocking (help needed from good, hones & heroic person from Montenegro on this one).
Added TV 3 channels to Serbia's list, and updated 2 links on that list as well.
2026-01-22 13:22:40 +01:00
Baleshevich Srdjan f6df52a817
Merge branch 'Free-TV:master' into master 2026-01-22 12:57:39 +01:00
PlaylistBot 88612960c2 Update Playlist (GitHub Actions) 2025-12-12 08:25:41 +00:00
Baleshevich Srdjan 38968ba931 Updated the Bosnia and Herzegovina playlist and list
Replaced non-working links of two TV stations for links that work. The source of those links is found on the web sites of those TV stations respectively.
2025-12-12 09:22:22 +01:00
92 changed files with 3452 additions and 3329 deletions

View File

@ -17,5 +17,5 @@ jobs:
git config user.email "playlistbot@users.noreply.github.com" || true
python3 ./make_playlist.py
git add .
git commit --quiet -m "Update Playlist (GitHub Actions)"
git push -f origin master
git diff --staged --quiet || git commit --quiet -m "Update Playlist (GitHub Actions)"
git diff --quiet HEAD @{u} || git push -f origin HEAD

View File

@ -4,11 +4,11 @@
|:---:|:--------------:|:-----:|:----:|:------:|
| 1 | BHT 1 | [>](https://bhrtstream.bhtelecom.ba/bhrtportal_hd.m3u8) | <img height="20" src="https://upload.wikimedia.org/wikipedia/commons/9/93/Logo_of_BHT_1_%282003-2012%29.png" /> | BHT1.ba |
| 2 | Federalna televizija (FTV) Ⓢ | [>](http://94.250.2.6:7374/play/a02s/index.m3u8) | <img height="20" src="https://i.imgur.com/Jpvs4u3.png" /> | FederalnaTV.ba |
| 3 | Televizija Republike Srpske (RTRS) | [>](https://parh.rtrs.tv/tv/live/playlist.m3u8) | <img height="20" src="https://upload.wikimedia.org/wikipedia/commons/thumb/7/7d/RTRS_Logo.svg/640px-RTRS_Logo.svg.png" /> | RTRSTV.ba |
| 3 | Televizija Republike Srpske (RTRS) | [>](https://parh.rtrs.tv/tv/live/playlist.m3u8) | <img height="20" src="https://upload.wikimedia.org/wikipedia/commons/thumb/7/7d/RTRS_Logo.svg/640px-RTRS_Logo.svg.png" /> | RTRSTV.ba |
| 3 | RTRS PLUS Ⓢ | [>](https://pluslive.rtrs.tv/plus/plus/playlist.m3u8) | <img height="20" src="https://i.imgur.com/k06WvYl.png"/> | RTRSplus.ba |
| 4 | N1 Bosna i Hercegovina | [>](https://best-str.umn.cdn.united.cloud/stream?channel=n1bos&p=n1Sh4redSecre7iNf0&sp=n1info&stream=sp1400&u=n1info) | <img height="20" src="https://i.imgur.com/72oMSWz.png"/> | N1BosniaHerzegovina.ba |
| 5 | RTV HB Ⓢ | [>](https://prd-hometv-live-open.spectar.tv/ERO_1_083/playlist.m3u8) | <img height="20" src="https://upload.wikimedia.org/wikipedia/en/6/60/Logo_of_TV_Herceg-Bosne.png"/> | RTVHB.ba |
| 6 | RTV BN | [>](https://rtvbn.tv:8080/live/index.m3u8) | <img height="20" src="https://i.imgur.com/DUBvfWb.png"/> | BNTV.ba |
| 6 | RTV BN | [>](https://stream.rtvbn.tv:8080/live/index.m3u8) | <img height="20" src="https://i.imgur.com/DUBvfWb.png"/> | BNTV.ba |
| 7 | RTV Glas Drine | [>](http://glasdrine.cutuk.net:8081/433ssdsw/GlasDrineSD/playlist.m3u8) | <img height="20" src="https://i.imgur.com/9NgxOdb.png"/> | RTVGlasDrine.ba |
| 8 | Sevdah Ⓢ | [>](https://restreamer2.tnt.ba/hls/stream.m3u8) | <img height="20" src="https://i.imgur.com/V6W3yEp.png"/> | SevdahTV.ba |
| 9 | TNT Kids | [>](https://restreamer1.tnt.ba/hls/tntkids.m3u8) | <img height="20" src="https://i.imgur.com/irTDbpn.png"/> | TNTKidsTV.ba |

View File

@ -35,7 +35,6 @@
| 29 | TV5 Monde Info | [>](https://ott.tv5monde.com/Content/HLS/Live/channel(info)/index.m3u8) | <img height="20" src="https://i.imgur.com/NcysrWH.png"/> | TV5MondeInfo.fr |
| 30 | TV5 Monde FBS | [>](https://ott.tv5monde.com/Content/HLS/Live/channel(fbs)/index.m3u8) | <img height="20" src="https://i.imgur.com/uPmwTo9.png"/> | TV5MondeFranceBelgiumSwitzerland.fr |
| 31 | TV5 Monde Europe | [>](https://ott.tv5monde.com/Content/HLS/Live/channel(europe)/index.m3u8) | <img height="20" src="https://i.imgur.com/uPmwTo9.png"/> | TV5MondeEurope.fr |
| 0 | RT France Ⓖ | [>](https://rt-fra.rttv.com/dvr/rtfrance/playlist.m3u8) | <img height="20" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b8/RT-France-logo.svg/512px-RT-France-logo.svg.png"/> | RTFrance.fr |
<h2>Unreliable (other)</h2>
@ -46,7 +45,7 @@
| 15 | BFM TV | [x](https://bfmtvalive1-a.akamaihd.net/r8ef15893bf3d4c2db0105218bdfe87f4/eu-central-1/876450610001/playlist.m3u8) | <img height="20" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Logo_BFM_TV_%282019%29.png/53px-Logo_BFM_TV_%282019%29.png"/> | BFMTV.fr |
| 18 | Gulli | [x](https://d13anarbtxy8c5.cloudfront.net/6play/short/clr/gulli/sdindex.m3u8) | <img height="20" src="https://upload.wikimedia.org/wikipedia/fr/thumb/4/43/18._Gulli.png/57px-18._Gulli.png"/> | Gulli.fr |
| 22 | 6ter | [x]() | <img height="20" src="https://upload.wikimedia.org/wikipedia/fr/thumb/a/a9/6ter_2012.png/73px-6ter_2012.png"/> | 6ter.fr |
| 26 | LCI | [x](https://sv0.data-stream.top/hls/lci.m3u8) | <img height="20" src="https://upload.wikimedia.org/wikipedia/fr/thumb/3/38/LCI_-_Logo_%28Ao%C3%BBt_2017%29.svg/62px-LCI_-_Logo_%28Ao%C3%BBt_2017%29.svg.png"/> | LCI.fr |
| 26 | LCI | [x](https://sv0.data-stream.top/hls/lci.m3u8) | <img height="20" src="https://upload.wikimedia.org/wikipedia/fr/8/85/LCI.png/> | LCI.fr |
<h2>Unreliable (tntdirect)</h2>

View File

@ -17,6 +17,10 @@ https://en.wikipedia.org/wiki/List_of_4K_channels_in_India
| 8 | DD Kisan Ⓨ | [>](https://www.youtube.com/@DDKisan/live) | <img height="20" src="https://i.imgur.com/x56WJEa.png" /> | DDKisan.in |
| 9 | DD Urdu Ⓨ | [>](https://www.youtube.com/@DDUrdu/live) | <img height="20" src="https://i.imgur.com/OiQPS34.png" /> | DDUrdu.in |
| 10 | India Today Ⓨ | [>](https://www.youtube.com/watch?v=sYZtOFzM78M) | <img height="20" src="https://i.imgur.com/C7KK3Fd.png" /> | IndiaToday.in |
| 11 | Aaj Tak Ⓨ | [>](https://www.youtube.com/watch?v=Nq2wYlWFucg) | <img height="20" src="https://upload.wikimedia.org/wikipedia/commons/2/28/Aaj_tak_logo.png" /> | AajTak.in |
| 12 | India TV Ⓨ | [>](https://www.youtube.com/watch?v=e1FIApIafWE) | <img height="20" src="https://upload.wikimedia.org/wikipedia/en/thumb/6/60/India_tv_logo-en.png/500px-India_tv_logo-en.png" /> | IndiaTV.in |
| 13 | TV9 Bharatvarsh Ⓨ | [>](https://www.youtube.com/watch?v=nSpwwcHVp80) | <img height="20" src="https://upload.wikimedia.org/wikipedia/en/thumb/a/a6/TV9_Bharatvarsh.svg/500px-TV9_Bharatvarsh.svg.png" /> | TV9Bharatvarsh.in |
| 14 | Republic Bharat Ⓨ | [>](https://www.youtube.com/watch?v=3DbTO_AMhhc) | <img height="20" src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Republic_Bharat_logo.svg/500px-Republic_Bharat_logo.svg.png" /> | RepublicBharat.in |
<h2>Invalid</h2>

View File

@ -2,7 +2,7 @@
| # | Channel | Link | Logo | EPG id |
|:---:|:--------------:|:-----:|:----:|:------:|
| 1 | TVCG 1 | [>](http://cdn3.bcdn.rs:1935/cg1/smil:cg1.smil/playlist.m3u8) | <img height="20" src="https://i.imgur.com/QORHrXu.png"/> | TVCG1.me |
| 2 | TVCG 2 | [>](http://cdn3.bcdn.rs:1935/cg2/smil:cg2.smil/playlist.m3u8) | <img height="20" src="https://i.imgur.com/WECmUKH.png"/> | TVCG2.me |
| 3 | TVCG 3 | [>](https://parlament.rtcg.me:1936/pr/smil:parlament.smil/playlist.m3u8) | <img height="20" src="https://i.imgur.com/XC7zVog.png"/> | Parlamentarnikanal.me |
| 99 | TVCG MNE | [>](http://cdn3.bcdn.rs:1935/cgsat/smil:cgsat.smil/playlist.m3u8) | <img height="20" src="https://i.imgur.com/pf8VEwf.png"/> | TVCGMNE.me |
| 1 | TVCG 1 Ⓖ | [>](https://rtcg-live-open-geo.morescreens.com/RTCG_1_001/playlist.m3u8) | <img height="20" src="https://i.imgur.com/QORHrXu.png"/> | TVCG1.me |
| 2 | TVCG 2 Ⓖ | [>](https://rtcg-live-open-geo.morescreens.com/RTCG_1_002/playlist.m3u8) | <img height="20" src="https://i.imgur.com/WECmUKH.png"/> | TVCG2.me |
| 3 | TVCG 3 Ⓖ | [>](https://rtcg-live-open-geo.morescreens.com/RTCG_1_003/playlist.m3u8) | <img height="20" src="https://i.imgur.com/XC7zVog.png"/> | TVCG3.me |
| 99 | TVCG MNE | [>](https://rtcg-live-open.morescreens.com/RTCG_1_004/playlist.m3u8) | <img height="20" src="https://i.imgur.com/pf8VEwf.png"/> | TVCGMNE.me |

View File

@ -74,9 +74,9 @@ https://ru.wikipedia.org/wiki/Цифровоеелевидение_в_Рос
| 0 | Небеса ТВ7 Ⓢ | [>](https://vod.tv7.fi/tv7-ru/tv7-ru.smil/playlist.m3u8) | <img height="20" src="https://www.nebesatv7.com/wp-content/themes/tv7-theme/assets/img/logo_nebesa_short.png"/> | NebesaTV7.ru |
| 0 | Север | [>](https://live.mediacdn.ru/sr1/sever/playlist.m3u8) | <img height="20" src="https://i.imgur.com/sTOQLYl.png"/> | Sever.ru |
| 0 | Смотрим - Детям | [x]() | <img height="20" src="https://cdn-st1.smotrim.ru/vh/pictures/r/424/215/2.png"/> |
| 0 | Смотрим - Мелодрамы | [>](https://live-vgtrksmotrim.cdnvideo.ru/vgtrksmotrim/smotrim-live-02.smil/playlist.m3u8) | <img height="20" src="https://cdn-st1.smotrim.ru/vh/pictures/r/456/967/6.png"/> |
| 0 | Смотрим - Тайны | [>](https://live-vgtrksmotrim.cdnvideo.ru/vgtrksmotrim/smotrim-live-07.smil/playlist.m3u8) | <img height="20" src="https://cdn-st3.smotrim.ru/vh/pictures/r/456/396/2.png"/> |
| 0 | Смотрим - Честный Детектив | [>](https://live-vgtrksmotrim.cdnvideo.ru/vgtrksmotrim/smotrim-live-01.smil/playlist.m3u8) | <img height="20" src="https://cdn-st3.smotrim.ru/vh/pictures/r/444/241/8.png"/> |
| 0 | Смотрим: Мелодрамы | [>](https://live-vgtrksmotrim.cdnvideo.ru/vgtrksmotrim/smotrim-live-02.smil/playlist.m3u8) | <img height="20" src="https://cdn-st1.smotrim.ru/vh/pictures/r/456/967/6.png"/> |
| 0 | Смотрим: Тайны | [>](https://live-vgtrksmotrim.cdnvideo.ru/vgtrksmotrim/smotrim-live-07.smil/playlist.m3u8) | <img height="20" src="https://cdn-st3.smotrim.ru/vh/pictures/r/456/396/2.png"/> |
| 0 | Смотрим: Честный Детектив | [>](https://live-vgtrksmotrim.cdnvideo.ru/vgtrksmotrim/smotrim-live-01.smil/playlist.m3u8) | <img height="20" src="https://cdn-st3.smotrim.ru/vh/pictures/r/444/241/8.png"/> |
| 0 | Соловьёв Live | [>](https://player.smotrim.ru/iframe/stream/live_id/63338) | <img height="20" src="https://i.imgur.com/v0OYe1d.png"/> | SolovyovLive.ru |
| 0 | Ю Ⓢ | [>](https://strm.yandex.ru/kal/utv/utv0.m3u8) | <img height="20" src="https://upload.wikimedia.org/wikipedia/ru/a/ac/%D0%9B%D0%BE%D0%B3%D0%BE%D1%82%D0%B8%D0%BF_%D1%82%D0%B5%D0%BB%D0%B5%D0%BA%D0%B0%D0%BD%D0%B0%D0%BB%D0%B0_%C2%AB%D0%AE%C2%BB_%28%D1%81_3_%D1%81%D0%B5%D0%BD%D1%82%D1%8F%D0%B1%D1%80%D1%8F_2018_%D0%B3%D0%BE%D0%B4%D0%B0%29.png"/> | U.ru |

View File

@ -2,15 +2,18 @@
| # | Channel | Link | Logo | EPG id |
|:---:|:--------------:|:-----:|:----:|:------:|
| 1 | RTS 1 | [>](https://webtvstream.bhtelecom.ba/rts1.m3u8) | <img height="20" src="https://i.imgur.com/S1pKHSR.png"/> | RTS1.rs |
| 2 | RTS 2 | [>](https://webtvstream.bhtelecom.ba/rts2.m3u8) | <img height="20" src="https://i.imgur.com/jltAf5h.png"/> | RTS2.rs |
| 3 | RTS 3 | [x]() | <img height="20" src="https://i.imgur.com/gxuGB4J.png"/> | RTS3.rs |
| 0 | RTS Svet | [x]() | <img height="20" src="https://upload.wikimedia.org/wikipedia/commons/8/8a/Rts-svet.png"/> | RTSSvet.rs |
| 0 | Euronews Serbia | [>](https://d1ei8ofhgfmkac.cloudfront.net/app-19518-1306/ngrp:QoZfNjsg_all/playlist.m3u8) | <img height="20" src="https://i.imgur.com/b24QKcq.png"/> | EuroNewsSerbia.rs |
| 1 | RTS 1 | [>](https://webtvstream.bhtelecom.ba/rts1.m3u8) | <img height="20" src="https://i.imgur.com/S1pKHSR.png"/> | RTS1.rs |
| 2 | RTS 2 | [>](https://webtvstream.bhtelecom.ba/rts2.m3u8) | <img height="20" src="https://i.imgur.com/jltAf5h.png"/> | RTS2.rs |
| 3 | RTS 3 | [x]() | <img height="20" src="https://i.imgur.com/gxuGB4J.png"/> | RTS3.rs |
| 4 | Red TV | [>](https://edge8.pink.rs/redtv/chunklist_w1213385221.m3u8) | <img height="20" src="https://i.imgur.com/cpN7NrL.png"/> | RedTV.rs |
| 5 | Kurir TV | [>](https://static.am.mediaoutcast.com/storage/nQJnjJkO/nQJnjJkO/stream/O68x4o8g/720p/720p.m3u8) | <img height="20" src="https://i.imgur.com/HBPnUD5.png"/> | KurirTV.rs |
| 6 | Informer TV | [>](https://edge-rs-03.maksnet.tv/informertv-secure/web/playlist.m3u8) | <img height="20" src="https://i.imgur.com/9wdEHRf.png"/> | InformerTV.rs |
| 0 | RTS Svet | [x]() | <img height="20" src="https://upload.wikimedia.org/wikipedia/commons/8/8a/Rts-svet.png"/> | RTSSvet.rs |
| 0 | Euronews Serbia | [x](https://d1ei8ofhgfmkac.cloudfront.net/app-19518-1306/ngrp:QoZfNjsg_all/playlist.m3u8) | <img height="20" src="https://i.imgur.com/b24QKcq.png"/> | EuroNewsSerbia.rs |
<h3>Vojvodina</h3>
| # | Channel | Link | Logo | EPG id |
|:---:|:--------------:|:-----:|:----:|:------:|
| 1 | RTV 1 | [>](rtsp://212.200.255.151/rtv1) | <img height="20" src="https://i.imgur.com/CG44YT3.png"/> | RTV1.rs |
| 2 | RTV 2 | [>](rtsp://212.200.255.151/rtv2) | <img height="20" src="https://i.imgur.com/skpr66t.png"/> | RTV2.rs |
| 1 | RTV 1 | [>](rtmp://212.200.230.50:1935/RTV/rtv1) | <img height="20" src="https://i.imgur.com/CG44YT3.png"/> | RTV1.rs |
| 2 | RTV 2 | [>](rtmp://212.200.230.50:1935/RTV/rtv2) | <img height="20" src="https://i.imgur.com/skpr66t.png"/> | RTV2.rs |

View File

@ -3,11 +3,98 @@
import os
import re
EPG_LIST = open('epglist.txt',"r") # for a clean code
COUNTRY_CODES = {
"albania": "AL",
"andorra": "AD",
"argentina": "AR",
"armenia": "AM",
"australia": "AU",
"austria": "AT",
"azerbaijan": "AZ",
"belarus": "BY",
"belgium": "BE",
"bosnia_and_herzegovina": "BA",
"brazil": "BR",
"bulgaria": "BG",
"canada": "CA",
"chad": "TD",
"chile": "CL",
"china": "CN",
"costa_rica": "CR",
"croatia": "HR",
"cyprus": "CY",
"czech_republic": "CZ",
"denmark": "DK",
"dominican_republic": "DO",
"egypt": "EG",
"estonia": "EE",
"faroe_islands": "FO",
"finland": "FI",
"france": "FR",
"georgia": "GE",
"germany": "DE",
"greece": "GR",
"greenland": "GL",
"hong_kong": "HK",
"hongkong": "HK",
"hungary": "HU",
"iceland": "IS",
"india": "IN",
"indonesia": "ID",
"iran": "IR",
"iraq": "IQ",
"ireland": "IE",
"israel": "IL",
"italy": "IT",
"japan": "JP",
"korea": "KR",
"kosovo": "XK",
"latvia": "LV",
"lithuania": "LT",
"luxembourg": "LU",
"macau": "MO",
"malta": "MT",
"mexico": "MX",
"moldova": "MD",
"monaco": "MC",
"montenegro": "ME",
"netherlands": "NL",
"north_korea": "KP",
"north_macedonia": "MK",
"norway": "NO",
"paraguay": "PY",
"peru": "PE",
"poland": "PL",
"portugal": "PT",
"qatar": "QA",
"romania": "RO",
"russia": "RU",
"san_marino": "SM",
"saudi_arabia": "SA",
"serbia": "RS",
"slovakia": "SK",
"slovenia": "SI",
"somalia": "SO",
"spain": "ES",
"spain_vod": "ES",
"sweden": "SE",
"switzerland": "CH",
"taiwan": "TW",
"trinidad": "TT",
"turkey": "TR",
"uk": "GB",
"ukraine": "UA",
"united_arab_emirates": "AE",
"usa": "US",
"usa_vod": "US",
"venezuela": "VE",
}
class Channel:
def __init__(self, group, md_line):
def __init__(self, group, md_line, country_code=""):
self.group = group
self.country_code = country_code
md_line = md_line.strip()
parts = md_line.split("|")
self.number = parts[1].strip()
@ -22,39 +109,49 @@ class Channel:
self.epg = None
def to_m3u_line(self):
country = f' tvg-country="{self.country_code}"' if self.country_code else ""
if self.epg is None:
return (f'#EXTINF:-1 tvg-name="{self.name}" tvg-logo="{self.logo}" group-title="{self.group}",{self.name}\n{self.url}')
return (f'#EXTINF:-1 tvg-name="{self.name}" tvg-logo="{self.logo}"{country} group-title="{self.group}",{self.name}\n{self.url}')
else:
return (f'#EXTINF:-1 tvg-name="{self.name}" tvg-logo="{self.logo}" tvg-id="{self.epg}" group-title="{self.group}",{self.name}\n{self.url}')
return (f'#EXTINF:-1 tvg-name="{self.name}" tvg-logo="{self.logo}" tvg-id="{self.epg}"{country} group-title="{self.group}",{self.name}\n{self.url}')
def main():
dir_playlists = 'playlists'
if not (os.path.isdir(dir_playlists)):
base_dir = os.path.dirname(os.path.abspath(__file__))
lists_dir = os.path.join(base_dir, "lists")
dir_playlists = os.path.join(base_dir, "playlists")
if not os.path.isdir(dir_playlists):
os.mkdir(dir_playlists)
with open("playlist.m3u8", "w", encoding='utf-8') as playlist:
processed_epg_list = ", ".join(EPG_LIST).replace('\n', '')
head_playlist = f'#EXTM3U x-tvg-url="{processed_epg_list}"'
print(f'#EXTM3U x-tvg-url="{processed_epg_list}"', file=playlist)
os.chdir("lists")
for filename in sorted(os.listdir(".")):
with open(os.path.join(base_dir, "epglist.txt"), encoding='utf-8') as epg_file:
epg_urls = [line.strip() for line in epg_file if line.strip()]
processed_epg_list = ", ".join(epg_urls)
head_playlist = f'#EXTM3U x-tvg-url="{processed_epg_list}"\n'
with open(os.path.join(base_dir, "playlist.m3u8"), "w", encoding='utf-8') as playlist:
playlist.write(head_playlist)
for filename in sorted(os.listdir(lists_dir)):
if filename == "README.md" or not filename.endswith(".md"):
continue
with open(filename, encoding='utf-8') as markup_file:
file_country = os.path.join("..", dir_playlists, "playlist_" + filename[:-3:] + ".m3u8")
playlist_country = open(file_country, "w", encoding='utf-8')
playlist_country.write(head_playlist + "\n")
group = filename.replace(".md", "").title()
print(f"Generating {group}")
markup_path = os.path.join(lists_dir, filename)
country_path = os.path.join(dir_playlists, "playlist_" + filename[:-3] + ".m3u8")
country_key = filename[:-3]
group = country_key.replace("_", " ").title()
country_code = COUNTRY_CODES.get(country_key, "")
print(f"Generating {group}")
with open(markup_path, encoding='utf-8') as markup_file, \
open(country_path, "w", encoding='utf-8') as playlist_country:
playlist_country.write(head_playlist)
for line in markup_file:
if "<h1>" in line.lower() and "</h1>" in line.lower():
group = re.sub('<[^<>]+>', '', line.strip())
if not "[>]" in line:
if "[>]" not in line:
continue
channel = Channel(group, line)
print(channel.to_m3u_line(), file=playlist)
print(channel.to_m3u_line(), file=playlist_country)
playlist_country.close()
channel = Channel(group, line, country_code)
m3u_line = channel.to_m3u_line()
print(m3u_line, file=playlist)
print(m3u_line, file=playlist_country)
if __name__ == "__main__":
main()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long