Python module (submodule repositary), which provides content (video streams) from various online stream sources to corresponding Enigma2, Kodi, Plex plugins

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. #!/usr/bin/env python
  2. # coding=utf8
  3. #
  4. # This file is part of PlayStream - enigma2 plugin to play video streams from various sources
  5. # Copyright (c) 2016 ivars777 (ivars777@gmail.com)
  6. # Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
  7. #
  8. try:
  9. import json
  10. except:
  11. import simplejson as json
  12. import urllib2, urllib
  13. import datetime, re, sys,os
  14. from collections import OrderedDict
  15. import ssl
  16. if "_create_unverified_context" in dir(ssl):
  17. ssl._create_default_https_context = ssl._create_unverified_context
  18. from SourceBase import SourceBase
  19. import util
  20. headers2dict = lambda h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
  21. headers0 = headers2dict("""
  22. User-Agent: Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.04
  23. Accept: application/json, text/javascript, */*; q=0.01
  24. Accept-Language: en-US,en;q=0.5
  25. Accept-Encoding: gzip, deflate, br
  26. Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  27. X-Requested-With: XMLHttpRequest""")
  28. import HTMLParser
  29. h = HTMLParser.HTMLParser()
  30. class Source(SourceBase):
  31. def __init__(self,country="lv",cfg_path=None):
  32. self.name = "tvdom"
  33. self.title = "TVDom.tv"
  34. self.img = "tvdom.png"
  35. self.desc = "TVDom.tv portāla satura skatīšanās"
  36. self.headers = headers0
  37. self.url = "https://tvdom.tv/"
  38. self.country=country
  39. self.session = None
  40. self.token = None
  41. cur_directory = os.path.dirname(os.path.abspath(__file__))
  42. if not cfg_path: cfg_path = cur_directory
  43. self.config_file = os.path.join(cfg_path,self.name+".cfg")
  44. self.options = OrderedDict([("user","lietotajs"),("password","parole"), ("region", "lv"), ("lang", "lv")])
  45. self.options_read()
  46. def login(self,user="",password=""):
  47. self.options_read()
  48. if not user: user=self.options["user"]
  49. if not password: password = self.options["password"]
  50. headers = headers2dict("""
  51. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0
  52. Accept: */*
  53. Accept-Language: en-US,en;q=0.5
  54. Accept-Encoding: gzip, deflate, br
  55. Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  56. X-Requested-With: XMLHttpRequest
  57. Referer: https://tvdom.tv/
  58. """)
  59. url = "https://tvdom.tv/infinity/on_register_user"
  60. params = "email=%s&password=%s&remember=false&auth_type=login"%(user,password)
  61. import requests
  62. try:
  63. from requests.packages.urllib3.exceptions import InsecureRequestWarning
  64. requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
  65. except:
  66. pass
  67. r = requests.post(url, data=params, headers=headers)
  68. js = json.loads(r.content)
  69. if 'success' in r.content:
  70. self.token = js["access_token"]
  71. if 'PHPSESSID' in r.cookies:
  72. self.session = r.cookies["PHPSESSID"]
  73. return True
  74. else:
  75. raise Exception(js["error"])
  76. def get_content(self, data):
  77. print "[tvdom] get_content:", data
  78. source,data,path,plist,clist,params,qs = self.parse_data(data)
  79. lang = self.options["lang"]
  80. region = self.options["region"]
  81. content=[]
  82. content.append(("..return", "back","back.png","Return back"))
  83. if clist=="home":
  84. content.extend([
  85. ("Live stream", "tvdom::tiesraides","","TV live streams"),
  86. ("Archive - last", "tvdom::arhivs?filter=new&page=0&limit=30&region=%s&language=%s" % (region, lang),"","Video archive - last videos"),
  87. ("Archive - popular", "tvdom::arhivs?filter=new&page=0&limit=30&region=%s&language=%s"% (region, lang),"","Video archive - popular video"),
  88. ("Archive - categories", "tvdom::arhivs","","Video archive by categories"),
  89. ("Search", "tvdom::search/?srch-term={0}","","Search archive"),
  90. #("Archive - all", "tvdom::arhivs_all","","Video archive all"),
  91. ])
  92. return content
  93. ### Tiesraides kanalu saraksts ###
  94. elif data=="tiesraides":
  95. data1 = "infinity/on_front_filter_channels_list.json"
  96. params = "hd=&language=%s&region=%s" % (self.options["lang"], self.options["region"])
  97. r = self.call_json(data1, params)
  98. for genre in r["data"]:
  99. for item in r["data"][genre]:
  100. ch = item["channel_name"]
  101. title = u"%s - %s" % (item["channel_name"], item["program_title"])
  102. img = "https://tvdom.tv"+item["channel_logo"]
  103. data2 = item["program_url"][1:]
  104. desc = u"%s\n%s-%s"%(title,item["time_start"],item["time_stop"])
  105. content.append((title,self.name+"::"+data2,img,desc))
  106. return content
  107. # elif clist == "tiesraides":
  108. # if not self.session:
  109. # self.login()
  110. # url = "https://tvdom.tv/" + data
  111. # headers = self.headers
  112. # headers["Cookie"] = "PHPSESSID=%s; neverending_story=1;"%self.session
  113. # r = self._http_request(url,headers=headers)
  114. # m = re.search("var streamConnectionUrl = '([^']+)'", r, re.DOTALL)
  115. # if m:
  116. # data2 = m.group(1)
  117. # else:
  118. # return ("No stream found %s"%data,"","","No stream found")
  119. # m = re.search('title: "([^"]+)"', r, re.DOTALL)
  120. # title = m.group(1) if m else data2
  121. # m = re.search('<div id="panel">([^<]+)<', r, re.DOTALL)
  122. # desc = m.group(1) if m else title
  123. # m = re.search('<div id="panel">([^<]+)<', r, re.DOTALL)
  124. # desc = m.group(1) if m else title
  125. # m = re.search('var promo_image *= "([^"]+)', r, re.DOTALL)
  126. # img = m.group(1) if m else ""
  127. # return (title,data2,img,desc)
  128. ### Search ###
  129. elif clist=="search":
  130. url = "https://tvdom.tv/" + data
  131. r = self._http_request(url)
  132. result = re.findall(r'<div class="film-block_img">\s*<img src="([^"]+).+?<a href="/([^"]+)">([^<]+)</a>\s*</div>\s*<ul class="film-block_descr_tag">\s*<li><a href="">([^<]+)</a>', r, re.DOTALL)
  133. for item in result:
  134. title = item[2] + " ("+ item[3] + ")"
  135. title = h.unescape(title.decode("utf8")).encode("utf8")
  136. img = "https://tvdom.tv" + item[0]
  137. data2 = item[1]
  138. desc = title
  139. content.append((title,self.name+"::"+data2,img,desc))
  140. return content
  141. ### Arhīva kategorijas ###
  142. elif data=="arhivs":
  143. url = "https://tvdom.tv/"+data
  144. headers = self.headers
  145. headers["Cookie"] = "neverending_story=1; user_selected_language=%s"% (self.options["lang"])
  146. r = self._http_request(url)
  147. result = re.findall(r'data-text-mobile="(.+?)" data-id="(\d+)" data-filter-type="archive_genre">', r)
  148. for item in result:
  149. title = item[0]
  150. img = ""
  151. data2 = "arhivs?" + "genre1=%s&filter=new&region=%s&lang=%s&page=0&limit=30" % (item[1], region, lang)
  152. desc = title
  153. content.append((title,self.name+"::"+data2,img,desc))
  154. return content
  155. ### Arhīva kategorijas programmas ###
  156. elif clist=="arhivs":
  157. data1 = "infinity/on_front_archive_get_events2.json"
  158. r = self.call_json(data1, params[1:])
  159. for item in r["data"]:
  160. title = item["title"] + "- " + item["online_time"]
  161. img = "https://tvdom.tv"+item["image"]
  162. data2 = item["url"][1:]
  163. desc = u"%s\nlast: %s\npopularity: %s\n%s" % (title, item["online_time"], item["popularity"], item["channel_code"])
  164. content.append((title,self.name+"::"+data2,img,desc))
  165. if len(r["data"]) == 30:
  166. page = int(qs["page"]) + 1
  167. data2 = re.sub("page=\d+", "page=%s" % page, data)
  168. content.append(("Next page",self.name+"::"+data2,"","Go to next page"))
  169. return content
  170. ### Arhīva programmas video saraksts ###
  171. elif clist=="play_arhivs" and len(data.split("/"))==3 and not re.search("_\d+",plist[2]):
  172. url = "https://tvdom.tv/"+data
  173. r = self._http_request(url)
  174. vid=re.search('materialIdentifier":"(\d+)', r, re.DOTALL).group(1)
  175. pname = re.split("[_\.\-]", plist[-1])[0]
  176. data2 = data+"_"+vid
  177. m = re.search(r'var program_title\s*= "(.+?)"', r)
  178. title = title0 = m.group(1) if m else data2
  179. m = re.search('<p class="content-info__descr-item">(.+?)</p>', r, re.DOTALL)
  180. datums = m.group(1).strip() if m else ""
  181. title = title + " " + datums
  182. m = re.search('<p class="video-player__descr-text" style="height: 100px;">(.+?)<span', r, re.DOTALL)
  183. desc = m.group(1).strip() if m else title
  184. m = re.search('var share_image\s*= "([^"]+)', r, re.DOTALL)
  185. img = m.group(1) if m else ""
  186. content.append((title,self.name+"::"+data2,img,desc))
  187. i2 = r.find("content content--indent-pb")
  188. r2 = r if i2 == -1 else r[:i2]
  189. result = re.findall(r'<img src="([^"]+)" class="content-item__image" alt=""><a href="/([^"]+)" class="content-item__hide-info">.+?<h3 class="content-item__name">\s*<a href="#">\s*([^<]*)\s*<br>\s*([^<]*)\s*</a>\s*</h3>', r2, re.DOTALL)
  190. for item in result:
  191. #if pname not in item[1]:
  192. # continue
  193. title = item[2] + " " + item[3].strip()
  194. title = h.unescape(title.decode("utf8")).encode("utf8")
  195. img = "https://tvdom.tv"+item[0]
  196. data2 = item[1]
  197. desc = title # TODO
  198. content.append((title,self.name+"::"+data2,img,desc))
  199. return content
  200. ### Arhīva video
  201. # elif clist=="play_arhivs" and len(data.split("/"))==3 and re.search("_\d+",plist[2]):
  202. # url = "https://tvdom.tv/" + data
  203. # headers = self.headers
  204. # headers["Cookie"] = "PHPSESSID=%s; neverending_story=1;"%self.session
  205. # r = self._http_request(url,headers=headers)
  206. # m = re.search('var streamConnectionUrl = "([^"]+)"', r, re.DOTALL)
  207. # if m:
  208. # data2 = m.group(1)
  209. # else:
  210. # return ("No stream found %s"%data,"","","No stream found")
  211. # m = re.search('program_title = "([^"]+)"', r, re.DOTALL)
  212. # title = m.group(1) if m else data2
  213. # m = re.search('<a class="episode">Pārraides laiks ēterā: <span>([^<]+)</span></a>', r, re.DOTALL)
  214. # datums = m.group(1) if m else ""
  215. # title = title + " " + datums
  216. # m = re.search('<div id="panel">([^<]+)<', r, re.DOTALL)
  217. # desc = m.group(1) if m else title
  218. # m = re.search('<div id="panel">([^<]+)<', r, re.DOTALL)
  219. # desc = m.group(1) if m else title
  220. # m = re.search('var share_image *= "([^"]+)', r, re.DOTALL)
  221. # img = m.group(1) if m else ""
  222. # return (title,data2,img,desc)
  223. def get_streams(self,data):
  224. print "[tvdom] get_streams:", data
  225. if not self.is_video(data):
  226. return []
  227. source,data,path,plist,clist,params,qs = self.parse_data(data)
  228. if not self.session:
  229. self.login()
  230. url = "https://tvdom.tv/" + data
  231. headers = self.headers
  232. headers["Cookie"] = "PHPSESSID=%s; neverending_story=1;"%self.session
  233. r = self._http_request(url,headers=headers)
  234. if clist == "play_arhivs":
  235. m = re.search('program_title = "([^"]+)"', r, re.DOTALL)
  236. title = m.group(1) if m else data2
  237. m = re.search('<a class="episode">Pārraides laiks ēterā: <span>([^<]+)</span></a>', r, re.DOTALL)
  238. datums = m.group(1) if m else ""
  239. title = title + " " + datums
  240. m = re.search('<div id="panel">([^<]+)<', r, re.DOTALL)
  241. desc = m.group(1) if m else title
  242. m = re.search('<div id="panel">([^<]+)<', r, re.DOTALL)
  243. desc = m.group(1) if m else title
  244. m = re.search('var share_image *= "([^"]+)', r, re.DOTALL)
  245. img = m.group(1) if m else ""
  246. m = re.search(r"var streams\s*= ({[^;]+);", r, re.DOTALL)
  247. if not m:
  248. raise Exception("No stream found")
  249. js = json.loads(m.group(1))
  250. streams = []
  251. for st in js:
  252. if st == "qualities": continue
  253. s = js[st]
  254. data2 = s["url"]
  255. stream = util.item()
  256. stream["name"] = title
  257. stream["url"] = data2
  258. stream["img"] = img
  259. stream["desc"] = desc
  260. stream["resolver"] = "tvdom"
  261. stream["quality"] = st
  262. stream["order"] = int(st[:-1])
  263. streams.append(stream)
  264. streams = sorted(streams,key=lambda item: item["order"],reverse=True)
  265. return streams
  266. # Tiešraides video
  267. else:
  268. #m = re.search("var streamConnectionUrl = '([^']+)'", r, re.DOTALL)
  269. m = re.search(r"sources: (\[.+?\]),", r, re.DOTALL)
  270. if m:
  271. js = json.loads(m.group(1))
  272. data2 = js[0]["src"]
  273. else:
  274. if "no_player_body" in r:
  275. raise Exception("Lai skatītos maksas kanālus, nepieciešams iegādāties abonementu")
  276. else:
  277. raise Exception("No stream found")
  278. m = re.search('title: "([^"]+)"', r, re.DOTALL)
  279. title = m.group(1) if m else data2
  280. m = re.search('<div class="fp-descr">([^<]+)<', r, re.DOTALL)
  281. desc = m.group(1).strip() if m else title
  282. m = re.search('class="content-item content-item--on-air catchUpEvent".+?<img src="(.+?)"', r, re.DOTALL)
  283. img = "https://tvdom.tv" + m.group(1) if m else ""
  284. stream = util.item()
  285. stream["name"] = title
  286. stream["url"] = data2
  287. stream["img"] = img
  288. stream["desc"] = desc
  289. stream["resolver"] = "tvdom"
  290. return [stream]
  291. def is_video(self,data):
  292. source,data,path,plist,clist,params,qs = self.parse_data(data)
  293. cmd = data.split("/")
  294. if cmd[0] in ("tiesraides") and len(cmd)>1:
  295. return True
  296. elif cmd[0]=="play_arhivs" and len(cmd)==3 and re.search("_\d+",plist[2]):
  297. return True
  298. else:
  299. return False
  300. if __name__ == "__main__":
  301. sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
  302. import run
  303. source = Source()
  304. data= sys.argv[1] if len(sys.argv)>1 else source.name+"::home"
  305. run.run(source, data)
  306. sys.exit()