#!/usr/bin/env python # coding=utf8 # # This file is part of PlayStream - enigma2 plugin to play video streams from various sources # Copyright (c) 2016 ivars777 (ivars777@gmail.com) # Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html # try: import json except: import simplejson as json import requests try: from requests.packages.urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning) except: pass import urlparse, urllib import datetime, time,re, sys,os from collections import OrderedDict import ssl if "_create_unverified_context" in dir(ssl): ssl._create_default_https_context = ssl._create_unverified_context from SourceBase import SourceBase try: import util except: parent = os.path.dirname(os.path.abspath(__file__)) parent = os.sep.join(parent.split(os.sep)[:-1]) sys.path.insert(0,parent) import util headers2dict = lambda h: dict([l.strip().split(": ") for l in h.strip().splitlines()]) class Source(SourceBase): def __init__(self,language="en",cfg_path=None): self.name = "viaplay" self.title = "viaplay.lv" self.img = "https://yt3.ggpht.com/-noVdjbNR-V8/AAAAAAAAAAI/AAAAAAAAAAA/yZ9XNP5urLY/s900-c-k-no-mo-rj-c0xffffff/photo.jpg" self.desc = "Viaplay.lv saturs" self.url = "https://viaplay.lv/" self.headers = headers2dict(""" User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Connection: keep-alive Upgrade-Insecure-Requests: 1 """) #self.language=language cur_directory = os.path.dirname(os.path.abspath(__file__)) if not cfg_path: cfg_path = cur_directory self.config_file = os.path.join(cfg_path,self.name+".cfg") self.options = OrderedDict([("user","change_user"),("password","change_password"),("device","")]) self.options_read() self.device = self.options["device"] self.r = None # requests self.play_session = None self.s = None def login(self,user="",password=""): self.options_read() if not user: user=self.options["user"] if not password: password = self.options["password"] self.s = requests.Session() ### Dabu sesijas ID === headers = headers2dict(""" User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Referer: https://viaplay.lv/ Cookie: ott_cookies_confirmed=1; DNT: 1 Connection: keep-alive Upgrade-Insecure-Requests: 1 """) r = requests.get(self.url,headers=headers) if not "PLAY_SESSION" in r.cookies: return False self.play_session = r.cookies["PLAY_SESSION"] self.csrfToken = re.search("csrfToken=(.+)",self.play_session).group(1) ### Ielogojamies ### headers = headers2dict(""" User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Referer: https://viaplay.lv/ Cookie: ott_cookies_confirmed=1; PLAY_SESSION=e618c42b377a65021298ff63309d5a907988ed1b-PSESSIONID=b010ea1b-fc5e-4a18-aa15-ebbe8b57b3f0&csrfToken=b4eb35263d9be16ef9f7b2f5d10a8ee99dfe75a8-1478051634814-63682b20f1e7e5579de6d056 DNT: 1 Connection: keep-alive Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded """) url = "https://viaplay.lv/tdi/login/nav/form?csrfToken=%s"%self.csrfToken # https://viaplay.lv/tdi/login/nav/form?_infuse=1&_ts=1490554674901&csrfToken= params = "nav_redirectUri=https%3A%2F%2Fviaplay.lv%2F&nav_email={}&nav_password={}".format(urllib.quote(user),urllib.quote(password)) # nav_redirectUri=https%3A%2F%2Fviaplay.lv%2F&nav_email=ivars777%40gmail.com&nav_password=kaskade7&nav_remember=true headers["Cookie"] = "ott_cookies_confirmed=1; PLAY_SESSION=%s;"%self.play_session if self.device: headers["Cookie"] += "ott_dids=%s"%self.device #cookie = dict(PLAY_SESSION=self.play_session,_hjIncludedInSample=1, mobileAppPromo="shown") r = requests.post(url,params,headers=headers,allow_redirects=False) if not "Set-Cookie" in r.headers: self.play_session = None return False if not "ott_web_sac" in r.cookies: self.play_session = None return False self.ott = r.cookies["ott_web_sac"] ### Dabu iekārtas ID ### if not self.device: headers = headers2dict(""" User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36 Accept: application/xml, text/xml, */*; q=0.01 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With: XMLHttpRequest Referer: https://viaplay.lv/movies/me-and-earl-and-the-dying-girl DNT: 1 Connection: keep-alive """) url = "https://viaplay.lv/tdi/account/device/create?_infuse=1&csrfToken=%s"%self.csrfToken params = "successRedirectUri=https%3A%2F%2Fviaplay.lv%2Fmovies%2F&slotId=&title=Enigma2" headers["Cookie"] = "PLAY_SESSION=%s; ott_cookies_confirmed=1; ott_web_sac=%s;"%(self.play_session,self.ott) #cookie = dict(PLAY_SESSION=self.play_session,_hjIncludedInSample=1, mobileAppPromo="shown") r = requests.post(url,params,headers=headers,allow_redirects=False) if not ("Set-Cookie" in r.headers and "ott_dids" in r.headers["Set-Cookie"]): self.play_session = None return False self.device = r.cookies["ott_dids"] self.options["device"] = self.device self.options_write(self.options) return True def logout(self): return True def is_logedin(self): if self.play_session: return True else: return False def get_video_info(self,vid): import demjson ### Dabu strimus ### headers = headers2dict(""" Host: viaplay.lv User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 9_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/47.0.2526.70 Mobile/13C71 Safari/601.1.46 Accept: application/xml, text/xml, */*; q=0.01 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br X-Requested-With: XMLHttpRequest DNT: 1 Connection: keep-alive Referer: https://viaplay.lv/ """) url = "https://viaplay.lv/prehravac/init?_infuse=1&productId=%s"%vid #t110623 headers["Cookie"] = "ott_cookies_confirmed=1; ott_dids=%s; PLAY_SESSION=%s"%(self.device,self.play_session) r = requests.get(url,headers=headers,allow_redirects=False) statuss = re.search("(.+?)", r.content).group(1) if statuss.lower() <> "ok": raise Exception(statuss) #print r.content m = re.search(r"\s+", r.content, re.DOTALL) if not m: raise "Can not find stream info" txt = m.group(1) txt = re.sub("// .+$", "", txt, flags=re.MULTILINE) #print txt #for m in re.finditer("// .+$", txt, re.MULTILINE): # txt = txt[:m.start()] + txt[m.end():] #print txt js = demjson.decode(txt) return js #return txt def get_content(self, data): print "[%s] get_content:"%self.name, data source,data,path,plist,clist,params,qs = self.parse_data(data) content=[] content.append(("..return", "back","","Return back")) if clist=="home": content.extend([ ("Search", "viaplay::search-results-all?query={0}",self.img,"Meklēt"), ("Filmas", "viaplay::movies",self.img,"Filmas"), ("Seriāli", "viaplay::series",self.img,"Seriāli"), ("Bērniem", "viaplay::kids",self.img,"Bērniem"), ("Dokumentalās filmas", "viaplay::documentary",self.img,"Dokumentalās filmas"), ("Sports", "viaplay::live",self.img,"Sports"), ]) return content ### Meklēt ### elif clist=="search-results-all": url = "https://viaplay.lv/"+data r = self._http_request(url) result = re.findall(r'
.+?.+?

