|
|
@ -5,76 +5,142 @@ import json |
|
|
|
import argparse |
|
|
|
import argparse |
|
|
|
import requests |
|
|
|
import requests |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__author__ = "Meliurwen" |
|
|
|
|
|
|
|
__version__ = "0.1.1" |
|
|
|
|
|
|
|
__license__ = "GPL3" |
|
|
|
|
|
|
|
|
|
|
|
with open('channels.json', 'r') as myfile: |
|
|
|
def get_link_m3u(source, channel, chan_dict): |
|
|
|
channelsDict = json.loads(myfile.read()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser( |
|
|
|
headers = { |
|
|
|
prog='IPTV Network Extract', |
|
|
|
|
|
|
|
description='Extracts original m3u8 links from multiple IPTV networks.' |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
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) " |
|
|
|
"User-Agent": ("Mozilla/5.0 (Windows NT 10.0; rv:75.0) " |
|
|
|
"Gecko/20100101 Firefox/75.0"), |
|
|
|
"Gecko/20100101 Firefox/75.0"), |
|
|
|
"Accept-Language": "en-US;q=0.9,en;q=0.8,en-GB;q=0.7", |
|
|
|
"Accept-Language": "en-US;q=0.9,en;q=0.8,en-GB;q=0.7", |
|
|
|
"X-Requested-With": "XMLHttpRequest", |
|
|
|
"X-Requested-With": "XMLHttpRequest", |
|
|
|
"Connection": "keep-alive", |
|
|
|
"Connection": "keep-alive", |
|
|
|
"Referer": str(channelsDict[channel]["data"]["referer"]), |
|
|
|
"Referer": str(chan_dict[source][channel]["data"]["referer"]), |
|
|
|
"cb-enabled": "enabled", |
|
|
|
"cb-enabled": "enabled", |
|
|
|
"DNT": "1", |
|
|
|
"DNT": "1", |
|
|
|
"Pragma": "no-cache", |
|
|
|
"Pragma": "no-cache", |
|
|
|
"Cache-Control": "no-cache" |
|
|
|
"Cache-Control": "no-cache" |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
content = requests.get( |
|
|
|
content = requests.get( |
|
|
|
channelsDict[channel]["url"], |
|
|
|
chan_dict[source][channel]["url"], |
|
|
|
headers=HEADERS, |
|
|
|
headers=headers, |
|
|
|
timeout=(3, 300) |
|
|
|
timeout=(3, 300) |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
content = { |
|
|
|
content = { |
|
|
|
"status_code": content.status_code, |
|
|
|
"status_code": content.status_code, |
|
|
|
"content": content.content, |
|
|
|
"content": content.content, |
|
|
|
"encoding": content.encoding, |
|
|
|
"url": content.url |
|
|
|
"cookies": content.cookies, |
|
|
|
} |
|
|
|
"request": content.request, |
|
|
|
|
|
|
|
"url": content.url, |
|
|
|
if content["status_code"] == 200: |
|
|
|
"reason": content.reason, |
|
|
|
ugly_payload = json.loads(content["content"].decode('unicode_escape')[1:-1]) |
|
|
|
"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( |
|
|
|
print( |
|
|
|
uglyPayload["data"]["attributes"]["streaming"]["hls"]["url"], |
|
|
|
ugly_payload["data"]["attributes"]["streaming"]["hls"]["url"], |
|
|
|
sep='', |
|
|
|
sep='', |
|
|
|
end='', |
|
|
|
end='\n', |
|
|
|
file=sys.stdout, |
|
|
|
file=sys.stdout, |
|
|
|
flush=False |
|
|
|
flush=False |
|
|
|
) |
|
|
|
) |
|
|
|
else: |
|
|
|
sys.exit(0) |
|
|
|
|
|
|
|
else: |
|
|
|
print( |
|
|
|
print( |
|
|
|
"[ERROR] Http status code: " + str(content["status_code"]), |
|
|
|
"[ERROR] Http status code: {stat_code}".format(stat_code=content["status_code"]), |
|
|
|
sep='', |
|
|
|
file=sys.stderr |
|
|
|
end='\n', |
|
|
|
|
|
|
|
file=sys.stderr, |
|
|
|
|
|
|
|
) |
|
|
|
) |
|
|
|
sys.exit(1) |
|
|
|
sys.exit(1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def is_supp_source(chan_dict, source): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if source not in chan_dict.keys(): |
|
|
|
|
|
|
|
print( |
|
|
|
|
|
|
|
"[ERROR] Source not supported: {source}".format(source=source), |
|
|
|
|
|
|
|
file=sys.stderr |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
sys.exit(1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def is_supp_channel(chan_dict, source, channel): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if channel not in chan_dict[source].keys(): |
|
|
|
|
|
|
|
print( |
|
|
|
|
|
|
|
"[ERROR] Channel not supported: {channel}".format(channel=channel), |
|
|
|
|
|
|
|
file=sys.stderr |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
sys.exit(1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_list(source, chan_dict): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if source: |
|
|
|
|
|
|
|
is_supp_source(chan_dict, source) |
|
|
|
|
|
|
|
print(*chan_dict[source].keys(), sep = "\n") |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
print(*chan_dict.keys(), sep = "\n") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sys.exit(1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main(arguments): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
source = arguments.source[0] if args.source else None |
|
|
|
|
|
|
|
channel = arguments.channel[0] if args.channel else None |
|
|
|
|
|
|
|
is_list = arguments.list if args.list else False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with open('channels.json', 'r') as myfile: |
|
|
|
|
|
|
|
chan_dict = json.loads(myfile.read()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if source and channel: |
|
|
|
|
|
|
|
is_supp_source(chan_dict, source) |
|
|
|
|
|
|
|
is_supp_channel(chan_dict, source, channel) |
|
|
|
|
|
|
|
get_link_m3u(source, channel, chan_dict) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if is_list: |
|
|
|
|
|
|
|
get_list(source, chan_dict) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser( |
|
|
|
|
|
|
|
prog='IPTV Network Extract', |
|
|
|
|
|
|
|
usage='%(prog)s [-h] [[-s SOURCE -c CHANNEL] | [-s SOURCE -l]] [-l] [--version]', |
|
|
|
|
|
|
|
description='Extracts original m3u8 links from multiple IPTV networks.' |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
parser.add_argument( |
|
|
|
|
|
|
|
"-s", "--source", |
|
|
|
|
|
|
|
nargs=1, |
|
|
|
|
|
|
|
required=False, |
|
|
|
|
|
|
|
help="source where getting the channel" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
parser.add_argument( |
|
|
|
|
|
|
|
"-c", "--channel", |
|
|
|
|
|
|
|
nargs=1, |
|
|
|
|
|
|
|
required=False, |
|
|
|
|
|
|
|
help="TV channel name" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
parser.add_argument( |
|
|
|
|
|
|
|
"-l", "--list", |
|
|
|
|
|
|
|
required=False, |
|
|
|
|
|
|
|
action='store_true', |
|
|
|
|
|
|
|
help="List supported networks and channels" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
parser.add_argument( |
|
|
|
|
|
|
|
"--version", |
|
|
|
|
|
|
|
action="version", |
|
|
|
|
|
|
|
version="%(prog)s (version {version})".format(version=__version__) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
args = parser.parse_args() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if len(sys.argv) <= 1: |
|
|
|
|
|
|
|
parser.error("at least 1 argument is required") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if len(sys.argv) == 3 and args.channel: |
|
|
|
|
|
|
|
parser.error("--source is required for this parameter") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if args.source and not bool(args.channel) ^ bool(args.list): |
|
|
|
|
|
|
|
parser.error("--source requires either --channel CHANNEL or --list") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if args.list and args.channel: |
|
|
|
|
|
|
|
parser.error("--list should either be used singularly or with --source") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
main(args) |
|
|
|