diff --git a/SickBeard.py b/SickBeard.py index f583e10c..e811e542 100755 --- a/SickBeard.py +++ b/SickBeard.py @@ -53,6 +53,7 @@ import threading import signal import traceback import getopt +import time import sickbeard @@ -384,13 +385,16 @@ def main(): sickbeard.start() # Launch browser if we're supposed to - if sickbeard.LAUNCH_BROWSER and not noLaunch and not sickbeard.DAEMON: + if sickbeard.LAUNCH_BROWSER and not noLaunch and not sickbeard.DAEMON and not sickbeard.restarted: sickbeard.launchBrowser(startPort) # Start an update if we're supposed to if forceUpdate or sickbeard.UPDATE_SHOWS_ON_START: sickbeard.showUpdateScheduler.action.run(force=True) # @UndefinedVariable + if sickbeard.restarted: + sickbeard.restarted = False + # create ioloop io_loop = IOLoop.current() @@ -408,4 +412,16 @@ def main(): if __name__ == "__main__": if sys.hexversion >= 0x020600F0: freeze_support() - main() \ No newline at end of file + + while(True): + main() + + # check if restart was requested + if not sickbeard.restarted: + if sickbeard.CREATEPID: + logger.log(u"Removing pidfile " + str(sickbeard.PIDFILE)) + sickbeard.remove_pid_file(sickbeard.PIDFILE) + break + + # restart + logger.log("Restarting SickRage, please stand by...") \ No newline at end of file diff --git a/gui/slick/js/restart.js b/gui/slick/js/restart.js index edc4074f..9ff51ab0 100644 --- a/gui/slick/js/restart.js +++ b/gui/slick/js/restart.js @@ -13,7 +13,7 @@ else var base_url = window.location.protocol+'//'+window.location.host+sbRoot; var is_alive_url = sbRoot+'/home/is_alive'; var timeout_id; -var current_pid = ''; +var restarted = ''; var num_restart_waits = 0; function is_alive() { @@ -28,9 +28,9 @@ function is_alive() { setTimeout('is_alive()', 1000); } else { // if this is before we've even shut down then just try again later - if (current_pid == '' || data.msg == current_pid) { - current_pid = data.msg; - setTimeout(is_alive, 1000); + if (restarted == '' || data.restarted == restarted) { + restarted = data.restarted; + setTimeout('is_alive()', 1000); // if we're ready to go then redirect to new url } else { diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index c9c6824b..cf80c3b3 100644 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -477,7 +477,7 @@ def initialize(consoleLogging=True): USE_FAILED_DOWNLOADS, DELETE_FAILED, ANON_REDIRECT, LOCALHOST_IP, REMOTE_IP, TMDB_API_KEY, DEBUG, PROXY_SETTING, \ AUTOPOSTPROCESSER_FREQUENCY, DEFAULT_AUTOPOSTPROCESSER_FREQUENCY, MIN_AUTOPOSTPROCESSER_FREQUENCY, \ ANIME_DEFAULT, NAMING_ANIME, ANIMESUPPORT, USE_ANIDB, ANIDB_USERNAME, ANIDB_PASSWORD, ANIDB_USE_MYLIST, \ - ANIME_SPLIT_HOME, maintenanceScheduler, SCENE_DEFAULT + ANIME_SPLIT_HOME, maintenanceScheduler, SCENE_DEFAULT, RES if __INITIALIZED__: return False @@ -1309,44 +1309,9 @@ def cleanup_tornado_sockets(io_loop): pass def saveAndShutdown(): - halt() saveAll() - cleanup_tornado_sockets(IOLoop.current()) - - if CREATEPID: - logger.log(u"Removing pidfile " + str(PIDFILE)) - remove_pid_file(PIDFILE) - - if restarted: - install_type = versionCheckScheduler.action.install_type - - popen_list = [] - - if install_type in ('git', 'source'): - popen_list = [sys.executable, MY_FULLNAME] - elif install_type == 'win': - if hasattr(sys, 'frozen'): - # c:\dir\to\updater.exe 12345 c:\dir\to\sickbeard.exe - popen_list = [os.path.join(PROG_DIR, 'updater.exe'), str(PID), sys.executable] - else: - logger.log(u"Unknown SB launch method, please file a bug report about this", logger.ERROR) - popen_list = [sys.executable, os.path.join(PROG_DIR, 'updater.py'), str(PID), sys.executable, - MY_FULLNAME] - - if popen_list: - popen_list += MY_ARGS - if '--nolaunch' not in popen_list: - popen_list += ['--nolaunch'] - - logger.log(u"Restarting SickRage with " + str(popen_list)) - logger.close() - - subprocess.Popen(popen_list, cwd=os.getcwd()) - - os._exit(0) - def invoke_command(to_call, *args, **kwargs): def delegate(): @@ -1375,6 +1340,7 @@ def restart(soft=True): initialize() else: restarted=True + time.sleep(5) webserveInit.shutdown() diff --git a/sickbeard/tv.py b/sickbeard/tv.py index 24bea507..8221df84 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -53,42 +53,48 @@ from common import NAMING_DUPLICATE, NAMING_EXTEND, NAMING_LIMITED_EXTEND, NAMIN NAMING_LIMITED_EXTEND_E_PREFIXED +def dirty_setter(attr_name): + def wrapper(self, val): + if getattr(self, attr_name) != val: + setattr(self, attr_name, val) + self.dirty = True + + return wrapper + class TVShow(object): def __init__(self, indexer, indexerid, lang=""): - - self.indexerid = int(indexerid) - self.indexer = int(indexer) - self.name = "" + self._indexerid = int(indexerid) + self._indexer = int(indexer) + self._name = "" self._location = "" - self.imdbid = "" - self.network = "" - self.genre = "" - self.classification = "" - self.runtime = 0 - self.imdb_info = {} - self.quality = int(sickbeard.QUALITY_DEFAULT) - self.flatten_folders = int(sickbeard.FLATTEN_FOLDERS_DEFAULT) + self._imdbid = "" + self._network = "" + self._genre = "" + self._classification = "" + self._runtime = 0 + self._imdb_info = {} + self._quality = int(sickbeard.QUALITY_DEFAULT) + self._flatten_folders = int(sickbeard.FLATTEN_FOLDERS_DEFAULT) + self._status = "" + self._airs = "" + self._startyear = 0 + self._paused = 0 + self._air_by_date = 0 + self._subtitles = int(sickbeard.SUBTITLES_DEFAULT if sickbeard.SUBTITLES_DEFAULT else 0) + self._dvdorder = 0 + self._archive_firstmatch = 0 + self._lang = lang + self._last_update_indexer = 1 + self._sports = 0 + self._anime = 0 + self._scene = 0 + self._rls_ignore_words = "" + self._rls_require_words = "" - self.status = "" - self.airs = "" - self.startyear = 0 - self.paused = 0 - self.air_by_date = 0 - self.sports = 0 - self.subtitles = int(sickbeard.SUBTITLES_DEFAULT if sickbeard.SUBTITLES_DEFAULT else 0) - self.dvdorder = 0 - self.archive_firstmatch = 0 - self.lang = lang - self.last_update_indexer = 1 - self.anime = 0 - self.scene = 0 - - self.rls_ignore_words = "" - self.rls_require_words = "" + self.dirty = True self.lock = threading.Lock() - self._isDirGood = False - + self.isDirGood = False self.episodes = {} otherShow = helpers.findCertainShow(sickbeard.showList, self.indexerid) @@ -97,6 +103,34 @@ class TVShow(object): self.loadFromDB() + name = property(lambda self: self._name, dirty_setter("_name")) + indexerid = property(lambda self: self._indexerid, dirty_setter("_indexerid")) + indexer = property(lambda self: self._indexer, dirty_setter("_indexer")) + #location = property(lambda self: self._location, dirty_setter("_location")) + imdbid = property(lambda self: self._imdbid, dirty_setter("_imdbid")) + network = property(lambda self: self._network, dirty_setter("_network")) + genre = property(lambda self: self._genre, dirty_setter("_genre")) + classification = property(lambda self: self._classification, dirty_setter("_classification")) + runtime = property(lambda self: self._runtime, dirty_setter("_runtime")) + imdb_info = property(lambda self: self._imdb_info, dirty_setter("_imdb_info")) + quality = property(lambda self: self._quality, dirty_setter("_quality")) + flatten_folders = property(lambda self: self._flatten_folders, dirty_setter("_flatten_folders")) + status = property(lambda self: self._status, dirty_setter("_status")) + airs = property(lambda self: self._airs, dirty_setter("_airs")) + startyear = property(lambda self: self._startyear, dirty_setter("_startyear")) + paused = property(lambda self: self._paused, dirty_setter("_paused")) + air_by_date = property(lambda self: self._air_by_date, dirty_setter("_air_by_date")) + subtitles = property(lambda self: self._subtitles, dirty_setter("_subtitles")) + dvdorder = property(lambda self: self._dvdorder, dirty_setter("_dvdorder")) + archive_firstmatch = property(lambda self: self._archive_firstmatch, dirty_setter("_archive_firstmatch")) + lang = property(lambda self: self._lang, dirty_setter("_lang")) + last_update_indexer = property(lambda self: self._last_update_indexer, dirty_setter("_last_update_indexer")) + sports = property(lambda self: self._sports, dirty_setter("_sports")) + anime = property(lambda self: self._anime, dirty_setter("_anime")) + scene = property(lambda self: self._scene, dirty_setter("_scene")) + rls_ignore_words = property(lambda self: self._rls_ignore_words, dirty_setter("_rls_ignore_words")) + rls_require_words = property(lambda self: self._rls_require_words, dirty_setter("_rls_require_words")) + def _is_anime(self): if (self.anime > 0): return True @@ -139,7 +173,6 @@ class TVShow(object): self._isDirGood = True else: raise exceptions.NoNFOException("Invalid folder for the show!") - location = property(_getLocation, _setLocation) # delete references to anything that's not in the internal lists @@ -815,6 +848,9 @@ class TVShow(object): else: self.imdb_info = dict(zip(sqlResults[0].keys(), sqlResults[0])) + self.dirty = False + return True + def loadFromIndexer(self, cache=True, tvapi=None, cachedSeason=None): logger.log(str(self.indexerid) + u": Loading show info from " + sickbeard.indexerApi(self.indexer).name) @@ -1101,7 +1137,12 @@ class TVShow(object): return - def saveToDB(self): + def saveToDB(self, forceSave=False): + + if not self.dirty and not forceSave: + logger.log(str(self.indexerid) + u": Not saving show to db - record is not dirty", logger.DEBUG) + return + logger.log(str(self.indexerid) + u": Saving show info to database", logger.DEBUG) controlValueDict = {"indexer_id": self.indexerid} @@ -1262,16 +1303,6 @@ class TVShow(object): else: return Overview.GOOD - -def dirty_setter(attr_name): - def wrapper(self, val): - if getattr(self, attr_name) != val: - setattr(self, attr_name, val) - self.dirty = True - - return wrapper - - class TVEpisode(object): def __init__(self, show, season, episode, file=""): self._name = "" diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 9d19d19b..261f08de 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -3004,9 +3004,9 @@ class Home(MainHandler): self.set_header('Access-Control-Allow-Headers', 'x-requested-with') if sickbeard.started: - return callback + '(' + json.dumps({"msg": str(sickbeard.PID)}) + ');' + return callback + '(' + json.dumps({"msg": str(sickbeard.PID), "restarted": str(sickbeard.restarted)}) + ');' else: - return callback + '(' + json.dumps({"msg": "nope"}) + ');' + return callback + '(' + json.dumps({"msg": "nope", "restarted": str(sickbeard.restarted)}) + ');' def index(self, *args, **kwargs): @@ -3322,8 +3322,8 @@ class Home(MainHandler): t = PageTemplate(file="restart.tmpl") t.submenu = HomeMenu() - # do a soft restart - threading.Timer(2, sickbeard.invoke_restart, [False]).start() + # restart + threading.Timer(5, sickbeard.invoke_restart, [False]).start() return _munge(t) diff --git a/sickbeard/webserveInit.py b/sickbeard/webserveInit.py index 565fe935..c7c3c57f 100644 --- a/sickbeard/webserveInit.py +++ b/sickbeard/webserveInit.py @@ -1,5 +1,6 @@ import os import traceback +import time import sickbeard import webserve import webapi @@ -114,10 +115,10 @@ def initWebServer(options={}): def shutdown(): global server - logger.log('Shutting down tornado') + logger.log('Shutting down tornado io loop') try: IOLoop.current().stop() except RuntimeError: pass except: - logger.log('Failed shutting down the server: %s' % traceback.format_exc(), logger.ERROR) \ No newline at end of file + logger.log('Failed shutting down tornado io loop: %s' % traceback.format_exc(), logger.ERROR) \ No newline at end of file