├── .github └── workflows │ └── actions.yaml ├── .gitignore ├── README.md ├── config.py ├── helpers ├── __init__.py └── res │ ├── logo-fraudiay.json │ └── playlist-header.txt ├── main.py ├── playlists ├── aesport.m3u └── daddyhd.m3u ├── requirements.txt └── services ├── __init__.py ├── aesport.py └── daddyhd.py /.github/workflows/actions.yaml: -------------------------------------------------------------------------------- 1 | name: Playlist-Generator workflow 2 | 3 | on: 4 | schedule: 5 | - cron: "* * * * *" 6 | push: 7 | branches: 8 | - master 9 | - main 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | - name: Set up Python 18 | 19 | uses: actions/setup-python@v4 20 | with: 21 | python-version: "3.11" 22 | 23 | - name: Run updater script 24 | run: | 25 | pip3 install -r requirements.txt 26 | python3 main.py 27 | 28 | - name: Commit playlists 29 | run: | 30 | git config --global user.email "actions@github.com" 31 | git config --global user.name "GitHub Actions" 32 | git add playlists 33 | git commit -m "Updated via AutoBot 🤖" || echo "No changes to commit" 34 | git push 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tests 2 | 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | share/python-wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | MANIFEST 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .nox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | *.py,cover 52 | .hypothesis/ 53 | .pytest_cache/ 54 | cover/ 55 | 56 | # Translations 57 | *.mo 58 | *.pot 59 | 60 | # Django stuff: 61 | *.log 62 | local_settings.py 63 | db.sqlite3 64 | db.sqlite3-journal 65 | 66 | # Flask stuff: 67 | instance/ 68 | .webassets-cache 69 | 70 | # Scrapy stuff: 71 | .scrapy 72 | 73 | # Sphinx documentation 74 | docs/_build/ 75 | 76 | # PyBuilder 77 | .pybuilder/ 78 | target/ 79 | 80 | # Jupyter Notebook 81 | .ipynb_checkpoints 82 | 83 | # IPython 84 | profile_default/ 85 | ipython_config.py 86 | 87 | # pyenv 88 | # For a library or package, you might want to ignore these files since the code is 89 | # intended to run in multiple environments; otherwise, check them in: 90 | # .python-version 91 | 92 | # pipenv 93 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 94 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 95 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 96 | # install all needed dependencies. 97 | #Pipfile.lock 98 | 99 | # poetry 100 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 101 | # This is especially recommended for binary packages to ensure reproducibility, and is more 102 | # commonly ignored for libraries. 103 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 104 | #poetry.lock 105 | 106 | # pdm 107 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 108 | #pdm.lock 109 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 110 | # in version control. 111 | # https://pdm.fming.dev/#use-with-ide 112 | .pdm.toml 113 | 114 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 115 | __pypackages__/ 116 | 117 | # Celery stuff 118 | celerybeat-schedule 119 | celerybeat.pid 120 | 121 | # SageMath parsed files 122 | *.sage.py 123 | 124 | # Environments 125 | .env 126 | .venv 127 | env/ 128 | venv/ 129 | ENV/ 130 | env.bak/ 131 | venv.bak/ 132 | 133 | # Spyder project settings 134 | .spyderproject 135 | .spyproject 136 | 137 | # Rope project settings 138 | .ropeproject 139 | 140 | # mkdocs documentation 141 | /site 142 | 143 | # mypy 144 | .mypy_cache/ 145 | .dmypy.json 146 | dmypy.json 147 | 148 | # Pyre type checker 149 | .pyre/ 150 | 151 | # pytype static type analyzer 152 | .pytype/ 153 | 154 | # Cython debug symbols 155 | cython_debug/ 156 | 157 | # PyCharm 158 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 159 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 160 | # and can be added to the global gitignore or merged into this file. For a more nuclear 161 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 162 | #.idea/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🎬 Playlist Generator 2 | 3 | ### 🔗 Active Playlists 4 | 5 | | Service | Source | Playlist | 6 | | ------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------- | 7 | | AESport | https://aesport.tv | [playlists/aesport.m3u](https://raw.githubusercontent.com/YoCodeCrafters/playlist-generator/main/playlists/aesport.m3u) | 8 | | DaddyHD | https://dlhd.sx | [playlists/daddyhd.m3u](https://raw.githubusercontent.com/YoCodeCrafters/playlist-generator/main/playlists/daddyhd.m3u) | 9 | 10 | ### 🎁 Features 11 | 12 | - Fully open-source. 13 | - No re-streaming/proxifying needed. 14 | - Playlists are updated every 5-10 minutes. 15 | - More services will be added as time goes. 16 | 17 | ### ⚡ Recommended Players 18 | 19 | - [VLC Media Player](https://www.videolan.org/vlc/) 20 | - [OTT Navigator](https://www.apkmirror.com/apk/sia-scillarium-studio/ott-navigator-iptv/) 21 | - [TiviMate](https://play.google.com/store/apps/details?id=ar.tvplayer.tv&hl=en&gl=US) 22 | 23 | ### 💙 Contributing 24 | 25 | Pull requests are always welcome. If you're considering major changes, please join one of our chat groups or open an issue first to discuss what you would like to change. 26 | 27 | ### 🌌 CodeCrafters Network 28 | 29 | [![telegram](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white)](https://t.me/realcodecrafters) 30 | [![discord](https://img.shields.io/badge/Discord-7289DA?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/codecrafters) 31 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | from services.aesport import AESport 2 | from services.daddyhd import DaddyHD 3 | 4 | services = [ 5 | AESport(), 6 | DaddyHD() 7 | ] 8 | -------------------------------------------------------------------------------- /helpers/__init__.py: -------------------------------------------------------------------------------- 1 | import re 2 | from difflib import get_close_matches 3 | from urllib.parse import urlparse 4 | from typing import List, Dict 5 | from datetime import datetime 6 | from jinja2 import Template 7 | import json 8 | import os 9 | 10 | PLAYLISTS_DIR = "playlists" 11 | RESOURCES_DIR = "helpers/res" 12 | 13 | 14 | def get_base_url(url: str) -> str: 15 | parsed_url = urlparse(url) 16 | base_url = parsed_url.scheme + "://" + parsed_url.netloc 17 | return base_url 18 | 19 | 20 | def generate_playlist(service_name: str, data: List[Dict[str, Dict]]) -> str: 21 | playlist_splitted = ["#EXTM3U"] 22 | 23 | with open(os.path.join(RESOURCES_DIR, "playlist-header.txt"), encoding="utf-8") as file: 24 | header_template = Template(file.read()) 25 | 26 | current_time = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC") 27 | 28 | playlist_splitted.append("\n" + header_template.render( 29 | time_of_update=current_time, 30 | service_name=service_name, 31 | num_of_channels=str(len(data)) 32 | ) + "\n") 33 | 34 | for channel in data: 35 | channel_name = channel.get("name") 36 | channel_logo = channel.get("logo") 37 | channel_group = channel.get("group") 38 | channel_url = channel.get("stream-url") 39 | channel_headers = channel.get("headers") 40 | 41 | playlist_splitted.append( 42 | f'#EXTINF:-1 tvg-name="{channel_name}" tvg-logo="{channel_logo}" group-title="{channel_group}",{channel_name}') 43 | 44 | channel_referer = channel_headers.get("referer") 45 | if channel_referer: 46 | playlist_splitted.append( 47 | f"#EXTVLCOPT:http-referrer={channel_referer}") 48 | 49 | channel_headers.pop("referer") 50 | 51 | channel_UA = channel_headers.get("user-agent") 52 | if channel_UA: 53 | playlist_splitted.append( 54 | f"#EXTVLCOPT:http-user-agent={channel_UA}") 55 | 56 | channel_headers.pop("user-agent") 57 | 58 | if channel_headers: 59 | playlist_splitted.append("EXTHTTP:" + json.dumps(channel_headers)) 60 | 61 | playlist_splitted.append(channel_url) 62 | 63 | playlist_splitted.append("") 64 | 65 | playlist = "\n".join(playlist_splitted) 66 | return playlist 67 | 68 | 69 | def get_logo_url(channel_name: str) -> str: 70 | logo_data = json.load( 71 | open(os.path.join("helpers", "res", "logo-fraudiay.json"), encoding="utf-8")) 72 | 73 | logo_tree = logo_data.get("tree", []) 74 | 75 | logo_paths = [logo.get("path", "") 76 | for logo in logo_tree if ".png" in logo.get("path", "")] 77 | logo_names = [logo_path.split( 78 | "/")[-1] if "/" in logo_path else "" for logo_path in logo_paths] 79 | 80 | channel_logo_matches = get_close_matches( 81 | channel_name, logo_names, cutoff=0.5) 82 | channel_logo_path = logo_paths[logo_names.index( 83 | channel_logo_matches[0])] if channel_logo_matches else None 84 | 85 | if channel_logo_path: 86 | return f"https://raw.githubusercontent.com/fraudiay79/logos/master/{channel_logo_path}" 87 | 88 | return None 89 | -------------------------------------------------------------------------------- /helpers/res/playlist-header.txt: -------------------------------------------------------------------------------- 1 | # █▀▀ █▀█ █▀▄ █▀▀ █▀▀ █▀█ ▄▀█ █▀▀ ▀█▀ █▀▀ █▀█ █▀ 2 | # █▄▄ █▄█ █▄▀ ██▄ █▄▄ █▀▄ █▀█ █▀░ ░█░ ██▄ █▀▄ ▄█ 3 | # ―――――――――――――――――――――――――――――――――――――――――――――― 4 | # (●) Last Update: {{ time_of_update }} 5 | # (●) Service: {{ service_name }} 6 | # (●) Total Channels: {{ num_of_channels }} 7 | # (●) Join: https://t.me/realcodecrafters -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from config import services 2 | 3 | for service in services: 4 | service.update() 5 | -------------------------------------------------------------------------------- /playlists/aesport.m3u: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | 3 | # █▀▀ █▀█ █▀▄ █▀▀ █▀▀ █▀█ ▄▀█ █▀▀ ▀█▀ █▀▀ █▀█ █▀ 4 | # █▄▄ █▄█ █▄▀ ██▄ █▄▄ █▀▄ █▀█ █▀░ ░█░ ██▄ █▀▄ ▄█ 5 | # ―――――――――――――――――――――――――――――――――――――――――――――― 6 | # (●) Last Update: 2024-05-21 20:23:54 UTC 7 | # (●) Service: AESport 8 | # (●) Total Channels: 40 9 | # (●) Join: https://t.me/realcodecrafters 10 | 11 | #EXTINF:-1 tvg-name="TNT SPORT 1" tvg-logo="https://image.azencode.com/upload/Livetv/tntsport1.png" group-title="UK Channels",TNT SPORT 1 12 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 13 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 14 | https://thumb.score806.cc/uk_bts1/index.m3u8 15 | 16 | #EXTINF:-1 tvg-name="TNT SPORT 2" tvg-logo="https://image.azencode.com/upload/Livetv/tntsport2.png" group-title="UK Channels",TNT SPORT 2 17 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 18 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 19 | https://thumb.score806.cc/uk_bts2/index.m3u8 20 | 21 | #EXTINF:-1 tvg-name="TNT SPORT 3" tvg-logo="https://image.azencode.com/upload/Livetv/tntsport3.png" group-title="UK Channels",TNT SPORT 3 22 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 23 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 24 | https://thumb.score806.cc/uk_bts3/index.m3u8 25 | 26 | #EXTINF:-1 tvg-name="PREMIER SPORTS 1" tvg-logo="https://image.azencode.com/upload/Livetv/Premier Sports1.png" group-title="UK Channels",PREMIER SPORTS 1 27 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 28 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 29 | https://thumb.score806.cc/uk_premiersports1/index.m3u8 30 | 31 | #EXTINF:-1 tvg-name="TNT SPORT 4" tvg-logo="https://image.azencode.com/upload/Livetv/tnt4.jpeg" group-title="UK Channels",TNT SPORT 4 32 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 33 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 34 | https://thumb.score806.cc/uk_bts4/index.m3u8 35 | 36 | #EXTINF:-1 tvg-name="PREMIER SPORTS 2" tvg-logo="https://image.azencode.com/upload/Livetv/Premier Sports 2.png" group-title="UK Channels",PREMIER SPORTS 2 37 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 38 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 39 | https://thumb.score806.cc/uk_premiersports2/index.m3u8 40 | 41 | #EXTINF:-1 tvg-name="Sky Sports Football" tvg-logo="https://image.azencode.com/upload/Livetv/skysports-football.png" group-title="UK Channels",Sky Sports Football 42 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 43 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 44 | https://thumb.score806.cc/uk_ssfb/index.m3u8 45 | 46 | #EXTINF:-1 tvg-name="Sky Sports Premier League" tvg-logo="https://image.azencode.com/upload/Livetv/skysports-premierleague.png" group-title="UK Channels",Sky Sports Premier League 47 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 48 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 49 | https://thumb.score806.cc/uk_ssepl/index.m3u8 50 | 51 | #EXTINF:-1 tvg-name="Sky Sports Main Event" tvg-logo="https://image.azencode.com/upload/Livetv/sky-sport-main.png" group-title="UK Channels",Sky Sports Main Event 52 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 53 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 54 | https://thumb.score806.cc/uk_ssmain/index.m3u8 55 | 56 | #EXTINF:-1 tvg-name="Sky Sports Criket" tvg-logo="https://image.azencode.com/upload/Livetv/skysports-cricket.png" group-title="UK Channels",Sky Sports Criket 57 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 58 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 59 | https://thumb.score806.cc/uk_sscricket/index.m3u8 60 | 61 | #EXTINF:-1 tvg-name="Sky Sports F1" tvg-logo="https://image.azencode.com/upload/Livetv/skysports-f1.png" group-title="UK Channels",Sky Sports F1 62 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 63 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 64 | https://thumb.score806.cc/uk_ssf1/index.m3u8 65 | 66 | #EXTINF:-1 tvg-name="Sky Sports Golf" tvg-logo="https://image.azencode.com/upload/Livetv/skysports-golf.png" group-title="UK Channels",Sky Sports Golf 67 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 68 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 69 | https://thumb.score806.cc/uk_ssgolf/index.m3u8 70 | 71 | #EXTINF:-1 tvg-name="Sky Sports Mix" tvg-logo="https://image.azencode.com/upload/Livetv/ukssmix.png" group-title="UK Channels",Sky Sports Mix 72 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 73 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 74 | https://thumb.score806.cc/uk_ssmix/index.m3u8 75 | 76 | #EXTINF:-1 tvg-name="Sky Sports News" tvg-logo="https://image.azencode.com/upload/Livetv/skysports-news.png" group-title="UK Channels",Sky Sports News 77 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 78 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 79 | https://thumb.score806.cc/uk_ssnews/index.m3u8 80 | 81 | #EXTINF:-1 tvg-name="BBC One" tvg-logo="https://image.azencode.com/upload/Livetv/ukbbc1.png" group-title="UK Channels",BBC One 82 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 83 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 84 | https://thumb.score806.cc/uk_bbc1/index.m3u8 85 | 86 | #EXTINF:-1 tvg-name="BBC Two" tvg-logo="https://image.azencode.com/upload/Livetv/ukbbc2.png" group-title="UK Channels",BBC Two 87 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 88 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 89 | https://thumb.score806.cc/uk_bbc2/index.m3u8 90 | 91 | #EXTINF:-1 tvg-name="BBC Three" tvg-logo="https://image.azencode.com/upload/Livetv/ukbbc3.png" group-title="UK Channels",BBC Three 92 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 93 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 94 | https://thumb.score806.cc/uk_bbc3/index.m3u8 95 | 96 | #EXTINF:-1 tvg-name="ITV 1" tvg-logo="https://image.azencode.com/upload/tvs/104.png" group-title="UK Channels",ITV 1 97 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 98 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 99 | https://thumb.score806.cc/uk_itv1/index.m3u8 100 | 101 | #EXTINF:-1 tvg-name="ITV 2" tvg-logo="https://image.azencode.com/tvs/105.png" group-title="UK Channels",ITV 2 102 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 103 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 104 | https://thumb.score806.cc/uk_itv2/index.m3u8 105 | 106 | #EXTINF:-1 tvg-name="Channel 4" tvg-logo="https://image.azencode.com/upload/Livetv/ukchannel4.png" group-title="UK Channels",Channel 4 107 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 108 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 109 | https://thumb.score806.cc/uk_channel4/index.m3u8 110 | 111 | #EXTINF:-1 tvg-name="Channel 5" tvg-logo="https://image.azencode.com/upload/Livetv/ukchannel5.png" group-title="UK Channels",Channel 5 112 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 113 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 114 | https://thumb.score806.cc/uk_channel5/index.m3u8 115 | 116 | #EXTINF:-1 tvg-name="BBC World News" tvg-logo="https://image.azencode.com/tvs/67.png" group-title="UK Channels",BBC World News 117 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 118 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 119 | https://thumb.score806.cc/uk_bbcnews/index.m3u8 120 | 121 | #EXTINF:-1 tvg-name="MTV" tvg-logo="https://image.azencode.com/upload/Livetv/ukmtv.png" group-title="UK Channels",MTV 122 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 123 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 124 | https://thumb.score806.cc/uk_mtv/index.m3u8 125 | 126 | #EXTINF:-1 tvg-name="FS1" tvg-logo="https://image.azencode.com/upload/Livetv/usfs1.png" group-title="US Channels",FS1 127 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 128 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 129 | https://thumb.score806.cc/us_fs1/index.m3u8 130 | 131 | #EXTINF:-1 tvg-name="FS2" tvg-logo="https://image.azencode.com/upload/Livetv/usfs2.png" group-title="US Channels",FS2 132 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 133 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 134 | https://thumb.score806.cc/us_fs2/index.m3u8 135 | 136 | #EXTINF:-1 tvg-name="NFL Network" tvg-logo="https://image.azencode.com/upload/Livetv/nfl-network.png" group-title="US Channels",NFL Network 137 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 138 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 139 | https://thumb.score806.cc/us_nflnetwork/index.m3u8 140 | 141 | #EXTINF:-1 tvg-name="CBS Sports Network" tvg-logo="https://image.azencode.com/tvs/70.png" group-title="US Channels",CBS Sports Network 142 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 143 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 144 | https://thumb.score806.cc/us_cbssportsnetwork/index.m3u8 145 | 146 | #EXTINF:-1 tvg-name="NBA TV" tvg-logo="https://image.azencode.com/upload/tvs/43.png" group-title="US Channels",NBA TV 147 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 148 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 149 | https://thumb.score806.cc/us_nbatv/index.m3u8 150 | 151 | #EXTINF:-1 tvg-name="Willow Cricket" tvg-logo="https://image.azencode.com/upload/Livetv/uswillow.png" group-title="US Channels",Willow Cricket 152 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 153 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 154 | https://thumb.score806.cc/us_willow/index.m3u8 155 | 156 | #EXTINF:-1 tvg-name="WWE Network" tvg-logo="https://image.azencode.com/tvs/117.png" group-title="US Channels",WWE Network 157 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 158 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 159 | https://thumb.score806.cc/us_wwe/index.m3u8 160 | 161 | #EXTINF:-1 tvg-name="BEIN SPORTS 1" tvg-logo="https://image.azencode.com/tvs/40.png" group-title="France Channels",BEIN SPORTS 1 162 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 163 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 164 | https://thumb.score806.cc/fr_beinsports1/index.m3u8 165 | 166 | #EXTINF:-1 tvg-name="BEIN SPORTS 2" tvg-logo="https://image.azencode.com/tvs/41.png" group-title="France Channels",BEIN SPORTS 2 167 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 168 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 169 | https://thumb.score806.cc/fr_beinsports2/index.m3u8 170 | 171 | #EXTINF:-1 tvg-name="RMC SPORT 1" tvg-logo="https://image.azencode.com/upload/tvs/13.png" group-title="France Channels",RMC SPORT 1 172 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 173 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 174 | https://thumb.score806.cc/fr_rmcsport1/index.m3u8 175 | 176 | #EXTINF:-1 tvg-name="RMC SPORT 2" tvg-logo="https://image.azencode.com/upload/Livetv/RMC_SPORT_2.png" group-title="France Channels",RMC SPORT 2 177 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 178 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 179 | https://thumb.score806.cc/fr_rmcsport2/index.m3u8 180 | 181 | #EXTINF:-1 tvg-name="Eleven Sport 1" tvg-logo="https://image.azencode.com/tvs/33.png" group-title="Portugal Channels",Eleven Sport 1 182 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 183 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 184 | https://thumb.score806.cc/pt_elevensport1/index.m3u8 185 | 186 | #EXTINF:-1 tvg-name="Eleven Sport 2" tvg-logo="https://image.azencode.com/tvs/32.png" group-title="Portugal Channels",Eleven Sport 2 187 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 188 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 189 | https://thumb.score806.cc/pt_elevensport2/index.m3u8 190 | 191 | #EXTINF:-1 tvg-name="Eleven Sport 3" tvg-logo="https://image.azencode.com/tvs/31.png" group-title="Portugal Channels",Eleven Sport 3 192 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 193 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 194 | https://thumb.score806.cc/pt_elevensport3/index.m3u8 195 | 196 | #EXTINF:-1 tvg-name="Sport TV 1" tvg-logo="https://image.azencode.com/tvs/36.png" group-title="Portugal Channels",Sport TV 1 197 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 198 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 199 | https://thumb.score806.cc/pt_sporttv1/index.m3u8 200 | 201 | #EXTINF:-1 tvg-name="Sport TV 2" tvg-logo="https://image.azencode.com/tvs/37.png" group-title="Portugal Channels",Sport TV 2 202 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 203 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 204 | https://thumb.score806.cc/pt_sporttv2/index.m3u8 205 | 206 | #EXTINF:-1 tvg-name="Sport TV 3" tvg-logo="https://image.azencode.com/tvs/38.png" group-title="Portugal Channels",Sport TV 3 207 | #EXTVLCOPT:http-referrer=https://aesport.tv/ 208 | #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 209 | https://thumb.score806.cc/pt_sporttv3/index.m3u8 210 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YoCodeCrafters/playlist-generator/b962f5525870b8ed79963b77691bc40c59c5b3c8/requirements.txt -------------------------------------------------------------------------------- /services/__init__.py: -------------------------------------------------------------------------------- 1 | from helpers import PLAYLISTS_DIR, generate_playlist 2 | import requests 3 | import os 4 | 5 | 6 | class BaseService: 7 | def __init__(self, SERVICE_NAME: str, SERVICE_URL: str) -> None: 8 | self.SERVICE_URL = SERVICE_URL 9 | self.SERVICE_NAME = SERVICE_NAME 10 | self.PLAYLIST_PATH = os.path.join( 11 | PLAYLISTS_DIR, self.SERVICE_NAME.lower() + ".m3u") 12 | 13 | self.requests_session = requests.Session() 14 | 15 | self.USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36" 16 | self.requests_session.headers = { 17 | "User-Agent": self.USER_AGENT 18 | } 19 | 20 | def update(self) -> None: 21 | playlist_str = self._get_playlist() 22 | 23 | os.makedirs(os.path.dirname(self.PLAYLIST_PATH), exist_ok=True) 24 | 25 | with open(self.PLAYLIST_PATH, "w", encoding="utf-8") as file: 26 | file.write(playlist_str) 27 | 28 | def _get_playlist(self) -> str: 29 | channels_data = self._get_data() 30 | return generate_playlist(self.SERVICE_NAME, channels_data) 31 | 32 | def _get_src(self) -> str: 33 | response = self.requests_session.get(self.SERVICE_URL) 34 | source_code = response.text 35 | 36 | return source_code 37 | -------------------------------------------------------------------------------- /services/aesport.py: -------------------------------------------------------------------------------- 1 | from helpers import get_base_url 2 | from bs4 import BeautifulSoup 3 | from . import BaseService 4 | 5 | 6 | class AESport(BaseService): 7 | def __init__(self) -> None: 8 | super().__init__( 9 | SERVICE_NAME="AESport", 10 | SERVICE_URL="https://aesport.tv/live-tv.html", 11 | ) 12 | 13 | def _get_data(self) -> dict: 14 | soup = BeautifulSoup(self._get_src(), "html.parser") 15 | 16 | channels_data = [] 17 | 18 | sections_divs = soup.select(".section-focus") 19 | for section_div in sections_divs: 20 | channels_divs = section_div.select(".tv-item") 21 | for channel_div in channels_divs: 22 | channels_data.append({ 23 | "name": channel_div.select_one("div.channel-name").text.strip(), 24 | "logo": channel_div.select_one("img.hide").get("src"), 25 | "group": section_div.select_one("div.left").text.strip(), 26 | "stream-url": channel_div.select_one("img.preview-tv").get("src").replace("preview.jpg", "index.m3u8"), 27 | "headers": { 28 | "referer": get_base_url(channel_div.parent.get("href")) + "/", 29 | "user-agent": self.USER_AGENT 30 | } 31 | }) 32 | 33 | return channels_data 34 | -------------------------------------------------------------------------------- /services/daddyhd.py: -------------------------------------------------------------------------------- 1 | from urllib.parse import urlparse 2 | from bs4 import BeautifulSoup 3 | from . import BaseService 4 | import requests 5 | import re 6 | 7 | 8 | class DaddyHD(BaseService): 9 | def __init__(self) -> None: 10 | super().__init__( 11 | SERVICE_NAME="DaddyHD", 12 | SERVICE_URL="https://dlhd.sx/24-7-channels.php", 13 | ) 14 | 15 | def _get_data(self) -> dict: 16 | soup = BeautifulSoup(self._get_src(), "html.parser") 17 | config_data = self._get_config_data() 18 | 19 | channels_data = [] 20 | 21 | channels_divs = soup.select("div.grid-item") 22 | for channel_div in channels_divs: 23 | channel_slug = channel_div.select_one("a").get("href").strip() 24 | 25 | FIRST_INDEX = channel_slug.find("stream-") + len("stream-") 26 | LAST_INDEX = channel_slug.find(".php") 27 | 28 | channel_id = channel_slug[FIRST_INDEX:LAST_INDEX] 29 | channel_name = channel_div.text.strip() 30 | 31 | if "18+" in channel_name: 32 | continue 33 | 34 | channels_data.append({ 35 | "name": channel_name, 36 | "logo": "", 37 | "group": "DaddyHD", 38 | "stream-url": config_data.get("endpoint").replace("STREAM-ID", channel_id), 39 | "headers": { 40 | "referer": config_data.get("referer"), 41 | "user-agent": self.USER_AGENT 42 | } 43 | }) 44 | 45 | return channels_data 46 | 47 | def _get_config_data(self) -> dict: 48 | EMBED_URL = "https://dlhd.sx/embed/stream-1.php" 49 | parsed_embed = urlparse(EMBED_URL) 50 | 51 | response = requests.get(EMBED_URL) 52 | soup = BeautifulSoup(response.text, "html.parser") 53 | 54 | iframe_url = soup.find("iframe", {"id": "thatframe"})["src"] 55 | iframe_parsed = urlparse(iframe_url) 56 | iframe_response = requests.get(iframe_url, headers={ 57 | "Referer": f"{parsed_embed.scheme}://{parsed_embed.netloc}/"}) 58 | iframe_source = iframe_response.text 59 | iframe_pattern = r"source:'(https:\/\/[^\s']+)'" 60 | 61 | matches = re.findall(iframe_pattern, iframe_source) 62 | 63 | config_endpoint = matches[1].replace("1", "STREAM-ID") 64 | 65 | config = { 66 | "endpoint": config_endpoint, 67 | "referer": f"{iframe_parsed.scheme}://{iframe_parsed.netloc}/" 68 | } 69 | 70 | return config 71 | --------------------------------------------------------------------------------