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

ltc.py 51KB

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