import sys, os, urllib2, re, requests #CLI_MODE = True from kodiswift import xbmc, xbmcgui, CLI_MODE from kodiswift import Plugin, storage from resources.lib.content import util, ContentSources #from resources.lib.content import Downloader #from twisted.web import client #from twisted.internet import reactor, defer #plugin = Plugin() #plugin.load_addon_settings() #playlist = plugin.get_setting("general_playlist",str) #proxy_url = plugin.get_setting("general_proxy_url",str) cunicode = lambda s: s.decode("utf8") if isinstance(s, str) else s cstr = lambda s: s.encode("utf8") if isinstance(s, unicode) else s cmd = sys.argv[1] title = sys.argv[2] data = sys.argv[3] download_dir = sys.argv[4] cur_directory = os.path.dirname(__file__) sources_directory = os.path.join(cur_directory,"resources","lib", "content", "sources") sources = ContentSources.ContentSources(sources_directory) def main(): if not sources.is_video(data): print "It is not video link" notify("It is not video link") sys.exit(1) streams = sources.get_streams(data) if not CLI_MODE: ret = 0 #ret = xbmcgui.Dialog().select("Select stream",streams) # TODO else: ret = 0 stream = streams[ret] #output = stream["name"].replace("\\"," ").replace(":"," ").replace("|"," ") output = re.sub("[\\/\n\r\t,:\?\|'~\.]","_",title) if isinstance(output, str): output = output.decode("utf8") for sub in stream["subs"]: suburl = sub["url"] slang = "_" + sub["lang"] if sub["lang"] else "" download_sub(suburl, output+slang) if "nfo" in stream and stream["nfo"]: nfofile = os.path.join(download_dir, output+".nfo") with open(nfofile,"w") as f: nfo_txt = util.nfo2xml(stream["nfo"]) f.write(nfo_txt) download_video(stream["url"], os.path.join(download_dir, output), stream["headers"]) #d = Downloader.download_video(stream["url"], os.path.join(download_dir, output), stream["headers"]) #reactor.run() #xbmcgui.Dialog().ok("Info","Start download") #mode = "a" if os.path.exists("context_menu.log") else "w" #with open("context_menu.log", mode) as f: # f.write("%s %s %s %s", sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]) def download_video(url,output,headers=None): #output = stream["name"].replace("\\"," ").replace(":"," ").replace("|"," ") if not headers: headers = {"user-agent":"Enigma2"} try: h = get_header(url,headers=headers) mtype = h.get("content-type") ext,stream_type = get_ext(mtype) except Exception as e: ext,stream_type = (".ts","hls") output = output+ext if stream_type == "hls": download_hls(url, output, headers=headers) else: download_file(url, output, headers=headers) def download_hls(url, title, download_dir="", headers=None, overwrite=True, limit=None): UA = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0" if not headers: headers = {"User-Agent" : UA} key = headers["key"] if "key" in headers else "" # if not "User-Agent" in headers: # headers["User-Agent"] = UA tsname = os.path.join(download_dir,title) notify("Download started - %s" % title) print "Start download" print url try: r = requests.get(url,headers=headers) except Exception as e: raise Exception("Cannot open manifsest file - %s"%url) if not r.content.startswith("#EXTM3U"): raise Exception("Not valid manifest file - %s" % url) streams = re.findall(r"#EXT-X-STREAM-INF:.*?BANDWIDTH=(\d+).*?\n(.+?)$", r.content, re.IGNORECASE | re.MULTILINE) i = 0 while streams: if i > 4: break sorted(streams, key=lambda item: int(item[0]), reverse=True) base_url = "/".join(url.split("?")[0].split("/")[:-1])+"/" url = streams[0][1] if not url.startswith("http"): url = base_url + url print url try: r = requests.get(url, headers=headers) except Exception as e: raise Exception("Cannot open manifsest file - %s"%url) i += 1 streams = re.findall(r"#EXT-X-STREAM-INF:.*?BANDWIDTH=(\d+).*?\n(.+?)$", r.content, re.IGNORECASE | re.MULTILINE) ts_list = re.findall(r"#EXTINF:([\d\.]+),.*?\n(.+?)$", r.content, re.IGNORECASE | re.MULTILINE) base_url = "/".join(url.split("/")[:-1])+"/" if not len(ts_list): raise Exception("Cannot read fragment list in manifsest file - %s"%url) ts_num = 0 type = "vod" if "#EXT-X-ENDLIST" in r.content else "live" currentbytes = 0.0 totalbytes = -1 currenttime = 0.0 totaltime = sum(map(float,zip(*ts_list)[0])) #ts_file = open(outputfile, "wb") if isinstance(tsname, str): tsname = tsname.decode("utf8") tsfile = open(tsname,"wb") for ts in ts_list: url2 = ts[1] #print "Downloading ", url2 #fname = os.path.join(download_dir,url2.split("/")[-1]) if not url2.startswith("http"): url2 = base_url + url2 r = requests.get(url2, headers=headers, verify=False) content = r.content if key: from Crypto.Cipher import AES key2 = binascii.a2b_hex(key) iv = content[:16] d = AES.new(key2, AES.MODE_CBC, iv) content = d.decrypt(content[16:]) #with open(fname,"wb") as f: #f.write(content) tsfile.write(content) content_length = len(content) currentbytes += content_length currenttime += float(ts_list[ts_num][0]) totalbytes = currentbytes * totaltime / currenttime ts_num += 1 #print "Fragment %s downloaded (%s)"%(self.ts_num,len(content)) progress = float(currentbytes)/float(totalbytes)*100 print "%.1f%% (%i/%i)"%(progress,currentbytes,totalbytes) if type == "vod": if ts_num >= len(ts_list) or (limit and currenttime>limit): break else: if limit and currenttime>limit: # TODO break print "Finished" notify("Download finished - %s" % title) tsfile.close() def download_file(url, title, download_dir="", headers=None, overwrite=True, limit=None): UA = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0" if not headers: headers = {"User-Agent" : UA} key = headers["key"] if "key" in headers else "" # if not "User-Agent" in headers: # headers["User-Agent"] = UA fname = os.path.join(download_dir,title) if isinstance(fname, str): fname = fname.decode("utf8") notify("Download started - %s" % title) print "Start download" print url try: r = requests.get(url,headers=headers, stream=True) except Exception as e: raise Exception("Cannot open url - %s"%url) currentbytes = 0.0 totalbytes = int(r.headers["content-length"]) with open(fname, 'wb') as fd: for chunk in r.iter_content(chunk_size=1024*1024): fd.write(chunk) currentbytes += len(chunk) progress = float(currentbytes)/float(totalbytes)*100 print "%.1f%% (%i/%i)"%(progress,currentbytes,totalbytes) print "Finished" notify("Download finished - %s" % title) def download_sub(suburl, output): try: subs = urllib2.urlopen(suburl).read() except: subs = None if subs: if ".xml" in suburl: subs = util.ttaf2srt(subs) subext = ".srt" elif ".vtt" in suburl: subext = ".vtt" elif ".srt" in suburl: subext = ".srt" else: subext = "" if subext: subfile = cunicode(os.path.join(download_dir, output+subext)) with open(subfile,"w") as f: f.write(subs) else: print "\n Error downloading subtitle %s"%suburl def get_header(url,headers=None): r = requests.head(url,headers=headers) return r.headers def get_ext(mtype): stype = "http" if mtype in ("vnd.apple.mpegURL","application/x-mpegURL",'application/x-mpegurl',"application/vnd.apple.mpegurl"): return ".ts","hls" elif mtype in ("application/dash+xml"): return ".ts","dash" # TODO dash stream type could be different ! elif mtype in ("video/mp4"): return ".mp4","http" elif mtype in ("video/MP2T","video/mp2t"): return ".ts","http" elif mtype in ("video/x-flv"): return ".flv","http" elif mtype in ("video/quicktime"): return ".mov","http" elif mtype in ("video/x-msvideo"): return ".avi","http" elif mtype in ("video/x-ms-wmv"): return ".wmv","http" elif mtype in ("video/x-matroska"): return ".mkv","http" else: return ".mp4","http" def notify(text, title="Info", time=10000): if isinstance(text, unicode): text = text.encode("utf8") #xbmc.executebuiltin('Notification(Hello World,This is a simple example of notifications,5000,/script.hellow.world.png)') xbmc.executebuiltin('Notification(%s, %s, %d, %s)'%("Info", text, time, xbmcgui.NOTIFICATION_INFO)) if __name__ == '__main__': main()