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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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. import ConfigParser
  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. headers2dict = lambda h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
  20. import HTMLParser
  21. h = HTMLParser.HTMLParser()
  22. class Source(SourceBase):
  23. def __init__(self,country="",cfg_path=None):
  24. self.hidden = True # nerāda menu nestrādājošos avotus
  25. self.name = "serialguru"
  26. self.title = "SerialGURU.ru"
  27. self.img = "http://serialguru.ru/images/xlogo_new.png.pagespeed.ic.0sre2_2OJN.png"
  28. self.desc = "Serialguru.ru portāla satura skatīšanās"
  29. self.country=country
  30. self.headers = headers2dict("""
  31. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36
  32. Referer: http://serialguru.ru/
  33. """)
  34. self.headers2 = headers2dict("""
  35. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36
  36. X-Requested-With: XMLHttpRequest
  37. Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  38. Referer: http://serialguru.ru/
  39. """)
  40. self.url = "http://serialguru.ru/"
  41. #self.login()
  42. def login(self,user="",password=""):
  43. return True
  44. def get_content(self, data):
  45. print "[tvdom] get_content:", data
  46. if "::" in data:
  47. data = data.split("::")[1]
  48. path = data.split("?")[0]
  49. clist = path.split("/")[0]
  50. params = data[data.find("?"):] if "?" in data else ""
  51. qs = dict(map(lambda x:x.split("="),re.findall("[%\w]+=\w+",params)))
  52. lang = qs["lang"] if "lang" in qs else self.country
  53. content=[]
  54. content.append(("..return", "back","","Return back"))
  55. if clist=="home":
  56. content.extend([
  57. ("Search", "serialguru::search/{0}","","Search content"),
  58. ("Last", "serialguru::last","","Last series"),
  59. ("Series", "serialguru::serials","","TV Series"),
  60. ("Shows", "serialguru::tv","","TV Shows"),
  61. ("Animations", "serialguru::mult","","Animation series"),
  62. #("Archive - all", "tvdom::arhivs_all","","Video archive all"),
  63. ])
  64. return content
  65. elif data == "last":
  66. r = self.call("")
  67. for item in re.findall(r'<li><a href="(http://serialguru\.ru/[^"]+)"><i>([^<]+)</i> <i>([^<]+)</i> <b>([^<]+)</b></a></li>', r, re.DOTALL):
  68. title = item[1] + " - " + item[2]+"/"+item[3]
  69. img = ""
  70. data2 = item[0].replace(self.url, "")
  71. desc = title
  72. content.append((title, self.name+"::"+data2, img, desc))
  73. return content
  74. elif data=="serials":
  75. content.extend([
  76. ("All", "serialguru::serials?o=0&t=S","","All series"),
  77. ("Russian", "serialguru::serials?c%5B%5D=53&c%5B%5D=61&c%5B%5D=33&c%5B%5D=42&c%5B%5D=31&o=0&t=S","","Russian countries series"),
  78. ("English", "serialguru::serials?c%5B%5D=27&c%5B%5D=26&c%5B%5D=43&c%5B%5D=30&c%5B%5D=34&c%5B%5D=25&o=0&t=S","","English countries series"),
  79. ("Europe", "serialguru::serials?c%5B%5D=29&c%5B%5D=66&c%5B%5D=44&c%5B%5D=28&c%5B%5D=51&c%5B%5D=65&c%5B%5D=62&c%5B%5D=40&c%5B%5D=45&c%5B%5D=68&c%5B%5D=59&c%5B%5D=39&c%5B%5D=35&c%5B%5D=47&o=0&t=S","","European countries series"),
  80. ("Other", "serialguru::serials?c%5B%5D=36&c%5B%5D=32&c%5B%5D=67&c%5B%5D=63&c%5B%5D=60&c%5B%5D=64&c%5B%5D=38&c%5B%5D=52&c%5B%5D=41&c%5B%5D=58&c%5B%5D=57&c%5B%5D=37&c%5B%5D=50&c%5B%5D=46&o=0&t=S","","Other countries series"),
  81. #("Archive - all", "tvdom::arhivs_all","","Video archive all"),
  82. ])
  83. return content
  84. elif data=="tv":
  85. content.extend([
  86. ("All", "serialguru::tv?o=0&t=S","","All series"),
  87. ("Russian", "serialguru::tv?c%5B%5D=53&c%5B%5D=61&c%5B%5D=33&c%5B%5D=42&c%5B%5D=31&o=0&t=P","","Russian countries TV shows"),
  88. ("English", "serialguru::tv?c%5B%5D=27&c%5B%5D=26&c%5B%5D=43&c%5B%5D=30&c%5B%5D=34&c%5B%5D=25&o=0&t=P","","English countries TV shows"),
  89. ("Europe", "serialguru::tv?c%5B%5D=29&c%5B%5D=66&c%5B%5D=44&c%5B%5D=28&c%5B%5D=51&c%5B%5D=65&c%5B%5D=62&c%5B%5D=40&c%5B%5D=45&c%5B%5D=68&c%5B%5D=59&c%5B%5D=39&c%5B%5D=35&c%5B%5D=47&o=0&t=P","","European countries TV shows series"),
  90. ("Other", "serialguru::tv?c%5B%5D=36&c%5B%5D=32&c%5B%5D=67&c%5B%5D=63&c%5B%5D=60&c%5B%5D=64&c%5B%5D=38&c%5B%5D=52&c%5B%5D=41&c%5B%5D=58&c%5B%5D=57&c%5B%5D=37&c%5B%5D=50&c%5B%5D=46&o=0&t=P","","Other countries TV shows"),
  91. #("Archive - all", "tvdom::arhivs_all","","Video archive all"),
  92. ])
  93. return content
  94. elif data=="mult":
  95. content.extend([
  96. ("All", "serialguru::mult?o=0&t=S","","All series"),
  97. ("Russian", "serialguru::mult?c%5B%5D=53&c%5B%5D=61&c%5B%5D=33&c%5B%5D=42&c%5B%5D=31&o=0&t=M","","Russian countries animantions"),
  98. ("English", "serialguru::mult?c%5B%5D=27&c%5B%5D=26&c%5B%5D=43&c%5B%5D=30&c%5B%5D=34&c%5B%5D=25&o=0&t=M","","English countries animantions"),
  99. ("Europe", "serialguru::mult?c%5B%5D=29&c%5B%5D=66&c%5B%5D=44&c%5B%5D=28&c%5B%5D=51&c%5B%5D=65&c%5B%5D=62&c%5B%5D=40&c%5B%5D=45&c%5B%5D=68&c%5B%5D=59&c%5B%5D=39&c%5B%5D=35&c%5B%5D=47&o=0&t=M","","European countries animantions"),
  100. ("Other", "serialguru::mult?c%5B%5D=36&c%5B%5D=32&c%5B%5D=67&c%5B%5D=63&c%5B%5D=60&c%5B%5D=64&c%5B%5D=38&c%5B%5D=52&c%5B%5D=41&c%5B%5D=58&c%5B%5D=57&c%5B%5D=37&c%5B%5D=50&c%5B%5D=46&o=0&t=M","","Other countries animantions"),
  101. #("Archive - all", "tvdom::arhivs_all","","Video archive all"),
  102. ])
  103. return content
  104. elif clist=="search":
  105. if data.split("/")>1:
  106. term = data.split("/")[1]
  107. else:
  108. return content
  109. r = self.call("main/autocomplete?term=%s"%(term))
  110. if r=="null":
  111. return content
  112. js = json.loads(r)
  113. for item in js:
  114. title = item["name"].encode("utf8")
  115. data2 = item["url"].encode("utf8")
  116. img = "http://serialguru.ru/uploads/cover/"+item["image_s"].replace("_s","")+".jpg"
  117. rating = item["rating"].encode("utf8") if item["rating"] else ""
  118. desc = title +"\nRating:%s (%s+/%s-)"%(rating,item["plus_cnt"].encode("utf8"),item["minus_cnt"].encode("utf8"))
  119. content.append((title,self.name+"::"+data2,img,desc))
  120. return content
  121. elif path=="serials" or path=="tv" or path=="mult":
  122. if path=="serials" and not "cat%5B%5D" in data:
  123. #content.append(("All", "serialguru::"+data+"&cat%5B%5D=","","All series"))
  124. categories = self.get_categories(path)
  125. for c in categories:
  126. content.append((c[1], "serialguru::"+data+"&cat%5B%5D="+c[0],"",c[1]))
  127. return content
  128. else:
  129. r = self.call("main/load", params[1:], headers=self.headers2)
  130. for item in re.findall('<li><a href="([^"]+)"><div>.*?<img src="([^"]+)" alt="([^"]+)"[^<]*?><p>([^<]+)<i><span class="r">([^<]+)</span> <span class="plus">([^<]+)</span> <span class="minus">([^<]+)</span></i></p></div>([^<]+)</a></li>', r, re.DOTALL):
  131. title = "%s (%s)"%(item[2],item[3])
  132. img = item[1].replace("_s.jpg","_l.jpg")
  133. data2 = item[0].replace(self.url,"")
  134. desc = title +"\nRating:%s (%s+/%s-)"%(item[4],item[5],item[6])
  135. content.append((title,self.name+"::"+data2,img,desc))
  136. page=int(re.search("o=(\d+)",data).group(1))
  137. data2 = re.sub("o=(\d+)","o=%s"%(page+15),data)
  138. content.append(("Next page",self.name+"::"+data2,"","Go to next page"))
  139. return content
  140. ### Pārraide
  141. else:
  142. r = self.call(clist)
  143. title0=re.search('<h2>(.+?)</h2>',r,re.DOTALL).group(1)
  144. m=re.search('<div class="description">(.+?)</div>',r,re.DOTALL)
  145. desc0=m.group(1) if m else ""
  146. desc0=desc0.replace("<p>","").replace("</p>","\n").replace('<a href="#">ПОКАЗАТЬ ПОЛНОСТЬЮ</a>',"")
  147. desc0=title0+"\n"+desc0.strip()
  148. img0=""
  149. m = re.search("http://serialguru.ru/main/playlist/\d+",r)
  150. if m:
  151. url = m.group()
  152. else:
  153. raise Exception ("No stream found")
  154. r = self._http_request(url)
  155. js = json.loads(r,"utf8")
  156. if not "/" in data: # sezonas
  157. for i,item in enumerate(js["playlist"]):
  158. title = title0 + " - " + item["comment"].encode("utf8")
  159. img = img0
  160. data2 = "%s/%s"%(data,i)
  161. desc = desc0
  162. content.append((title,self.name+"::"+data2,img,desc))
  163. else:
  164. snum = int(data.split("/")[1])
  165. title1 = js["playlist"][snum]["comment"].encode('utf8')
  166. for i,item in enumerate(js["playlist"][snum]["playlist"]):
  167. title = title0 + " - " + title1+"/"+item["comment"].encode("utf8")
  168. img = img0
  169. data2 = item["file"].encode("utf8")
  170. desc = desc0
  171. content.append((title,data2,img,desc))
  172. return content
  173. def is_video(self,data):
  174. if "::" in data:
  175. data = data.split("::")[1]
  176. if "live/view" in data:
  177. return True
  178. else:
  179. return False
  180. def get_categories(self,data):
  181. r = self.call(data)
  182. r2 = re.search('<td class="category">(.+?)</td>', r, re.DOTALL).group(1)
  183. items = re.findall(r'<a href="#" data-id="(\d+)">([^<]+)</a>', r2, re.DOTALL)
  184. return items
  185. def call(self, data,params = None, headers=None):
  186. if not headers: headers = self.headers
  187. #if not lang: lang = self.country
  188. url = self.url + data
  189. content = self._http_request(url,params, headers)
  190. return content
  191. if __name__ == "__main__":
  192. country= "lv"
  193. c = Source(country)
  194. if len(sys.argv)>1:
  195. data= sys.argv[1]
  196. else:
  197. data = "home"
  198. content = c.get_content(data)
  199. for item in content:
  200. print item
  201. #cat = api.get_categories(country)
  202. #chan = api.get_channels("lv")
  203. #prog = api.get_programs(channel=6400)
  204. #prog = api.get_programs(category=55)
  205. #seas = api.get_seasons(program=6453)
  206. #str = api.get_streams(660243)
  207. #res = api.get_videos(802)
  208. #formats = api.getAllFormats()
  209. #det = api.detailed("1516")
  210. #vid = api.getVideos("13170")
  211. pass