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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. #!/bin/env python
  2. '''
  3. ***
  4. Modified generic daemon class
  5. ***
  6. Author:
  7. https://web.archive.org/web/20160305151936/http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
  8. Modified by ivars777@gmail.com
  9. License: http://creativecommons.org/licenses/by-sa/3.0/
  10. '''
  11. # Core modules
  12. from __future__ import print_function
  13. import atexit
  14. import errno
  15. import os
  16. import sys
  17. import time
  18. import signal
  19. class Daemon(object):
  20. """
  21. A generic daemon class.
  22. Usage: subclass the Daemon class and override the run() method
  23. """
  24. def __init__(self, app, pidfile, stdin=os.devnull,
  25. stdout=os.devnull, stderr=os.devnull,
  26. home_dir='.', umask=0o22, verbose=1,
  27. use_gevent=False, use_eventlet=False):
  28. self.app = app
  29. self.stdin = stdin
  30. self.stdout = stdout
  31. self.stderr = stderr
  32. self.pidfile = pidfile
  33. self.home_dir = home_dir
  34. self.verbose = verbose
  35. self.umask = umask
  36. self.daemon_alive = True
  37. self.use_gevent = use_gevent
  38. self.use_eventlet = use_eventlet
  39. def log(self, *args):
  40. if self.verbose >= 1:
  41. print(*args)
  42. def daemonize(self):
  43. """
  44. Do the UNIX double-fork magic, see Stevens' "Advanced
  45. Programming in the UNIX Environment" for details (ISBN 0201563177)
  46. http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
  47. """
  48. if self.use_eventlet:
  49. import eventlet.tpool
  50. eventlet.tpool.killall()
  51. try:
  52. pid = os.fork()
  53. if pid > 0:
  54. # Exit first parent
  55. sys.exit(0)
  56. except OSError as e:
  57. sys.stderr.write(
  58. "fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
  59. sys.exit(1)
  60. # Decouple from parent environment
  61. os.chdir(self.home_dir)
  62. os.setsid()
  63. os.umask(self.umask)
  64. # Do second fork
  65. try:
  66. pid = os.fork()
  67. if pid > 0:
  68. # Exit from second parent
  69. sys.exit(0)
  70. except OSError as e:
  71. sys.stderr.write(
  72. "fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
  73. sys.exit(1)
  74. if sys.platform != 'darwin': # This block breaks on OS X
  75. # Redirect standard file descriptors
  76. sys.stdout.flush()
  77. sys.stderr.flush()
  78. si = open(self.stdin, 'r')
  79. so = open(self.stdout, 'a+')
  80. if self.stderr:
  81. try:
  82. se = open(self.stderr, 'a+', 0)
  83. except ValueError:
  84. # Python 3 can't have unbuffered text I/O
  85. se = open(self.stderr, 'a+', 1)
  86. else:
  87. se = so
  88. os.dup2(si.fileno(), sys.stdin.fileno())
  89. os.dup2(so.fileno(), sys.stdout.fileno())
  90. os.dup2(se.fileno(), sys.stderr.fileno())
  91. def sigtermhandler(signum, frame):
  92. self.daemon_alive = False
  93. sys.exit()
  94. if self.use_gevent:
  95. import gevent
  96. gevent.reinit()
  97. gevent.signal(signal.SIGTERM, sigtermhandler, signal.SIGTERM, None)
  98. gevent.signal(signal.SIGINT, sigtermhandler, signal.SIGINT, None)
  99. else:
  100. signal.signal(signal.SIGTERM, sigtermhandler)
  101. signal.signal(signal.SIGINT, sigtermhandler)
  102. self.log("Started")
  103. # Write pidfile
  104. atexit.register(
  105. self.delpid) # Make sure pid file is removed if we quit
  106. pid = str(os.getpid())
  107. open(self.pidfile, 'w+').write("%s\n" % pid)
  108. def delpid(self):
  109. try:
  110. # the process may fork itself again
  111. pid = int(open(self.pidfile, 'r').read().strip())
  112. if pid == os.getpid():
  113. os.remove(self.pidfile)
  114. except OSError as e:
  115. if e.errno == errno.ENOENT:
  116. pass
  117. else:
  118. raise
  119. def start(self, *args, **kwargs):
  120. """
  121. Start the daemon
  122. """
  123. self.log("Starting...")
  124. # Check for a pidfile to see if the daemon already runs
  125. try:
  126. pf = open(self.pidfile, 'r')
  127. pid = int(pf.read().strip())
  128. pf.close()
  129. except IOError:
  130. pid = None
  131. except SystemExit:
  132. pid = None
  133. if pid:
  134. message = "pidfile %s already exists. Is it already running?\n"
  135. sys.stderr.write(message % self.pidfile)
  136. sys.exit(1)
  137. # Start the daemon
  138. self.daemonize()
  139. self.run(*args, **kwargs)
  140. def stop(self):
  141. """
  142. Stop the daemon
  143. """
  144. if self.verbose >= 1:
  145. self.log("Stopping...")
  146. # Get the pid from the pidfile
  147. pid = self.get_pid()
  148. if not pid:
  149. message = "pidfile %s does not exist. Not running?\n"
  150. sys.stderr.write(message % self.pidfile)
  151. # Just to be sure. A ValueError might occur if the PID file is
  152. # empty but does actually exist
  153. if os.path.exists(self.pidfile):
  154. os.remove(self.pidfile)
  155. return # Not an error in a restart
  156. # Try killing the daemon process
  157. try:
  158. i = 0
  159. while 1:
  160. os.kill(pid, signal.SIGTERM)
  161. time.sleep(0.1)
  162. i = i + 1
  163. if i % 10 == 0:
  164. os.kill(pid, signal.SIGHUP)
  165. except OSError as err:
  166. if err.errno == errno.ESRCH:
  167. if os.path.exists(self.pidfile):
  168. os.remove(self.pidfile)
  169. else:
  170. print(str(err))
  171. sys.exit(1)
  172. self.log("Stopped")
  173. def restart(self):
  174. """
  175. Restart the daemon
  176. """
  177. self.stop()
  178. self.start()
  179. def get_pid(self):
  180. try:
  181. pf = open(self.pidfile, 'r')
  182. pid = int(pf.read().strip())
  183. pf.close()
  184. except IOError:
  185. pid = None
  186. except SystemExit:
  187. pid = None
  188. return pid
  189. def is_running(self):
  190. pid = self.get_pid()
  191. if pid is None:
  192. self.log('Process is stopped')
  193. return False
  194. elif os.path.exists('/proc/%d' % pid):
  195. self.log('Process (pid %d) is running...' % pid)
  196. return True
  197. else:
  198. self.log('Process (pid %d) is killed' % pid)
  199. return False
  200. def run(self, *args, **kwargs):
  201. """
  202. Running app
  203. """
  204. self.app(*args, **kwargs)
  205. #self.log("Starting foreground...")
  206. def main(cmd):
  207. from datetime import datetime
  208. from time import sleep
  209. import subprocess
  210. print("Starting cmd: ")
  211. print(str(cmd))
  212. subprocess.call(cmd)
  213. #while True:
  214. # print(str(datetime.now()))
  215. # sleep(5)
  216. #def main2(cmd):
  217. # from bottle import route, run
  218. # @route('/')
  219. # def index():
  220. # return '<b>Hello </b>!'
  221. # run(host='localhost', port=8080)
  222. if __name__ == "__main__":
  223. if len(sys.argv) > 1:
  224. cmd=sys.argv[2:]
  225. app = cmd[0] if cmd else "daemonize2"
  226. pid = "/var/run/%s.pid"%app
  227. daemon = Daemon(main,pid)
  228. if "start" == sys.argv[1]:
  229. daemon.start(cmd)
  230. elif "stop" == sys.argv[1]:
  231. daemon.stop()
  232. elif "restart" == sys.argv[1]:
  233. daemon.restart()
  234. elif "manualstart" == sys.argv[1]:
  235. daemon.run(cmd)
  236. elif "status" == sys.argv[1]:
  237. daemon.is_running()
  238. else:
  239. print("Unknown command")
  240. sys.exit(2)
  241. sys.exit(0)
  242. else:
  243. print("usage: %s start|stop|restart|manualstart" % sys.argv[0])
  244. sys.exit(2)