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

filmas.py 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #!/usr/bin/env python
  2. # coding=utf8
  3. #
  4. # This file is part of PlayStream - enigma2 plugin to play video streams from various sources
  5. # Copyright (c) 2016 ivars777 (ivars777@gmail.com)
  6. # Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
  7. #
  8. try:
  9. import json
  10. except:
  11. import simplejson as json
  12. import urllib2, urllib
  13. import binascii
  14. import datetime, re, sys,os, time
  15. import ConfigParser
  16. from collections import OrderedDict
  17. from SourceBase import SourceBase
  18. import requests
  19. import ssl
  20. if "_create_unverified_context" in dir(ssl):
  21. ssl._create_default_https_context = ssl._create_unverified_context
  22. try:
  23. from requests.packages.urllib3.exceptions import InsecureRequestWarning
  24. requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
  25. except:
  26. pass
  27. #import resolver
  28. try:
  29. import util
  30. except:
  31. sys.path.insert(0,'..')
  32. import util
  33. headers2dict = lambda h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
  34. class Source(SourceBase):
  35. def __init__(self, country="",cfg_path=None):
  36. self.hidden = True # nerāda menu nestrādājošos avotus
  37. self.name = "filmas"
  38. self.title = "Filmas.lv"
  39. self.img = "filmas.png"
  40. self.desc = "Filmas.lv - Latvijas filmas"
  41. self.headers = headers2dict("""
  42. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0
  43. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  44. Accept-Language: en-US,en;q=0.5
  45. Accept-Encoding: gzip, deflate, br
  46. """)
  47. self.headers2 = headers2dict("""
  48. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
  49. X-Requested-With: XMLHttpRequest
  50. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  51. """)
  52. self.url = "https://www.filmas.lv/"
  53. ######### Entry point ########
  54. def get_content(self, data):
  55. print "[filmas] get_content:", data
  56. source, data, path, plist, clist, params, qs = self.parse_data(data)
  57. content = []
  58. content.append(("..return", "back","back.png","Return back"))
  59. if clist=="home":
  60. content.extend([
  61. ("Meklēt", "filmas::filmu-katalogs/?mn={0}&tab=movies&sub_tab=movies-search","","Meklēt"),
  62. ("Visas", "filmas::filmu-katalogs/?tab=movies&sub_tab=movies-view-2","","Visur skatam visas filmas"),
  63. ("Spēlfilmas", "filmas::filmu-katalogs/?tab=movies&sub_tab=movies-view-2&mp20=112","","Visur skatamās spēlfilmas"),
  64. ("Animācijas filmas", "filmas::filmu-katalogs/?tab=movies&sub_tab=movies-view-2&mp20=113","","Visur skatamās animācijas filmas"),
  65. ("Dokumentalās filmas", "filmas::filmu-katalogs/?tab=movies&sub_tab=movies-view-2&mp20=111","","Visur skatamās dokumentalās filmas"),
  66. ("Kinohronikas", "filmas::filmu-katalogs/?tab=movies&sub_tab=movies-view-2&mp20=150","","Visur skatamās kinohronikas") ,
  67. ])
  68. return content
  69. elif clist=="filmu-katalogs":
  70. r=self.call(data)
  71. result = re.findall(r'<a href="/(movie/\d+)">.+?<img src="/([^"]+)">.+?Pieejama.+?<div class="katalogs-filma-teksts">\s*(.+?)\s*<span style="font-weight:normal; ">\((\d+)\)</span>', r, re.DOTALL)
  72. for item in result:
  73. title = item[2]+'(%s)'%item[3]
  74. data2 = item[0]
  75. img = self.url + item[1].replace("thumbs_m/","")
  76. desc = title
  77. content.append((title,self.name+"::"+data2,img,desc))
  78. m = re.search(r"<a class='pagenum' href='(\?tab=movies&sub_tab=movies-view-2[^']+)'>&gt;</a>", r, re.DOTALL)
  79. if m:
  80. data2 = "filmu-katalogs/"+m.group(1)
  81. content.append(("Next page",self.name+"::"+data2, "","Next page"))
  82. return content
  83. ### kaut kas neparedzets ###
  84. else:
  85. return content
  86. def is_video(self,data):
  87. source,data,path,plist,clist,params,qs = self.parse_data(data)
  88. if clist=="movie":
  89. return True
  90. else:
  91. return False
  92. def call(self, data,params=None,headers=None,lang=""):
  93. if not headers: headers = self.headers
  94. url = self.url+data
  95. result = self._http_request(url,params,headers=headers)
  96. return result
  97. def get_streams(self,data):
  98. print "[filmas] get_streams:", data
  99. source, data, path, plist, clist, params, qs = self.parse_data(data)
  100. streams = []
  101. url = self.url+data
  102. mid = data.split("/")[1]
  103. r = requests.get(url, headers=self.headers, verify=False)
  104. if not "PHPSESSID" in r.cookies:
  105. return streams
  106. phpsessid = r.cookies["PHPSESSID"]
  107. ### Main playlist ###
  108. hid = re.search('src: "/lmdb/hls/playlist/(\w+).m3u8"', r.content).group(1)
  109. url = "https://www.filmas.lv/lmdb/hls/playlist/%s.m3u8"%hid
  110. headers = headers2dict("""
  111. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0
  112. Accept: */*
  113. Accept-Language: en-US,en;q=0.5
  114. Accept-Encoding: gzip, deflate, br
  115. Referer: https://www.filmas.lv/movie/%s/
  116. """%mid)
  117. r = requests.get(url, headers=headers, verify=False, cookies={"phpsessid":phpsessid} )
  118. filmassession = r.cookies["filmassession"]
  119. result = re.findall(r'#EXT-X-STREAM-INF:PROGRAM-ID=(\d+),BANDWIDTH=(\d+),RESOLUTION=(.+?),CODECS="(.+?)"\n(.+?)$', r.content, re.IGNORECASE | re.MULTILINE)
  120. title = url.split("/")[-1].split(".")[0]
  121. ### Initial key requests
  122. url = "https://www.filmas.lv/lmdb/hls/key/request/%s?%s"%(mid,int(time.time()))
  123. r=requests.get(url,headers=headers,cookies = {"filmassession":filmassession}, verify=False )
  124. filmassession = r.cookies["filmassession"]
  125. ### Metada ###
  126. url = "https://www.filmas.lv/charts/api/api/?method=search_movie&query=%s"%mid
  127. r = requests.get(url, headers=headers, verify=False)
  128. if not "error" in r.content:
  129. title = r.json()["nodes"][0]["name"]
  130. img = self.url+r.json()["nodes"][0]["image"]
  131. desc = r.json()["nodes"][0]["plot"]
  132. else:
  133. img = desc = ""
  134. for h in result:
  135. url = h[4]
  136. ### Key request ###
  137. headers["Origin"] = "https://www.filmas.lv"
  138. r=requests.get(url,headers=headers, verify=False)
  139. url_key = re.search('#EXT-X-KEY:METHOD=AES-128,URI="(.+?)"', r.content, re.IGNORECASE | re.MULTILINE).group(1)
  140. r=requests.get(url_key,headers=headers, cookies={"filmassession":filmassession,"PHPSESSID":phpsessid}, verify=False)
  141. key = r.content if not "error" in r.content else ""
  142. stream = util.item()
  143. stream["name"] = title
  144. stream["url"] = url
  145. stream["img"] = img
  146. stream["desc"] = desc
  147. stream["headers"] = {"key":binascii.b2a_hex(key)}
  148. stream["quality"] = h[2]
  149. stream["order"] = int(h[1])
  150. stream["resolver"] = "filmas"
  151. streams.append(stream)
  152. return sorted(streams,key=lambda item: item["order"],reverse=True)
  153. def download_hls(url, title, download_dir="", headers=None, overwrite=True):
  154. UA = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0"
  155. if not headers:
  156. headers = {"User-Agent" : UA}
  157. key = headers["key"] if "key" in headers else ""
  158. if not "User-Agent" in headers:
  159. headers["User-Agent"] = UA
  160. tsname = os.path.join(download_dir,title+".ts")
  161. if not os.path.exists(tsname) or overwrite:
  162. tsfile = open(tsname,"wb")
  163. print "Downloading ", tsname
  164. try:
  165. r=requests.get(url,headers=headers, verify=False)
  166. except Exception as e:
  167. print "Got Exception: ", str(e)
  168. import traceback
  169. traceback.print_exc()
  170. sys.exit()
  171. ts_list = re.findall(r"#EXTINF:([\d\.]+),\n(.+?)$", r.content, re.IGNORECASE | re.MULTILINE)
  172. for ts in ts_list:
  173. url2 = ts[1]
  174. #print "Downloading ", url2
  175. #fname = os.path.join(download_dir,url2.split("/")[-1])
  176. r = requests.get(url2, headers=headers, verify=False)
  177. content = r.content
  178. if key:
  179. from Crypto.Cipher import AES
  180. key2 = binascii.a2b_hex(key)
  181. iv = content[:16]
  182. d = AES.new(key2, AES.MODE_CBC, iv)
  183. content = d.decrypt(content[16:])
  184. #with open(fname,"wb") as f:
  185. #f.write(content)
  186. tsfile.write(content)
  187. #lfile.write("file '%s'"%fname)
  188. #lfile.close()
  189. tsfile.close()
  190. from subprocess import call
  191. cmd = [r"ffmpeg.exe","-i", tsname.encode(sys.getfilesystemencoding()), "-c","copy", os.path.join(download_dir,title+".mp4").encode(sys.getfilesystemencoding())]
  192. ret = call(cmd)
  193. if __name__ == "__main__":
  194. #url = "http://localhost:88/https%3A//as2.filmas.lv/FilmasLV/508D4024A83FDC1AA61D727DE5046D12/index-f3-v1-a1.m3u8?~key=4cb5c12b2aaa3d2cf211583cc9add2dd"
  195. #download_hls(url, "video", "")
  196. c = Source()
  197. if len(sys.argv)>1:
  198. data= sys.argv[1]
  199. else:
  200. data = "movie/3112/"
  201. if "movie" in data:
  202. if data.startswith("http"):
  203. data = data.replace("https://www.filmas.lv/","")
  204. streams = c.get_streams(data)
  205. #for s in streams:
  206. s = streams[0]
  207. download_hls(s["url"],"%s %s"%(s["name"],s["quality"]),"",s["headers"])
  208. sys.exit()
  209. sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
  210. import run
  211. source = Source()
  212. data= sys.argv[1] if len(sys.argv)>1 else source.name+"::home"
  213. run.run(source, data)
  214. sys.exit()