([^<]+)

.*?

([^<]+).+?

.+?

([^<]+)

.+?

([^<]+)

', r, re.DOTALL) for item in result: vid = item[0] data2 = item[1].replace("https://viaplay.lv/","") img = item[2] ep = item[3] title= item[4] seas = item[5].replace("\n","").replace("\t","") desc = item[6] desc2 = item[7] if ep==title: title = "%s (%s)"%(title,seas) else: title = "%s - %s%s"%(title,seas,ep) desc = "%s\n%s\n%s"%(title,desc2,desc) content.append((title,self.name+"::"+data2,img,desc)) return content ### Sadalas ## elif data in ["movies","series","kids","documentary"]: r = self._http_request(self.url+data) # https://viaplay.lv/tdi/movies/next?sections[]=MOVIES&genres[]=a3591&sort[]=latest&offset=0 # https://viaplay.lv/tdi/series/next?sections[]=SERIES&sort[]=latest&offset=0 # https://viaplay.lv/tdi/kids/next?sections[]=KIDS&cat[]=SERIES&cat[]=MOVIE&sort[]=latest&offset=18 # https://viaplay.lv/kids?sections[]=KIDS&cat[]=SERIES&sort[]=latest sections = {"movies":"MOVIES","series":"SERIES","kids":"KIDS","documentary":"DOCUMENTS"} nosaukums = {"movies":"Flmas","series":"Seriāli","kids":"Bērnu","documentary":"Dokumentalās"} #availability = {"new":"jaunākās","last":"pēdējā iespēja"} sort = OrderedDict([("latest","jaunākais"),("title","pēc nosaukuma"),("popular","pēc popularitātes"),("year","pēc gada")]) for s in sort: if data in ("movies","series"): title = "%s - %s"%(nosaukums[data],sort[s]) data2 = "%s/next?sections[]=%s&sort[]=%s"%(data,sections[data],s) content.append((title,self.name+"::"+data2,self.img,title)) else: title = "%s filmas - %s"%(nosaukums[data],sort[s]) data2 = "%s/next?sections[]=%s&cat[]=MOVIE&sort[]=%s"%(data,sections[data],s) content.append((title,self.name+"::"+data2,self.img,title)) title = "%s seriāli - %s"%(nosaukums[data],sort[s]) data2 = "%s/next?sections[]=%s&cat[]=SERIES&sort[]=%s"%(data,sections[data],s) content.append((title,self.name+"::"+data2,self.img,title)) # Pievienojam žanru sarakstu result = re.findall(r'name="genres\[\]" value="([^"]+)">.+?class="">([^<]+)', r, re.DOTALL) for item in result: s = "latest" genre = item[1].replace("&","&") title = "%s: %s"%(nosaukums[data],genre) data2 = "%s/next?sections[]=%s&genres[]=%s&sort[]=%s"%(data,sections[data],item[0],s) content.append((title,self.name+"::"+data2,self.img,title)) return content ### Filmu/seriālu/sēriju saraksts ### elif clist in ("movies","series","kids","documentary") and plist[1] == "next": url = "https://viaplay.lv/tdi/"+data r = self._http_request(url) if clist == "series" and "season" in qs: result = re.findall(r'
.+?.+?

