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

euronews.py 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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, time,re, sys,os
  14. from collections import OrderedDict
  15. from SourceBase import SourceBase
  16. import util
  17. import ssl
  18. if "_create_unverified_context" in dir(ssl):
  19. ssl._create_default_https_context = ssl._create_unverified_context
  20. headers2dict = lambda h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
  21. import HTMLParser
  22. h = HTMLParser.HTMLParser()
  23. class Source(SourceBase):
  24. def __init__(self,language="en",cfg_path=None):
  25. self.name = "euronews"
  26. self.title = "Euronews"
  27. self.img = "http://pbs.twimg.com/profile_images/732665354242150400/tZsCnjuh_400x400.jpg"
  28. self.desc = "Euronews live and archive"
  29. self.headers = headers2dict("""
  30. User-Agent: Euronews/4.0.126
  31. Content-Type: application/json
  32. Connection: keep-alive
  33. """)
  34. #self.language=language
  35. cur_directory = os.path.dirname(os.path.abspath(__file__))
  36. if not cfg_path: cfg_path = cur_directory
  37. self.config_file = os.path.join(cfg_path,self.name+".cfg")
  38. self.options = OrderedDict([("language","en")])
  39. self.options_read()
  40. self.vid={"1": "News", "2": "European Affairs", "3": "Lifestyle", "4": "Knowledge"}
  41. self.languages = []
  42. try:
  43. self.get_languages()
  44. except:
  45. pass
  46. def login(self,user="",password=""):
  47. return True
  48. def get_content(self, data):
  49. print "[%s] get_content:"%self.name, data
  50. source,data,path,plist,clist,params,qs = self.parse_data(data)
  51. #lang = qs["lang"] if "lang" in qs else self.language
  52. lang = self.options["language"]
  53. if not lang in self.get_languages():
  54. raise Exception("Not valid default language - '%s'"%lang)
  55. content=[]
  56. content.append(("..return", "back","","Return back"))
  57. if clist=="home":
  58. content.extend([
  59. ("Search", "euronews::content/getSearch?lang=%s&byPage=40&page=1&text={0}"%lang,self.img,"Top stories timeline"),
  60. ("Live stream", "euronews::live?lang=%s"%lang,self.img,"Euronews live stream"),
  61. ("Just in", "euronews::content/getTimeline?lang=%s&byPage=40&page=1"%lang,self.img,"News timeline"),
  62. ("Top stories", "euronews::content/getTopStories?lang=%s"%lang,self.img,"Top stories timeline"),
  63. ("Category - News", "euronews::content/getVertical?lang=%s&byPage=40&page=1&vId=1"%lang,self.img,"Category - News"),
  64. ("Category - European Affairs", "euronews::content/getVertical?lang=%s&byPage=40&page=1&vId=2"%lang,self.img,"Category - European Affairs"),
  65. ("Category - Lifestyle", "euronews::content/getVertical?lang=%s&byPage=40&page=1&vId=3"%lang,self.img,"Category - Lifestyle"),
  66. ("Category - Knowledge", "euronews::content/getVertical?lang=%s&byPage=40&page=1&vId=4"%lang,self.img,"Category - Knowledge"),
  67. ("Latest programs", "euronews::content/getLatestPrograms?lang=%s&byPage=40&page=1"%lang,self.img,"Latest programs"),
  68. ("Programs list", "euronews::content/getPrograms?lang=%s"%lang,self.img,"Programs list"),
  69. ])
  70. return content
  71. ### Video arhīvs ###
  72. elif clist=="content":
  73. if "lang" in qs:
  74. del qs["lang"]
  75. params = json.dumps(qs)
  76. req = '{"methodName":"content.%s","apiKey":"androidPhoneEuronews-1.0","params":%s,"language":"%s"}'%(plist[1],params,lang)
  77. r = self.call(req)
  78. if not r:
  79. return content
  80. lst = r["timeline"] if "timeline" in r else\
  81. r["topstorieslist"] if "topstorieslist" in r else\
  82. r["programs"] if "programs" in r else\
  83. r["programDetailsList"] if "programDetailsList" in r else\
  84. r["programlist"] if "programlist" in r else\
  85. r["articlelist"] if "articlelist" in r else\
  86. r["verticals"] if "verticals" in r else\
  87. []
  88. if not lst:
  89. return content
  90. for item in lst:
  91. if plist[1] in ("getTimeline"):
  92. article = item["article"]
  93. atype = item["type"]
  94. if item["type"] == "wire":
  95. continue # TODO
  96. else:
  97. article = item
  98. atype = "article"
  99. if plist[1]=="getPrograms":
  100. title = article["title"]
  101. id = article["pId"]
  102. desc = title
  103. img = "http://static.euronews.com/articles/programs/533x360_%s"%article["img"]
  104. data2 = "content/getProgramDetails?lang=%s&byPage=40&page=1&pId=%s"%(lang,id)
  105. content.append((title,self.name+"::"+data2,img,desc))
  106. else:
  107. title = article["title"] if "title" in article else article["text"] if "text" in article else "No title"
  108. if atype <> "article":
  109. title = "[%s] %s"%(atype,title)
  110. atime = datetime.datetime.fromtimestamp(int(article["uts"]))
  111. #atime = datetime.datetime.fromtimestamp(int(article["uts"])-time.altzone)
  112. atime = atime.strftime("%Y-%m-%d %H:%M")
  113. vert = self.vid[article["vId"]] if "vId" in article else ""
  114. ptitle = article["pTitle"] if "pTitle" in article else ""
  115. id = article["id"]
  116. desc = "%s\n%s\n%s %s"%(title,atime,vert,ptitle)
  117. img = "http://static.euronews.com/articles/%s/399x225_%s.jpg"%(id,id)
  118. if not atype in ("breakingnews","wire"):
  119. data2 = "content/getArticle?lang=%s&id=%s"%(lang,id)
  120. else:
  121. data2 = ""
  122. content.append((title,self.name+"::"+data2,img,desc))
  123. if "page=" in data:
  124. data2 = re.sub("page=\d+","page=%s"%(int(qs["page"])+1),data)
  125. content.append(("Next page",self.name+"::"+data2,self.img,"Next page"))
  126. return content
  127. def is_video(self,data):
  128. source,data,path,plist,clist,params,qs = self.parse_data(data)
  129. if path == "live":
  130. return True
  131. elif clist=="content" and plist[1]=="getArticle":
  132. return True
  133. else:
  134. return False
  135. def get_streams(self, data):
  136. print "[euronews] get_streams:", data
  137. if not self.is_video(data):
  138. return []
  139. source,data,path,plist,clist,params,qs = self.parse_data(data)
  140. #lang = qs["lang"] if "lang" in qs else self.language
  141. lang = self.options["language"]
  142. if not lang in self.get_languages():
  143. raise Exception("Not valid default language - '%s'"%lang)
  144. streams = []
  145. if path == "live":
  146. url = "http://www.euronews.com/api/watchlive.json" if lang == "en" else "http://%s.euronews.com/api/watchlive.json" % lang
  147. r = self._http_request(url)
  148. try:
  149. js = json.loads(r)
  150. url = js["url"]
  151. except:
  152. raise Exception("No live stream found")
  153. r = self._http_request(url)
  154. try:
  155. js = json.loads(r)
  156. if not js["status"]=="ok":
  157. raise Exception("No live stream found")
  158. except:
  159. raise Exception("No live stream found")
  160. stream = util.item()
  161. stream["url"]=js["primary"]
  162. stream["lang"]= lang
  163. stream["quality"]="variant"
  164. stream["name"]="Euronews live [%s]"%lang
  165. stream["desc"]=stream["name"]
  166. stream["type"]="hls" #stream_type(url)
  167. streams.append(stream)
  168. elif clist=="content" and plist[1] == "getArticle":
  169. if "lang" in qs:
  170. del qs["lang"]
  171. languages = self.get_languages()
  172. for lang in languages:
  173. id = qs["id"]
  174. req = '{"methodName":"content.getArticle","apiKey":"androidPhoneEuronews-1.0","params":{"id":"%s"},"language":"%s"}'%(id,lang)
  175. r = self.call(req)
  176. if not r:
  177. raise Exception("No live stream found")
  178. if not "articlelist" in r:
  179. msg = r["label"] if "label" in r else "No article find"
  180. continue
  181. #raise Exception(msg)
  182. article = r["articlelist"]
  183. stream = util.item()
  184. stream["url"]=article["videoUri"] if "videoUri" in article else ""
  185. if not stream["url"]:
  186. return []
  187. stream["lang"]=lang
  188. stream["quality"]="?"
  189. stream["name"]= article["title"]
  190. stream["desc"]=article["text"] if "text" in article else article["title"]
  191. stream["type"]="http" #stream_type(url)
  192. streams.append(stream)
  193. else:
  194. raise Exception("No live stream found")
  195. ### TODO - sakārtot sarakstu, lai pirmais ir labakais video
  196. qlist = ["???","lq","mq","hq","hd","variant"]
  197. llist = ["fr","en","ru","lv"]
  198. for s in streams:
  199. if s["lang"]==self.options["language"]:
  200. s["order"] = 10000
  201. continue
  202. lv = llist.index(s["lang"])*10 if s["lang"] in llist else 0
  203. qv=qlist.index(s["quality"]) if s["quality"] in qlist else 0
  204. s["order"] = lv+qv
  205. streams = sorted(streams,key=lambda item: item["order"],reverse=True)
  206. return streams
  207. def get_languages(self):
  208. if self.languages: return self.languages
  209. url = "http://www.euronews.com/"
  210. r = self._http_request(url)
  211. result = re.findall(r'<option value="([^"]+)"\s*(selected)*\slang="([^"]+)" hreflang="([^"]+)">', r, re.DOTALL)
  212. languages = []
  213. for item in result:
  214. languages.append(item[3])
  215. if not languages:
  216. raise Exception("Can not get languages list")
  217. self.languages = languages
  218. return self.languages
  219. def get_languages0(self):
  220. if self.languages: return self.languages
  221. url = "http://www.euronews.com/api/watchlive.json"
  222. r = self._http_request(url)
  223. try:
  224. js = json.loads(r)
  225. url = js["url"]
  226. except:
  227. raise Exception("Can not get languages list")
  228. r = self._http_request(url)
  229. try:
  230. js = json.loads(r)
  231. if not js["status"]=="ok":
  232. raise Exception("Can not get languages list")
  233. except:
  234. raise Exception("Can not get languages list")
  235. slist = js["primary"]
  236. self.languages=slist.keys()
  237. return self.languages
  238. def call(self, data,params = None, headers=None):
  239. if not headers: headers = self.headers
  240. #if not lang: lang = self.country
  241. url = "http://api.euronews.com/ipad/"
  242. headers = headers2dict("""
  243. User-Agent: Euronews/4.0.126
  244. Content-Type: multipart/form-data, boundary=AaB03xBounDaRy; charset=UTF-8
  245. Host: api.euronews.com
  246. Connection: Keep-Alive
  247. """)
  248. params = """
  249. --AaB03xBounDaRy
  250. content-disposition: form-data; name=request
  251. %s
  252. --AaB03xBounDaRy--
  253. """%data
  254. content = self._http_request(url, params, headers)
  255. if content:
  256. try:
  257. result = json.loads(content)
  258. return result
  259. except Exception, ex:
  260. return None
  261. else:
  262. return None
  263. if __name__ == "__main__":
  264. language= "en"
  265. c = Source(language)
  266. data = '{"methodName":"content.getTimeline","apiKey":"androidPhoneEuronews-1.0","params":{"page":"1","byPage":"30"},"language":"en"}'
  267. r = c.call(data)
  268. if len(sys.argv)>1:
  269. data= sys.argv[1]
  270. else:
  271. data = "home"
  272. content = c.get_content(data)
  273. for item in content:
  274. print item
  275. pass