@ -2,28 +2,25 @@
import os
import platform
import signal
import subprocess
import sys
import time
import atexit
from bazarr . get_args import args
from libs . six import PY3
def check_python_version ( ) :
python_version = platform . python_version_tuple ( )
minimum_py2_tuple = ( 2 , 7 , 13 )
minimum_py3_tuple = ( 3 , 7 , 0 )
minimum_py2_str = " . " . join ( str ( i ) for i in minimum_py2_tuple )
minimum_py3_str = " . " . join ( str ( i ) for i in minimum_py3_tuple )
if int ( python_version [ 0 ] ) < 3 :
if int ( python_version [ 0 ] ) < minimum_py3_tuple [ 0 ] :
print ( " Python " + minimum_py3_str + " or greater required. "
" Current version is " + platform . python_version ( ) + " . Please upgrade Python. " )
sys . exit ( 1 )
elif ( int ( python_version [ 0 ] ) == minimum_py3_tuple [ 0 ] and int ( python_version [ 1 ] ) < minimum_py3_tuple [ 1 ] ) or \
( int ( python_version [ 0 ] ) != minimum_py3_tuple [ 0 ] and int ( python_version [ 0 ] ) != minimum_py2_tuple [ 0 ] ) :
( int ( python_version [ 0 ] ) != minimum_py3_tuple [ 0 ] ) :
print ( " Python " + minimum_py3_str + " or greater required. "
" Current version is " + platform . python_version ( ) + " . Please upgrade Python. " )
sys . exit ( 1 )
@ -34,138 +31,55 @@ check_python_version()
dir_name = os . path . dirname ( __file__ )
class ProcessRegistry :
def register ( self , process ) :
pass
def unregister ( self , process ) :
pass
class DaemonStatus ( ProcessRegistry ) :
def __init__ ( self ) :
self . __should_stop = False
self . __processes = set ( )
def register ( self , process ) :
self . __processes . add ( process )
def unregister ( self , process ) :
self . __processes . remove ( process )
@staticmethod
def __send_signal ( processes , signal_no , live_processes = None ) :
"""
Sends to every single of the specified processes the given signal and ( if live_processes is not None ) append to
it processes which are still alive .
"""
for ep in processes :
if ep . poll ( ) is None :
if live_processes is not None :
live_processes . append ( ep )
try :
ep . send_signal ( signal_no )
except Exception as e :
print ( ' Failed sending signal %s to process %s because of an unexpected error: %s ' % (
signal_no , ep . pid , e ) )
return live_processes
def stop ( self ) :
"""
Flags this instance as should stop and terminates as smoothly as possible children processes .
"""
self . __should_stop = True
DaemonStatus . __send_signal ( self . __processes , signal . SIGINT , list ( ) )
def force_stop ( self ) :
self . __should_stop = True
DaemonStatus . __send_signal ( self . __processes , signal . SIGTERM )
def should_stop ( self ) :
return self . __should_stop
def start_bazarr ( process_registry = ProcessRegistry ( ) ) :
def start_bazarr ( ) :
script = [ sys . executable , " -u " , os . path . normcase ( os . path . join ( dir_name , ' bazarr ' , ' main.py ' ) ) ] + sys . argv [ 1 : ]
print ( " Bazarr starting... " )
if PY3 :
ep = subprocess . Popen ( script , stdout = None , stderr = None , stdin = subprocess . DEVNULL )
else :
ep = subprocess . Popen ( script , stdout = None , stderr = None , stdin = None )
process_registry . register ( ep )
try :
ep . wait ( )
process_registry . unregister ( ep )
except KeyboardInterrupt :
pass
ep = subprocess . Popen ( script , stdout = None , stderr = None , stdin = subprocess . DEVNULL )
atexit . register ( lambda : ep . kill ( ) )
def check_status ( ) :
if os . path . exists ( stopfile ) :
try :
os . remove ( stopfile )
except Exception :
print ( ' Unable to delete stop file. ' )
finally :
print ( ' Bazarr exited. ' )
sys . exit ( 0 )
if os . path . exists ( restartfile ) :
try :
os . remove ( restartfile )
except Exception :
print ( ' Unable to delete restart file. ' )
else :
print ( " Bazarr is restarting... " )
start_bazarr ( )
if __name__ == ' __main__ ' :
restartfile = os . path . normcase ( os . path . join ( args . config_dir , ' bazarr.restart ' ) )
stopfile = os . path . normcase ( os . path . join ( args . config_dir , ' bazarr.stop ' ) )
restartfile = os . path . join ( args . config_dir , ' bazarr.restart ' )
stopfile = os . path . join ( args . config_dir , ' bazarr.stop ' )
# Cleanup leftover files
try :
os . remove ( restartfile )
except Exception :
except FileNotFoundError :
pass
try :
os . remove ( stopfile )
except Exception :
except FileNotFoundError :
pass
def daemon ( bazarr_runner = lambda : start_bazarr ( ) ) :
if os . path . exists ( stopfile ) :
try :
os . remove ( stopfile )
except Exception :
print ( ' Unable to delete stop file. ' )
else :
print ( ' Bazarr exited. ' )
sys . exit ( 0 )
if os . path . exists ( restartfile ) :
try :
os . remove ( restartfile )
except Exception :
print ( ' Unable to delete restart file. ' )
else :
bazarr_runner ( )
bazarr_runner = lambda : start_bazarr ( )
should_stop = lambda : False
if PY3 :
daemonStatus = DaemonStatus ( )
def force_shutdown ( ) :
# force the killing of children processes
daemonStatus . force_stop ( )
# if a new SIGTERM signal is caught the standard behaviour should be followed
signal . signal ( signal . SIGTERM , signal . SIG_DFL )
# emulate a Ctrl C command on itself (bypasses the signal thing but, then, emulates the "Ctrl+C break")
os . kill ( os . getpid ( ) , signal . SIGINT )
def shutdown ( ) :
# indicates that everything should stop
daemonStatus . stop ( )
# if a new sigterm signal is caught it should force the shutdown of children processes
signal . signal ( signal . SIGTERM , lambda signal_no , frame : force_shutdown ( ) )
signal . signal ( signal . SIGTERM , lambda signal_no , frame : shutdown ( ) )
should_stop = lambda : daemonStatus . should_stop ( )
bazarr_runner = lambda : start_bazarr ( daemonStatus )
bazarr_runner ( )
# Initial start of main bazarr process
print ( " Bazarr starting... " )
start_bazarr ( )
# Keep the script running forever until stop is requested through term or keyboard interrupt
while not should_stop ( ) :
daemon ( bazarr_runner )
time . sleep ( 1 )
while True :
check_status ( )
try :
time . sleep ( 1 )
except ( KeyboardInterrupt , SystemExit ) :
pass