([^<]+)

.*?

([^<]+).+?

.+?

([^<]+)

.+?

([^<]+)

', r, re.DOTALL) for item in result: vid = item[0] data2 = item[1].replace("https://viaplay.lv/","") img = item[2] ep = item[3] title= item[4] seas = item[5] desc = item[6] desc2 = item[7] title = "%s - %s%s"%(title,seas,ep) desc = "%s\n%s\n%s"%(title,desc2,desc) content.append((title,self.name+"::"+data2,img,desc)) else: # filmas result = re.findall(r'
.+?.+?

([^<]+)

.+?

([^<]+).+?

(.+?)

.+?

([^<]+)

', r, re.DOTALL) for item in result: vid = item[0] data2 = item[1].replace("https://viaplay.lv/","") img = item[2] title = item[3] year = item[4] year = year.replace("\n","").replace("\t","") title = title +"(%s)"%year desc= item[5] genre = re.findall(">([^<]+)<", item[6], re.DOTALL) genre = ("".join(genre)).replace("&","&") desc2 = item[7] desc = "%s\n%s\n%s"%(genre,desc2,desc) content.append((title,self.name+"::"+data2, img,desc)) m = re.search(r"data\('href', 'https://viaplay\.lv/tdi/([^']+)'\)", r, re.DOTALL) if m: data2 = m.group(1) content.append(("Next page",self.name+"::"+data2,img,"Next page")) return content ### Seriāls ### elif clist == "series" and len(plist)==2: url = "https://viaplay.lv/"+data r = self._http_request(url) result = re.findall(r'
  • .*?([^<]+).*?
  • ', r, re.DOTALL) for item in result: title = item[1] data2 = item[0] data2 = data2.replace("series/","series/next/") data2 = data2+"&sort[]=ord" #series/littlest-pet-shop?season=t6821 #series/next/peppa-pig?season=t8430 # &sort[]=ord if "availability=" in data2: continue content.append((title,self.name+"::"+data2,self.img,title)) #TODO bilde return content def is_video(self,data): source,data,path,plist,clist,params,qs = self.parse_data(data) if clist in ("movies","documentary","kids") and len(plist)>1 and plist[1]<>"next": return True elif clist == "series" and len(plist)>1 and plist[1] == "episode": return True else: return False def get_streams(self, data): print "[viaplay] get_streams:", data if not self.is_video(data): return [] source,data,path,plist,clist,params,qs = self.parse_data(data) if not self.is_logedin(): self.login() if not self.is_logedin(): raise Exception("Could not login to viaplay.lv, check username/password in options") streams = [] url = "https://viaplay.lv/"+data r = self._http_request(url) if clist in ("series","livestream"): # TODO nerāda overtime u.c. m = re.search(r'

    (.+?)

    .*?

    .*?

    (.+?)

    \s+

    (.+?)

    ', r, re.DOTALL) if not m: raise Exception("Problem getting video information") title = m.group(1).replace("\n"," ").replace("\t","").strip() title = re.sub("<[^>]+>","",title).strip() desc2 = m.group(2).replace("\n"," ").replace("\t","").strip() desc2 = re.sub("<[^>]+>","",desc2).strip() desc = m.group(3) desc = "%s\n%s"%(desc2,desc) vid = re.search('data-productid="(\w+)"',r).group(1) else: m = re.search(r'

    ([^<]+)

    .*?

    ([^<]+)

    .*?

    (.+?)

    \s+

    (.+?)

    ', r, re.DOTALL) if not m: raise Exception("Problem getting video information") title = m.group(2).strip() title2 = m.group(3).strip() title = "%s | %s"%(title,title2) desc = m.group(5).strip() desc2 = m.group(4).strip() desc2 = re.sub("<[^>]+>","",desc2) desc2 = desc2.replace("\n"," ").replace("\t","") desc = "%s\n%s"%(desc2,desc) vid = m.group(1) js = self.get_video_info(vid) #for m in re.finditer(r"lang: '(?P\w+)',\s+src: '(?P[^']+)',\s+type: '(?P[^']+)',\s+drm: \[(?P.+?)\]\s*\}", r, re.DOTALL): if not js: return [] tracks = js["tracks"] #if not tracks["HLS"]: # raise Exception("Encrypted DASH playing not yet implemented") captions = [] llist = ["fr","en","ru","lv"] for st in js["plugins"]["settings"]["subtitles"]: sub = {} sub["url"] = st["src"] sub["lang"] = st["srclang"] sub["name"] = st["label"] sub["type"] = "vtt" sub["order"] = llist.index(sub["lang"])*10 if sub["lang"] in llist else 0 captions.append(sub) captions = sorted(captions,key=lambda item: item["order"],reverse=True) for s in tracks["HLS"] if tracks["HLS"] else tracks["DASH"] : stype = "DASH" if "dash" in s["type"] else "HLS" if "drm" in s: ### # TODO, encrypted stream raise Exception("Can not play DRM protected stream!\nOnly local and Russian content available without DRM") continue url = s["src"] #urlp = util.streamproxy_encode(s["src"]) stream = util.item() stream["url"]=url stream["resolver"] = "viaplay" stream["lang"]=s["lang"] stream["quality"]="variant" stream["bitrate"]= "1000000" stream["name"]= title stream["desc"]=desc stream["type"]=stype stream["subs"] = captions print url if stype=="DASH": streams.append(stream) if stype == "HLS": # izvelkam individuālos strimus r = requests.get(url) result = re.findall("#EXT-X-STREAM-INF:BANDWIDTH=(\d+),RESOLUTION=(\d+x\d+)\n(\w+.m3u8)", r.content) if not result: continue for s2 in result: ### TODO vajag lietot cookie ar tokenu no playlista requesta if "set-cookie" in r.headers: headers = {"Cookie":r.headers["set-cookie"]} else: headers={} #url2 = re.sub(r"(http.*://.+/)\w+.m3u8", r"\1"+s2[2], url) url2 = "/".join(url.split("/")[:-1])+"/"+s2[2] #r2 = requests.get(url2,headers=headers) #if "set-cookie" in r2.headers: #headers = {"Cookie":r2.headers["set-cookie"]} #else: #headers={} #url2p=util.streamproxy_encode(url2,headers) stream = util.item() stream["url"]=url2 stream["lang"]=s["lang"] stream["quality"]="%s"%(s2[1]) stream["name"]= title stream["desc"]=desc stream["bitrate"]=s2[0] stream["type"]="DASH" if "dash" in s["type"] else "HLS" streams.append(stream) ### TODO - sakārtot sarakstu, lai pirmais ir labakais video qlist = ["","512","640","758","1024","variant"] llist = ["lt","et","fr","en","ru","lv"] for s in streams: lv = llist.index(s["lang"])*10000000 if s["lang"] in llist else 0 #qv=qlist.index(s["quality"]) if s["quality"] in qlist else 0 qv = int(s["bitrate"]) if s["bitrate"] else 0 s["order"] = lv+qv #print s["lang"],s["quality"],s["bitrate"],s["order"] streams = sorted(streams,key=lambda item: item["order"],reverse=True) return streams def call(self, data,params = None, headers=None): if not headers: headers = self.headers #if not lang: lang = self.country url = "https://viaplay.lv/tdi/" + data content = self._http_request(url, params, headers) return content if __name__ == "__main__": if len(sys.argv)>1: data= sys.argv[1] else: data = "kids/child-and-karlson" c = Source() print "login: %s"%c.login() if "/" in data: streams = c.get_streams(data) util.play_video(streams) else: vinfo = c.get_video_info(data) if "HLS" in vinfo["tracks"] and vinfo["tracks"]["HLS"]: url = vinfo["tracks"]["HLS"][0]["src"] urlp = util.streamproxy_encode(url) util.player(urlp) else: print "No HLS stream" sys.exit() r = requests.get("https://viaplay.lv/movies?sections[]=MOVIES") result = re.findall(r'
    .+?.+?

    ([^<]+)<', r.content, re.DOTALL) for item in result: vid = item[0] url = item[1] img = item[2] title = item[3] desc= item[4] print "\n%s (%s):"%(title,vid) vinfo = c.get_video_info(vid) if "HLS" in vinfo["tracks"]: for s in vinfo["tracks"]["HLS"]: print "HLS %s: \n%s"%(s["lang"],s["src"]) if "DASH" in vinfo["tracks"]: for s in vinfo["tracks"]["DASH"]: print "DASH %s: \n%s"%(s["lang"],s["src"]) #except Exception,ex: #print ex.message #content = c.get_content(data) #for item in content: # print item pass