Merge pull request #825 from JackDandy/feature/ChangeShutdown

Change consolidate shutdown with restart, improve systemd support, br…
This commit is contained in:
JackDandy 2016-11-13 01:56:14 +00:00 committed by GitHub
commit 6da0f7f7fe
9 changed files with 361 additions and 382 deletions

View file

@ -191,6 +191,7 @@
* Change improve performance and reduce start up time
* Fix button "Checkout branch" when stuck on disabled
* Add 'Download Log' to 'Logs & Errors' page
* Change consolidate shutdown with restart, improve systemd support, bring order to on-init globals
[develop changelog]
* Change send nzb data to NZBGet for Anizb instead of url

View file

@ -80,48 +80,69 @@ class SickGear(object):
sickbeard.events = Events(self.shutdown)
# daemon constants
self.runAsDaemon = False
self.CREATEPID = False
self.PIDFILE = ''
self.run_as_daemon = False
self.create_pid = False
self.pid_file = ''
self.run_as_systemd = False
self.console_logging = False
# webserver constants
self.webserver = None
self.forceUpdate = False
self.forcedPort = None
self.noLaunch = False
self.force_update = False
self.forced_port = None
self.no_launch = False
self.web_options = None
self.webhost = None
self.start_port = None
self.log_dir = None
@staticmethod
def help_message():
"""
print help message for commandline options
"""
help_msg = '\n'
help_msg += 'Usage: %s <option> <another option>\n' % sickbeard.MY_FULLNAME
help_msg += '\n'
help_msg += 'Options:\n'
help_msg += '\n'
help_msg += ' -h --help Prints this message\n'
help_msg += ' -f --forceupdate Force update all shows in the DB (from tvdb) on startup\n'
help_msg += ' -q --quiet Disables logging to console\n'
help_msg += ' --nolaunch Suppress launching web browser on startup\n'
help_msg = ['']
help_msg += ['Usage: %s <option> <another option>\n' % sickbeard.MY_FULLNAME]
help_msg += ['Options:\n']
if sys.platform == 'win32':
help_msg += ' -d --daemon Running as real daemon is not supported on Windows\n'
help_msg += ' On Windows, --daemon is substituted with: --quiet --nolaunch\n'
help_tmpl = ' %-10s%-17s%s'
for ln in [
('-h', '--help', 'Prints this message'),
('-f', '--forceupdate', 'Force update all shows in the DB (from tvdb) on startup'),
('-q', '--quiet', 'Disables logging to console'),
('', '--nolaunch', 'Suppress launching web browser on startup')
]:
help_msg += [help_tmpl % ln]
if 'win32' == sys.platform:
for ln in [
('-d', '--daemon', 'Running as daemon is not supported on Windows'),
('', '', 'On Windows, --daemon is substituted with: --quiet --nolaunch')
]:
help_msg += [help_tmpl % ln]
else:
help_msg += ' -d --daemon Run as double forked daemon (includes options --quiet --nolaunch)\n'
help_msg += ' --pidfile=<path> Combined with --daemon creates a pidfile (full path including filename)\n'
for ln in [
('-d', '--daemon', 'Run as double forked daemon (includes options --quiet --nolaunch)'),
('-s', '--systemd', 'Run as systemd service (includes options --quiet --nolaunch)'),
('', '--pidfile=<path>', 'Combined with --daemon creates a pidfile (full path including filename)')
]:
help_msg += [help_tmpl % ln]
help_msg += ' -p <port> --port=<port> Override default/configured port to listen on\n'
help_msg += ' --datadir=<path> Override folder (full path) as location for\n'
help_msg += ' storing database, configfile, cache, logfiles \n'
help_msg += ' Default: %s\n' % sickbeard.PROG_DIR
help_msg += ' --config=<path> Override config filename (full path including filename)\n'
help_msg += ' to load configuration from \n'
help_msg += ' Default: config.ini in %s or --datadir location\n' % sickbeard.PROG_DIR
help_msg += ' --noresize Prevent resizing of the banner/posters even if PIL is installed\n'
for ln in [
('-p <port>', '--port=<port>', 'Override default/configured port to listen on'),
('', '--datadir=<path>', 'Override folder (full path) as location for'),
('', '', 'storing database, configfile, cache, logfiles'),
('', '', 'Default: %s' % sickbeard.PROG_DIR),
('', '--config=<path>', 'Override config filename (full path including filename)'),
('', '', 'to load configuration from'),
('', '', 'Default: config.ini in %s or --datadir location' % sickbeard.PROG_DIR),
('', '--noresize', 'Prevent resizing of the banner/posters even if PIL is installed')
]:
help_msg += [help_tmpl % ln]
return help_msg
return '\n'.join(help_msg)
def start(self):
# do some preliminary stuff
@ -150,23 +171,23 @@ class SickGear(object):
try:
# pylint: disable=E1101
# On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError
# On non-unicode builds this raises an AttributeError, if encoding type is not valid it throws a LookupError
sys.setdefaultencoding(sickbeard.SYS_ENCODING)
except:
except (StandardError, Exception):
print('Sorry, you MUST add the SickGear folder to the PYTHONPATH environment variable')
print('or find another way to force Python to use %s for string encoding.' % sickbeard.SYS_ENCODING)
sys.exit(1)
# Need console logging for SickBeard.py and SickBeard-console.exe
self.consoleLogging = (not hasattr(sys, 'frozen')) or (sickbeard.MY_NAME.lower().find('-console') > 0)
self.console_logging = (not hasattr(sys, 'frozen')) or (sickbeard.MY_NAME.lower().find('-console') > 0)
# Rename the main thread
threading.currentThread().name = 'MAIN'
try:
opts, args = getopt.getopt(sys.argv[1:], 'hfqdp::',
['help', 'forceupdate', 'quiet', 'nolaunch', 'daemon', 'pidfile=', 'port=',
'datadir=', 'config=', 'noresize']) # @UnusedVariable
opts, args = getopt.getopt(sys.argv[1:], 'hfqdsp::',
['help', 'forceupdate', 'quiet', 'nolaunch', 'daemon', 'systemd', 'pidfile=',
'port=', 'datadir=', 'config=', 'noresize']) # @UnusedVariable
except getopt.GetoptError:
sys.exit(self.help_message())
@ -177,43 +198,50 @@ class SickGear(object):
# For now we'll just silence the logging
if o in ('-q', '--quiet'):
self.consoleLogging = False
self.console_logging = False
# Should we update (from indexer) all shows in the DB right away?
if o in ('-f', '--forceupdate'):
self.forceUpdate = True
self.force_update = True
# Suppress launching web browser
# Needed for OSes without default browser assigned
# Prevent duplicate browser window when restarting in the app
if o in ('--nolaunch',):
self.noLaunch = True
self.no_launch = True
# Override default/configured port
if o in ('-p', '--port'):
try:
self.forcedPort = int(a)
self.forced_port = int(a)
except ValueError:
sys.exit('Port: %s is not a number. Exiting.' % a)
# Run as a double forked daemon
if o in ('-d', '--daemon'):
self.runAsDaemon = True
self.run_as_daemon = True
# When running as daemon disable consoleLogging and don't start browser
self.consoleLogging = False
self.noLaunch = True
self.console_logging = False
self.no_launch = True
if sys.platform == 'win32':
self.runAsDaemon = False
if 'win32' == sys.platform:
self.run_as_daemon = False
# Run as a systemd service
if o in ('-s', '--systemd') and 'win32' != sys.platform:
self.run_as_systemd = True
self.run_as_daemon = False
self.console_logging = False
self.no_launch = True
# Write a pidfile if requested
if o in ('--pidfile',):
self.CREATEPID = True
self.PIDFILE = str(a)
self.create_pid = True
self.pid_file = str(a)
# If the pidfile already exists, sickbeard may still be running, so exit
if os.path.exists(self.PIDFILE):
sys.exit('PID file: %s already exists. Exiting.' % self.PIDFILE)
if os.path.exists(self.pid_file):
sys.exit('PID file: %s already exists. Exiting.' % self.pid_file)
# Specify folder to load the config file from
if o in ('--config',):
@ -228,19 +256,19 @@ class SickGear(object):
sickbeard.NO_RESIZE = True
# The pidfile is only useful in daemon mode, make sure we can write the file properly
if self.CREATEPID:
if self.runAsDaemon:
pid_dir = os.path.dirname(self.PIDFILE)
if self.create_pid:
if self.run_as_daemon:
pid_dir = os.path.dirname(self.pid_file)
if not os.access(pid_dir, os.F_OK):
sys.exit(u"PID dir: %s doesn't exist. Exiting." % pid_dir)
if not os.access(pid_dir, os.W_OK):
sys.exit(u'PID dir: %s must be writable (write permissions). Exiting.' % pid_dir)
else:
if self.consoleLogging:
if self.console_logging:
print(u'Not running in daemon mode. PID file creation disabled')
self.CREATEPID = False
self.create_pid = False
# If they don't specify a config file then put it in the data dir
if not sickbeard.CONFIG_FILE:
@ -266,7 +294,7 @@ class SickGear(object):
% os.path.dirname(sickbeard.CONFIG_FILE))
os.chdir(sickbeard.DATA_DIR)
if self.consoleLogging:
if self.console_logging:
print(u'Starting up SickGear from %s' % sickbeard.CONFIG_FILE)
# Load the config and publish it to the sickbeard package
@ -307,19 +335,19 @@ class SickGear(object):
print(u'Rollback of [%s] successful.' % d)
# Initialize the config and our threads
sickbeard.initialize(consoleLogging=self.consoleLogging)
sickbeard.initialize(console_logging=self.console_logging)
if self.runAsDaemon:
if self.run_as_daemon:
self.daemonize()
# Get PID
sickbeard.PID = os.getpid()
if self.forcedPort:
logger.log(u'Forcing web server to port %s' % self.forcedPort)
self.startPort = self.forcedPort
if self.forced_port:
logger.log(u'Forcing web server to port %s' % self.forced_port)
self.start_port = self.forced_port
else:
self.startPort = sickbeard.WEB_PORT
self.start_port = sickbeard.WEB_PORT
if sickbeard.WEB_LOG:
self.log_dir = sickbeard.LOG_DIR
@ -338,7 +366,7 @@ class SickGear(object):
# web server options
self.web_options = {
'port': int(self.startPort),
'port': int(self.start_port),
'host': self.webhost,
'data_root': os.path.join(sickbeard.PROG_DIR, 'gui', sickbeard.GUI_NAME),
'web_root': sickbeard.WEB_ROOT,
@ -358,24 +386,26 @@ class SickGear(object):
self.webserver = WebServer(self.web_options)
self.webserver.start()
except Exception:
logger.log(u'Unable to start web server, is something else running on port %d?' % self.startPort,
except (StandardError, Exception):
logger.log(u'Unable to start web server, is something else running on port %d?' % self.start_port,
logger.ERROR)
if sickbeard.LAUNCH_BROWSER and not self.runAsDaemon:
if self.run_as_systemd:
self.exit(0)
if sickbeard.LAUNCH_BROWSER and not self.no_launch:
logger.log(u'Launching browser and exiting', logger.ERROR)
sickbeard.launch_browser(self.startPort)
os._exit(1)
sickbeard.launch_browser(self.start_port)
self.exit(1)
# Check if we need to perform a restore first
restoreDir = os.path.join(sickbeard.DATA_DIR, 'restore')
if os.path.exists(restoreDir):
if self.restore(restoreDir, sickbeard.DATA_DIR):
restore_dir = os.path.join(sickbeard.DATA_DIR, 'restore')
if os.path.exists(restore_dir):
if self.restore(restore_dir, sickbeard.DATA_DIR):
logger.log(u'Restore successful...')
else:
logger.log_error_and_exit(u'Restore FAILED!')
# Build from the DB to start with
self.loadShowsFromDB()
self.load_shows_from_db()
# Fire up all our threads
sickbeard.start()
@ -395,12 +425,12 @@ class SickGear(object):
failed_history.trimHistory()
# Start an update if we're supposed to
if self.forceUpdate or sickbeard.UPDATE_SHOWS_ON_START:
if self.force_update or sickbeard.UPDATE_SHOWS_ON_START:
sickbeard.showUpdateScheduler.action.run(force=True) # @UndefinedVariable
# Launch browser
if sickbeard.LAUNCH_BROWSER and not (self.noLaunch or self.runAsDaemon):
sickbeard.launch_browser(self.startPort)
if sickbeard.LAUNCH_BROWSER and not self.no_launch:
sickbeard.launch_browser(self.start_port)
# main loop
while True:
@ -415,9 +445,9 @@ class SickGear(object):
try:
pid = os.fork() # @UndefinedVariable - only available in UNIX
if pid != 0:
os._exit(0)
except OSError as e:
sys.stderr.write('fork #1 failed: %d (%s)\n' % (e.errno, e.strerror))
self.exit(0)
except OSError as er:
sys.stderr.write('fork #1 failed: %d (%s)\n' % (er.errno, er.strerror))
sys.exit(1)
os.setsid() # @UndefinedVariable - only available in UNIX
@ -430,20 +460,20 @@ class SickGear(object):
try:
pid = os.fork() # @UndefinedVariable - only available in UNIX
if pid != 0:
os._exit(0)
except OSError as e:
sys.stderr.write('fork #2 failed: %d (%s)\n' % (e.errno, e.strerror))
self.exit(0)
except OSError as er:
sys.stderr.write('fork #2 failed: %d (%s)\n' % (er.errno, er.strerror))
sys.exit(1)
# Write pid
if self.CREATEPID:
if self.create_pid:
pid = str(os.getpid())
logger.log(u'Writing PID: %s to %s' % (pid, self.PIDFILE))
logger.log(u'Writing PID: %s to %s' % (pid, self.pid_file))
try:
open(self.PIDFILE, 'w').write('%s\n' % pid)
except IOError as e:
logger.log_error_and_exit(
u'Unable to write PID file: %s Error: %s [%s]' % (self.PIDFILE, e.strerror, e.errno))
open(self.pid_file, 'w').write('%s\n' % pid)
except IOError as er:
logger.log_error_and_exit('Unable to write PID file: %s Error: %s [%s]' % (
self.pid_file, er.strerror, er.errno))
# Redirect all output
sys.stdout.flush()
@ -458,10 +488,10 @@ class SickGear(object):
os.dup2(stderr.fileno(), sys.stderr.fileno())
@staticmethod
def remove_pid_file(PIDFILE):
def remove_pid_file(pidfile):
try:
if os.path.exists(PIDFILE):
os.remove(PIDFILE)
if os.path.exists(pidfile):
os.remove(pidfile)
except (IOError, OSError):
return False
@ -469,43 +499,42 @@ class SickGear(object):
return True
@staticmethod
def loadShowsFromDB():
def load_shows_from_db():
"""
Populates the showList with shows from the database
"""
logger.log(u'Loading initial show list')
myDB = db.DBConnection()
sqlResults = myDB.select('SELECT * FROM tv_shows')
my_db = db.DBConnection()
sql_results = my_db.select('SELECT * FROM tv_shows')
sickbeard.showList = []
for sqlShow in sqlResults:
for sqlShow in sql_results:
try:
curShow = TVShow(int(sqlShow['indexer']), int(sqlShow['indexer_id']))
curShow.nextEpisode()
sickbeard.showList.append(curShow)
except Exception as e:
logger.log(
u'There was an error creating the show in %s: %s' % (sqlShow['location'], str(e).decode('utf-8',
'replace')),
logger.ERROR)
cur_show = TVShow(int(sqlShow['indexer']), int(sqlShow['indexer_id']))
cur_show.nextEpisode()
sickbeard.showList.append(cur_show)
except Exception as er:
logger.log('There was an error creating the show in %s: %s' % (
sqlShow['location'], str(er).decode('utf-8', 'replace')), logger.ERROR)
def restore(self, srcDir, dstDir):
@staticmethod
def restore(src_dir, dst_dir):
try:
for file in os.listdir(srcDir):
srcFile = os.path.join(srcDir, file)
dstFile = os.path.join(dstDir, file)
bakFile = os.path.join(dstDir, file + '.bak')
shutil.move(dstFile, bakFile)
shutil.move(srcFile, dstFile)
for filename in os.listdir(src_dir):
src_file = os.path.join(src_dir, filename)
dst_file = os.path.join(dst_dir, filename)
bak_file = os.path.join(dst_dir, '%s.bak' % filename)
shutil.move(dst_file, bak_file)
shutil.move(src_file, dst_file)
os.rmdir(srcDir)
os.rmdir(src_dir)
return True
except:
except (StandardError, Exception):
return False
def shutdown(self, type):
def shutdown(self, ev_type):
if sickbeard.started:
# stop all tasks
sickbeard.halt()
@ -519,14 +548,15 @@ class SickGear(object):
self.webserver.shutDown()
try:
self.webserver.join(10)
except:
except (StandardError, Exception):
pass
# if run as daemon delete the pidfile
if self.runAsDaemon and self.CREATEPID:
self.remove_pid_file(self.PIDFILE)
if self.run_as_daemon and self.create_pid:
self.remove_pid_file(self.pid_file)
if sickbeard.events.SystemEvent.RESTART == ev_type:
if type == sickbeard.events.SystemEvent.RESTART:
install_type = sickbeard.versionCheckScheduler.action.install_type
popen_list = []
@ -536,6 +566,12 @@ class SickGear(object):
if popen_list:
popen_list += sickbeard.MY_ARGS
if self.run_as_systemd:
logger.log(u'Restarting SickGear with exit(1) handler and %s' % popen_list)
logger.close()
self.exit(1)
if '--nolaunch' not in popen_list:
popen_list += ['--nolaunch']
logger.log(u'Restarting SickGear with %s' % popen_list)
@ -543,8 +579,11 @@ class SickGear(object):
subprocess.Popen(popen_list, cwd=os.getcwd())
# system exit
os._exit(0)
self.exit(0)
@staticmethod
def exit(code):
os._exit(code)
if __name__ == '__main__':
if sys.hexversion >= 0x020600F0:

View file

@ -56,7 +56,7 @@
<span class="component-desc">
<select name="tag" id="tag" class="form-control form-control-inline input-sm">
#for $tag in $sickbeard.SHOW_TAGS:
<option value="$tag" #if $tag == $sickbeard.DEFAULT_SHOW_TAG then 'selected="selected"' else ''#>$tag</option>
<option value="$tag" #if $tag == $getattr(sickbeard, 'SHOW_TAG_DEFAULT', $getattr(sickbeard, 'DEFAULT_SHOW_TAG', None)) then 'selected="selected"' else ''#>$tag</option>
#end for
</select>
<span>and display on the show list page under this section</span>

View file

@ -1,3 +1,10 @@
##
#set sgHost = $sbHost
#set sgPort = $sbHttpPort
#set sgRoot = $sbRoot
#set sgUseHttps = $sbHttpsEnabled
#set themeSpinner = '-dark' if 'dark' == $sbThemeName else ''
##
<!DOCTYPE html>
<head>
<meta charset="utf-8">
@ -26,26 +33,12 @@
<meta name="msapplication-config" content="$sbRoot/css/browserconfig.xml">
<script type="text/javascript" src="$sbRoot/js/lib/jquery-1.8.3.min.js?v=$sbPID"></script>
#try:
#set sgHost = $sbHost
#set sgPort = $sbHttpPort
#set sgUseHttps = $sbHttpsEnabled
#set themeSpinner = $sbThemeName
#except NameMapper.NotFound:
#set sgHost = 'localhost'
#set sgPort = $sickbeard.WEB_PORT
#set sgUseHttps = False
#set themeSpinner = $sickbeard.THEME_NAME
#end try
#set themeSpinner = '-dark' if 'dark' == themeSpinner else ''
##
<script type="text/javascript" charset="utf-8">
<!--
\$.SickGear = {
Root: '$sbRoot',
Host: '$sgHost',
Port: '$sgPort',
Root: '$sgRoot',
UseHttps: #echo ('!1', '!0')[False != $sgUseHttps and 0 != $sgUseHttps]#
};
//-->
@ -58,12 +51,12 @@ body{padding-top:0 !important}.sglogo{display:block;width:138px;height:74px;marg
</style>
<link rel="stylesheet" type="text/css" href="$sbRoot/css/style.css?v=$sbPID">
<link rel="stylesheet" type="text/css" href="$sbRoot/css/#echo ('dark', 'light')['' == themeSpinner]#.css?v=$sbPID">
<link rel="stylesheet" type="text/css" href="$sbRoot/css/#echo ('dark', 'light')['' == $themeSpinner]#.css?v=$sbPID">
</head><body><span class="sglogo"></span>
<div class="bfr"><img src="$sbRoot/images/loading16${themeSpinner}.gif" /><img src="$sbRoot/images/yes16.png" /><img src="$sbRoot/images/no16.png" /></div>
<h2 class="sub-title">Performing Restart</h2>
<h2 class="sub-title">Performing #echo ('Restart', 'Shutdown')[$shutdown]#</h2>
<div id="shut_down_message">
<span class="desc"><span class="grey-text">Waiting for SickGear to</span> shut down: </span>
@ -71,17 +64,23 @@ body{padding-top:0 !important}.sglogo{display:block;width:138px;height:74px;marg
</div>
<div class="hide" id="restart_message">
#if not $shutdown
<span class="desc"><span class="grey-text">Waiting for SickGear to</span> start up: </span>
<span class="images"><i class="spinner"></i><span class="hide-yes"><i class="yes"></i></span><span class="hide-no"><i class="no"></i></span></span>
#end if
</div>
<div class="hide" id="refresh_message">
#if not $shutdown
<span class="desc"><span class="grey-text">Waiting for SickGear </span> home page: </span>
<span class="images"><i class="spinner"></i></span>
#end if
</div>
<div class="hide" id="restart_fail_message">
#if not $shutdown
<span class="red-text">Error:</span> The restart timed out, perhaps something prevented SickGear from starting ?
#end if
</div>
</body></html>

View file

@ -11,8 +11,7 @@
# Putting a minus (-) in front of file means no error warning if the file doesn't exist
#
# - Adjust ExecStart= to point to your python and SickGear executables.
# The FIRST token of the command line must be an ABSOLUTE FILE NAME,
# then followed by arguments for the process.
# The FIRST token of the command line must be an ABSOLUTE FILE NAME, followed by arguments for the process.
# If no --datadir is given, data is stored in same dir as SickBeard.py
# Arguments can also be set in EnvironmentFile (except python)
#
@ -21,16 +20,6 @@
# graphical.target equates to runlevel 5 (multi-user X11 graphical mode)
#
### Example Using SickGear as daemon with pid file
# Type=forking
# PIDFile=/var/run/sickgear/sickgear.pid
# ExecStart=/usr/bin/python2 /opt/sickgear/app/SickBeard.py -q --daemon --nolaunch --pidfile=/var/run/sickgear/sickgear.pid --datadir=/opt/sickgear/data
## Example Using SickGear as daemon without pid file
# Type=forking
# GuessMainPID=no
# ExecStart=/usr/bin/python2 /opt/sickgear/app/SickBeard.py -q --daemon --nolaunch --datadir=/opt/sickgear/data
### Example Using simple
# Type=simple
# ExecStart=/usr/bin/python2 /opt/sickgear/app/SickBeard.py -q --nolaunch
@ -43,15 +32,16 @@
### Configuration
[Unit]
Description=SickGear Daemon
Description=SickGear Service
[Service]
User=sickgear
Group=sickgear
Type=forking
GuessMainPID=no
ExecStart=/usr/bin/python2 /opt/sickgear/app/SickBeard.py -q --daemon --nolaunch --datadir=/opt/sickgear/data
Environment=PYTHONUNBUFFERED=true
ExecStart=/usr/bin/python2 /opt/sickgear/app/SickBeard.py --systemd --datadir=/opt/sickgear/data
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target

View file

@ -83,7 +83,7 @@ searchQueueScheduler = None
properFinderScheduler = None
autoPostProcesserScheduler = None
subtitlesFinderScheduler = None
traktCheckerScheduler = None
# traktCheckerScheduler = None
background_mapping_task = None
showList = None
@ -146,11 +146,8 @@ TRASH_ROTATE_LOGS = False
HOME_SEARCH_FOCUS = True
SORT_ARTICLE = False
DEBUG = False
DISPLAY_BACKGROUND = False
DISPLAY_BACKGROUND_TRANSPARENT = None
DISPLAY_ALL_SEASONS = True
SHOW_TAGS = []
DEFAULT_SHOW_TAG = ''
SHOW_TAG_DEFAULT = ''
SHOWLIST_TAGVIEW = ''
METADATA_XBMC = None
@ -203,13 +200,13 @@ TORRENT_DIR = None
DOWNLOAD_PROPERS = False
CHECK_PROPERS_INTERVAL = None
ALLOW_HIGH_PRIORITY = False
NEWZNAB_DATA = ''
AUTOPOSTPROCESSER_FREQUENCY = None
RECENTSEARCH_FREQUENCY = None
RECENTSEARCH_FREQUENCY = 0
UPDATE_FREQUENCY = None
RECENTSEARCH_STARTUP = False
BACKLOG_FREQUENCY = None
BACKLOG_STARTUP = False
BACKLOG_NOFULL = False
DEFAULT_AUTOPOSTPROCESSER_FREQUENCY = 10
@ -458,7 +455,8 @@ EXTRA_SCRIPTS = []
GIT_PATH = None
IGNORE_WORDS = 'core2hd, hevc, MrLss, reenc, x265, danish, deutsch, dutch, flemish, french, german, italian, nordic, norwegian, portuguese, spanish, swedish, turkish'
IGNORE_WORDS = 'core2hd, hevc, MrLss, reenc, x265, danish, deutsch, dutch, flemish, french, ' + \
'german, italian, nordic, norwegian, portuguese, spanish, swedish, turkish'
REQUIRE_WORDS = ''
CALENDAR_UNPROTECTED = False
@ -499,81 +497,119 @@ def get_backlog_cycle_time():
return max([cycletime, 720])
def initialize(consoleLogging=True):
def initialize(console_logging=True):
with INIT_LOCK:
global BRANCH, GIT_REMOTE, CUR_COMMIT_HASH, CUR_COMMIT_BRANCH, ACTUAL_LOG_DIR, LOG_DIR, FILE_LOGGING_PRESET, WEB_PORT, WEB_LOG, ENCRYPTION_VERSION, WEB_ROOT, WEB_USERNAME, WEB_PASSWORD, WEB_HOST, WEB_IPV6, USE_API, API_KEY, ENABLE_HTTPS, HTTPS_CERT, HTTPS_KEY, \
HANDLE_REVERSE_PROXY, USE_NZBS, USE_TORRENTS, NZB_METHOD, NZB_DIR, DOWNLOAD_PROPERS, CHECK_PROPERS_INTERVAL, ALLOW_HIGH_PRIORITY, TORRENT_METHOD, \
SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, SAB_HOST, \
NZBGET_USERNAME, NZBGET_PASSWORD, NZBGET_CATEGORY, NZBGET_PRIORITY, NZBGET_HOST, NZBGET_USE_HTTPS, backlogSearchScheduler, \
TORRENT_USERNAME, TORRENT_PASSWORD, TORRENT_HOST, TORRENT_PATH, TORRENT_SEED_TIME, TORRENT_PAUSED, TORRENT_HIGH_BANDWIDTH, TORRENT_LABEL, TORRENT_VERIFY_CERT, \
USE_EMBY, EMBY_UPDATE_LIBRARY, EMBY_HOST, EMBY_APIKEY, \
USE_KODI, KODI_ALWAYS_ON, KODI_NOTIFY_ONSNATCH, KODI_NOTIFY_ONDOWNLOAD, KODI_NOTIFY_ONSUBTITLEDOWNLOAD,\
KODI_UPDATE_FULL, KODI_UPDATE_ONLYFIRST, KODI_UPDATE_LIBRARY, KODI_HOST, KODI_USERNAME, KODI_PASSWORD, \
USE_XBMC, XBMC_ALWAYS_ON, XBMC_NOTIFY_ONSNATCH, XBMC_NOTIFY_ONDOWNLOAD, XBMC_NOTIFY_ONSUBTITLEDOWNLOAD,\
XBMC_UPDATE_FULL, XBMC_UPDATE_ONLYFIRST, XBMC_UPDATE_LIBRARY, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, \
USE_PLEX, PLEX_NOTIFY_ONSNATCH, PLEX_NOTIFY_ONDOWNLOAD, PLEX_NOTIFY_ONSUBTITLEDOWNLOAD, \
PLEX_UPDATE_LIBRARY, PLEX_SERVER_HOST, PLEX_HOST, PLEX_USERNAME, PLEX_PASSWORD, \
USE_TRAKT, TRAKT_CONNECTED_ACCOUNT, TRAKT_ACCOUNTS, TRAKT_MRU, TRAKT_VERIFY, TRAKT_REMOVE_WATCHLIST, TRAKT_TIMEOUT, TRAKT_USE_WATCHLIST, TRAKT_METHOD_ADD, TRAKT_START_PAUSED, traktCheckerScheduler, TRAKT_SYNC, TRAKT_DEFAULT_INDEXER, TRAKT_REMOVE_SERIESLIST, TRAKT_UPDATE_COLLECTION, \
BACKLOG_FREQUENCY, DEFAULT_BACKLOG_FREQUENCY, MIN_BACKLOG_FREQUENCY, MAX_BACKLOG_FREQUENCY, BACKLOG_STARTUP, BACKLOG_NOFULL, SKIP_REMOVED_FILES, \
showUpdateScheduler, __INITIALIZED__, LAUNCH_BROWSER, TRASH_REMOVE_SHOW, TRASH_ROTATE_LOGS, HOME_SEARCH_FOCUS, SORT_ARTICLE, showList, loadingShowList, UPDATE_SHOWS_ON_START, SHOW_UPDATE_HOUR, \
NEWZNAB_DATA, INDEXER_DEFAULT, INDEXER_TIMEOUT, USENET_RETENTION, TORRENT_DIR, \
QUALITY_DEFAULT, FLATTEN_FOLDERS_DEFAULT, SUBTITLES_DEFAULT, STATUS_DEFAULT, WANTED_BEGIN_DEFAULT, WANTED_LATEST_DEFAULT, RECENTSEARCH_STARTUP, \
GROWL_NOTIFY_ONSNATCH, GROWL_NOTIFY_ONDOWNLOAD, GROWL_NOTIFY_ONSUBTITLEDOWNLOAD, TWITTER_NOTIFY_ONSNATCH, TWITTER_NOTIFY_ONDOWNLOAD, TWITTER_NOTIFY_ONSUBTITLEDOWNLOAD, \
USE_GROWL, GROWL_HOST, GROWL_PASSWORD, USE_PROWL, PROWL_NOTIFY_ONSNATCH, PROWL_NOTIFY_ONDOWNLOAD, PROWL_NOTIFY_ONSUBTITLEDOWNLOAD, PROWL_API, PROWL_PRIORITY, PROG_DIR, \
USE_PYTIVO, PYTIVO_NOTIFY_ONSNATCH, PYTIVO_NOTIFY_ONDOWNLOAD, PYTIVO_NOTIFY_ONSUBTITLEDOWNLOAD, PYTIVO_UPDATE_LIBRARY, PYTIVO_HOST, PYTIVO_SHARE_NAME, PYTIVO_TIVO_NAME, \
# Misc
global __INITIALIZED__, showList, providerList, newznabProviderList, torrentRssProviderList, \
WEB_HOST, WEB_ROOT, ACTUAL_CACHE_DIR, CACHE_DIR, ZONEINFO_DIR, ADD_SHOWS_WO_DIR, CREATE_MISSING_SHOW_DIRS, \
RECENTSEARCH_STARTUP, NAMING_FORCE_FOLDERS, SOCKET_TIMEOUT, DEBUG, INDEXER_DEFAULT, REMOVE_FILENAME_CHARS, \
CONFIG_FILE
# Schedulers
# global traktCheckerScheduler
global recentSearchScheduler, backlogSearchScheduler, showUpdateScheduler, \
versionCheckScheduler, showQueueScheduler, searchQueueScheduler, \
properFinderScheduler, autoPostProcesserScheduler, subtitlesFinderScheduler, background_mapping_task
# Add Show Defaults
global STATUS_DEFAULT, QUALITY_DEFAULT, SHOW_TAG_DEFAULT, FLATTEN_FOLDERS_DEFAULT, SUBTITLES_DEFAULT, \
WANTED_BEGIN_DEFAULT, WANTED_LATEST_DEFAULT, SCENE_DEFAULT, ANIME_DEFAULT
# Post processing
global KEEP_PROCESSED_DIR
# Views
global GUI_NAME, HOME_LAYOUT, POSTER_SORTBY, POSTER_SORTDIR, DISPLAY_SHOW_SPECIALS, \
EPISODE_VIEW_LAYOUT, EPISODE_VIEW_SORT, EPISODE_VIEW_DISPLAY_PAUSED, \
EPISODE_VIEW_MISSED_RANGE, HISTORY_LAYOUT
# Gen Config/Misc
global LAUNCH_BROWSER, UPDATE_SHOWS_ON_START, SHOW_UPDATE_HOUR, \
TRASH_REMOVE_SHOW, TRASH_ROTATE_LOGS, ACTUAL_LOG_DIR, LOG_DIR, INDEXER_TIMEOUT, ROOT_DIRS, \
VERSION_NOTIFY, AUTO_UPDATE, UPDATE_FREQUENCY, NOTIFY_ON_UPDATE
# Gen Config/Interface
global THEME_NAME, DEFAULT_HOME, SHOWLIST_TAGVIEW, SHOW_TAGS, \
HOME_SEARCH_FOCUS, USE_IMDB_INFO, IMDB_ACCOUNTS, SORT_ARTICLE, FUZZY_DATING, TRIM_ZERO, \
DATE_PRESET, TIME_PRESET, TIME_PRESET_W_SECONDS, TIMEZONE_DISPLAY, \
WEB_USERNAME, WEB_PASSWORD, CALENDAR_UNPROTECTED, USE_API, API_KEY, WEB_PORT, WEB_LOG, \
ENABLE_HTTPS, HTTPS_CERT, HTTPS_KEY, WEB_IPV6, HANDLE_REVERSE_PROXY
# Gen Config/Advanced
global BRANCH, CUR_COMMIT_BRANCH, GIT_REMOTE, CUR_COMMIT_HASH, GIT_PATH, CPU_PRESET, ANON_REDIRECT, \
ENCRYPTION_VERSION, PROXY_SETTING, PROXY_INDEXERS, FILE_LOGGING_PRESET
# Search Settings/Episode
global DOWNLOAD_PROPERS, CHECK_PROPERS_INTERVAL, RECENTSEARCH_FREQUENCY, \
BACKLOG_DAYS, BACKLOG_NOFULL, BACKLOG_FREQUENCY, USENET_RETENTION, IGNORE_WORDS, REQUIRE_WORDS, \
ALLOW_HIGH_PRIORITY, SEARCH_UNAIRED, UNAIRED_RECENT_SEARCH_ONLY
# Search Settings/NZB search
global USE_NZBS, NZB_METHOD, NZB_DIR, SAB_HOST, SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, \
NZBGET_USE_HTTPS, NZBGET_HOST, NZBGET_USERNAME, NZBGET_PASSWORD, NZBGET_CATEGORY, NZBGET_PRIORITY
# Search Settings/Torrent search
global USE_TORRENTS, TORRENT_METHOD, TORRENT_DIR, TORRENT_HOST, TORRENT_USERNAME, TORRENT_PASSWORD, \
TORRENT_LABEL, TORRENT_PATH, TORRENT_SEED_TIME, TORRENT_PAUSED, TORRENT_HIGH_BANDWIDTH, TORRENT_VERIFY_CERT
# Search Providers
global PROVIDER_ORDER, NEWZNAB_DATA, PROVIDER_HOMES
# Subtitles
global USE_SUBTITLES, SUBTITLES_LANGUAGES, SUBTITLES_DIR, SUBTITLES_FINDER_FREQUENCY, \
SUBTITLES_HISTORY, SUBTITLES_SERVICES_ENABLED, SUBTITLES_SERVICES_LIST
# Post Processing/Post-Processing
global TV_DOWNLOAD_DIR, PROCESS_METHOD, PROCESS_AUTOMATICALLY, AUTOPOSTPROCESSER_FREQUENCY, \
POSTPONE_IF_SYNC_FILES, EXTRA_SCRIPTS, \
DEFAULT_AUTOPOSTPROCESSER_FREQUENCY, MIN_AUTOPOSTPROCESSER_FREQUENCY, \
UNPACK, SKIP_REMOVED_FILES, MOVE_ASSOCIATED_FILES, NFO_RENAME, RENAME_EPISODES, AIRDATE_EPISODES, \
USE_FAILED_DOWNLOADS, DELETE_FAILED
# Post Processing/Episode Naming
global NAMING_PATTERN, NAMING_MULTI_EP, NAMING_STRIP_YEAR, NAMING_CUSTOM_ABD, NAMING_ABD_PATTERN, \
NAMING_CUSTOM_SPORTS, NAMING_SPORTS_PATTERN, \
NAMING_CUSTOM_ANIME, NAMING_ANIME_PATTERN, NAMING_ANIME_MULTI_EP, NAMING_ANIME
# Post Processing/Metadata
global metadata_provider_dict, METADATA_KODI, METADATA_MEDE8ER, METADATA_XBMC, METADATA_MEDIABROWSER, \
METADATA_PS3, METADATA_TIVO, METADATA_WDTV, METADATA_XBMC_12PLUS
# Notification Settings/HT and NAS
global USE_EMBY, EMBY_UPDATE_LIBRARY, EMBY_HOST, EMBY_APIKEY, \
USE_KODI, KODI_ALWAYS_ON, KODI_UPDATE_LIBRARY, KODI_UPDATE_FULL, KODI_UPDATE_ONLYFIRST, \
KODI_HOST, KODI_USERNAME, KODI_PASSWORD, KODI_NOTIFY_ONSNATCH, \
KODI_NOTIFY_ONDOWNLOAD, KODI_NOTIFY_ONSUBTITLEDOWNLOAD, \
USE_XBMC, XBMC_ALWAYS_ON, XBMC_NOTIFY_ONSNATCH, XBMC_NOTIFY_ONDOWNLOAD, XBMC_NOTIFY_ONSUBTITLEDOWNLOAD, \
XBMC_UPDATE_LIBRARY, XBMC_UPDATE_FULL, XBMC_UPDATE_ONLYFIRST, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, \
USE_PLEX, PLEX_USERNAME, PLEX_PASSWORD, PLEX_UPDATE_LIBRARY, PLEX_SERVER_HOST, \
PLEX_NOTIFY_ONSNATCH, PLEX_NOTIFY_ONDOWNLOAD, PLEX_NOTIFY_ONSUBTITLEDOWNLOAD, PLEX_HOST, \
USE_NMJ, NMJ_HOST, NMJ_DATABASE, NMJ_MOUNT, \
USE_NMJv2, NMJv2_HOST, NMJv2_DATABASE, NMJv2_DBLOC, \
USE_SYNOINDEX, \
USE_SYNOLOGYNOTIFIER, SYNOLOGYNOTIFIER_NOTIFY_ONSNATCH, \
SYNOLOGYNOTIFIER_NOTIFY_ONDOWNLOAD, SYNOLOGYNOTIFIER_NOTIFY_ONSUBTITLEDOWNLOAD, \
USE_PYTIVO, PYTIVO_HOST, PYTIVO_SHARE_NAME, PYTIVO_TIVO_NAME, \
PYTIVO_NOTIFY_ONSNATCH, PYTIVO_NOTIFY_ONDOWNLOAD, PYTIVO_NOTIFY_ONSUBTITLEDOWNLOAD, PYTIVO_UPDATE_LIBRARY
# Notification Settings/Devices
global USE_GROWL, GROWL_NOTIFY_ONSNATCH, GROWL_NOTIFY_ONDOWNLOAD, GROWL_NOTIFY_ONSUBTITLEDOWNLOAD, \
GROWL_HOST, GROWL_PASSWORD, \
USE_PROWL, PROWL_NOTIFY_ONSNATCH, PROWL_NOTIFY_ONDOWNLOAD, PROWL_NOTIFY_ONSUBTITLEDOWNLOAD, \
PROWL_API, PROWL_PRIORITY, \
USE_LIBNOTIFY, LIBNOTIFY_NOTIFY_ONSNATCH, LIBNOTIFY_NOTIFY_ONDOWNLOAD, \
LIBNOTIFY_NOTIFY_ONSUBTITLEDOWNLOAD, \
USE_PUSHOVER, PUSHOVER_NOTIFY_ONSNATCH, PUSHOVER_NOTIFY_ONDOWNLOAD, PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD, \
PUSHOVER_USERKEY, PUSHOVER_APIKEY, PUSHOVER_PRIORITY, PUSHOVER_DEVICE, PUSHOVER_SOUND, \
USE_BOXCAR2, BOXCAR2_NOTIFY_ONSNATCH, BOXCAR2_NOTIFY_ONDOWNLOAD, BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD, \
BOXCAR2_ACCESSTOKEN, BOXCAR2_SOUND, \
USE_NMA, NMA_NOTIFY_ONSNATCH, NMA_NOTIFY_ONDOWNLOAD, NMA_NOTIFY_ONSUBTITLEDOWNLOAD, NMA_API, NMA_PRIORITY, \
USE_PUSHALOT, PUSHALOT_NOTIFY_ONSNATCH, PUSHALOT_NOTIFY_ONDOWNLOAD, PUSHALOT_NOTIFY_ONSUBTITLEDOWNLOAD, PUSHALOT_AUTHORIZATIONTOKEN, \
USE_PUSHBULLET, PUSHBULLET_NOTIFY_ONSNATCH, PUSHBULLET_NOTIFY_ONDOWNLOAD, PUSHBULLET_NOTIFY_ONSUBTITLEDOWNLOAD, PUSHBULLET_ACCESS_TOKEN, PUSHBULLET_DEVICE_IDEN, \
versionCheckScheduler, VERSION_NOTIFY, AUTO_UPDATE, NOTIFY_ON_UPDATE, PROCESS_AUTOMATICALLY, UNPACK, CPU_PRESET, \
KEEP_PROCESSED_DIR, PROCESS_METHOD, TV_DOWNLOAD_DIR, MIN_RECENTSEARCH_FREQUENCY, DEFAULT_UPDATE_FREQUENCY, MIN_UPDATE_FREQUENCY, UPDATE_FREQUENCY, \
showQueueScheduler, searchQueueScheduler, ROOT_DIRS, CACHE_DIR, ACTUAL_CACHE_DIR, ZONEINFO_DIR, TIMEZONE_DISPLAY, \
NAMING_PATTERN, NAMING_MULTI_EP, NAMING_ANIME_MULTI_EP, NAMING_FORCE_FOLDERS, NAMING_ABD_PATTERN, NAMING_CUSTOM_ABD, NAMING_SPORTS_PATTERN, NAMING_CUSTOM_SPORTS, NAMING_ANIME_PATTERN, NAMING_CUSTOM_ANIME, NAMING_STRIP_YEAR, \
RENAME_EPISODES, AIRDATE_EPISODES, properFinderScheduler, PROVIDER_ORDER, PROVIDER_HOMES, autoPostProcesserScheduler, \
providerList, newznabProviderList, torrentRssProviderList, \
EXTRA_SCRIPTS, USE_TWITTER, TWITTER_USERNAME, TWITTER_PASSWORD, TWITTER_PREFIX, RECENTSEARCH_FREQUENCY, \
USE_BOXCAR2, BOXCAR2_ACCESSTOKEN, BOXCAR2_NOTIFY_ONDOWNLOAD, BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD, BOXCAR2_NOTIFY_ONSNATCH, BOXCAR2_SOUND, \
USE_PUSHOVER, PUSHOVER_USERKEY, PUSHOVER_APIKEY, PUSHOVER_NOTIFY_ONDOWNLOAD, PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD, PUSHOVER_NOTIFY_ONSNATCH, PUSHOVER_PRIORITY, PUSHOVER_DEVICE, PUSHOVER_SOUND, \
USE_LIBNOTIFY, LIBNOTIFY_NOTIFY_ONSNATCH, LIBNOTIFY_NOTIFY_ONDOWNLOAD, LIBNOTIFY_NOTIFY_ONSUBTITLEDOWNLOAD, USE_NMJ, NMJ_HOST, NMJ_DATABASE, NMJ_MOUNT, USE_NMJv2, NMJv2_HOST, NMJv2_DATABASE, NMJv2_DBLOC, USE_SYNOINDEX, \
USE_SYNOLOGYNOTIFIER, SYNOLOGYNOTIFIER_NOTIFY_ONSNATCH, SYNOLOGYNOTIFIER_NOTIFY_ONDOWNLOAD, SYNOLOGYNOTIFIER_NOTIFY_ONSUBTITLEDOWNLOAD, \
USE_EMAIL, EMAIL_OLD_SUBJECTS, EMAIL_HOST, EMAIL_PORT, EMAIL_TLS, EMAIL_USER, EMAIL_PASSWORD, EMAIL_FROM, EMAIL_NOTIFY_ONSNATCH, EMAIL_NOTIFY_ONDOWNLOAD, EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD, EMAIL_LIST, \
METADATA_XBMC, METADATA_XBMC_12PLUS, METADATA_MEDIABROWSER, METADATA_PS3, METADATA_KODI, metadata_provider_dict, \
GIT_PATH, MOVE_ASSOCIATED_FILES, POSTPONE_IF_SYNC_FILES, recentSearchScheduler, NFO_RENAME, \
GUI_NAME, DEFAULT_HOME, HOME_LAYOUT, HISTORY_LAYOUT, DISPLAY_SHOW_SPECIALS, EPISODE_VIEW_LAYOUT, EPISODE_VIEW_SORT, EPISODE_VIEW_DISPLAY_PAUSED, EPISODE_VIEW_MISSED_RANGE, FUZZY_DATING, TRIM_ZERO, DATE_PRESET, TIME_PRESET, TIME_PRESET_W_SECONDS, THEME_NAME, \
POSTER_SORTBY, POSTER_SORTDIR, \
METADATA_WDTV, METADATA_TIVO, METADATA_MEDE8ER, IGNORE_WORDS, REQUIRE_WORDS, CALENDAR_UNPROTECTED, CREATE_MISSING_SHOW_DIRS, \
ADD_SHOWS_WO_DIR, REMOVE_FILENAME_CHARS, USE_SUBTITLES, SUBTITLES_LANGUAGES, SUBTITLES_DIR, SUBTITLES_SERVICES_LIST, SUBTITLES_SERVICES_ENABLED, SUBTITLES_HISTORY, SUBTITLES_FINDER_FREQUENCY, subtitlesFinderScheduler, \
USE_FAILED_DOWNLOADS, DELETE_FAILED, ANON_REDIRECT, TMDB_API_KEY, DEBUG, PROXY_SETTING, PROXY_INDEXERS, \
AUTOPOSTPROCESSER_FREQUENCY, DEFAULT_AUTOPOSTPROCESSER_FREQUENCY, MIN_AUTOPOSTPROCESSER_FREQUENCY, \
ANIME_DEFAULT, NAMING_ANIME, USE_ANIDB, ANIDB_USERNAME, ANIDB_PASSWORD, ANIDB_USE_MYLIST, \
SCENE_DEFAULT, BACKLOG_DAYS, SEARCH_UNAIRED, UNAIRED_RECENT_SEARCH_ONLY, ANIME_TREAT_AS_HDTV, \
COOKIE_SECRET, USE_IMDB_INFO, IMDB_ACCOUNTS, DISPLAY_BACKGROUND, DISPLAY_BACKGROUND_TRANSPARENT, DISPLAY_ALL_SEASONS, \
SHOW_TAGS, DEFAULT_SHOW_TAG, SHOWLIST_TAGVIEW, background_mapping_task, CACHE_IMAGE_URL_LIST
USE_PUSHALOT, PUSHALOT_NOTIFY_ONSNATCH, PUSHALOT_NOTIFY_ONDOWNLOAD, \
PUSHALOT_NOTIFY_ONSUBTITLEDOWNLOAD, PUSHALOT_AUTHORIZATIONTOKEN, \
USE_PUSHBULLET, PUSHBULLET_NOTIFY_ONSNATCH, PUSHBULLET_NOTIFY_ONDOWNLOAD, \
PUSHBULLET_NOTIFY_ONSUBTITLEDOWNLOAD, PUSHBULLET_ACCESS_TOKEN, PUSHBULLET_DEVICE_IDEN
# Notification Settings/Social
global USE_TWITTER, TWITTER_NOTIFY_ONSNATCH, TWITTER_NOTIFY_ONDOWNLOAD, TWITTER_NOTIFY_ONSUBTITLEDOWNLOAD, \
TWITTER_USERNAME, TWITTER_PASSWORD, TWITTER_PREFIX, \
USE_TRAKT, TRAKT_CONNECTED_ACCOUNT, TRAKT_ACCOUNTS, TRAKT_MRU, TRAKT_VERIFY, \
TRAKT_USE_WATCHLIST, TRAKT_REMOVE_WATCHLIST, TRAKT_TIMEOUT, TRAKT_METHOD_ADD, TRAKT_START_PAUSED, \
TRAKT_SYNC, TRAKT_DEFAULT_INDEXER, TRAKT_REMOVE_SERIESLIST, TRAKT_UPDATE_COLLECTION, \
USE_EMAIL, EMAIL_NOTIFY_ONSNATCH, EMAIL_NOTIFY_ONDOWNLOAD, EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD, EMAIL_FROM, \
EMAIL_HOST, EMAIL_PORT, EMAIL_TLS, EMAIL_USER, EMAIL_PASSWORD, EMAIL_LIST, EMAIL_OLD_SUBJECTS
# Anime Settings
global ANIME_TREAT_AS_HDTV, USE_ANIDB, ANIDB_USERNAME, ANIDB_PASSWORD, ANIDB_USE_MYLIST
if __INITIALIZED__:
return False
CheckSection(CFG, 'General')
CheckSection(CFG, 'Blackhole')
CheckSection(CFG, 'SABnzbd')
CheckSection(CFG, 'NZBget')
CheckSection(CFG, 'Emby')
CheckSection(CFG, 'Kodi')
CheckSection(CFG, 'XBMC')
CheckSection(CFG, 'PLEX')
CheckSection(CFG, 'Growl')
CheckSection(CFG, 'Prowl')
CheckSection(CFG, 'Twitter')
CheckSection(CFG, 'Boxcar2')
CheckSection(CFG, 'NMJ')
CheckSection(CFG, 'NMJv2')
CheckSection(CFG, 'Synology')
CheckSection(CFG, 'SynologyNotifier')
CheckSection(CFG, 'pyTivo')
CheckSection(CFG, 'NMA')
CheckSection(CFG, 'Pushalot')
CheckSection(CFG, 'Pushbullet')
CheckSection(CFG, 'Subtitles')
for stanza in ('General', 'Blackhole', 'SABnzbd', 'NZBget', 'Emby', 'Kodi', 'XBMC', 'PLEX',
'Growl', 'Prowl', 'Twitter', 'Boxcar2', 'NMJ', 'NMJv2', 'Synology', 'SynologyNotifier',
'pyTivo', 'NMA', 'Pushalot', 'Pushbullet', 'Subtitles'):
CheckSection(CFG, stanza)
# wanted branch
BRANCH = check_setting_str(CFG, 'General', 'branch', '')
@ -619,12 +655,9 @@ def initialize(consoleLogging=True):
TIME_PRESET_W_SECONDS = check_setting_str(CFG, 'GUI', 'time_preset', '%I:%M:%S %p')
TIME_PRESET = TIME_PRESET_W_SECONDS.replace(u':%S', u'')
TIMEZONE_DISPLAY = check_setting_str(CFG, 'GUI', 'timezone_display', 'network')
DISPLAY_BACKGROUND = bool(check_setting_int(CFG, 'General', 'display_background', 0))
DISPLAY_BACKGROUND_TRANSPARENT = check_setting_str(CFG, 'General', 'display_background_transparent',
'transparent')
DISPLAY_ALL_SEASONS = bool(check_setting_int(CFG, 'General', 'display_all_seasons', 1))
SHOW_TAGS = check_setting_str(CFG, 'GUI', 'show_tags', 'Show List').split(',')
DEFAULT_SHOW_TAG = check_setting_str(CFG, 'GUI', 'default_show_tag', 'Show List')
SHOW_TAG_DEFAULT = check_setting_str(CFG, 'GUI', 'show_tag_default',
check_setting_str(CFG, 'GUI', 'default_show_tag', 'Show List'))
SHOWLIST_TAGVIEW = check_setting_str(CFG, 'GUI', 'showlist_tagview', 'standard')
ACTUAL_LOG_DIR = check_setting_str(CFG, 'General', 'log_dir', 'Logs')
@ -639,17 +672,10 @@ def initialize(consoleLogging=True):
SOCKET_TIMEOUT = check_setting_int(CFG, 'General', 'socket_timeout', 30)
socket.setdefaulttimeout(SOCKET_TIMEOUT)
try:
WEB_PORT = check_setting_int(CFG, 'General', 'web_port', 8081)
except:
WEB_PORT = 8081
if WEB_PORT < 21 or WEB_PORT > 65535:
WEB_PORT = 8081
WEB_HOST = check_setting_str(CFG, 'General', 'web_host', '0.0.0.0')
WEB_IPV6 = bool(check_setting_int(CFG, 'General', 'web_ipv6', 0))
WEB_PORT = minimax(check_setting_int(CFG, 'General', 'web_port', 8081), 8081, 21, 65535)
WEB_ROOT = check_setting_str(CFG, 'General', 'web_root', '').rstrip('/')
WEB_IPV6 = bool(check_setting_int(CFG, 'General', 'web_ipv6', 0))
WEB_LOG = bool(check_setting_int(CFG, 'General', 'web_log', 0))
ENCRYPTION_VERSION = check_setting_int(CFG, 'General', 'encryption_version', 0)
WEB_USERNAME = check_setting_str(CFG, 'General', 'web_username', '')
@ -740,7 +766,6 @@ def initialize(consoleLogging=True):
ALLOW_HIGH_PRIORITY = bool(check_setting_int(CFG, 'General', 'allow_high_priority', 1))
RECENTSEARCH_STARTUP = bool(check_setting_int(CFG, 'General', 'recentsearch_startup', 0))
BACKLOG_STARTUP = bool(check_setting_int(CFG, 'General', 'backlog_startup', 0))
BACKLOG_NOFULL = bool(check_setting_int(CFG, 'General', 'backlog_nofull', 0))
SKIP_REMOVED_FILES = check_setting_int(CFG, 'General', 'skip_removed_files', 0)
@ -1033,8 +1058,8 @@ def initialize(consoleLogging=True):
NEWZNAB_DATA = check_setting_str(CFG, 'Newznab', 'newznab_data', '')
newznabProviderList = providers.getNewznabProviderList(NEWZNAB_DATA)
TORRENTRSS_DATA = check_setting_str(CFG, 'TorrentRss', 'torrentrss_data', '')
torrentRssProviderList = providers.getTorrentRssProviderList(TORRENTRSS_DATA)
torrentrss_data = check_setting_str(CFG, 'TorrentRss', 'torrentrss_data', '')
torrentRssProviderList = providers.getTorrentRssProviderList(torrentrss_data)
# dynamically load provider settings
for torrent_prov in [curProvider for curProvider in providers.sortedProviderList()
@ -1077,7 +1102,7 @@ def initialize(consoleLogging=True):
if hasattr(torrent_prov, 'enable_recentsearch'):
torrent_prov.enable_recentsearch = bool(check_setting_int(CFG, prov_id_uc,
prov_id + '_enable_recentsearch', 1)) or \
not getattr(torrent_prov, 'supports_backlog', True)
not getattr(torrent_prov, 'supports_backlog')
if hasattr(torrent_prov, 'enable_backlog'):
torrent_prov.enable_backlog = bool(check_setting_int(CFG, prov_id_uc, prov_id + '_enable_backlog', 1))
if hasattr(torrent_prov, 'search_mode'):
@ -1104,7 +1129,7 @@ def initialize(consoleLogging=True):
if hasattr(nzb_prov, 'enable_recentsearch'):
nzb_prov.enable_recentsearch = bool(check_setting_int(CFG, prov_id_uc,
prov_id + '_enable_recentsearch', 1)) or \
not getattr(nzb_prov, 'supports_backlog', True)
not getattr(nzb_prov, 'supports_backlog')
if hasattr(nzb_prov, 'enable_backlog'):
nzb_prov.enable_backlog = bool(check_setting_int(CFG, prov_id_uc, prov_id + '_enable_backlog', 1))
@ -1113,7 +1138,7 @@ def initialize(consoleLogging=True):
save_config()
# start up all the threads
logger.sb_log_instance.initLogging(consoleLogging=consoleLogging)
logger.sb_log_instance.initLogging(consoleLogging=console_logging)
# initialize the main SB database
my_db = db.DBConnection()
@ -1183,8 +1208,7 @@ def initialize(consoleLogging=True):
search_recent.RecentSearcher(),
cycleTime=update_interval,
threadName='RECENTSEARCHER',
run_delay=update_now if RECENTSEARCH_STARTUP
else datetime.timedelta(minutes=5),
run_delay=update_now if RECENTSEARCH_STARTUP else datetime.timedelta(minutes=5),
prevent_cycle_run=searchQueueScheduler.action.is_recentsearch_in_progress)
if [x for x in providers.sortedProviderList() if x.is_active() and
@ -1229,17 +1253,16 @@ def initialize(consoleLogging=True):
# processors
autoPostProcesserScheduler = scheduler.Scheduler(
auto_post_processer.PostProcesser(),
cycleTime=datetime.timedelta(
minutes=AUTOPOSTPROCESSER_FREQUENCY),
cycleTime=datetime.timedelta(minutes=AUTOPOSTPROCESSER_FREQUENCY),
threadName='POSTPROCESSER',
silent=not PROCESS_AUTOMATICALLY)
"""
traktCheckerScheduler = scheduler.Scheduler(
traktChecker.TraktChecker(),
cycleTime=datetime.timedelta(hours=1),
threadName='TRAKTCHECKER',
silent=not USE_TRAKT)
"""
subtitlesFinderScheduler = scheduler.Scheduler(
subtitles.SubtitlesFinder(),
cycleTime=datetime.timedelta(hours=SUBTITLES_FINDER_FREQUENCY),
@ -1247,7 +1270,6 @@ def initialize(consoleLogging=True):
silent=not USE_SUBTITLES)
showList = []
loadingShowList = {}
background_mapping_task = threading.Thread(name='LOAD-MAPPINGS', target=indexermapper.load_mapped_ids)
@ -1255,60 +1277,56 @@ def initialize(consoleLogging=True):
return True
def enabled_schedulers(is_init=False):
# ([], [traktCheckerScheduler])[USE_TRAKT] + \
for s in ([], [events])[is_init] + \
[recentSearchScheduler, backlogSearchScheduler, showUpdateScheduler,
versionCheckScheduler, showQueueScheduler, searchQueueScheduler] + \
([], [properFinderScheduler])[DOWNLOAD_PROPERS] + \
([], [autoPostProcesserScheduler])[PROCESS_AUTOMATICALLY] + \
([], [subtitlesFinderScheduler])[USE_SUBTITLES] + \
([events], [])[is_init]:
yield s
def start():
global __INITIALIZED__, backlogSearchScheduler, \
showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \
properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \
subtitlesFinderScheduler, USE_SUBTITLES, traktCheckerScheduler, \
recentSearchScheduler, events, started, background_mapping_task
global started
with INIT_LOCK:
if __INITIALIZED__:
# Load all Indexer mappings in background
indexermapper.defunct_indexer = [i for i in indexerApi().all_indexers if indexerApi(i).config.get('defunct')]
indexermapper.defunct_indexer = [
i for i in indexerApi().all_indexers if indexerApi(i).config.get('defunct')]
indexermapper.indexer_list = [i for i in indexerApi().all_indexers]
background_mapping_task.start()
# start sysetm events queue
events.start()
# start the recent search scheduler
recentSearchScheduler.start()
# start the backlog scheduler
backlogSearchScheduler.start()
# start the show updater
showUpdateScheduler.start()
# start the version checker
versionCheckScheduler.start()
# start the queue checker
showQueueScheduler.start()
# start the search queue checker
searchQueueScheduler.start()
# start the queue checker
if DOWNLOAD_PROPERS:
properFinderScheduler.start()
# start the proper finder
if PROCESS_AUTOMATICALLY:
autoPostProcesserScheduler.start()
# start the subtitles finder
if USE_SUBTITLES:
subtitlesFinderScheduler.start()
# start the trakt checker
# if USE_TRAKT:
# traktCheckerScheduler.start()
for thread in enabled_schedulers(is_init=True):
thread.start()
started = True
def restart(soft=True):
if soft:
halt()
save_all()
logger.log(u'Re-initializing all data')
initialize()
else:
events.put(events.SystemEvent.RESTART)
def sig_handler(signum=None, _=None):
is_ctrlbreak = 'win32' == sys.platform and signal.SIGBREAK == signum
msg = u'Signal "%s" found' % (signal.SIGINT == signum and 'CTRL-C' or is_ctrlbreak and 'CTRL+BREAK' or
signal.SIGTERM == signum and 'Termination' or signum)
if None is signum or signum in (signal.SIGINT, signal.SIGTERM) or is_ctrlbreak:
logger.log('%s, saving and exiting...' % msg)
events.put(events.SystemEvent.SHUTDOWN)
else:
logger.log('%s, not exiting' % msg)
def halt():
global __INITIALIZED__, started
@ -1318,83 +1336,33 @@ def halt():
logger.log(u'Aborting all threads')
schedulers = [
recentSearchScheduler,
backlogSearchScheduler,
showUpdateScheduler,
versionCheckScheduler,
showQueueScheduler,
searchQueueScheduler,
properFinderScheduler,
autoPostProcesserScheduler,
subtitlesFinderScheduler,
events
]
for thread in schedulers:
for thread in enabled_schedulers():
thread.stop.set()
for thread in schedulers:
for thread in enabled_schedulers():
logger.log('Waiting for the %s thread to exit' % thread.name)
try:
thread.join(10)
except RuntimeError:
pass
if PROCESS_AUTOMATICALLY:
autoPostProcesserScheduler.stop.set()
logger.log(u'Waiting for the POSTPROCESSER thread to exit')
try:
autoPostProcesserScheduler.join(10)
except:
pass
if DOWNLOAD_PROPERS:
properFinderScheduler.stop.set()
logger.log(u'Waiting for the PROPERFINDER thread to exit')
try:
properFinderScheduler.join(10)
except:
pass
if USE_SUBTITLES:
subtitlesFinderScheduler.stop.set()
logger.log(u'Waiting for the SUBTITLESFINDER thread to exit')
try:
subtitlesFinderScheduler.join(10)
except:
pass
if ADBA_CONNECTION:
try:
ADBA_CONNECTION.logout()
except AniDBBannedError as e:
logger.log(u'ANIDB Error %s' % ex(e), logger.DEBUG)
except AniDBError as e:
except AniDBError:
pass
logger.log(u'Waiting for the ANIDB CONNECTION thread to exit')
try:
ADBA_CONNECTION.join(10)
except:
except (StandardError, Exception):
pass
__INITIALIZED__ = False
started = False
def sig_handler(signum=None, frame=None):
is_ctrlbreak = 'win32' == sys.platform and signal.SIGBREAK == signum
msg = u'Signal "%s" found' % (signal.SIGINT == signum and 'CTRL-C' or is_ctrlbreak and 'CTRL+BREAK' or
signal.SIGTERM == signum and 'Termination' or signum)
if None is signum or signum in (signal.SIGINT, signal.SIGTERM) or is_ctrlbreak:
logger.log('%s, saving and exiting...' % msg)
events.put(events.SystemEvent.SHUTDOWN)
else:
logger.log('%s, not exiting' % msg)
def save_all():
global showList
@ -1408,16 +1376,6 @@ def save_all():
save_config()
def restart(soft=True):
if soft:
halt()
save_all()
logger.log(u'Re-initializing all data')
initialize()
else:
events.put(events.SystemEvent.RESTART)
def save_config():
new_config = ConfigObj()
new_config.filename = CONFIG_FILE
@ -1463,7 +1421,6 @@ def save_config():
new_config['General']['check_propers_interval'] = CHECK_PROPERS_INTERVAL
new_config['General']['allow_high_priority'] = int(ALLOW_HIGH_PRIORITY)
new_config['General']['recentsearch_startup'] = int(RECENTSEARCH_STARTUP)
new_config['General']['backlog_startup'] = int(BACKLOG_STARTUP)
new_config['General']['backlog_nofull'] = int(BACKLOG_NOFULL)
new_config['General']['skip_removed_files'] = int(SKIP_REMOVED_FILES)
new_config['General']['quality_default'] = int(QUALITY_DEFAULT)
@ -1501,9 +1458,6 @@ def save_config():
new_config['General']['sort_article'] = int(SORT_ARTICLE)
new_config['General']['proxy_setting'] = PROXY_SETTING
new_config['General']['proxy_indexers'] = int(PROXY_INDEXERS)
new_config['General']['display_background'] = int(DISPLAY_BACKGROUND)
new_config['General']['display_background_transparent'] = DISPLAY_BACKGROUND_TRANSPARENT
new_config['General']['display_all_seasons'] = int(DISPLAY_ALL_SEASONS)
new_config['General']['metadata_xbmc'] = METADATA_XBMC
new_config['General']['metadata_xbmc_12plus'] = METADATA_XBMC_12PLUS
@ -1800,6 +1754,10 @@ def save_config():
new_config['GUI']['date_preset'] = DATE_PRESET
new_config['GUI']['time_preset'] = TIME_PRESET_W_SECONDS
new_config['GUI']['timezone_display'] = TIMEZONE_DISPLAY
new_config['GUI']['show_tags'] = ','.join(SHOW_TAGS)
new_config['GUI']['showlist_tagview'] = SHOWLIST_TAGVIEW
new_config['GUI']['home_layout'] = HOME_LAYOUT
new_config['GUI']['history_layout'] = HISTORY_LAYOUT
new_config['GUI']['display_show_specials'] = int(DISPLAY_SHOW_SPECIALS)
@ -1811,7 +1769,7 @@ def save_config():
new_config['GUI']['poster_sortdir'] = POSTER_SORTDIR
new_config['GUI']['show_tags'] = ','.join(SHOW_TAGS)
new_config['GUI']['showlist_tagview'] = SHOWLIST_TAGVIEW
new_config['GUI']['default_show_tag'] = DEFAULT_SHOW_TAG
new_config['GUI']['show_tag_default'] = SHOW_TAG_DEFAULT
new_config['Subtitles'] = {}
new_config['Subtitles']['use_subtitles'] = int(USE_SUBTITLES)
@ -1842,14 +1800,11 @@ def save_config():
def launch_browser(start_port=None):
if not start_port:
start_port = WEB_PORT
if ENABLE_HTTPS:
browser_url = 'https://localhost:%d%s' % (start_port, WEB_ROOT)
else:
browser_url = 'http://localhost:%d%s' % (start_port, WEB_ROOT)
browser_url = 'http%s://localhost:%d%s' % (('s' or '')[not ENABLE_HTTPS], start_port, WEB_ROOT)
try:
webbrowser.open(browser_url, 2, 1)
except:
except (StandardError, Exception):
try:
webbrowser.open(browser_url, 1, 1)
except:
logger.log(u'Unable to launch a browser', logger.ERROR)
except (StandardError, Exception):
logger.log('Unable to launch a browser', logger.ERROR)

View file

@ -740,7 +740,6 @@ class ConfigMigrator():
def _migrate_v8(self):
# removing settings from gui and making it a hidden debug option
sickbeard.RECENTSEARCH_STARTUP = False
sickbeard.BACKLOG_STARTUP = False
def _migrate_v9(self):
sickbeard.PUSHBULLET_ACCESS_TOKEN = check_setting_str(self.config_obj, 'Pushbullet', 'pushbullet_api', '')

View file

@ -1106,12 +1106,12 @@ class Home(MainHandler):
if str(pid) != str(sickbeard.PID):
return self.redirect('/home/')
t = PageTemplate(headers=self.request.headers, file='restart.tmpl')
t.shutdown = True
sickbeard.events.put(sickbeard.events.SystemEvent.SHUTDOWN)
title = 'Shutting down'
message = 'SickGear is shutting down...'
return self._genericMessage(title, message)
return t.respond()
def restart(self, pid=None):
@ -1119,8 +1119,8 @@ class Home(MainHandler):
return self.redirect('/home/')
t = PageTemplate(headers=self.request.headers, file='restart.tmpl')
t.shutdown = False
# restart
sickbeard.events.put(sickbeard.events.SystemEvent.RESTART)
return t.respond()
@ -4275,7 +4275,7 @@ class ConfigGeneral(Config):
sickbeard.SCENE_DEFAULT = config.checkbox_to_value(default_scene)
sickbeard.SUBTITLES_DEFAULT = config.checkbox_to_value(default_subtitles)
sickbeard.ANIME_DEFAULT = config.checkbox_to_value(default_anime)
sickbeard.DEFAULT_SHOW_TAG = default_tag
sickbeard.SHOW_TAG_DEFAULT = default_tag
sickbeard.save_config()
@ -4311,7 +4311,6 @@ class ConfigGeneral(Config):
proxy_setting=None, proxy_indexers=None, anon_redirect=None, git_path=None, git_remote=None, calendar_unprotected=None,
fuzzy_dating=None, trim_zero=None, date_preset=None, date_preset_na=None, time_preset=None,
indexer_timeout=None, rootDir=None, theme_name=None, default_home=None, use_imdb_info=None,
display_background=None, display_background_transparent=None, display_all_seasons=None,
show_tags=None, showlist_tagview=None):
results = []
@ -4331,9 +4330,6 @@ class ConfigGeneral(Config):
sickbeard.LAUNCH_BROWSER = config.checkbox_to_value(launch_browser)
sickbeard.HOME_SEARCH_FOCUS = config.checkbox_to_value(home_search_focus)
sickbeard.USE_IMDB_INFO = config.checkbox_to_value(use_imdb_info)
sickbeard.DISPLAY_BACKGROUND = config.checkbox_to_value(display_background)
sickbeard.DISPLAY_BACKGROUND_TRANSPARENT = display_background_transparent
sickbeard.DISPLAY_ALL_SEASONS = config.checkbox_to_value(display_all_seasons)
sickbeard.SORT_ARTICLE = config.checkbox_to_value(sort_article)
sickbeard.CPU_PRESET = cpu_preset
sickbeard.FILE_LOGGING_PRESET = file_logging_preset

View file

@ -35,7 +35,7 @@ from sickbeard.name_parser.parser import NameParser
from sickbeard.tv import TVShow
class XEMBasicTests(test.SickbeardTestDBCase):
def loadShowsFromDB(self):
def load_shows_from_db(self):
"""
Populates the showList with shows from the database
"""