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

ltc.py 52KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113
  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. import sys, os, os.path, re, sys
  9. import urllib,urllib2,urlparse
  10. #from xml.sax.saxutils import unescape,escape
  11. from urllib import quote, unquote
  12. import datetime
  13. import HTMLParser
  14. import json
  15. from SourceBase import SourceBase, stream_type
  16. import util
  17. from util import unescape
  18. from collections import OrderedDict
  19. import ssl
  20. if "_create_unverified_context" in dir(ssl):
  21. ssl._create_default_https_context = ssl._create_unverified_context
  22. user_agent = "Mozilla/5.0 (iPhone; U; CPU iPhone OS 5_1_1 like Mac OS X; da-dk) AppleWebKit/534.46.0 (KHTML, like Gecko) CriOS/19.0.1084.60 Mobile/9B206 Safari/7534.48.3"
  23. headers2dict = lambda h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
  24. h = HTMLParser.HTMLParser()
  25. class Source(SourceBase):
  26. def __init__(self,cfg_path=None):
  27. self.name = "ltc"
  28. self.title = "Shortcut.lv (lattelecom.tv)"
  29. self.img = "shortcut.png"
  30. self.desc = "Shortcut.lv (lattelecom.tv) satura skatīšanās"
  31. self.token = "" # manstv.lattelecom.tv
  32. self.session_id = "" # www.shortcut.lv
  33. self.api_url = "https://manstv.lattelecom.tv/api/v1.4/get/"
  34. self.api_url2 = "https://www.shortcut.lv/"
  35. self.headers = headers2dict("""
  36. User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.4.2; SM-G900FD Build/KOT49H)
  37. Host: manstv.lattelecom.tv
  38. Connection: Keep-Alive
  39. """)
  40. self.headers2 = headers2dict("""
  41. Connection: keep-alive
  42. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
  43. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36
  44. Accept-Language: en-US,en;q=0.8
  45. """)
  46. self.channels = None
  47. ### specific service info ###
  48. self.ch = []
  49. self.ch2 = []
  50. self.ch_id={}
  51. self.ch_id2={}
  52. self.ch_name={}
  53. self.epg=[]
  54. self.epg_id={}
  55. self.epg_id2={}
  56. self.epg_date={}
  57. self.epg_ch={}
  58. self.epgdates = []
  59. self.today = datetime.date.today()
  60. self.today2 = self.today.strftime("%d.%m.%Y")
  61. cur_directory = os.path.dirname(os.path.abspath(__file__))
  62. if not cfg_path: cfg_path = cur_directory
  63. self.config_file = os.path.join(cfg_path,self.name+".cfg")
  64. self.options = OrderedDict([("user","lietotajs"),("password","parole")])
  65. self.options_read()
  66. def get_content(self, data):
  67. print "[ltc] get_content:", data
  68. source, data, path, plist, clist, params, qs = self.parse_data(data)
  69. content=[]
  70. content.append(("..return", "back","back.png","Return back"))
  71. if clist=="home":
  72. content.extend([
  73. #("Meklēt TV arhīvā", "ltc::search/{0}","","Meklēt TV arhīvā"), #TODO
  74. ("Meklēt filmas", "ltc::viss/search/?cat=movies&q={0}","","Meklēt filmu sadaļā"),
  75. ("Meklēt seriālus", "ltc::viss/search/?cat=series&q={0}","","Meklēt seriālu sadaļā"),
  76. ("TV tiešraides", "ltc::tiesraide","","TV tiesraides"),
  77. ("TV arhīvs", "ltc::arhivs","","TV arhīvs atseviškiem kanāliem"),
  78. ("Videonoma", "ltc::videonoma","","Filmas (ari Priemiere) un seriāli"),
  79. ])
  80. return content
  81. ### Meklēt TV (1.4 API)
  82. elif clist == "search": #TODO vod/search/{q}
  83. #r = self.call("vod/"+data)
  84. return content
  85. ### Meklēsana video (www )###
  86. elif path == 'viss/search/': #TODO vod/search/{q}
  87. r = self.call2(data)
  88. if "cat=movies" in data:
  89. result = re.findall('class="forward-link" href="/([^"]+)">(<div class="new-movie">Premiere</div>)*<img src="([^"]+)".+?class="categorie-one-title">([^<]+)<', r, re.MULTILINE)
  90. else:
  91. result = re.findall('class="forward-link" href="/([^"]+)">(<div class="new-movie">Premiere</div>)*<img src="([^"]+)".+?class="categorie-one-title">([^<]+)<', r, re.MULTILINE)
  92. for item in result:
  93. title = item[3]
  94. if not item[1]:
  95. title = title + "[P]"
  96. data2 = item[0][0:-1]
  97. img = "https://www.shortcut.lv" + item[2]
  98. desc = title
  99. content.append((title,self.name+"::"+data2,img,desc))
  100. return content
  101. ### Tiešraides kanānālu saraksts ###
  102. elif data=="tiesraide":
  103. #r = self.call2(data)
  104. #m = re.search("var xprs_ides_array = (.+);", r, re.MULTILINE)
  105. #if m:
  106. # js=json.loads(m.group(1))
  107. #else:
  108. # raise Exception("Error reading channel list")
  109. r = self.call2("program-snippet.json")
  110. try:
  111. js = json.loads(r)
  112. except:
  113. js = {}
  114. for item in self.get_channels():
  115. if item["live"]=='0':continue
  116. title = item["name"]
  117. data2 = "content/live-streams/%s?include=quality"%item["id"]
  118. if item["xprs_id"] in js:
  119. epg = js[item["xprs_id"]]
  120. desc = "%s - %s (%s-%s)"%(title,epg[0]["t"],epg[0]["hs"],epg[0]["he"])
  121. title = desc
  122. img = "https://www.shortcut.lv" + epg[0]["p"]
  123. #img = "https://manstv.shortcut.lv/"+ item['broadcast_default_picture']
  124. else:
  125. img = "https://manstv.shortcut.lv/"+ item['broadcast_default_picture']
  126. desc = title
  127. content.append((title,self.name+"::"+data2,img,desc))
  128. return content
  129. ### TV arhīva sākums ###
  130. elif data=="archive" or data=="arhivs":
  131. #self.get_epg()
  132. content.extend([
  133. ("Archive - categories", "ltc::archive/categories","","TV live archive by categories"),
  134. ("Archive - channels", "ltc::archive/channels","","TV live archive by channels"),
  135. #("Archive - dates", "ltc::archive/dates","","TV live archive by dates"),
  136. ])
  137. return content
  138. ### Arhīva kategorijas
  139. elif data=="archive/categories":
  140. #https://manstv.lattelecom.tv/api/v1.3/get/archive/records/?filter[category]=13&limit=10&until_id=1458681019238
  141. #https://manstv.lattelecom.tv/api/v1.3/get/archive/categories/
  142. r = self.call(data)
  143. for item in r["items"]:
  144. title = item["name"]
  145. data2 = "archive/records?filter[category]=%s&limit=40"%item["id"]
  146. img = "https://manstv.lattelecom.tv/"+ item['image']
  147. desc = title
  148. content.append((title,self.name+"::"+data2,img,desc))
  149. return content
  150. ### Arhīva kategoriju video
  151. elif "archive/records" in data:
  152. #https://manstv.lattelecom.tv/api/v1.3/get/archive/records/?filter[category]=13&limit=10&until_id=1458681019238
  153. #https://manstv.lattelecom.tv/api/v1.3/get/archive/categories/
  154. r = self.call(data)
  155. for i,item in enumerate(r["items"]):
  156. #if not item["is_archive"]==u"1":continue # TODO jānočeko, kurs no atributiem apzīmē, ka ir arhīvs
  157. if not self.epg_id.has_key(item["id"]):
  158. item["time_start2"] = datetime.datetime.fromtimestamp(int(item["unix_start"]))
  159. item["time_stop2"] = datetime.datetime.fromtimestamp(int(item["unix_stop"]))
  160. item["date"]=item["time_start2"].strftime("%Y-%m-%d")
  161. self.epg.append(item)
  162. index = self.epg.index(item)
  163. self.epg_id[item["id"]]=index
  164. if not item["date"] in self.epg_date:
  165. self.epg_date[item["date"]]=[]
  166. self.epg_date[item["date"]].append(index)
  167. if not item["channel_id"] in self.epg_ch:
  168. self.epg_ch[item["channel_id"]]=[]
  169. self.epg_ch[item["channel_id"]].append(index)
  170. item = self.get_epg_id(item["id"])
  171. ch = self.get_channel_by_id2(item["channel_id"])
  172. ch_name = ch["name"] if ch else item["channel_id"]
  173. title = u"%s (%s-%s)"%(item["title"], item["time_start2"].strftime("%H:%M"),item["time_stop2"].strftime("%H:%M"))
  174. #data2 = "archive/get-stream/%s?channelid=%s"%(item["id"],ch["id"])
  175. data2 = "content/record-streams/%s?include=quality"%item["id"]
  176. img = "https://manstv.lattelecom.tv/"+ item["url"]
  177. desc = u"%s - %s\n%s %s-%s\n%s\n%s"%(ch_name,item["title"], item["date"], item["time_start2"].strftime("%H:%M"),item["time_stop2"].strftime("%H:%M"),
  178. item["category1"],item["description"])
  179. content.append((title,self.name+"::"+data2,img,desc))
  180. if "until_id" in data:
  181. data2 = re.sub("until_id=\d+","until_id="+item["id"],data)
  182. else:
  183. data2 = data + "&until_id=%s"%item["id"]
  184. content.append(("Next page",self.name+"::"+data2,"","Go to next page"))
  185. return content
  186. ### Arhīva kanānālu saraksts
  187. elif data=="archive/channels":
  188. for item in self.get_channels():
  189. if not item["is_archive"]==u"1":continue
  190. title = item["name"]
  191. data2 = "archive/channel/%s?date=%s"%(item["id"],self.today.strftime("%Y-%m-%d"))
  192. img = "https://manstv.lattelecom.tv/"+ item['broadcast_default_picture']
  193. desc = title
  194. content.append((title,self.name+"::"+data2,img,desc))
  195. return content
  196. ### Arhīva kanānāla video saraksta
  197. elif "archive/channel/" in data:
  198. chid = path.split("/")[2]
  199. for item in self.get_epg_date(qs["date"],chid):
  200. if item["is_archive"]=='0':continue
  201. if item["time_stop2"] > datetime.datetime.now(): continue
  202. ch = self.get_channel_by_id2(item["channel_id"])
  203. ch_name = ch["name"] if ch else item["channel_id"]
  204. #title = u"[%s %s-%s] %s - %s"%(item["date"],item["time_start2"].strftime("%H:%M"),item["time_stop2"].strftime("%H:%M"),ch_name,item["title"])
  205. title = u"%s (%s-%s)"%(item["title"], item["time_start2"].strftime("%H:%M"),item["time_stop2"].strftime("%H:%M"))
  206. #data2 = "archive/get-stream/%s?channelid=%s"%(item["id"],ch["id"])
  207. data2 = "content/record-streams/%s?include=quality"%item["id"]
  208. img = "https://manstv.lattelecom.tv/"+ item["url"]
  209. desc = u"%s - %s\n%s %s-%s\n%s\n%s"%(ch_name,item["title"], item["date"], item["time_start2"].strftime("%H:%M"),item["time_stop2"].strftime("%H:%M"),
  210. item["category1"],item["description"])
  211. content.append((title,self.name+"::"+data2,img,desc))
  212. #date2=datetime.datetime.strptime(qs["date"], '%Y-%m-%d').date()-datetime.timedelta(days=1)
  213. date2 = datetime.date(*tuple(map(int, qs["date"].split("-")))) - datetime.timedelta(days=1)
  214. date2 = date2.strftime("%Y-%m-%d")
  215. if "date=" in data:
  216. data2 = re.sub("date=[\d-]+","date="+date2,data)
  217. else:
  218. data2 = data + "&date=%s"%date2
  219. content.append(("Previous day (%s)"%date2,self.name+"::"+data2,"","Go previous day"))
  220. return content
  221. ### Arhīva datumi
  222. elif clist=="arhivs" and len(data.split("/"))==2: # TODO - pasreiz nestrada
  223. ch = data.split("/")[1]
  224. r= self.call(data)
  225. m = re.search('class="spac no_select">([^<]+)</span>', r, re.IGNORECASE)
  226. if m:
  227. ch_name = m.group(1)
  228. else:
  229. ch_name = ""
  230. today = datetime.date.today()
  231. for i in range(7):
  232. date = today-datetime.timedelta(i)
  233. title = ch_name + " - " + date.strftime("%d.%m.%Y")
  234. data2 = "%s/%s"%(data,date.strftime("%Y-%m-%d"))
  235. img = ""
  236. desc = title
  237. content.append((title,self.name+"::"+data2,img,desc))
  238. return content
  239. ### Arhīva dienas raidijumi
  240. elif clist=="arhivs" and len(data.split("/"))==3: # TODO - nestrādā
  241. ch = data.split("/")[1]
  242. date = data.split("/")[2]
  243. r= self.call(data)
  244. m = re.search('class="spac no_select">([^<]+)</span>', r, re.IGNORECASE)
  245. if m:
  246. ch_name = m.group(1)
  247. else:
  248. ch_name = ""
  249. for item in re.findall('(?i)href="/([^"]+?)" id="" class="archive_programm_a"><div class="archive_programm "><div class="chanel_time"><span>([^<]+)</span></div><div class="archive_programm_one"><span>([^<]+)', r):
  250. title = "%s - %s"%(item[1],item[2])
  251. data2 = item[0]
  252. img = ""
  253. desc = "%s (%s)\n%s"%(ch_name,date,title)
  254. content.append((title,self.name+"::"+data2,img,desc))
  255. return content
  256. ### Videonoma galvenā
  257. elif data=="videonoma":
  258. content.extend([
  259. ("Filmas - jaunākās", "ltc::videonoma?page=0&genre=all_movies&sorts=laiks&cnt=40&clear=true&filter={}","https://www.shortcut.lv/media/features/2013-12-17/aa3b_videonoma_dropdown_filmas.png","Jaunākās filmas"),
  260. ("Filmas - pēc nosaukuma", "ltc::videonoma?page=0&genre=all_movies&sorts=title&cnt=40&clear=true&filter={}","https://www.shortcut.lv/media/features/2013-12-17/aa3b_videonoma_dropdown_filmas.png","Filmas pēc nosaukuma"),
  261. ("Filmas - latviski", 'ltc::videonoma?page=0&genre=all_movies&sorts=laiks&cnt=40&clear=true&filter={"valoda":["lv"]}',"https://www.shortcut.lv/media/features/2013-12-17/aa3b_videonoma_dropdown_filmas.png","Filmas latviešu valodā"),
  262. ("Filmas - pēc reitinga", "ltc::videonoma?page=0&genre=all_movies&sorts=imbd&cnt=40&clear=true&filter={}","https://www.shortcut.lv/media/features/2013-12-17/aa3b_videonoma_dropdown_filmas.png","Filmas pēc IMBD reitinga"),
  263. ("Filmas bērniem - jaunākās", "ltc::videonoma?page=0&genre=3&sorts=laiks&cnt=40&clear=true&filter={}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_berniem.png","Jaunākie bernu video"),
  264. ("Filmas bērniem - pēc nosaukuma", "ltc::videonoma?page=0&genre=3&sorts=title&cnt=40&clear=true&filter={}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_berniem.png","Bērnu video pēc nosaukuma"),
  265. ("Filmas bērniem - latviski", 'ltc::videonoma?page=0&genre=3&sorts=laiks&cnt=40&clear=true&filter={"valoda":[\"lv\"]}',"https://www.shortcut.lv/images/redesign/videonoma_dropdown_berniem.png","Bērnu video latviski"),
  266. ("Filmas bērniem - pēc reitinga", "ltc::videonoma?page=0&genre=3&sorts=imbd&cnt=40&clear=true&filter={}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_berniem.png","Bērnu video pēc IMBD reitinga"),
  267. ("Sērijas - jaunākās", "ltc::videonoma?page=0&genre=27&sorts=laiks&cnt=40&clear=true&filter={}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_raidijumi.png","Jaunākās sērijas"),
  268. ("Sērijas - pēc nosaukuma", "ltc::videonoma?page=0&genre=27&sorts=title&cnt=40&clear=true&filter={}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_raidijumi.png","Sērijas pēc pēc nosaukuma"),
  269. ("Sērijas animācijas - jaunākās", "ltc::videonoma?page=0&genre=27&sorts=laiks&cnt=40&clear=true&filter={\"zanrs\":[\"201\"]}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_raidijumi.png","Animācijas serijas"),
  270. ("Sērijas animācijas - pēc nosaukuma", "ltc::videonoma?page=0&genre=27&sorts=title&cnt=40&clear=true&filter={\"zanrs\":[\"201\"]}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_raidijumi.png","Animācijas serijas"),
  271. ("Sērijas ģimenes - jaunākās", "ltc::videonoma?page=0&genre=27&sorts=laiks&cnt=40&clear=true&filter={\"zanrs\":[\"195\"]}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_raidijumi.png","Animācijas serijas"),
  272. ("Sērijas ģimenes - pēc nosaukuma", "ltc::videonoma?page=0&genre=27&sorts=title&cnt=40&clear=true&filter={\"zanrs\":[\"195\"]}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_raidijumi.png","Animācijas serijas"),
  273. ("Sērijas latviski - jaunākās", 'ltc::videonoma?page=0&genre=27&sorts=laiks&cnt=40&clear=true&filter={"valoda":["lv"]}',"https://www.shortcut.lv/images/redesign/videonoma_dropdown_raidijumi.png","Sērijas latviski"),
  274. ("Sērijas latviski - pēc nosaukuma", 'ltc::videonoma?page=0&genre=27&sorts=title&cnt=40&clear=true&filter={"valoda":["lv"]}',"https://www.shortcut.lv/images/redesign/videonoma_dropdown_raidijumi.png","Sērijas latviski"),
  275. ("Koncerti - jaunākie", "ltc::videonoma?page=0&genre=19&sorts=laiks&cnt=40&clear=true&filter={}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_koncerti.png","Jaunākie koncerti"),
  276. ("Koncerti - pēc nosaukuma", "ltc::videonoma?page=0&genre=19&sorts=title&cnt=40&clear=true&filter={}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_koncerti.png","Koncerti pēc pēc nosaukuma"),
  277. ])
  278. return content
  279. ### Videonomas saraksti
  280. elif path == "videonoma":
  281. url = "https://www.shortcut.lv/movies-snippet.json"+params
  282. r = self._http_request(url,headers=self.headers2)
  283. if not r:
  284. return content
  285. js = json.loads(r,"utf8")
  286. if not r:
  287. return content
  288. for item in js["movies"]:
  289. if not item["title"]:
  290. continue
  291. title = item["title"].encode("utf8")
  292. data2 = item["url"][1:].encode("utf8")
  293. if data2[-1]=="/": data2=data2[:-1]
  294. if "/raidijumi/" in data2:
  295. data2 += "?series" # TODO
  296. img = "https://www.shortcut.lv"+item["image"].encode("utf8")
  297. desc = "%s\n%s"%(title,item["genre"].encode("utf8"))
  298. if "is_premium" in item and item["is_premium"]:
  299. title = title + " [P]"
  300. desc = desc + "\nPremium"
  301. content.append((title,self.name+"::"+data2,img,desc))
  302. m = re.search("page=(\d+)",data)
  303. if m:
  304. page = int(m.group(1))
  305. data2 = re.sub("page=\d+","page=%s"%(page+1),data)
  306. content.append(("Next page",self.name+"::"+data2,"","Go to next page"))
  307. return content
  308. ### Sērijas
  309. elif clist=="videonoma" and (params=="?series" or "season_nr" in qs):
  310. url = "https://www.shortcut.lv/"+path
  311. r = self._http_request(url,headers=self.headers2)
  312. if not r:
  313. return content
  314. m = re.search('<div class="movie_titles"><div class="en">([^<]+)</div>', r)
  315. raidijums = m.group(1) if m else "Series"
  316. img0 = re.search('<meta name="og:image" content="([^"]+)">', r).group(1) if re.search('<meta name="dr:say:img" content="([^"]+)">', r) else ""
  317. m = re.search('season_choice', r)
  318. # Ir sezonas
  319. if m:
  320. result = re.findall(r"""season_choice\(.+?'epizode','([^']*)',[^,]+,'(\d+)',[^,]+,[^,]+\)">([^<]+)<""", r, re.MULTILINE)
  321. if not result:
  322. raise Exception("No seasons find!")
  323. vid = result[0][0]
  324. if not "season_nr" in qs: # Sezonu saraksts
  325. for s,it in enumerate(result):
  326. title = "%s - %s" % (raidijums, it[2])
  327. data2 = path+"?season_nr=%s"%(it[1])
  328. img = img0
  329. desc = title
  330. content.append((title, self.name + "::" + data2, img, desc))
  331. return content
  332. else: # Sezonas epizožu saraksts
  333. if not "season_nr" in qs:
  334. qs["season_nr"]="0"
  335. # https://www.shortcut.lv/api/episode-loader-design17/0?chunk_size=4&sorting=epizode&series_id=dora_the_explorer
  336. # https://www.shortcut.lv/api/episode-loader-design17/3?chunk_size=4&sorting=epizode&series_id=dora_the_explorer&movie_id=10161&z360tv=&is_active_season=false HTTP/1.1
  337. # https://www.shortcut.lv/api/episode-loader-design17/3?chunk_size=4&sorting=epizode&series_id=dora_the_explorer
  338. url = "https://www.shortcut.lv/api/episode-loader-design17/%s?chunk_size=4&sorting=epizode&series_id=%s" % (qs["season_nr"], vid)
  339. r = self._http_request(url,headers=self.headers2)
  340. try:
  341. js = json.loads(r)
  342. except:
  343. raise Exception("Error getting episode list")
  344. result = re.findall(r'class="" href="([^"]+)".+?image:url\(([^ \)]+)\); "></div><div class="episode_titlez_design17">([^<]+)</div><div class="episode_number_design17">([^<]+)</div></a>', js["data"])
  345. for item in result:
  346. title = "%s - %s(%s)"%(raidijums,item[2],item[3])
  347. data2 = item[0][1:]
  348. img = "https://www.shortcut.lv"+item[1]
  349. desc = title
  350. content.append((title,self.name+"::"+data2,img,desc))
  351. return content
  352. # Nav sezonu
  353. else:
  354. result = re.findall(r'class="" href="([^"]+)".+?image:url\(([^ \)]+)\).+?class="episode_titlez_design17">([^<]+)</div><div class="episode_number_design17">([^<]+)</div></a>', r)
  355. for item in result:
  356. title = "%s - %s(%s)"%(raidijums,item[2],item[3])
  357. data2 = item[0][1:]
  358. img = "https://www.shortcut.lv"+item[1]
  359. desc = title
  360. content.append((title,self.name+"::"+data2,img,desc))
  361. return content
  362. ### Videonomas video
  363. elif clist=="videonoma" and len(data.split("/"))>1:
  364. ch = data.split("/")[1]
  365. video_id=data[data.find("/")+1:]
  366. #video_id=data.split("/")[-1]
  367. if not self.is_logedin2():
  368. if not self.login2():
  369. content=("Can not login\nPlease check lattelecom.tv username/password in\n/usr/lib/enigma2/python/Plugins/Extensions/sources/ltc.cfg file","","","No stream found. Please check lattelecom.tv username/password in sources/ltc.cfg file ")
  370. return content
  371. data2 = self.get_noma_url(video_id)
  372. if not data2:
  373. content=("No stream found for '%s'"%data,"","","No stream found")
  374. return content
  375. r = self.call2(data)
  376. m = re.search('<meta name="dr:say:title" content="([^"]+)">', r, re.IGNORECASE)
  377. if m:
  378. title = m.group(1)
  379. else:
  380. title = ""
  381. desc = title
  382. content = (title,data2,"",desc)
  383. return content
  384. else:
  385. return content
  386. def get_streams(self, data):
  387. print "[ltc] get_streams:", data
  388. if "::" in data: data = data.split("::")[1]
  389. if not self.is_video(data):
  390. return []
  391. ### Video nomas strīmus pagaidām dabu no mājas lapas TODO
  392. if data.split("/")[0]=="videonoma" and len(data.split("/"))>1:
  393. #video_id=data.split("/")[-1]
  394. streams = self.get_stream_url2(data)
  395. else:
  396. if not self.is_logedin():
  397. if not self.login():
  398. return []
  399. r = self.call(data)
  400. if not r: return []
  401. if "errors" in r:
  402. return []
  403. self.refresh_token()
  404. token = "&auth_token=app_%s"%(self.token)
  405. vid = data.split("/")[2].split("?")[0]
  406. vtype = data.split("/")[1]
  407. if vtype == "live-streams":
  408. ch = self.get_channel_by_id(vid)
  409. offset = "%2B03%3A00" # TODO - vajag aktuālo laika nobidi no GMS
  410. data2 = "tv/epg-live/%s/?offset=%s"%(ch["xprs_id"],offset)
  411. r2 = self.call(data2)
  412. if r2 and r2["items"]:
  413. title = r2["items"][0]["title"].encode("utf8")
  414. t1 = datetime.datetime.fromtimestamp(int(r2["items"][0]["unix_start"])).strftime('%H:%M')
  415. t2 = datetime.datetime.fromtimestamp(int(r2["items"][0]["unix_stop"])).strftime('%H:%M')
  416. title = "%s (%s-%s)"%(title,t1,t2)
  417. img = "https://manstv.lattelecom.tv/cache/" + r2["items"][0]["url"]
  418. desc = r2["items"][0]["description"]
  419. else:
  420. title = ch["name"]
  421. desc = title
  422. elif vtype == "record-streams":
  423. epg = self.get_epg_id(vid)
  424. if epg:
  425. title = epg["title"].encode("utf8")
  426. t1 = datetime.datetime.fromtimestamp(int(epg["unix_start"])).strftime('%H:%M')
  427. t2 = datetime.datetime.fromtimestamp(int(epg["unix_stop"])).strftime('%H:%M')
  428. date = epg["date"]
  429. title = "%s (%s %s-%s)"%(title,date,t1,t2)
  430. desc = epg["description"]
  431. else:
  432. title = desc = data
  433. streams = []
  434. for s in r["data"]:
  435. stream = util.item()
  436. stream["url"]=(s["attributes"]["stream-url"]+token.encode("utf8")).encode("utf8")
  437. stream["name"]=title
  438. stream["desc"]=desc
  439. stream["type"]="hls"
  440. m=re.search(".+_(\w\w)_(\w\w)\.\w+",s["id"])
  441. if m:
  442. stream["quality"]=m.group(2).encode("utf8")
  443. stream["lang"]=m.group(1).encode("utf8")
  444. streams.append(stream)
  445. ### TODO - sakārtot sarakstu, lai pirmais ir labakais video
  446. qlist = ["???","lq","mq","hq","hd"]
  447. llist = ["fr","en","ru","lv"]
  448. for s in streams:
  449. lv = llist.index(s["lang"])*10 if s["lang"] in llist else 0
  450. qv=qlist.index(s["quality"]) if s["quality"] in qlist else 0
  451. s["order"] = lv+qv
  452. streams = sorted(streams,key=lambda item: item["order"],reverse=True)
  453. return streams
  454. def is_video(self,data):
  455. if "::" in data:
  456. data = data.split("::")[1]
  457. cmd = data.split("/")
  458. if "get-stream" in data:
  459. return True
  460. elif cmd[0] in ("content") and cmd[1] in ("live-streams","record-streams","vod-streams"):
  461. return True
  462. elif cmd[0]=="arhivs" and len(cmd)==4:
  463. return True
  464. elif cmd[0]=="videonoma" and len(cmd)==3 and not "?" in data:
  465. return True
  466. else:
  467. return False
  468. def get_channels(self):
  469. if self.ch:
  470. return self.ch
  471. if not self.check_logedin():
  472. self.login() # citādi nerāda TV3, LNT, TV6
  473. r= self.call("tv/channels")
  474. self.ch=[]
  475. for i,item in enumerate(r["items"]):
  476. self.ch.append(item)
  477. self.ch_id[item["id"]]=i
  478. self.ch_id2[item["xprs_id"]]=i
  479. self.ch_name[item["name"]]=i
  480. return self.ch
  481. def get_channel_by_id(self,chid):
  482. if not self.ch:
  483. self.get_channels()
  484. if not self.ch:
  485. return None
  486. return self.ch[self.ch_id[chid]] if self.ch_id.has_key(chid) else None
  487. def get_channel_by_id2(self,chid):
  488. if not self.ch:
  489. self.get_channels()
  490. if not self.ch:
  491. return None
  492. return self.ch[self.ch_id2[chid]] if self.ch_id2.has_key(chid) else None
  493. def get_channels2(self):
  494. if self.ch2:
  495. return self.ch2
  496. r= self.call2("tiesraide")
  497. self.ch2=[]
  498. for item in re.findall(r'<div class="entry forward-link.+?data-xprs="(\d+)".+?title="([^"]+)" href="/tiesraide/([^"]+)"', r, re.DOTALL):
  499. ch={}
  500. ch["id2"]=item[0]
  501. ch["name"]=item[2]
  502. ch["title"]=item[1]
  503. self.ch2.append(ch)
  504. return self.ch2
  505. def get_channel_by_name2(self,name):
  506. if not self.ch2:
  507. self.get_channels2()
  508. for c in self.ch2:
  509. if c["name"]==name:
  510. return c
  511. return None
  512. def get_channel_by_name(self,name):
  513. if not self.ch:
  514. self.get_channels()
  515. ch2 = self.get_channel_by_name2(name)
  516. if not ch2:
  517. return None
  518. ch = self.get_channel_by_id2(ch2["id2"])
  519. return ch
  520. def get_epg(self,date=None,update=False):
  521. #https://manstv.lattelecom.tv/api/v1.3/get/tv/epg/?daynight=2016-05-19
  522. today=datetime.date.today()
  523. if not date:
  524. date=datetime.date.today().strftime("%Y-%m-%d")
  525. if update:
  526. self.epg=[]
  527. self.epg_id={}
  528. self.epg_id2={}
  529. self.epg_date={}
  530. self.epg_ch={}
  531. self.epg_cat={}
  532. if not date in self.epgdates:
  533. r=self.call("tv/epg/?daynight=%s"%date)
  534. for item in r["items"]:
  535. if item["id"] in self.epg_id: continue
  536. else:
  537. item["time_start2"] = datetime.datetime.fromtimestamp(int(item["unix_start"]))
  538. item["time_stop2"] = datetime.datetime.fromtimestamp(int(item["unix_stop"]))
  539. item["date"]=item["time_start2"].strftime("%Y-%m-%d")
  540. self.epg.append(item)
  541. index = self.epg.index(item)
  542. self.epg_id[item["id"]]=index
  543. if not item["date"] in self.epg_date:
  544. self.epg_date[item["date"]]=[]
  545. self.epg_date[item["date"]].append(index)
  546. if not item["channel_id"] in self.epg_ch:
  547. self.epg_ch[item["channel_id"]]=[]
  548. self.epg_ch[item["channel_id"]].append(index)
  549. if not date in self.epgdates:
  550. self.epgdates.append(date)
  551. def get_epg_id(self,epgid):
  552. if self.epg and epgid in self.epg_id:
  553. return self.epg[self.epg_id[epgid]]
  554. else:
  555. r=self.call("content/epgs/%s" % epgid)
  556. if not r:
  557. return None
  558. item = r["data"][0]["attributes"]
  559. item["unix_start"] = item["unix-start"]
  560. item["unix_stop"] = item["unix-stop"]
  561. item["time_start2"] = datetime.datetime.fromtimestamp(int(item["unix_start"]))
  562. item["time_stop2"] = datetime.datetime.fromtimestamp(int(item["unix_stop"]))
  563. item["date"]=item["time_start2"].strftime("%Y-%m-%d")
  564. return item
  565. def get_epg_date(self,date,chid):
  566. if not date in self.epgdates:
  567. self.get_epg(date)
  568. items = []
  569. ch = self.get_channel_by_id(chid)
  570. for it in self.epg_date[date]:
  571. item = self.epg[it]
  572. if item["channel_id"]==ch["xprs_id"]:
  573. items.append(item)
  574. return items
  575. def call(self, data,params = None, headers=None):
  576. if not headers: headers = self.headers
  577. #if not lang: lang = self.country
  578. url = self.api_url + data
  579. content = self._http_request(url,params, headers)
  580. if content:
  581. try:
  582. result = json.loads(content)
  583. return result
  584. except Exception, ex:
  585. return None
  586. else:
  587. return None
  588. def call2(self, data,params = None, headers=None):
  589. if not headers: headers = self.headers2
  590. #if not lang: lang = self.country
  591. url = self.api_url2 + data
  592. content = self._http_request(url,params, headers)
  593. return content
  594. def _http_request0(self, url,params = None, headers=None):
  595. if not headers: headers = self.headers
  596. try:
  597. r = urllib2.Request(url, data=params, headers=headers)
  598. u = urllib2.urlopen(r)
  599. content = u.read()
  600. u.close()
  601. return content
  602. except Exception as ex:
  603. return None
  604. def login(self,user="",password=""):
  605. """Login in to site, get token"""
  606. self.options_read()
  607. if not user: user=self.options["user"]
  608. if not password: password = self.options["password"]
  609. # Dabūjam tokenu
  610. url = "https://manstv.lattelecom.tv/api/v1.3/post/user/login"
  611. params = "uid=7f777e938d35e017&password=%s&username=%s&"%(password,user)
  612. headers = headers2dict("""
  613. Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  614. User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.4.2; SM-G900FD Build/KOT49H)
  615. Host: manstv.lattelecom.tv
  616. """ )
  617. try:
  618. r = urllib2.Request(url, data=params, headers=headers)
  619. u = urllib2.urlopen(r)
  620. content = u.read()
  621. u.close()
  622. except Exception as ex:
  623. return None
  624. #r = self.call(data, params)
  625. if r and "token" in content:
  626. self.token=re.search('"token":"(.+?)"', content).group(1)
  627. return True
  628. else:
  629. return False
  630. def refresh_token(self):
  631. data = "user/refresh-token//%s"%self.token
  632. r = self.call(data)
  633. if 'token' in r:
  634. self.token = r["token"]
  635. return True
  636. else:
  637. self.token = ""
  638. return False
  639. def check_logedin(self):
  640. if not self.token:
  641. return False
  642. else:
  643. if self.refresh_token():
  644. return True
  645. else:
  646. return False
  647. def is_logedin(self):
  648. if self.token:
  649. return True
  650. else:
  651. return False
  652. #----------------------------------------------------------------------
  653. def get_tv_url(self,video_id):
  654. """Get m3u8 url for given live tv channel"""
  655. url = "https://m.lattelecom.tv/tiesraide/%s"%video_id
  656. data = self.get_stream_url2("tiesraide/%s"%video_id)
  657. #headers = self.headers
  658. #headers["Cookie"] = "%s; %s; _hjIncludedInSample=0; MobBitr=1; MobRentBitr=%s; MobRentLang=%s;"%(self.session_id,self.mobtv_cache,data["quality"],data["language"])
  659. #response = urllib2.urlopen(urllib2.Request(url, headers=headers))
  660. #html = response.read()
  661. #m3u8 = re.search('x-mpegURL" src="(.*?)"', html).group(1) if "x-mpegURL" in html else ""
  662. return data["stream"] if data else None
  663. #----------------------------------------------------------------------
  664. def get_noma_url(self,video_id,quality="hq",language="lv"):
  665. """Get m3u8 url for given rental video"""
  666. video_id1,video_id2=video_id.split("/")
  667. data = self.get_stream_url2(video_id)
  668. #url = "https://m.lattelecom.tv/free_origin?show_origin=1&type=4&video_url=%s&bitrate=%s&lng=%s"%(video_id2,data["quality"],data["language"])
  669. #headers = self.headers
  670. #headers["Cookie"] = "%s; %s; MobRentBitr=%s; MobBitr=1; MobRentLang=%s"%(self.session_id,self.mobtv_cache,quality,language)
  671. #response = urllib2.urlopen(urllib2.Request(url, headers=headers))
  672. #m3u8 = response.read()
  673. return data["stream"] if data else None
  674. #----------------------------------------------------------------------
  675. def get_arhivs_url(self,video_id):
  676. """Get m3u8 url for given archive video"""
  677. data = self.get_video_data(video_id)
  678. #url = "https://m.lattelecom.tv/free_origin?show_origin=1&type=arhivs&event_id=%s&bitrate=mhq"%(video_id) #,data["quality"])
  679. #headers = self.headers
  680. #headers["Cookie"] = "%s; %s; MobBitr=1; "%(self.session_id,self.mobtv_cache)
  681. #response = urllib2.urlopen(urllib2.Request(url, headers=headers))
  682. #m3u8 = response.read()
  683. return data["stream"] if data else None
  684. def get_stream_url(self,video_id,type="vod",chid=""):
  685. "Get stream urls (hls) using manstv api"
  686. if type=="vod":
  687. data = "vod/get-stream/%s"%video_id
  688. elif type=="tv":
  689. data = "tv/get-stream?id=%s"%video_id
  690. elif type=="archive":
  691. if not chid: return None
  692. data="archive/get-stream/%s?channelid=%s"%(video_id,chid)
  693. else:
  694. return None
  695. if not self.is_logedin():
  696. if not self.login():
  697. return None
  698. r = self.call(data)
  699. if not r:
  700. return None
  701. self.refresh_token()
  702. token = "&auth_token=app_%s"%(self.token)
  703. hls={}
  704. hls["stream"]=r["stream"]+token
  705. hls["streams"]=[]
  706. if "items" in r:
  707. for s in r["items"]["streams"]:
  708. s["stream"] += token
  709. hls["streams"].append(s)
  710. return hls
  711. def get_info2(self, data):
  712. # Get movie info (for VOD)
  713. nfo = {}
  714. tt = lambda p,r,d: re.search(p,r).group(1) if re.search(p,r) else d
  715. tt2 = lambda p,r,d: (re.sub("[\.]","",re.search(p,r).group(1))).split(", ") if re.search(p,r) else d
  716. r = self.call2(data)
  717. m = re.search(r'"movie_titles" data-movieid=(\d+)><div class="en">([^<]+)</div><div class="lv translated">([^<]+)</div>', r)
  718. if m:
  719. title1 = unescape(m.group(2))
  720. title2 = unescape(m.group(3))
  721. else:
  722. m = re.search('<meta name="dr:say:title" content="([^"]+)">', r, re.IGNORECASE)
  723. title1 = title2 = unescape(m.group(1)) if m else "Video"
  724. nfo["title"] = title2
  725. nfo["originaltitle"] = title1
  726. if nfo["originaltitle"] and not nfo["title"]:
  727. nfo["title"] = nfo["originaltitle"]
  728. if 'episode_switcher_title' in r:
  729. title2 = title2.replace("\xe2\x80\x93", "-")
  730. if " - " in title2:
  731. nfo["set"] = title2.split(" - ")[0]
  732. else:
  733. nfo["set"] = tt('<div class="movie_titles"><div class="en">(.+?)<', r, title2)
  734. m = re.search('<div class="serial_switcher_banner active".+?<div class="episode_titlez_design17">([^<]+)</div><div class="episode_number_design17">([^<]+)</div>', r)
  735. if m:
  736. ep1 = m.group(1)
  737. ep2 = m.group(2)
  738. nfo["title"] = "%s - %s(%s)"%(nfo["set"], ep1, ep2)
  739. nfo["originaltitle"] = nfo["originaltitle"] + "(%s)" % ep2
  740. m = re.search("S(\d+)E(\d+)", ep2)
  741. if m:
  742. nfo["season"] = m.group(1)
  743. nfo["eposode"] = m.group(2)
  744. nfo["thumb"] = tt('<meta name="og:image" content="([^"]+)"', r,"")
  745. nfo["thumb"] = nfo["thumb"].replace("http:", "https:")
  746. nfo["year"] = tt('movie-informatio-title">Gads<.+?content">([^<]+)<', r, "")
  747. nfo["runtime"] = tt('movie-informatio-title">Garums<.+?content">([^<]+)<', r, "")
  748. nfo["quality"] = tt('movie-informatio-title">Kvalitāte<.+?content">([^<]+)<', r, "")
  749. nfo["genre"]=tt('movie-informatio-title">Žanrs<.+?content">([^<]+)<', r, "")
  750. nfo["director"] = tt('movie-informatio-title">Režisors<.+?content">([^<]+)<', r, "")
  751. nfo["actor"] = tt2('movie-informatio-title">Aktieri<.+?content">([^<]+)<', r, "")
  752. nfo["language"] = tt2('movie-informatio-title">Valodas*<.+?content">([^<]+)<', r, "")
  753. nfo["subtitles"] = tt2('movie-informatio-title">Subtitri<.+?content">([^<]+)<', r, "")
  754. nfo["plot"] = tt('movie-informatio-title">Apraksts<.+?content">([^<]+)<', r, "")
  755. nfo["tagline"] = nfo["plot"]
  756. return nfo
  757. def get_stream_url2(self,data):
  758. video_id=data[data.find("/")+1:]
  759. if not self.is_logedin2():
  760. if not self.login2():
  761. return []
  762. #data2 = self.get_noma_url(video_id)
  763. nfo = self.get_info2(data)
  764. title = util.nfo2title(nfo)
  765. desc = util.nfo2desc(nfo)
  766. img = nfo["thumb"]
  767. #xml = util.nfo2xml(nfo)
  768. url = "https://www.shortcut.lv/xmls/%s.xml"%video_id
  769. headers = self.headers2
  770. headers["Cookie"] = self.session_id
  771. response = urllib2.urlopen(urllib2.Request(url, headers=headers))
  772. r = response.read()
  773. servers = re.findall("(?s)<origin>([^<]+)</origin>", r)
  774. streams_xml = re.findall('<stream quality="\w+">(mp4:\w+(\w\w)_(\w\w).mp4)</stream>',r)
  775. resource_id = re.search("(?s)<resource_id>([^<]+)</resource_id>", r).group(1)
  776. token = re.search("(?s)<auth_token>([^<]+)</auth_token>", r).group(1)
  777. streams=[]
  778. captions = []
  779. llist = ["fr","en","ru","lv"]
  780. for s in re.findall('<subtitles code="([^"]+)">([^<]+)</subtitles>', r, re.DOTALL):
  781. sub = {}
  782. sub["url"] = s[1]
  783. sub["lang"] = s[0]
  784. sub["name"] = "captions (vtt)"
  785. sub["type"] = "vtt"
  786. sub["order"] = llist.index(sub["lang"])*10 if sub["lang"] in llist else 0
  787. captions.append(sub)
  788. captions = sorted(captions,key=lambda item: item["order"],reverse=True)
  789. for s in streams_xml:
  790. for server in servers:
  791. stream = util.item()
  792. server2 = self.load_balancer(server)
  793. url = "http://%s/mobile-vod/%s/playlist.m3u8?resource_id=%s&auth_token=%s"%(server2,s[0],resource_id,token)
  794. # TODO Engima2 gstreamer vajag lai padod playlist nevis chunklist
  795. # r3 = self._http_request(url)
  796. # sss = re.findall(r"#EXT-X-STREAM-INF:.*?BANDWIDTH=(\d+).*?\n(.+?)$", r3, re.IGNORECASE | re.MULTILINE)
  797. # if sss:
  798. # url2 = sss[0][1]
  799. # stream["headers"] = {"Referer":url}
  800. # if url2.startswith("http"):
  801. # url = url2
  802. # else:
  803. # url = util.hls_base(url)+url2
  804. stream["url"]=url
  805. stream["lang"]=s[1]
  806. stream["quality"]=s[2]
  807. stream["name"]= unescape(title)
  808. stream["desc"]= unescape(desc)
  809. stream["img"] = img
  810. stream["nfo"] = {"movie":nfo}
  811. stream["type"]="hls" #stream_type(url)
  812. stream["subs"] = []
  813. for c in captions:
  814. c2= c.copy()
  815. #c2["url"] ="http://%s/mobile-vod/%s/%s?resource_id=%s&auth_token=%s"%(server2,s[0],c["url"],resource_id,token)
  816. c2["url"] ="http://%s/mobile-vod/%s/%s"%(server2,s[0],c["url"])
  817. stream["subs"].append(c2)
  818. pass
  819. streams.append(stream)
  820. break # TODO ņem tikai pirmo serveri, varētu pārbaudit, kurš no tiem strādā, kurš ne
  821. return streams
  822. #data = {}
  823. #data["server"] = re.findall("(?s)<origin>([^<]+)</origin>", r)[1]
  824. #data["language"]=re.findall('(?s)<language code="([^"]+)">', r)
  825. #data["language"]="lv" if "lv" in data["language"] else "ru" if "ru" in data["language"] else "en"
  826. #data["qs"]=re.findall('(?s)<stream quality="([^"]+)">([^<]+)</stream>', r)
  827. #data["qs"]=dict(data["qs"])
  828. #qs = data["qs"].keys()
  829. #data["quality"] = "hd" if "hd" in qs else "hq" if "hq" in qs else "mhq" if "mhq" in qs else "lq"
  830. #data["mp4"] = data["qs"][data["quality"]]
  831. #data["token"] = re.search("(?s)<auth_token>([^<]+)</auth_token>", r).group(1)
  832. #data["resource_id"]=re.search("(?s)<resource_id>([^<]+)</resource_id>", r).group(1)
  833. #data["server"]=self.load_balancer(data["server"])
  834. #data["hls"] = "http://%s/mobile-vod/%s/playlist.m3u8?resource_id=%s&auth_token=%s"%(data["server"],data["mp4"],data["resource_id"],data["token"])
  835. ##data["hls"]="http://%s/mobile-vod/mp4:%s/playlist.m3u8?resource_id=%s&auth_token=app_%s"%(data["server"],data["mp4"],data["resource_id"],data["token"])
  836. ### wwww.shortcut.lv izsaukumi
  837. def login2(self,user="",password=""):
  838. """Login in to site, create session cookies"""
  839. if not user: user=self.options["user"]
  840. if not password: password = self.options["password"]
  841. url0 = "https://www.shortcut.lv"
  842. class NoRedirectHandler(urllib2.HTTPRedirectHandler):
  843. def http_error_302(self, req, fp, code, msg, headers):
  844. infourl = urllib.addinfourl(fp, headers, req.get_full_url())
  845. infourl.status = code
  846. infourl.code = code
  847. return infourl
  848. http_error_300 = http_error_302
  849. http_error_301 = http_error_302
  850. http_error_303 = http_error_302
  851. http_error_307 = http_error_302
  852. # Dabūjam sesijas id un url_gif, kas redirektējas uz auth_url
  853. headers = headers2dict("""
  854. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
  855. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  856. Accept-Language: en-US,en;q=0.5
  857. DNT: 1
  858. Connection: keep-alive
  859. """)
  860. response = urllib2.urlopen(urllib2.Request(url0, headers=headers))
  861. session_id = response.headers["set-cookie"].split(";")[0]
  862. html = response.read()
  863. url_gif = url0 + re.search('(/auth/\d+\.gif)', html).group(1)
  864. # Dabūtjam auth_url
  865. headers = headers2dict("""
  866. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
  867. Accept: image/png,image/*;q=0.8,*/*;q=0.5
  868. Accept-Language: en-US,en;q=0.5
  869. DNT: 1
  870. Referer: https://www.shortcut.lv/
  871. """)
  872. headers["Cookie"] = session_id
  873. urllib2.install_opener(urllib2.build_opener(NoRedirectHandler()))
  874. response = urllib2.urlopen(urllib2.Request(url_gif, headers=headers))
  875. if response.code == 302:
  876. url_auth = response.headers["location"]
  877. else:
  878. self.error = u"auth.gif nenostrādāja"
  879. raise Exception(u"auth.gif nenostrādāja")
  880. #return False
  881. # Pierakstāmies iekš auth.lattelecom.lv
  882. headers = headers2dict("""
  883. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
  884. Accept: image/png,image/*;q=0.8,*/*;q=0.5
  885. Accept-Language: en-US,en;q=0.5
  886. DNT: 1
  887. Referer: https://www.shortcut.lv/
  888. """)
  889. response = urllib2.urlopen(urllib2.Request(url_auth, headers=headers))
  890. if not response.code == 302:
  891. self.error = u"pierakstīšanās auth.lattelecom.lv nenostrādāja"
  892. return False
  893. #raise "pierakstīšanās auth.lattelecom.lv nenostrādāja"
  894. # Mēģinam ielogoties
  895. headers = headers2dict("""
  896. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
  897. Accept: text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01
  898. Accept-Language: en-US,en;q=0.5
  899. DNT: 1
  900. X-Requested-With: XMLHttpRequest
  901. Referer: https://www.shortcut.lv/
  902. """)
  903. headers["Cookie"] = session_id
  904. #data = "login=yes&email=%s&passw=%s"%(user,password)
  905. url = "https://www.shortcut.lv/login.json?callback=jQuery111303344749731668816_1463817318435&username=%s&password=%s&captcha=&sid=&_="%(user,password)
  906. req = urllib2.Request(url, headers=headers)
  907. response = urllib2.urlopen(req)
  908. #with open("auth.htm","w") as f: f.write(response.read())
  909. if not response.code == 200:
  910. #self.error = u"kļūda ielogojoties"
  911. raise Exception(u"kļūda ielogojoties")
  912. html = response.read()
  913. if not '"success":true' in html:
  914. err = re.search('"error":"(.+?)"',html).group(1) if re.search('"error":"(.+?)"',html) else ""
  915. raise Exception(u"Kļūda ielogojoties - %s"%err.decode("utf8"))
  916. self.session_id = session_id
  917. self.headers2["Cookie"] = "%s; "%(self.session_id)
  918. self.error = ""
  919. return True
  920. def check_logedin2(self):
  921. if not self.session_id:
  922. return False
  923. else:
  924. url = "https://www.shortcut.lv/profils"
  925. response = urllib2.urlopen(urllib2.Request(url, headers=self.headers2))
  926. if response.code == 200:
  927. return True
  928. else:
  929. self.session_id = ""
  930. return False
  931. def is_logedin2(self):
  932. if self.session_id:
  933. return True
  934. else:
  935. return False
  936. def load_balancer(self,server,streams=[]):
  937. headers = headers2dict("""
  938. Connection: keep-alive
  939. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36
  940. X-Requested-With: ShockwaveFlash/21.0.0.242
  941. """)
  942. url = "http://%s/loadbalancer"%server
  943. response = urllib2.urlopen(urllib2.Request(url, headers=headers))
  944. r = response.read()
  945. statuss = re.search("<status>(\d+)</status>",r).group(1)
  946. edge = re.search("<edge>([^<>]+)</edge>",r).group(1)
  947. return edge
  948. def test_hls(self,url):
  949. headers = headers2dict("""
  950. Connection: keep-alive
  951. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36
  952. """)
  953. try:
  954. response = urllib2.urlopen(urllib2.Request(url, headers=headers))
  955. except Exception as ex:
  956. print "hls failed: %s %s"%(ex.getcode(),url)
  957. return False
  958. if response.code == 200:
  959. html = response.read()
  960. url0 = re.search("(http://[^/]+/)",url).group(1)
  961. chunklist = re.search("(chunklist.+)",html).group(1).strip()
  962. url2 = url.split('/')[:-1]
  963. url2 ="/".join(url2)+"/"+chunklist
  964. try:
  965. response2 = urllib2.urlopen(urllib2.Request(url2, headers=headers))
  966. except Exception as ex:
  967. print "hls chunk failed: %s %s"%(ex.getcode(),url2)
  968. return False
  969. if response2.code == 200:
  970. return True
  971. else:
  972. return False
  973. else:
  974. return False
  975. if __name__ == "__main__":
  976. sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
  977. import run
  978. source = Source()
  979. data= sys.argv[1] if len(sys.argv)>1 else source.name+"::home"
  980. run.run(source, data)
  981. sys.exit()
  982. c.get_info2(sys.argv[1])
  983. if len(sys.argv)>1 and not "ltc::" in sys.argv[1]:
  984. vid = vid2 = sys.argv[1]
  985. password = sys.argv[2]
  986. print "login - %s"%c.login("ivars777",password)
  987. #vid = "1069"
  988. #vid = "1462566072086"
  989. #channelid="101"
  990. #vid = "1350462656767"
  991. #data = c.get_stream_url(vid,"vod")
  992. #call([r"c:\Program Files\VideoLAN\VLC\vlc.exe",data["stream"]])
  993. #pass
  994. print "login2 - %s"%c.login2("ivars777",password)
  995. #vid2 = "animation/ultimate_avengers_ii"
  996. #vid2 = "animation/ice_age"
  997. #vid2 = "tiesraide/ltv1"
  998. #vid2 = "arhivs/1456521417815"
  999. streams = c.get_stream_url2(vid2)
  1000. stream = streams[-1]
  1001. print
  1002. #for s in data:
  1003. #call([r"c:\Program Files\VideoLAN\VLC\vlc.exe",stream["url"]])
  1004. cmd = ["ffplay.exe",
  1005. "-headers","Referer:%s"%(quote(stream["headers"]["Referer"])),
  1006. "-headers","Connection:Keep-Alive",
  1007. stream["url"]]
  1008. print " ".join(cmd)
  1009. call(cmd)
  1010. pass
  1011. else:
  1012. if len(sys.argv)>1:
  1013. data= sys.argv[1]
  1014. else:
  1015. data = "ltc::home"
  1016. content = c.get_content(data)
  1017. for item in content:
  1018. print item
  1019. #cat = api.get_categories(country)
  1020. #chan = api.get_channels("lv")
  1021. #prog = api.get_programs(channel=6400)
  1022. #prog = api.get_programs(category=55)
  1023. #seas = api.get_seasons(program=6453)
  1024. #str = api.get_streams(660243)
  1025. #res = api.get_videos(802)
  1026. #formats = api.getAllFormats()
  1027. #det = api.detailed("1516")
  1028. #vid = api.getVideos("13170")
  1029. pass