From 2166acfc0b2856e5a38b7d8386d57439c8673daf Mon Sep 17 00:00:00 2001 From: meliurwen Date: Tue, 29 Sep 2020 20:32:35 +0200 Subject: [PATCH] =?UTF-8?q?Let's=20start=20watching=20TV=20without=20usele?= =?UTF-8?q?ss=20clutter=20=F0=9F=93=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ README.md | 35 ++++++++++++++++++ channels.json | 68 +++++++++++++++++++++++++++++++++++ iptv_network_extract.py | 80 +++++++++++++++++++++++++++++++++++++++++ lint-requirements.txt | 2 ++ requirements.txt | 1 + setup.cfg | 5 +++ 7 files changed, 193 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 channels.json create mode 100755 iptv_network_extract.py create mode 100644 lint-requirements.txt create mode 100644 requirements.txt create mode 100644 setup.cfg diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b77d18e --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Virtual Environment +venv/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..afa9081 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# IPTV Network Extract + +Extracts m3u8 links for multiple IPTVs. + +## Channels Supported + ++ Italy 🇮🇹 + + Discovery Network + + realtime + + nove + + dmax + + giallo + + k-2 + + frisbee + + motor-trend + + food-network + + home-and-garden-tv + + eurosport1\* + + eurosport2\* + +\* the service is irregular/occasional + +## Use + +To extract the link for `dmax` and put it in `stdout`: + +```sh +./iptv_network_extract.py -c dmax +``` + +You can pipe the link to a player like `mpv`: + +```sh +./iptv_network_extract.py | mpv --playlist=- +``` diff --git a/channels.json b/channels.json new file mode 100644 index 0000000..5dd89f5 --- /dev/null +++ b/channels.json @@ -0,0 +1,68 @@ +{ + "realtime":{ + "url":"https://it.dplay.com/ajax/playbackjson/channel/2", + "data":{ + "referer":"https://it.dplay.com/realtime/" + } + }, + "nove":{ + "url":"https://it.dplay.com/ajax/playbackjson/channel/3", + "data":{ + "referer":"https://it.dplay.com/nove/" + } + }, + "dmax":{ + "url":"https://it.dplay.com/ajax/playbackjson/channel/5", + "data":{ + "referer":"https://it.dplay.com/dmax/" + } + }, + "giallo":{ + "url":"https://it.dplay.com/ajax/playbackjson/channel/6", + "data":{ + "referer":"https://it.dplay.com/giallo/" + } + }, + "k-2":{ + "url":"https://it.dplay.com/ajax/playbackjson/channel/7", + "data":{ + "referer":"https://it.dplay.com/k-2/" + } + }, + "frisbee":{ + "url":"https://it.dplay.com/ajax/playbackjson/channel/8", + "data":{ + "referer":"https://it.dplay.com/frisbee/" + } + }, + "motor-trend":{ + "url":"https://it.dplay.com/ajax/playbackjson/channel/19", + "data":{ + "referer":"https://it.dplay.com/motor-trend/" + } + }, + "food-network":{ + "url":"https://it.dplay.com/ajax/playbackjson/channel/21", + "data":{ + "referer":"https://it.dplay.com/food-network/" + } + }, + "home-and-garden-tv":{ + "url":"https://it.dplay.com/ajax/playbackjson/channel/36", + "data":{ + "referer":"https://it.dplay.com/home-and-garden-tv/" + } + }, + "eurosport1":{ + "url":"https://it.dplay.com/ajax/playbackjson/channel/49", + "data":{ + "referer":"https://it.dplay.com/eurosport1/" + } + }, + "eurosport2":{ + "url":"https://it.dplay.com/ajax/playbackjson/channel/50", + "data":{ + "referer":"https://it.dplay.com/eurosport2/" + } + } +} diff --git a/iptv_network_extract.py b/iptv_network_extract.py new file mode 100755 index 0000000..b296bb3 --- /dev/null +++ b/iptv_network_extract.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 + +import sys +import json +import argparse +import requests + + +with open('channels.json', 'r') as myfile: + channelsDict = json.loads(myfile.read()) + +parser = argparse.ArgumentParser( + prog='IPTV Network Extract', + description='Extracts m3u8 links for multiple IPTVs' +) +parser.add_argument( + "-c", "--channel", + nargs=1, + choices=list(channelsDict.keys()), + required=True, + help="TV channel name" +) +parser.add_argument( + "--version", + action="version", + version="%(prog)s 0.1" +) +args = parser.parse_args() + +channel = args.channel[0] + +HEADERS: dict = { + "User-Agent": ("Mozilla/5.0 (Windows NT 10.0; rv:75.0) " + "Gecko/20100101 Firefox/75.0"), + "Accept-Language": "en-US;q=0.9,en;q=0.8,en-GB;q=0.7", + "X-Requested-With": "XMLHttpRequest", + "Connection": "keep-alive", + "Referer": str(channelsDict[channel]["data"]["referer"]), + "cb-enabled": "enabled", + "DNT": "1", + "Pragma": "no-cache", + "Cache-Control": "no-cache" +} + +content = requests.get( + channelsDict[channel]["url"], + headers=HEADERS, + timeout=(3, 300) +) + +content = { + "status_code": content.status_code, + "content": content.content, + "encoding": content.encoding, + "cookies": content.cookies, + "request": content.request, + "url": content.url, + "reason": content.reason, + "headers": content.headers, + "elapsed": content.elapsed, + "history": content.history +} + +if content["status_code"] == 200: + uglyPayload = json.loads(content["content"].decode('unicode_escape')[1:-1]) + print( + uglyPayload["data"]["attributes"]["streaming"]["hls"]["url"], + sep='', + end='', + file=sys.stdout, + flush=False + ) +else: + print( + "[ERROR] Http status code: " + str(content["status_code"]), + sep='', + end='\n', + file=sys.stderr, + ) + sys.exit(1) diff --git a/lint-requirements.txt b/lint-requirements.txt new file mode 100644 index 0000000..98dec91 --- /dev/null +++ b/lint-requirements.txt @@ -0,0 +1,2 @@ +pylint>=2.6.0 +flake8>=3.8.3 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f1e8ee5 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +requests>=2.24.0 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..1e3b7f1 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,5 @@ +[flake8] +exclude = .venv,venv/*,.tox/*,dist/*,doc/*,build/*,*.egg,docs/*,*/migrations/ + +[pylint] +exclude = .venv,venv/*,.tox/*,dist/*,doc/*,build/*,*.egg,docs/*,*/migrations/