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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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 urllib2, urllib
  9. import datetime, re, sys,os
  10. import requests, json
  11. import ssl
  12. if "_create_unverified_context" in dir(ssl):
  13. ssl._create_default_https_context = ssl._create_unverified_context
  14. try:
  15. from requests.packages.urllib3.exceptions import InsecureRequestWarning
  16. requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
  17. except:
  18. pass
  19. from collections import OrderedDict
  20. import ConfigParser
  21. try:
  22. import util
  23. except:
  24. parent = os.path.dirname(os.path.abspath(__file__))
  25. parent = os.sep.join(parent.split(os.sep)[:-1])
  26. sys.path.insert(0,parent)
  27. import util
  28. headers2dict = lambda h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
  29. class SourceBase(object):
  30. """Stream source base class"""
  31. def __init__(self,country="lv"):
  32. self.name = "name"
  33. self.title = "Title"
  34. self.img = ""
  35. self.desc = ""
  36. self.options = OrderedDict()
  37. self.config_file = ""
  38. self.url = "http://www.bbb.com/"
  39. self.headers = headers2dict("""
  40. User-Agent: Mozilla/5.0 (Linux; U; Android 4.4.4; Nexus 5 Build/KTU84P) AppleWebkit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
  41. """)
  42. def login(self,user="",password=""):
  43. return False
  44. def logout(self):
  45. return True
  46. def get_content(self,data):
  47. ### To be overriden in child class
  48. return [("..atpakaļ","back","back.png","Kļūda, atgriezties atpakaļ")]
  49. def is_video(self,data):
  50. ### To be overriden in child class
  51. return False
  52. def get_streams(self,data):
  53. ### Normally to be overrided in child class
  54. if not self.is_video(data):
  55. return []
  56. content = self.get_content(data)
  57. stream = util.item()
  58. stream["name"] = content[0].encode("utf8") if isinstance(content[0],unicode) else content[0]
  59. stream["url"] = content[1].encode("utf8") if isinstance(content[1],unicode) else content[1]
  60. stream["img"] = content[2].encode("utf8") if isinstance(content[2],unicode) else content[2]
  61. stream["desc"] = content[3].encode("utf8") if isinstance(content[3],unicode) else content[3]
  62. stream["type"] = stream_type(content[1]).encode("utf8")
  63. return[stream]
  64. def get_epg(self,data):
  65. ### Normally to be overrided in child class
  66. return [self.get_info(data)]
  67. def options_read(self):
  68. if not ("options" in dir(self) and self.options): # process options only if self.options defined, self.config_file should be defined too
  69. return None
  70. config = ConfigParser.ConfigParser()
  71. if os.path.exists(self.config_file):
  72. options0 = self.options
  73. config.read(self.config_file)
  74. self.options = OrderedDict(config.items(self.name))
  75. for k in options0:
  76. if not k in self.options:
  77. self.options[k] = options0[k]
  78. self.options_write(self.options)
  79. else:
  80. self.options_write(self.options)
  81. return self.options
  82. def options_write(self,options):
  83. config = ConfigParser.ConfigParser()
  84. config.add_section(self.name)
  85. for k in options.keys():
  86. config.set(self.name, k,options[k])
  87. with open(self.config_file,"w") as f:
  88. config.write(f)
  89. self.options = OrderedDict(config.items(self.name))
  90. def call(self, data,params=None,headers=None,lang=""):
  91. if not headers: headers = self.headers
  92. url = self.url+data
  93. result = self._http_request(url,params,headers=headers)
  94. return result
  95. def call_json(self, data,params=None,headers=None,lang=""):
  96. result = self.call(data,params,headers)
  97. if result:
  98. result = json.loads(result)
  99. return result
  100. else:
  101. raise "No data returned"
  102. def _http_request(self, url,params = None, headers=None):
  103. if not headers:
  104. headers = self.headers if "headers" in dir(self) else headers2dict("User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0")
  105. try:
  106. if params:
  107. r = requests.post(url, data=params, headers=headers,verify=False)
  108. else:
  109. r = requests.get(url, headers=headers,verify=False)
  110. return r.content
  111. except Exception as ex:
  112. if "read" in ex:
  113. content = ex.read()
  114. else:
  115. content = None
  116. return content
  117. @staticmethod
  118. def stream_type(data):
  119. return stream_type(data)
  120. @staticmethod
  121. def parse_data(data):
  122. if "::" in data:
  123. source = data.split("::")[0]
  124. data = data.split("::")[1]
  125. else:
  126. source = ""
  127. path = data.split("?")[0]
  128. plist = path.split("/")
  129. clist = plist[0]
  130. params = data[data.find("?"):] if "?" in data else ""
  131. qs = dict(map(lambda x:x.split("="),re.findall("\w+=[\w\-]+",params)))
  132. return source,data,path,plist,clist,params,qs
  133. def stream_type(data):
  134. data = data.lower()
  135. m = re.search(r"^(\w+)://", data)
  136. prefix = m.group(1) if m else ""
  137. if prefix in ("http","https"):
  138. if ".m3u8" in data:
  139. return "hls"
  140. elif ".mpd" in data:
  141. return "dash"
  142. else:
  143. return "http"
  144. else:
  145. return prefix
  146. if __name__ == "__main__":
  147. pass