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

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