def run(self, force=False): updated = None if self.check_for_new_version(): if sickbeard.AUTO_UPDATE: logger.log( u"New update found for SickRage, starting auto-updater ..." ) updated = sickbeard.versionCheckScheduler.action.update() if updated: logger.log( u"Update was successfull, restarting SickRage ...") # do a soft restart threading.Timer(2, sickbeard.invoke_restart, [False]).start() if not updated: # refresh scene exceptions too scene_exceptions.retrieve_exceptions() # refresh network timezones network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory()
def run(self, force=False): self.amActive = True update_datetime = datetime.datetime.now() update_date = update_datetime.date() # refresh network timezones network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() logger.log(u"Doing full update on all shows") # select 10 'Ended' tv_shows updated more than 90 days ago to include in this update stale_should_update = [] stale_update_date = (update_date - datetime.timedelta(days=90)).toordinal() # last_update_date <= 90 days, sorted ASC because dates are ordinal myDB = db.DBConnection() sql_result = myDB.select( "SELECT indexer_id FROM tv_shows WHERE status = 'Ended' AND last_update_indexer <= ? ORDER BY last_update_indexer ASC LIMIT 10;", [stale_update_date]) for cur_result in sql_result: stale_should_update.append(int(cur_result['indexer_id'])) # start update process piList = [] for curShow in sickbeard.showList: try: # get next episode airdate curShow.nextEpisode() # if should_update returns True (not 'Ended') or show is selected stale 'Ended' then update, otherwise just refresh if curShow.should_update( update_date=update_date ) or curShow.indexerid in stale_should_update: try: piList.append( sickbeard.showQueueScheduler.action.updateShow( curShow, True)) # @UndefinedVariable except CantUpdateShowException as e: logger.log("Unable to update show: {0}".format(str(e)), logger.DEBUG) else: logger.log( u"Not updating episodes for show " + curShow.name + " because it's marked as ended and last/next episode is not within the grace period.", logger.DEBUG) piList.append( sickbeard.showQueueScheduler.action.refreshShow( curShow, True)) # @UndefinedVariable except (CantUpdateShowException, CantRefreshShowException), e: logger.log(u"Automatic update failed: " + ex(e), logger.ERROR)
def run(self): self.check_for_new_version() # refresh scene exceptions too scene_exceptions.retrieve_exceptions() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory()
def run(self, force=False): self.amActive = True update_datetime = datetime.datetime.now() update_date = update_datetime.date() # refresh network timezones network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() logger.log(u"Doing full update on all shows") # select 10 'Ended' tv_shows updated more than 90 days ago to include in this update stale_should_update = [] stale_update_date = (update_date - datetime.timedelta(days=90)).toordinal() # last_update_date <= 90 days, sorted ASC because dates are ordinal myDB = db.DBConnection() sql_result = myDB.select( "SELECT indexer_id FROM tv_shows WHERE status = 'Ended' AND last_update_indexer <= ? ORDER BY last_update_indexer ASC LIMIT 10;", [stale_update_date]) for cur_result in sql_result: stale_should_update.append(int(cur_result['indexer_id'])) # start update process piList = [] for curShow in sickbeard.showList: try: # get next episode airdate curShow.nextEpisode() # if should_update returns True (not 'Ended') or show is selected stale 'Ended' then update, otherwise just refresh if curShow.should_update(update_date=update_date) or curShow.indexerid in stale_should_update: try: piList.append(sickbeard.showQueueScheduler.action.updateShow(curShow, True)) # @UndefinedVariable except CantUpdateShowException as e: logger.log(u"Unable to update show: {0}".format(str(e)),logger.DEBUG) else: logger.log( u"Not updating episodes for show " + curShow.name + " because it's marked as ended and last/next episode is not within the grace period.", logger.DEBUG) piList.append(sickbeard.showQueueScheduler.action.refreshShow(curShow, True)) # @UndefinedVariable except (CantUpdateShowException, CantRefreshShowException) as e: logger.log(u"Automatic update failed: {}".format(ex(e)), logger.ERROR) ui.ProgressIndicators.setIndicator('dailyUpdate', ui.QueueProgressIndicator("Daily Update", piList)) logger.log(u"Completed full update on all shows") self.amActive = False
def run(self, force=False): update_datetime = datetime.datetime.now() update_date = update_datetime.date() # refresh network timezones network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() logger.log(u"Doing full update on all shows") # clean out cache directory, remove everything > 12 hours old sickbeard.helpers.clearCache() # select 10 'Ended' tv_shows updated more than 90 days ago to include in this update stale_should_update = [] stale_update_date = (update_date - datetime.timedelta(days=90)).toordinal() # last_update_date <= 90 days, sorted ASC because dates are ordinal myDB = db.DBConnection() sql_result = myDB.select( "SELECT indexer_id FROM tv_shows WHERE status = 'Ended' AND last_update_indexer <= ? ORDER BY last_update_indexer ASC LIMIT 10;", [stale_update_date]) for cur_result in sql_result: stale_should_update.append(int(cur_result['indexer_id'])) # start update process piList = [] for curShow in sickbeard.showList: try: # get next episode airdate curShow.nextEpisode() # if should_update returns True (not 'Ended') or show is selected stale 'Ended' then update, otherwise just refresh if curShow.should_update(update_date=update_date) or curShow.indexerid in stale_should_update: curQueueItem = sickbeard.showQueueScheduler.action.updateShow(curShow, True) # @UndefinedVariable else: logger.log( u"Not updating episodes for show " + curShow.name + " because it's marked as ended and last/next episode is not within the grace period.", logger.DEBUG) curQueueItem = sickbeard.showQueueScheduler.action.refreshShow(curShow, True) # @UndefinedVariable piList.append(curQueueItem) except (exceptions.CantUpdateException, exceptions.CantRefreshException), e: logger.log(u"Automatic update failed: " + ex(e), logger.ERROR)
def run(self, force=False): self.amActive = True # get and update scene exceptions lists scene_exceptions.retrieve_exceptions() # refresh network timezones network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() self.amActive = False
def run(self, force=False): self.amActive = True # refresh scene exceptions too scene_exceptions.retrieve_exceptions() # refresh network timezones network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() self.amActive = False
def run(self, force=False): update_datetime = datetime.datetime.now() update_date = update_datetime.date() # refresh network timezones network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() logger.log(u"Doing full update on all shows") # clean out cache directory, remove everything > 12 hours old if sickbeard.CACHE_DIR: for indexer in sickbeard.indexerApi().indexers: cache_dir = sickbeard.indexerApi(indexer).cache logger.log(u"Trying to clean cache folder " + cache_dir) # Does our cache_dir exists if not ek.ek(os.path.isdir, cache_dir): logger.log(u"Can't clean " + cache_dir + " if it doesn't exist", logger.WARNING) else: max_age = datetime.timedelta(hours=12) # Get all our cache files cache_files = ek.ek(os.listdir, cache_dir) for cache_file in cache_files: cache_file_path = ek.ek(os.path.join, cache_dir, cache_file) if ek.ek(os.path.isfile, cache_file_path): cache_file_modified = datetime.datetime.fromtimestamp( ek.ek(os.path.getmtime, cache_file_path) ) if update_datetime - cache_file_modified > max_age: try: ek.ek(os.remove, cache_file_path) except OSError, e: logger.log( u"Unable to clean " + cache_dir + ": " + repr(e) + " / " + str(e), logger.WARNING, ) break
def run(self): if self.check_for_new_version(): if sickbeard.AUTO_UPDATE: logger.log(u"New update found for SickBeard, starting auto-updater ...") updated = sickbeard.versionCheckScheduler.action.update() if updated: logger.log(u"Update was successfull, restarting SickBeard ...") sickbeard.restart(False) # refresh scene exceptions too scene_exceptions.retrieve_exceptions() # refresh network timezones network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory()
def run(self, force=False): self.amActive = True # clear internal name cache name_cache.clearCache() # get and update scene exceptions lists scene_exceptions.retrieve_exceptions() # build internal name cache for searches and parsing name_cache.buildNameCache() # refresh network timezones network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() self.amActive = False
def run(self): if self.check_for_new_version(): if sickbeard.AUTO_UPDATE: logger.log( u"New update found for SickBeard, starting auto-updater ..." ) updated = sickbeard.versionCheckScheduler.action.update() if updated: logger.log( u"Update was successfull, restarting SickBeard ...") sickbeard.restart(False) # refresh scene exceptions too scene_exceptions.retrieve_exceptions() # refresh network timezones network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory()
def run(self): updated = None if self.check_for_new_version(): if sickbeard.AUTO_UPDATE: logger.log(u"New update found for SickRage, starting auto-updater ...") updated = sickbeard.versionCheckScheduler.action.update() if updated: logger.log(u"Update was successfull, restarting SickRage ...") # do a soft restart threading.Timer(2, sickbeard.invoke_restart, [False]).start() if not updated: # refresh scene exceptions too scene_exceptions.retrieve_exceptions() # refresh network timezones network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory()
def start(self): # Rename the main thread threading.currentThread().name = "MAIN" # initalize encoding defaults encodingInit() # do some preliminary stuff sickbeard.MY_FULLNAME = ek(os.path.normpath, ek(os.path.abspath, __file__)) sickbeard.MY_NAME = ek(os.path.basename, sickbeard.MY_FULLNAME) sickbeard.PROG_DIR = ek(os.path.dirname, sickbeard.MY_FULLNAME) sickbeard.DATA_DIR = sickbeard.PROG_DIR sickbeard.MY_ARGS = sys.argv[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) # Do this before importing sickbeard, to prevent locked files and incorrect import oldtornado = ek( os.path.abspath, ek(os.path.join, ek(os.path.dirname, __file__), 'tornado')) if ek(os.path.isdir, oldtornado): ek(shutil.move, oldtornado, oldtornado + '_kill') ek(removetree, oldtornado + '_kill') try: opts, _ = getopt.getopt(sys.argv[1:], "hqdp::", [ 'help', 'quiet', 'nolaunch', 'daemon', 'pidfile=', 'port=', 'datadir=', 'config=', 'noresize' ]) except getopt.GetoptError: sys.exit(self.help_message()) for o, a in opts: # Prints help message if o in ('-h', '--help'): sys.exit(self.help_message()) # For now we'll just silence the logging if o in ('-q', '--quiet'): self.consoleLogging = False # 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 # Override default/configured port if o in ('-p', '--port'): try: self.forcedPort = int(a) except ValueError: sys.exit("Port: " + str(a) + " is not a number. Exiting.") # Run as a double forked daemon if o in ('-d', '--daemon'): self.runAsDaemon = True # When running as daemon disable consoleLogging and don't start browser self.consoleLogging = False self.noLaunch = True if sys.platform == 'win32' or sys.platform == 'darwin': self.runAsDaemon = False # Write a pidfile if requested if o in ('--pidfile', ): self.CREATEPID = True self.PIDFILE = str(a) # If the pidfile already exists, sickbeard may still be running, so exit if ek(os.path.exists, self.PIDFILE): sys.exit("PID file: " + self.PIDFILE + " already exists. Exiting.") # Specify folder to load the config file from if o in ('--config', ): sickbeard.CONFIG_FILE = ek(os.path.abspath, a) # Specify folder to use as the data dir if o in ('--datadir', ): sickbeard.DATA_DIR = ek(os.path.abspath, a) # Prevent resizing of the banner/posters even if PIL is installed if o in ('--noresize', ): 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 = ek(os.path.dirname, self.PIDFILE) if not ek(os.access, pid_dir, os.F_OK): sys.exit("PID dir: " + pid_dir + " doesn't exist. Exiting.") if not ek(os.access, pid_dir, os.W_OK): sys.exit("PID dir: " + pid_dir + " must be writable (write permissions). Exiting.") else: if self.consoleLogging: sys.stdout.write( "Not running in daemon mode. PID file creation disabled.\n" ) self.CREATEPID = False # If they don't specify a config file then put it in the data dir if not sickbeard.CONFIG_FILE: sickbeard.CONFIG_FILE = ek(os.path.join, sickbeard.DATA_DIR, "config.ini") # Make sure that we can create the data dir result = ek(os.access, sickbeard.DATA_DIR, os.F_OK) if not ek(os.access, sickbeard.DATA_DIR, os.F_OK): try: ek(os.makedirs, sickbeard.DATA_DIR, 0o744) except os.error as e: raise SystemExit("Unable to create datadir '" + sickbeard.DATA_DIR + "'") # Make sure we can write to the data dir if not ek(os.access, sickbeard.DATA_DIR, os.W_OK): raise SystemExit("Datadir must be writeable '" + sickbeard.DATA_DIR + "'") # Make sure we can write to the config file if not ek(os.access, sickbeard.CONFIG_FILE, os.W_OK): if ek(os.path.isfile, sickbeard.CONFIG_FILE): raise SystemExit("Config file '" + sickbeard.CONFIG_FILE + "' must be writeable.") elif not ek(os.access, ek(os.path.dirname, sickbeard.CONFIG_FILE), os.W_OK): raise SystemExit("Config file root dir '" + ek(os.path.dirname, sickbeard.CONFIG_FILE) + "' must be writeable.") ek(os.chdir, sickbeard.DATA_DIR) # Check if we need to perform a restore first restoreDir = ek(os.path.join, sickbeard.DATA_DIR, 'restore') if ek(os.path.exists, restoreDir): success = self.restoreDB(restoreDir, sickbeard.DATA_DIR) if self.consoleLogging: sys.stdout.write("Restore: restoring DB and config.ini %s!\n" % ("FAILED", "SUCCESSFUL")[success]) # Load the config and publish it to the sickbeard package if self.consoleLogging and not ek(os.path.isfile, sickbeard.CONFIG_FILE): sys.stdout.write("Unable to find '" + sickbeard.CONFIG_FILE + "' , all settings will be default!" + "\n") sickbeard.CFG = ConfigObj(sickbeard.CONFIG_FILE) # Initialize the config and our threads sickbeard.initialize(consoleLogging=self.consoleLogging) if self.runAsDaemon: sickbeard.DAEMONIZE = True self.daemonize() # Get PID sickbeard.PID = os.getpid() # Build from the DB to start with self.loadShowsFromDB() if self.forcedPort: logging.info("Forcing web server to port " + str(self.forcedPort)) self.startPort = self.forcedPort else: self.startPort = sickbeard.WEB_PORT if sickbeard.WEB_LOG: self.log_dir = sickbeard.LOG_DIR else: self.log_dir = None # sickbeard.WEB_HOST is available as a configuration value in various # places but is not configurable. It is supported here for historic reasons. if sickbeard.WEB_HOST and sickbeard.WEB_HOST != '0.0.0.0': self.webhost = sickbeard.WEB_HOST else: if sickbeard.WEB_IPV6: self.webhost = '::' else: self.webhost = '0.0.0.0' # Clean up after update if sickbeard.GIT_NEWVER: toclean = ek(os.path.join, sickbeard.CACHE_DIR, 'mako') for root, dirs, files in ek(os.walk, toclean, topdown=False): for name in files: ek(os.remove, ek(os.path.join, root, name)) for name in dirs: ek(os.rmdir, ek(os.path.join, root, name)) sickbeard.GIT_NEWVER = False # Fire up all our threads logging.info("Starting SiCKRAGE:[{}] CONFIG:[{}]".format( sickbeard.BRANCH, sickbeard.CONFIG_FILE)) sickbeard.start() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() # Check for metadata indexer updates for shows (Disabled until we use api) # sickbeard.showUpdateScheduler.forceRun() # start tornado web server sickbeard.WEB_SERVER = SRWebServer({ 'port': int(self.startPort), 'host': self.webhost, 'gui_root': sickbeard.GUI_DIR, 'web_root': sickbeard.WEB_ROOT, 'log_dir': self.log_dir, 'username': sickbeard.WEB_USERNAME, 'password': sickbeard.WEB_PASSWORD, 'enable_https': sickbeard.ENABLE_HTTPS, 'handle_reverse_proxy': sickbeard.HANDLE_REVERSE_PROXY, 'https_cert': ek(os.path.join, sickbeard.PROG_DIR, sickbeard.HTTPS_CERT), 'https_key': ek(os.path.join, sickbeard.PROG_DIR, sickbeard.HTTPS_KEY), }).start()
class SickRage(object): def __init__(self): # system event callback for shutdown/restart sickbeard.events = Events(self.shutdown) # daemon constants self.runAsDaemon = False self.CREATEPID = False self.PIDFILE = '' # webserver constants self.webserver = None self.forcedPort = None self.noLaunch = False def help_message(self): """ print help message for commandline options """ help_msg = "\n" help_msg += "Usage: " + sickbeard.MY_FULLNAME + " <option> <another option>\n" help_msg += "\n" help_msg += "Options:\n" help_msg += "\n" help_msg += " -h --help Prints this message\n" help_msg += " -q --quiet Disables logging to console\n" help_msg += " --nolaunch Suppress launching web browser on startup\n" if sys.platform == 'win32' or sys.platform == 'darwin': help_msg += " -d --daemon Running as real daemon is not supported on Windows\n" help_msg += " On Windows and MAC, --daemon is substituted with: --quiet --nolaunch\n" 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" 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: " + sickbeard.PROG_DIR + "\n" 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 " + sickbeard.PROG_DIR + " or --datadir location\n" help_msg += " --noresize Prevent resizing of the banner/posters even if PIL is installed\n" return help_msg def fix_clients_nonsense(self): files = ["sickbeard/clients/download_station.py", "sickbeard/clients/utorrent.py", "sickbeard/clients/qbittorrent.py", "sickbeard/clients/transmission.py", "sickbeard/clients/deluge.py", "sickbeard/clients/deluged.py", "sickbeard/clients/rtorrent.py" ] for file in files: file = ek.ek(os.path.join, sickbeard.PROG_DIR, file) try: if ek.ek(os.path.exists, file): ek.ek(os.remove, file) except: pass try: if ek.ek(os.path.exists, file + "c"): ek.ek(os.remove, file + "c") except: pass def start(self): # do some preliminary stuff sickbeard.MY_FULLNAME = os.path.normpath(os.path.abspath(__file__)) sickbeard.MY_NAME = os.path.basename(sickbeard.MY_FULLNAME) sickbeard.PROG_DIR = os.path.dirname(sickbeard.MY_FULLNAME) sickbeard.DATA_DIR = sickbeard.PROG_DIR sickbeard.MY_ARGS = sys.argv[1:] sickbeard.SYS_ENCODING = None try: locale.setlocale(locale.LC_ALL, "") sickbeard.SYS_ENCODING = locale.getpreferredencoding() except (locale.Error, IOError): pass # For OSes that are poorly configured I'll just randomly force UTF-8 if not sickbeard.SYS_ENCODING or sickbeard.SYS_ENCODING in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'): sickbeard.SYS_ENCODING = 'UTF-8' if not hasattr(sys, "setdefaultencoding"): reload(sys) if sys.platform == 'win32': if sys.getwindowsversion()[0] >= 6 and sys.stdout.encoding == 'cp65001': sickbeard.SYS_ENCODING = 'UTF-8' try: # pylint: disable=E1101 # On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError sys.setdefaultencoding(sickbeard.SYS_ENCODING) except: sys.exit("Sorry, you MUST add the SickRage folder to the PYTHONPATH environment variable\n" + "or find another way to force Python to use " + sickbeard.SYS_ENCODING + " for string encoding.") # Need console logging for SickBeard.py and SickBeard-console.exe self.consoleLogging = (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', 'quiet', 'nolaunch', 'daemon', 'pidfile=', 'port=', 'datadir=', 'config=', 'noresize']) # @UnusedVariable except getopt.GetoptError: sys.exit(self.help_message()) for o, a in opts: # Prints help message if o in ('-h', '--help'): sys.exit(self.help_message()) # For now we'll just silence the logging if o in ('-q', '--quiet'): self.consoleLogging = False # 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 # Override default/configured port if o in ('-p', '--port'): try: self.forcedPort = int(a) except ValueError: sys.exit("Port: " + str(a) + " is not a number. Exiting.") # Run as a double forked daemon if o in ('-d', '--daemon'): self.runAsDaemon = True # When running as daemon disable consoleLogging and don't start browser self.consoleLogging = False self.noLaunch = True if sys.platform == 'win32' or sys.platform == 'darwin': self.runAsDaemon = False # Write a pidfile if requested if o in ('--pidfile',): self.CREATEPID = True self.PIDFILE = str(a) # If the pidfile already exists, sickbeard may still be running, so exit if os.path.exists(self.PIDFILE): sys.exit("PID file: " + self.PIDFILE + " already exists. Exiting.") # Specify folder to load the config file from if o in ('--config',): sickbeard.CONFIG_FILE = os.path.abspath(a) # Specify folder to use as the data dir if o in ('--datadir',): sickbeard.DATA_DIR = os.path.abspath(a) # Prevent resizing of the banner/posters even if PIL is installed if o in ('--noresize',): 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 not os.access(pid_dir, os.F_OK): sys.exit("PID dir: " + pid_dir + " doesn't exist. Exiting.") if not os.access(pid_dir, os.W_OK): sys.exit("PID dir: " + pid_dir + " must be writable (write permissions). Exiting.") else: if self.consoleLogging: sys.stdout.write("Not running in daemon mode. PID file creation disabled.\n") self.CREATEPID = False # If they don't specify a config file then put it in the data dir if not sickbeard.CONFIG_FILE: sickbeard.CONFIG_FILE = os.path.join(sickbeard.DATA_DIR, "config.ini") # Make sure that we can create the data dir if not os.access(sickbeard.DATA_DIR, os.F_OK): try: os.makedirs(sickbeard.DATA_DIR, 0744) except os.error, e: raise SystemExit("Unable to create datadir '" + sickbeard.DATA_DIR + "'") # Make sure we can write to the data dir if not os.access(sickbeard.DATA_DIR, os.W_OK): raise SystemExit("Datadir must be writeable '" + sickbeard.DATA_DIR + "'") # Make sure we can write to the config file if not os.access(sickbeard.CONFIG_FILE, os.W_OK): if os.path.isfile(sickbeard.CONFIG_FILE): raise SystemExit("Config file '" + sickbeard.CONFIG_FILE + "' must be writeable.") elif not os.access(os.path.dirname(sickbeard.CONFIG_FILE), os.W_OK): raise SystemExit( "Config file root dir '" + os.path.dirname(sickbeard.CONFIG_FILE) + "' must be writeable.") os.chdir(sickbeard.DATA_DIR) # Check if we need to perform a restore first try: restoreDir = os.path.join(sickbeard.DATA_DIR, 'restore') if self.consoleLogging and os.path.exists(restoreDir): if self.restoreDB(restoreDir, sickbeard.DATA_DIR): sys.stdout.write("Restore: restoring DB and config.ini successful...\n") else: sys.stdout.write("Restore: restoring DB and config.ini FAILED!\n") except Exception as e: sys.stdout.write("Restore: restoring DB and config.ini FAILED!\n") # Load the config and publish it to the sickbeard package if self.consoleLogging and not os.path.isfile(sickbeard.CONFIG_FILE): sys.stdout.write("Unable to find '" + sickbeard.CONFIG_FILE + "' , all settings will be default!" + "\n") sickbeard.CFG = ConfigObj(sickbeard.CONFIG_FILE) # Initialize the config and our threads sickbeard.initialize(consoleLogging=self.consoleLogging) if self.runAsDaemon: self.daemonize() # Get PID sickbeard.PID = os.getpid() # Fix clients old files self.fix_clients_nonsense() # Build from the DB to start with self.loadShowsFromDB() if self.forcedPort: logger.log(u"Forcing web server to port " + str(self.forcedPort)) self.startPort = self.forcedPort else: self.startPort = sickbeard.WEB_PORT if sickbeard.WEB_LOG: self.log_dir = sickbeard.LOG_DIR else: self.log_dir = None # sickbeard.WEB_HOST is available as a configuration value in various # places but is not configurable. It is supported here for historic reasons. if sickbeard.WEB_HOST and sickbeard.WEB_HOST != '0.0.0.0': self.webhost = sickbeard.WEB_HOST else: if sickbeard.WEB_IPV6: self.webhost = '::' else: self.webhost = '0.0.0.0' # web server options self.web_options = { 'port': int(self.startPort), 'host': self.webhost, 'data_root': os.path.join(sickbeard.PROG_DIR, 'gui', sickbeard.GUI_NAME), 'web_root': sickbeard.WEB_ROOT, 'log_dir': self.log_dir, 'username': sickbeard.WEB_USERNAME, 'password': sickbeard.WEB_PASSWORD, 'enable_https': sickbeard.ENABLE_HTTPS, 'handle_reverse_proxy': sickbeard.HANDLE_REVERSE_PROXY, 'https_cert': os.path.join(sickbeard.PROG_DIR, sickbeard.HTTPS_CERT), 'https_key': os.path.join(sickbeard.PROG_DIR, sickbeard.HTTPS_KEY), } # start web server self.webserver = SRWebServer(self.web_options) self.webserver.start() if self.consoleLogging: print "Starting up SickRage " + sickbeard.BRANCH + " from " + sickbeard.CONFIG_FILE # Fire up all our threads sickbeard.start() # Build internal name cache name_cache.buildNameCache() # Prepopulate network timezones, it isn't thread safe network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() # Check for metadata indexer updates for shows (Disabled until we use api) #sickbeard.showUpdateScheduler.forceRun() # Launch browser if sickbeard.LAUNCH_BROWSER and not (self.noLaunch or self.runAsDaemon): sickbeard.launchBrowser('https' if sickbeard.ENABLE_HTTPS else 'http', self.startPort, sickbeard.WEB_ROOT) # main loop while (True): time.sleep(1)
def start(self): # do some preliminary stuff sickbeard.MY_FULLNAME = ek(os.path.normpath, ek(os.path.abspath, __file__)) sickbeard.MY_NAME = ek(os.path.basename, sickbeard.MY_FULLNAME) sickbeard.PROG_DIR = ek(os.path.dirname, sickbeard.MY_FULLNAME) sickbeard.DATA_DIR = sickbeard.PROG_DIR sickbeard.MY_ARGS = sys.argv[1:] try: locale.setlocale(locale.LC_ALL, "") sickbeard.SYS_ENCODING = locale.getpreferredencoding() except (locale.Error, IOError): sickbeard.SYS_ENCODING = 'UTF-8' # pylint: disable=no-member if not sickbeard.SYS_ENCODING or sickbeard.SYS_ENCODING.lower() in ('ansi_x3.4-1968', 'us-ascii', 'ascii', 'charmap') or \ (sys.platform.startswith('win') and sys.getwindowsversion()[0] >= 6 and str(getattr(sys.stdout, 'device', sys.stdout).encoding).lower() in ('cp65001', 'charmap')): sickbeard.SYS_ENCODING = 'UTF-8' # TODO: Continue working on making this unnecessary, this hack creates all sorts of hellish problems if not hasattr(sys, "setdefaultencoding"): reload(sys) try: # pylint: disable=no-member # On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError sys.setdefaultencoding(sickbeard.SYS_ENCODING) except Exception: sys.exit("Sorry, you MUST add the SickRage folder to the PYTHONPATH environment variable\n" + "or find another way to force Python to use " + sickbeard.SYS_ENCODING + " for string encoding.") # Need console logging for SickBeard.py and SickBeard-console.exe self.consoleLogging = (not hasattr(sys, "frozen")) or (sickbeard.MY_NAME.lower().find('-console') > 0) # Rename the main thread threading.currentThread().name = u"MAIN" try: opts, _ = getopt.getopt( sys.argv[1:], "hqdp::", ['help', 'quiet', 'nolaunch', 'daemon', 'pidfile=', 'port=', 'datadir=', 'config=', 'noresize'] ) except getopt.GetoptError: sys.exit(self.help_message()) for o, a in opts: # Prints help message if o in ('-h', '--help'): sys.exit(self.help_message()) # For now we'll just silence the logging if o in ('-q', '--quiet'): self.consoleLogging = False # 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 # Override default/configured port if o in ('-p', '--port'): try: self.forcedPort = int(a) except ValueError: sys.exit("Port: " + str(a) + " is not a number. Exiting.") # Run as a double forked daemon if o in ('-d', '--daemon'): self.runAsDaemon = True # When running as daemon disable consoleLogging and don't start browser self.consoleLogging = False self.noLaunch = True if sys.platform == 'win32' or sys.platform == 'darwin': self.runAsDaemon = False # Write a pidfile if requested if o in ('--pidfile',): self.CREATEPID = True self.PIDFILE = str(a) # If the pidfile already exists, sickbeard may still be running, so exit if ek(os.path.exists, self.PIDFILE): sys.exit("PID file: " + self.PIDFILE + " already exists. Exiting.") # Specify folder to load the config file from if o in ('--config',): sickbeard.CONFIG_FILE = ek(os.path.abspath, a) # Specify folder to use as the data dir if o in ('--datadir',): sickbeard.DATA_DIR = ek(os.path.abspath, a) # Prevent resizing of the banner/posters even if PIL is installed if o in ('--noresize',): 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 = ek(os.path.dirname, self.PIDFILE) if not ek(os.access, pid_dir, os.F_OK): sys.exit("PID dir: " + pid_dir + " doesn't exist. Exiting.") if not ek(os.access, pid_dir, os.W_OK): sys.exit("PID dir: " + pid_dir + " must be writable (write permissions). Exiting.") else: if self.consoleLogging: sys.stdout.write(u"Not running in daemon mode. PID file creation disabled.\n") self.CREATEPID = False # If they don't specify a config file then put it in the data dir if not sickbeard.CONFIG_FILE: sickbeard.CONFIG_FILE = ek(os.path.join, sickbeard.DATA_DIR, "config.ini") # Make sure that we can create the data dir if not ek(os.access, sickbeard.DATA_DIR, os.F_OK): try: ek(os.makedirs, sickbeard.DATA_DIR, 0744) except os.error: raise SystemExit("Unable to create datadir '" + sickbeard.DATA_DIR + "'") # Make sure we can write to the data dir if not ek(os.access, sickbeard.DATA_DIR, os.W_OK): raise SystemExit("Datadir must be writeable '" + sickbeard.DATA_DIR + "'") # Make sure we can write to the config file if not ek(os.access, sickbeard.CONFIG_FILE, os.W_OK): if ek(os.path.isfile, sickbeard.CONFIG_FILE): raise SystemExit("Config file '" + sickbeard.CONFIG_FILE + "' must be writeable.") elif not ek(os.access, ek(os.path.dirname, sickbeard.CONFIG_FILE), os.W_OK): raise SystemExit( "Config file root dir '" + ek(os.path.dirname, sickbeard.CONFIG_FILE) + "' must be writeable.") ek(os.chdir, sickbeard.DATA_DIR) # Check if we need to perform a restore first restoreDir = ek(os.path.join, sickbeard.DATA_DIR, 'restore') if ek(os.path.exists, restoreDir): success = self.restoreDB(restoreDir, sickbeard.DATA_DIR) if self.consoleLogging: sys.stdout.write(u"Restore: restoring DB and config.ini %s!\n" % ("FAILED", "SUCCESSFUL")[success]) # Load the config and publish it to the sickbeard package if self.consoleLogging and not ek(os.path.isfile, sickbeard.CONFIG_FILE): sys.stdout.write(u"Unable to find '" + sickbeard.CONFIG_FILE + "' , all settings will be default!" + "\n") sickbeard.CFG = ConfigObj(sickbeard.CONFIG_FILE) # Initialize the config and our threads sickbeard.initialize(consoleLogging=self.consoleLogging) if self.runAsDaemon: self.daemonize() # Get PID sickbeard.PID = os.getpid() # Build from the DB to start with self.loadShowsFromDB() if self.forcedPort: logger.log(u"Forcing web server to port " + str(self.forcedPort)) self.startPort = self.forcedPort else: self.startPort = sickbeard.WEB_PORT if sickbeard.WEB_LOG: self.log_dir = sickbeard.LOG_DIR else: self.log_dir = None # sickbeard.WEB_HOST is available as a configuration value in various # places but is not configurable. It is supported here for historic reasons. if sickbeard.WEB_HOST and sickbeard.WEB_HOST != '0.0.0.0': self.webhost = sickbeard.WEB_HOST else: if sickbeard.WEB_IPV6: self.webhost = '' else: self.webhost = '0.0.0.0' # web server options self.web_options = { 'port': int(self.startPort), 'host': self.webhost, 'data_root': ek(os.path.join, sickbeard.PROG_DIR, 'gui', sickbeard.GUI_NAME), 'web_root': sickbeard.WEB_ROOT, 'log_dir': self.log_dir, 'username': sickbeard.WEB_USERNAME, 'password': sickbeard.WEB_PASSWORD, 'enable_https': sickbeard.ENABLE_HTTPS, 'handle_reverse_proxy': sickbeard.HANDLE_REVERSE_PROXY, 'https_cert': ek(os.path.join, sickbeard.PROG_DIR, sickbeard.HTTPS_CERT), 'https_key': ek(os.path.join, sickbeard.PROG_DIR, sickbeard.HTTPS_KEY), } # start web server self.webserver = SRWebServer(self.web_options) self.webserver.start() if self.consoleLogging: print "Starting up SickRage " + sickbeard.BRANCH + " from " + sickbeard.CONFIG_FILE # Clean up after update if sickbeard.GIT_NEWVER: toclean = ek(os.path.join, sickbeard.CACHE_DIR, 'mako') for root, dirs, files in ek(os.walk, toclean, topdown=False): for name in files: ek(os.remove, ek(os.path.join, root, name)) for name in dirs: ek(os.rmdir, ek(os.path.join, root, name)) sickbeard.GIT_NEWVER = False # Fire up all our threads sickbeard.start() # Build internal name cache name_cache.buildNameCache() # Prepopulate network timezones, it isn't thread safe network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() # # Check for metadata indexer updates for shows (Disabled until we use api) # sickbeard.showUpdateScheduler.forceRun() # Launch browser if sickbeard.LAUNCH_BROWSER and not (self.noLaunch or self.runAsDaemon): sickbeard.launchBrowser('https' if sickbeard.ENABLE_HTTPS else 'http', self.startPort, sickbeard.WEB_ROOT) # main loop while True: time.sleep(1)
def start(self): # pylint: disable=too-many-branches,too-many-statements """ Start SickRage """ # do some preliminary stuff sickbeard.MY_FULLNAME = ek(os.path.normpath, ek(os.path.abspath, __file__)) sickbeard.MY_NAME = ek(os.path.basename, sickbeard.MY_FULLNAME) sickbeard.PROG_DIR = ek(os.path.dirname, sickbeard.MY_FULLNAME) sickbeard.DATA_DIR = sickbeard.PROG_DIR sickbeard.MY_ARGS = sys.argv[1:] try: locale.setlocale(locale.LC_ALL, "") sickbeard.SYS_ENCODING = locale.getpreferredencoding() except (locale.Error, IOError): sickbeard.SYS_ENCODING = "UTF-8" # pylint: disable=no-member if ( not sickbeard.SYS_ENCODING or sickbeard.SYS_ENCODING.lower() in ("ansi_x3.4-1968", "us-ascii", "ascii", "charmap") or ( sys.platform.startswith("win") and sys.getwindowsversion()[0] >= 6 and str(getattr(sys.stdout, "device", sys.stdout).encoding).lower() in ("cp65001", "charmap") ) ): sickbeard.SYS_ENCODING = "UTF-8" # TODO: Continue working on making this unnecessary, this hack creates all sorts of hellish problems if not hasattr(sys, "setdefaultencoding"): reload(sys) try: # On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError sys.setdefaultencoding(sickbeard.SYS_ENCODING) # pylint: disable=no-member except (AttributeError, LookupError): sys.exit( "Sorry, you MUST add the SickRage folder to the PYTHONPATH environment variable\n" "or find another way to force Python to use %s for string encoding." % sickbeard.SYS_ENCODING ) # Need console logging for SickBeard.py and SickBeard-console.exe 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, _ = getopt.getopt( sys.argv[1:], "hqdp::", ["help", "quiet", "nolaunch", "daemon", "pidfile=", "port=", "datadir=", "config=", "noresize"], ) except getopt.GetoptError: sys.exit(self.help_message()) for option, value in opts: # Prints help message if option in ("-h", "--help"): sys.exit(self.help_message()) # For now we'll just silence the logging if option in ("-q", "--quiet"): self.console_logging = False # Suppress launching web browser # Needed for OSes without default browser assigned # Prevent duplicate browser window when restarting in the app if option in ("--nolaunch",): self.no_launch = True # Override default/configured port if option in ("-p", "--port"): try: self.forced_port = int(value) except ValueError: sys.exit("Port: %s is not a number. Exiting." % value) # Run as a double forked daemon if option in ("-d", "--daemon"): self.run_as_daemon = True # When running as daemon disable console_logging and don't start browser self.console_logging = False self.no_launch = True if sys.platform == "win32" or sys.platform == "darwin": self.run_as_daemon = False # Write a pid file if requested if option in ("--pidfile",): self.create_pid = True self.pid_file = str(value) # If the pid file already exists, SickRage may still be running, so exit if ek(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 option in ("--config",): sickbeard.CONFIG_FILE = ek(os.path.abspath, value) # Specify folder to use as the data directory if option in ("--datadir",): sickbeard.DATA_DIR = ek(os.path.abspath, value) # Prevent resizing of the banner/posters even if PIL is installed if option in ("--noresize",): sickbeard.NO_RESIZE = True # The pid file is only useful in daemon mode, make sure we can write the file properly if self.create_pid: if self.run_as_daemon: pid_dir = ek(os.path.dirname, self.pid_file) if not ek(os.access, pid_dir, os.F_OK): sys.exit("PID dir: %s doesn't exist. Exiting." % pid_dir) if not ek(os.access, pid_dir, os.W_OK): sys.exit("PID dir: %s must be writable (write permissions). Exiting." % pid_dir) else: if self.console_logging: sys.stdout.write("Not running in daemon mode. PID file creation disabled.\n") self.create_pid = False # If they don't specify a config file then put it in the data dir if not sickbeard.CONFIG_FILE: sickbeard.CONFIG_FILE = ek(os.path.join, sickbeard.DATA_DIR, "config.ini") # Make sure that we can create the data dir if not ek(os.access, sickbeard.DATA_DIR, os.F_OK): try: ek(os.makedirs, sickbeard.DATA_DIR, 0o744) except os.error: raise SystemExit("Unable to create data directory: %s" % sickbeard.DATA_DIR) # Make sure we can write to the data dir if not ek(os.access, sickbeard.DATA_DIR, os.W_OK): raise SystemExit("Data directory must be writeable: %s" % sickbeard.DATA_DIR) # Make sure we can write to the config file if not ek(os.access, sickbeard.CONFIG_FILE, os.W_OK): if ek(os.path.isfile, sickbeard.CONFIG_FILE): raise SystemExit("Config file must be writeable: %s" % sickbeard.CONFIG_FILE) elif not ek(os.access, ek(os.path.dirname, sickbeard.CONFIG_FILE), os.W_OK): raise SystemExit( "Config file root dir must be writeable: %s" % ek(os.path.dirname, sickbeard.CONFIG_FILE) ) ek(os.chdir, sickbeard.DATA_DIR) # Check if we need to perform a restore first restore_dir = ek(os.path.join, sickbeard.DATA_DIR, "restore") if ek(os.path.exists, restore_dir): success = self.restore_db(restore_dir, sickbeard.DATA_DIR) if self.console_logging: sys.stdout.write("Restore: restoring DB and config.ini %s!\n" % ("FAILED", "SUCCESSFUL")[success]) # Load the config and publish it to the sickbeard package if self.console_logging and not ek(os.path.isfile, sickbeard.CONFIG_FILE): sys.stdout.write("Unable to find %s, all settings will be default!\n" % sickbeard.CONFIG_FILE) sickbeard.CFG = ConfigObj(sickbeard.CONFIG_FILE) # Initialize the config and our threads sickbeard.initialize(consoleLogging=self.console_logging) if self.run_as_daemon: self.daemonize() # Get PID sickbeard.PID = os.getpid() # Build from the DB to start with self.load_shows_from_db() logger.log("Starting SickRage [%s] from '%s'" % (sickbeard.BRANCH, sickbeard.CONFIG_FILE)) self.clear_cache() if self.forced_port: logger.log("Forcing web server to port %s" % self.forced_port) self.start_port = self.forced_port else: self.start_port = sickbeard.WEB_PORT if sickbeard.WEB_LOG: self.log_dir = sickbeard.LOG_DIR else: self.log_dir = None # sickbeard.WEB_HOST is available as a configuration value in various # places but is not configurable. It is supported here for historic reasons. if sickbeard.WEB_HOST and sickbeard.WEB_HOST != "0.0.0.0": self.web_host = sickbeard.WEB_HOST else: self.web_host = "" if sickbeard.WEB_IPV6 else "0.0.0.0" # web server options self.web_options = { "port": int(self.start_port), "host": self.web_host, "data_root": ek(os.path.join, sickbeard.PROG_DIR, "gui", sickbeard.GUI_NAME), "web_root": sickbeard.WEB_ROOT, "log_dir": self.log_dir, "username": sickbeard.WEB_USERNAME, "password": sickbeard.WEB_PASSWORD, "enable_https": sickbeard.ENABLE_HTTPS, "handle_reverse_proxy": sickbeard.HANDLE_REVERSE_PROXY, "https_cert": ek(os.path.join, sickbeard.PROG_DIR, sickbeard.HTTPS_CERT), "https_key": ek(os.path.join, sickbeard.PROG_DIR, sickbeard.HTTPS_KEY), } # start web server self.web_server = SRWebServer(self.web_options) self.web_server.start() # Fire up all our threads sickbeard.start() # Build internal name cache # name_cache.buildNameCache() # Pre-populate network timezones, it isn't thread safe network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() # # Check for metadata indexer updates for shows (Disabled until we use api) # sickbeard.showUpdateScheduler.forceRun() # Launch browser if sickbeard.LAUNCH_BROWSER and not (self.no_launch or self.run_as_daemon): sickbeard.launchBrowser("https" if sickbeard.ENABLE_HTTPS else "http", self.start_port, sickbeard.WEB_ROOT) # main loop while True: time.sleep(1)
def start(self): # do some preliminary stuff sickbeard.MY_FULLNAME = os.path.normpath(os.path.abspath(__file__)) sickbeard.MY_NAME = os.path.basename(sickbeard.MY_FULLNAME) sickbeard.PROG_DIR = os.path.dirname(sickbeard.MY_FULLNAME) sickbeard.DATA_DIR = sickbeard.PROG_DIR sickbeard.MY_ARGS = sys.argv[1:] sickbeard.SYS_ENCODING = None try: locale.setlocale(locale.LC_ALL, '') except (locale.Error, IOError): pass try: sickbeard.SYS_ENCODING = locale.getpreferredencoding() except (locale.Error, IOError): pass # For OSes that are poorly configured I'll just randomly force UTF-8 if not sickbeard.SYS_ENCODING or sickbeard.SYS_ENCODING in ( 'ANSI_X3.4-1968', 'US-ASCII', 'ASCII'): sickbeard.SYS_ENCODING = 'UTF-8' if not hasattr(sys, 'setdefaultencoding'): moves.reload_module(sys) try: # pylint: disable=E1101 # On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError sys.setdefaultencoding(sickbeard.SYS_ENCODING) except: 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) # 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 except getopt.GetoptError: sys.exit(self.help_message()) for o, a in opts: # Prints help message if o in ('-h', '--help'): sys.exit(self.help_message()) # For now we'll just silence the logging if o in ('-q', '--quiet'): self.consoleLogging = False # Should we update (from indexer) all shows in the DB right away? if o in ('-f', '--forceupdate'): self.forceUpdate = 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 # Override default/configured port if o in ('-p', '--port'): try: self.forcedPort = 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 # When running as daemon disable consoleLogging and don't start browser self.consoleLogging = False self.noLaunch = True if sys.platform == 'win32': self.runAsDaemon = False # Write a pidfile if requested if o in ('--pidfile', ): self.CREATEPID = True self.PIDFILE = 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) # Specify folder to load the config file from if o in ('--config', ): sickbeard.CONFIG_FILE = os.path.abspath(a) # Specify folder to use as the data dir if o in ('--datadir', ): sickbeard.DATA_DIR = os.path.abspath(a) # Prevent resizing of the banner/posters even if PIL is installed if o in ('--noresize', ): 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 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: print( u'Not running in daemon mode. PID file creation disabled' ) self.CREATEPID = False # If they don't specify a config file then put it in the data dir if not sickbeard.CONFIG_FILE: sickbeard.CONFIG_FILE = os.path.join(sickbeard.DATA_DIR, 'config.ini') # Make sure that we can create the data dir if not os.access(sickbeard.DATA_DIR, os.F_OK): try: os.makedirs(sickbeard.DATA_DIR, 0o744) except os.error: sys.exit(u'Unable to create data directory: %s Exiting.' % sickbeard.DATA_DIR) # Make sure we can write to the data dir if not os.access(sickbeard.DATA_DIR, os.W_OK): sys.exit( u'Data directory: %s must be writable (write permissions). Exiting.' % sickbeard.DATA_DIR) # Make sure we can write to the config file if not os.access(sickbeard.CONFIG_FILE, os.W_OK): if os.path.isfile(sickbeard.CONFIG_FILE): sys.exit( u'Config file: %s must be writeable (write permissions). Exiting.' % sickbeard.CONFIG_FILE) elif not os.access(os.path.dirname(sickbeard.CONFIG_FILE), os.W_OK): sys.exit( u'Config file directory: %s must be writeable (write permissions). Exiting' % os.path.dirname(sickbeard.CONFIG_FILE)) os.chdir(sickbeard.DATA_DIR) if self.consoleLogging: print(u'Starting up SickGear from %s' % sickbeard.CONFIG_FILE) # Load the config and publish it to the sickbeard package if not os.path.isfile(sickbeard.CONFIG_FILE): print(u'Unable to find "%s", all settings will be default!' % sickbeard.CONFIG_FILE) sickbeard.CFG = ConfigObj(sickbeard.CONFIG_FILE) # check all db versions for d, min_v, max_v, mo in [ ('failed.db', sickbeard.failed_db.MIN_DB_VERSION, sickbeard.failed_db.MAX_DB_VERSION, 'FailedDb'), ('cache.db', sickbeard.cache_db.MIN_DB_VERSION, sickbeard.cache_db.MAX_DB_VERSION, 'CacheDb'), ('sickbeard.db', sickbeard.mainDB.MIN_DB_VERSION, sickbeard.mainDB.MAX_DB_VERSION, 'MainDb') ]: cur_db_version = db.DBConnection(d).checkDBVersion() if cur_db_version > 0: if cur_db_version < min_v: print( u'Your [%s] database version (%s) is too old to migrate from with this version of SickGear' % (d, cur_db_version)) sys.exit(u'Upgrade using a previous version of SG first,' + u' or start with no database file to begin fresh') if cur_db_version > max_v: print( u'Your [%s] database version (%s) has been incremented past' u' what this version of SickGear supports. Trying to rollback now. Please wait...' % (d, cur_db_version)) try: rollback_loaded = db.get_rollback_module() if None is not rollback_loaded: rollback_loaded.__dict__[mo]().run(max_v) else: print( u'ERROR: Could not download Rollback Module.') except (StandardError, Exception): pass if db.DBConnection(d).checkDBVersion() > max_v: print(u'Rollback failed.') sys.exit( u'If you have used other forks, your database may be unusable due to their changes' ) print(u'Rollback of [%s] successful.' % d) # Initialize the config and our threads sickbeard.initialize(consoleLogging=self.consoleLogging) if self.runAsDaemon: 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 else: self.startPort = sickbeard.WEB_PORT if sickbeard.WEB_LOG: self.log_dir = sickbeard.LOG_DIR else: self.log_dir = None # sickbeard.WEB_HOST is available as a configuration value in various # places but is not configurable. It is supported here for historic reasons. if sickbeard.WEB_HOST and sickbeard.WEB_HOST != '0.0.0.0': self.webhost = sickbeard.WEB_HOST else: if sickbeard.WEB_IPV6: self.webhost = '::' else: self.webhost = '0.0.0.0' # web server options self.web_options = { 'port': int(self.startPort), 'host': self.webhost, 'data_root': os.path.join(sickbeard.PROG_DIR, 'gui', sickbeard.GUI_NAME), 'web_root': sickbeard.WEB_ROOT, 'log_dir': self.log_dir, 'username': sickbeard.WEB_USERNAME, 'password': sickbeard.WEB_PASSWORD, 'enable_https': sickbeard.ENABLE_HTTPS, 'handle_reverse_proxy': sickbeard.HANDLE_REVERSE_PROXY, 'https_cert': os.path.join(sickbeard.PROG_DIR, sickbeard.HTTPS_CERT), 'https_key': os.path.join(sickbeard.PROG_DIR, sickbeard.HTTPS_KEY), } # start web server try: # used to check if existing SG instances have been started sickbeard.helpers.wait_for_free_port(self.web_options['host'], self.web_options['port']) 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, logger.ERROR) if sickbeard.LAUNCH_BROWSER and not self.runAsDaemon: logger.log(u'Launching browser and exiting', logger.ERROR) sickbeard.launch_browser(self.startPort) os._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): logger.log(u'Restore successful...') else: logger.log_error_and_exit(u'Restore FAILED!') # Build from the DB to start with self.loadShowsFromDB() # Fire up all our threads sickbeard.start() # Build internal name cache name_cache.buildNameCache() # refresh network timezones network_timezones.update_network_dict() # load all ids from xem startup_background_tasks = threading.Thread( name='FETCH-XEMDATA', target=sickbeard.scene_exceptions.get_xem_ids) startup_background_tasks.start() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() # Start an update if we're supposed to if self.forceUpdate 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) # main loop while True: time.sleep(1)
def start(self): # do some preliminary stuff sickbeard.MY_FULLNAME = os.path.normpath(os.path.abspath(__file__)) sickbeard.MY_NAME = os.path.basename(sickbeard.MY_FULLNAME) sickbeard.PROG_DIR = os.path.dirname(sickbeard.MY_FULLNAME) sickbeard.DATA_DIR = sickbeard.PROG_DIR sickbeard.MY_ARGS = sys.argv[1:] sickbeard.SYS_ENCODING = None try: locale.setlocale(locale.LC_ALL, '') except (locale.Error, IOError): pass try: sickbeard.SYS_ENCODING = locale.getpreferredencoding() except (locale.Error, IOError): pass # For OSes that are poorly configured I'll just randomly force UTF-8 if not sickbeard.SYS_ENCODING or sickbeard.SYS_ENCODING in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'): sickbeard.SYS_ENCODING = 'UTF-8' if not hasattr(sys, 'setdefaultencoding'): reload(sys) try: # pylint: disable=E1101 # On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError sys.setdefaultencoding(sickbeard.SYS_ENCODING) except: 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) # 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 except getopt.GetoptError: sys.exit(self.help_message()) for o, a in opts: # Prints help message if o in ('-h', '--help'): sys.exit(self.help_message()) # For now we'll just silence the logging if o in ('-q', '--quiet'): self.consoleLogging = False # Should we update (from indexer) all shows in the DB right away? if o in ('-f', '--forceupdate'): self.forceUpdate = 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 # Override default/configured port if o in ('-p', '--port'): try: self.forcedPort = 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 # When running as daemon disable consoleLogging and don't start browser self.consoleLogging = False self.noLaunch = True if sys.platform == 'win32': self.runAsDaemon = False # Write a pidfile if requested if o in ('--pidfile',): self.CREATEPID = True self.PIDFILE = 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) # Specify folder to load the config file from if o in ('--config',): sickbeard.CONFIG_FILE = os.path.abspath(a) # Specify folder to use as the data dir if o in ('--datadir',): sickbeard.DATA_DIR = os.path.abspath(a) # Prevent resizing of the banner/posters even if PIL is installed if o in ('--noresize',): 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 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: print u'Not running in daemon mode. PID file creation disabled' self.CREATEPID = False # If they don't specify a config file then put it in the data dir if not sickbeard.CONFIG_FILE: sickbeard.CONFIG_FILE = os.path.join(sickbeard.DATA_DIR, 'config.ini') # Make sure that we can create the data dir if not os.access(sickbeard.DATA_DIR, os.F_OK): try: os.makedirs(sickbeard.DATA_DIR, 0744) except os.error: sys.exit(u'Unable to create data directory: %s Exiting.' % sickbeard.DATA_DIR) # Make sure we can write to the data dir if not os.access(sickbeard.DATA_DIR, os.W_OK): sys.exit(u'Data directory: %s must be writable (write permissions). Exiting.' % sickbeard.DATA_DIR) # Make sure we can write to the config file if not os.access(sickbeard.CONFIG_FILE, os.W_OK): if os.path.isfile(sickbeard.CONFIG_FILE): sys.exit(u'Config file: %s must be writeable (write permissions). Exiting.' % sickbeard.CONFIG_FILE) elif not os.access(os.path.dirname(sickbeard.CONFIG_FILE), os.W_OK): sys.exit(u'Config file directory: %s must be writeable (write permissions). Exiting' % os.path.dirname(sickbeard.CONFIG_FILE)) os.chdir(sickbeard.DATA_DIR) if self.consoleLogging: print u'Starting up SickGear from %s' % sickbeard.CONFIG_FILE # Load the config and publish it to the sickbeard package if not os.path.isfile(sickbeard.CONFIG_FILE): print u'Unable to find "%s", all settings will be default!' % sickbeard.CONFIG_FILE sickbeard.CFG = ConfigObj(sickbeard.CONFIG_FILE) CUR_DB_VERSION = db.DBConnection().checkDBVersion() if CUR_DB_VERSION > 0: if CUR_DB_VERSION < MIN_DB_VERSION: print u'Your database version (%s) is too old to migrate from with this version of SickGear' \ % CUR_DB_VERSION sys.exit(u'Upgrade using a previous version of SG first, or start with no database file to begin fresh') if CUR_DB_VERSION > MAX_DB_VERSION: print u'Your database version (%s) has been incremented past what this version of SickGear supports' \ % CUR_DB_VERSION sys.exit( u'If you have used other forks of SG, your database may be unusable due to their modifications') # Initialize the config and our threads sickbeard.initialize(consoleLogging=self.consoleLogging) if self.runAsDaemon: 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 else: self.startPort = sickbeard.WEB_PORT if sickbeard.WEB_LOG: self.log_dir = sickbeard.LOG_DIR else: self.log_dir = None # sickbeard.WEB_HOST is available as a configuration value in various # places but is not configurable. It is supported here for historic reasons. if sickbeard.WEB_HOST and sickbeard.WEB_HOST != '0.0.0.0': self.webhost = sickbeard.WEB_HOST else: if sickbeard.WEB_IPV6: self.webhost = '::' else: self.webhost = '0.0.0.0' # web server options self.web_options = { 'port': int(self.startPort), 'host': self.webhost, 'data_root': os.path.join(sickbeard.PROG_DIR, 'gui', sickbeard.GUI_NAME), 'web_root': sickbeard.WEB_ROOT, 'log_dir': self.log_dir, 'username': sickbeard.WEB_USERNAME, 'password': sickbeard.WEB_PASSWORD, 'enable_https': sickbeard.ENABLE_HTTPS, 'handle_reverse_proxy': sickbeard.HANDLE_REVERSE_PROXY, 'https_cert': os.path.join(sickbeard.PROG_DIR, sickbeard.HTTPS_CERT), 'https_key': os.path.join(sickbeard.PROG_DIR, sickbeard.HTTPS_KEY), } # start web server try: # used to check if existing SG instances have been started sickbeard.helpers.wait_for_free_port(self.web_options['host'], self.web_options['port']) 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, logger.ERROR) if sickbeard.LAUNCH_BROWSER and not self.runAsDaemon: logger.log(u'Launching browser and exiting', logger.ERROR) sickbeard.launchBrowser(self.startPort) os._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): logger.log(u'Restore successful...') else: logger.log_error_and_exit(u'Restore FAILED!') # Build from the DB to start with self.loadShowsFromDB() # Fire up all our threads sickbeard.start() # Build internal name cache name_cache.buildNameCache() # refresh network timezones network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() # Start an update if we're supposed to if self.forceUpdate 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.launchBrowser(self.startPort) # main loop while True: time.sleep(1)
def run(self, force=False): # pylint: disable=unused-argument, too-many-locals, too-many-branches, too-many-statements self.amActive = True bad_indexer = [INDEXER_TVRAGE] update_datetime = datetime.datetime.now() update_date = update_datetime.date() # update_timestamp = calendar.timegm(update_datetime.timetuple()) update_timestamp = time.mktime(update_datetime.timetuple()) cache_db_con = db.DBConnection('cache.db') result = cache_db_con.select("SELECT `time` FROM lastUpdate WHERE provider = 'theTVDB'") if result: last_update = int(result[0]['time']) else: last_update = update_timestamp - 86400 cache_db_con.action("INSERT INTO lastUpdate (provider,`time`) VALUES (?, ?)", ['theTVDB', last_update]) # refresh network timezones network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() update_delta = update_timestamp - last_update if update_delta >= 691200: # 8 days ( 7 days + 1 day of buffer time) update_file = 'updates_month.xml' elif update_delta >= 90000: # 25 hours ( 1 day + 1 hour of buffer time) update_file = 'updates_week.xml' else: update_file = 'updates_day.xml' # url = 'http://thetvdb.com/api/Updates.php?type=series&time=%s' % last_update url = 'http://thetvdb.com/api/{0}/updates/{1}'.format(sickbeard.indexerApi(INDEXER_TVDB).api_params['apikey'], update_file) data = helpers.getURL(url, session=self.session, returns='text') if not data: logger.info(u'Could not get the recently updated show data from {indexer}. Retrying later. Url was: {logurl}', indexer=sickbeard.indexerApi(INDEXER_TVDB).name, logurl=url) self.amActive = False return updated_shows = [] try: tree = ET.fromstring(data) for show in tree.findall("Series"): updated_shows.append(int(show.find('id').text)) except SyntaxError: pass logger.info(u'Doing full update on all shows') pi_list = [] for cur_show in sickbeard.showList: if cur_show.indexer in bad_indexer: logger.warning(u'Indexer is no longer available for show [ {show} ] ', show=cur_show.name) else: indexer_name = sickbeard.indexerApi(cur_show.indexer).name try: if indexer_name == 'theTVDB': if cur_show.indexerid in updated_shows: # If the cur_show is not 'paused' then add to the showQueueSchedular if not cur_show.paused: pi_list.append(sickbeard.showQueueScheduler.action.updateShow(cur_show, True)) else: logger.info(u'Show update skipped, show: {show} is paused.', show=cur_show.name) else: cur_show.next_episode() if cur_show.should_update(update_date=update_date): try: pi_list.append(sickbeard.showQueueScheduler.action.updateShow(cur_show, True)) except CantUpdateShowException as e: logger.debug(u'Unable to update show: {error}', error=e) else: logger.debug( u'Not updating episodes for show {show} because the last or next episode is not within the grace period.', show = cur_show.name) except (CantUpdateShowException, CantRefreshShowException) as e: logger.error(u'Automatic update failed: {0}', error=e) ui.ProgressIndicators.setIndicator('dailyUpdate', ui.QueueProgressIndicator("Daily Update", pi_list)) cache_db_con.action("UPDATE lastUpdate SET `time` = ? WHERE provider=?", [update_timestamp, 'theTVDB']) logger.info(u'Completed full update on all shows') self.amActive = False
def start(self): """ Start SickChill """ # do some preliminary stuff sickbeard.MY_FULLNAME = ek(os.path.normpath, ek(os.path.abspath, __file__)) sickbeard.MY_NAME = ek(os.path.basename, sickbeard.MY_FULLNAME) sickbeard.PROG_DIR = ek(os.path.dirname, sickbeard.MY_FULLNAME) sickbeard.LOCALE_DIR = ek(os.path.join, sickbeard.PROG_DIR, 'locale') sickbeard.DATA_DIR = sickbeard.PROG_DIR sickbeard.MY_ARGS = sys.argv[1:] try: locale.setlocale(locale.LC_ALL, '') sickbeard.SYS_ENCODING = locale.getpreferredencoding() except (locale.Error, IOError): sickbeard.SYS_ENCODING = 'UTF-8' if not sickbeard.SYS_ENCODING or sickbeard.SYS_ENCODING.lower() in ('ansi_x3.4-1968', 'us-ascii', 'ascii', 'charmap') or \ (sys.platform.startswith('win') and sys.getwindowsversion()[0] >= 6 and str(getattr(sys.stdout, 'device', sys.stdout).encoding).lower() in ('cp65001', 'charmap')): sickbeard.SYS_ENCODING = 'UTF-8' # TODO: Continue working on making this unnecessary, this hack creates all sorts of hellish problems if not hasattr(sys, 'setdefaultencoding'): reload_module(sys) try: # On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError sys.setdefaultencoding(sickbeard.SYS_ENCODING) except (AttributeError, LookupError): sys.exit( 'Sorry, you MUST add the SickChill folder to the PYTHONPATH environment variable\n' 'or find another way to force Python to use {} for string encoding.' .format(sickbeard.SYS_ENCODING)) # Rename the main thread threading.currentThread().name = 'MAIN' args = SickChillArgumentParser(sickbeard.PROG_DIR).parse_args() if args.force_update: result = self.force_update() sys.exit(int(not result)) # Ok -> 0 , Error -> 1 # Need console logging for SickBeard.py and SickBeard-console.exe sickbeard.NO_RESIZE = args.noresize self.console_logging = (not hasattr(sys, 'frozen')) or ( sickbeard.MY_NAME.lower().find('-console') > 0) and not args.quiet self.no_launch = args.nolaunch self.forced_port = args.port if args.daemon: self.run_as_daemon = platform.system() != 'Windows' self.console_logging = False self.no_launch = True self.create_pid = bool(args.pidfile) self.pid_file = args.pidfile if self.pid_file and ek(os.path.exists, self.pid_file): # If the pid file already exists, SickChill may still be running, so exit raise SystemExit('PID file: {0} already exists. Exiting.'.format( self.pid_file)) sickbeard.DATA_DIR = ek( os.path.abspath, args.datadir) if args.datadir else sickbeard.DATA_DIR sickbeard.CONFIG_FILE = ek( os.path.abspath, args.config) if args.config else ek( os.path.join, sickbeard.DATA_DIR, 'config.ini') # The pid file is only useful in daemon mode, make sure we can write the file properly if self.create_pid: if self.run_as_daemon: pid_dir = ek(os.path.dirname, self.pid_file) if not ek(os.access, pid_dir, os.F_OK): sys.exit('PID dir: {0} doesn\'t exist. Exiting.'.format( pid_dir)) if not ek(os.access, pid_dir, os.W_OK): raise SystemExit( 'PID dir: {0} must be writable (write permissions). Exiting.' .format(pid_dir)) else: if self.console_logging: sys.stdout.write( 'Not running in daemon mode. PID file creation disabled.\n' ) self.create_pid = False # Make sure that we can create the data dir if not ek(os.access, sickbeard.DATA_DIR, os.F_OK): try: ek(os.makedirs, sickbeard.DATA_DIR, 0o744) except os.error: raise SystemExit('Unable to create data directory: {0}'.format( sickbeard.DATA_DIR)) # Make sure we can write to the data dir if not ek(os.access, sickbeard.DATA_DIR, os.W_OK): raise SystemExit('Data directory must be writeable: {0}'.format( sickbeard.DATA_DIR)) # Make sure we can write to the config file if not ek(os.access, sickbeard.CONFIG_FILE, os.W_OK): if ek(os.path.isfile, sickbeard.CONFIG_FILE): raise SystemExit('Config file must be writeable: {0}'.format( sickbeard.CONFIG_FILE)) elif not ek(os.access, ek(os.path.dirname, sickbeard.CONFIG_FILE), os.W_OK): raise SystemExit( 'Config file root dir must be writeable: {0}'.format( ek(os.path.dirname, sickbeard.CONFIG_FILE))) ek(os.chdir, sickbeard.DATA_DIR) # Check if we need to perform a restore first restore_dir = ek(os.path.join, sickbeard.DATA_DIR, 'restore') if ek(os.path.exists, restore_dir): success = self.restore_db(restore_dir, sickbeard.DATA_DIR) if self.console_logging: sys.stdout.write( 'Restore: restoring DB and config.ini {0}!\n'.format( ('FAILED', 'SUCCESSFUL')[success])) # Load the config and publish it to the sickbeard package if self.console_logging and not ek(os.path.isfile, sickbeard.CONFIG_FILE): sys.stdout.write( 'Unable to find {0}, all settings will be default!\n'.format( sickbeard.CONFIG_FILE)) sickbeard.CFG = ConfigObj(sickbeard.CONFIG_FILE, encoding='UTF-8', options={'indent_type': ' '}) # Initialize the config and our threads sickbeard.initialize(consoleLogging=self.console_logging) if self.run_as_daemon: self.daemonize() # Get PID sickbeard.PID = os.getpid() # Build from the DB to start with self.load_shows_from_db() logger.log('Starting SickChill [{branch}] using \'{config}\''.format( branch=sickbeard.BRANCH, config=sickbeard.CONFIG_FILE)) self.clear_cache() if self.forced_port: logger.log('Forcing web server to port {port}'.format( port=self.forced_port)) self.start_port = self.forced_port else: self.start_port = sickbeard.WEB_PORT if sickbeard.WEB_LOG: self.log_dir = sickbeard.LOG_DIR else: self.log_dir = None # sickbeard.WEB_HOST is available as a configuration value in various # places but is not configurable. It is supported here for historic reasons. if sickbeard.WEB_HOST and sickbeard.WEB_HOST != '0.0.0.0': self.web_host = sickbeard.WEB_HOST else: self.web_host = '' if sickbeard.WEB_IPV6 else '0.0.0.0' # web server options self.web_options = { 'port': int(self.start_port), 'host': self.web_host, 'data_root': ek(os.path.join, sickbeard.PROG_DIR, 'gui', sickbeard.GUI_NAME), 'web_root': sickbeard.WEB_ROOT, 'log_dir': self.log_dir, 'username': sickbeard.WEB_USERNAME, 'password': sickbeard.WEB_PASSWORD, 'enable_https': sickbeard.ENABLE_HTTPS, 'handle_reverse_proxy': sickbeard.HANDLE_REVERSE_PROXY, 'https_cert': ek(os.path.join, sickbeard.PROG_DIR, sickbeard.HTTPS_CERT), 'https_key': ek(os.path.join, sickbeard.PROG_DIR, sickbeard.HTTPS_KEY), } # start web server self.web_server = SRWebServer(self.web_options) self.web_server.start() # Fire up all our threads sickbeard.start() # Build internal name cache name_cache.buildNameCache() # Pre-populate network timezones, it isn't thread safe network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() # Check for metadata indexer updates for shows (sets the next aired ep!) # sickbeard.showUpdateScheduler.forceRun() # Launch browser if sickbeard.LAUNCH_BROWSER and not (self.no_launch or self.run_as_daemon): sickbeard.launchBrowser( 'https' if sickbeard.ENABLE_HTTPS else 'http', self.start_port, sickbeard.WEB_ROOT) # main loop while True: time.sleep(1)
def run(self, force=False): self.amActive = True try: update_datetime = datetime.datetime.now() update_date = update_datetime.date() # refresh network timezones network_timezones.update_network_dict() # update xem id lists sickbeard.scene_exceptions.get_xem_ids() # update scene exceptions sickbeard.scene_exceptions.retrieve_exceptions() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() # clear the data of unused providers sickbeard.helpers.clear_unused_providers() logger.log(u'Doing full update on all shows') # clean out cache directory, remove everything > 12 hours old sickbeard.helpers.clearCache() # select 10 'Ended' tv_shows updated more than 90 days ago and all shows not updated more then 180 days ago to include in this update stale_should_update = [] stale_update_date = (update_date - datetime.timedelta(days=90)).toordinal() stale_update_date_max = (update_date - datetime.timedelta(days=180)).toordinal() # last_update_date <= 90 days, sorted ASC because dates are ordinal myDB = db.DBConnection() sql_results = myDB.mass_action([[ 'SELECT indexer_id FROM tv_shows WHERE last_update_indexer <= ? AND last_update_indexer >= ? ORDER BY last_update_indexer ASC LIMIT 10;', [stale_update_date, stale_update_date_max]], ['SELECT indexer_id FROM tv_shows WHERE last_update_indexer < ?;', [stale_update_date_max]]]) for sql_result in sql_results: for cur_result in sql_result: stale_should_update.append(int(cur_result['indexer_id'])) # start update process piList = [] for curShow in sickbeard.showList: try: # get next episode airdate curShow.nextEpisode() # if should_update returns True (not 'Ended') or show is selected stale 'Ended' then update, otherwise just refresh if curShow.should_update(update_date=update_date) or curShow.indexerid in stale_should_update: curQueueItem = sickbeard.showQueueScheduler.action.updateShow(curShow, scheduled_update=True) # @UndefinedVariable else: logger.log( u'Not updating episodes for show ' + curShow.name + ' because it\'s marked as ended and last/next episode is not within the grace period.', logger.DEBUG) curQueueItem = sickbeard.showQueueScheduler.action.refreshShow(curShow, True, True) # @UndefinedVariable piList.append(curQueueItem) except (exceptions.CantUpdateException, exceptions.CantRefreshException) as e: logger.log(u'Automatic update failed: ' + ex(e), logger.ERROR) ui.ProgressIndicators.setIndicator('dailyUpdate', ui.QueueProgressIndicator('Daily Update', piList)) logger.log(u'Added all shows to show queue for full update') finally: self.amActive = False
def run(self, force=False): # pylint: disable=unused-argument, too-many-locals, too-many-branches, too-many-statements self.amActive = True bad_indexer = [INDEXER_TVRAGE] update_datetime = datetime.datetime.now() update_date = update_datetime.date() # update_timestamp = calendar.timegm(update_datetime.timetuple()) update_timestamp = time.mktime(update_datetime.timetuple()) my_db = db.DBConnection('cache.db') result = my_db.select("SELECT `time` FROM lastUpdate WHERE provider = 'theTVDB'") if result: last_update = int(result[0]['time']) else: last_update = update_timestamp - 86400 my_db.action("INSERT INTO lastUpdate (provider,`time`) VALUES (?, ?)", ['theTVDB', last_update]) # refresh network timezones network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() update_delta = update_timestamp - last_update if update_delta >= 691200: # 8 days ( 7 days + 1 day of buffer time) update_file = 'updates_month.xml' elif update_delta >= 90000: # 25 hours ( 1 day + 1 hour of buffer time) update_file = 'updates_week.xml' else: update_file = 'updates_day.xml' # url = 'http://thetvdb.com/api/Updates.php?type=series&time=%s' % last_update url = 'http://thetvdb.com/api/%s/updates/%s' % (sickbeard.indexerApi(INDEXER_TVDB).api_params['apikey'], update_file) data = helpers.getURL(url, session=self.session) if not data: logger.log(u"Could not get the recently updated show data from %s. Retrying later. Url was: %s" % (sickbeard.indexerApi(INDEXER_TVDB).name, url)) self.amActive = False return updated_shows = [] try: tree = ET.fromstring(data) for show in tree.findall("Series"): updated_shows.append(int(show.find('id').text)) except SyntaxError: pass logger.log(u"Doing full update on all shows") pi_list = [] for cur_show in sickbeard.showList: if cur_show.indexer in bad_indexer: logger.log(u"Indexer is no longer available for show [ %s ] " % cur_show.name, logger.WARNING) else: indexer_name = sickbeard.indexerApi(cur_show.indexer).name try: if indexer_name == 'theTVDB': if cur_show.indexerid in updated_shows: pi_list.append(sickbeard.showQueueScheduler.action.updateShow(cur_show, True)) # else: # pi_list.append(sickbeard.showQueueScheduler.action.refreshShow(cur_show, True)) else: cur_show.nextEpisode() if cur_show.should_update(update_date=update_date): try: pi_list.append(sickbeard.showQueueScheduler.action.updateShow(cur_show, True)) except CantUpdateShowException as e: logger.log(u"Unable to update show: {0}".format(str(e)), logger.DEBUG) else: logger.log( u"Not updating episodes for show " + cur_show.name + " because it's last/next episode is not within the grace period.", logger.DEBUG) # pi_list.append(sickbeard.showQueueScheduler.action.refreshShow(cur_show, True)) except (CantUpdateShowException, CantRefreshShowException) as e: logger.log(u"Automatic update failed: " + ex(e), logger.ERROR) ui.ProgressIndicators.setIndicator('dailyUpdate', ui.QueueProgressIndicator("Daily Update", pi_list)) my_db.action("UPDATE lastUpdate SET `time` = ? WHERE provider=?", [update_timestamp, 'theTVDB']) logger.log(u"Completed full update on all shows") self.amActive = False
def start(self): # Rename the main thread threading.currentThread().name = "MAIN" # initalize encoding defaults encodingInit() # do some preliminary stuff sickbeard.MY_FULLNAME = ek(os.path.normpath, ek(os.path.abspath, __file__)) sickbeard.MY_NAME = ek(os.path.basename, sickbeard.MY_FULLNAME) sickbeard.PROG_DIR = ek(os.path.dirname, sickbeard.MY_FULLNAME) sickbeard.DATA_DIR = sickbeard.PROG_DIR sickbeard.MY_ARGS = sys.argv[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) # Do this before importing sickbeard, to prevent locked files and incorrect import oldtornado = ek(os.path.abspath, ek(os.path.join, ek(os.path.dirname, __file__), 'tornado')) if ek(os.path.isdir, oldtornado): ek(shutil.move, oldtornado, oldtornado + '_kill') ek(removetree, oldtornado + '_kill') try: opts, _ = getopt.getopt( sys.argv[1:], "hqdp::", ['help', 'quiet', 'nolaunch', 'daemon', 'pidfile=', 'port=', 'datadir=', 'config=', 'noresize'] ) except getopt.GetoptError: sys.exit(self.help_message()) for o, a in opts: # Prints help message if o in ('-h', '--help'): sys.exit(self.help_message()) # For now we'll just silence the logging if o in ('-q', '--quiet'): self.consoleLogging = False # 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 # Override default/configured port if o in ('-p', '--port'): try: self.forcedPort = int(a) except ValueError: sys.exit("Port: " + str(a) + " is not a number. Exiting.") # Run as a double forked daemon if o in ('-d', '--daemon'): self.runAsDaemon = True # When running as daemon disable consoleLogging and don't start browser self.consoleLogging = False self.noLaunch = True if sys.platform == 'win32' or sys.platform == 'darwin': self.runAsDaemon = False # Write a pidfile if requested if o in ('--pidfile',): self.CREATEPID = True self.PIDFILE = str(a) # If the pidfile already exists, sickbeard may still be running, so exit if ek(os.path.exists, self.PIDFILE): sys.exit("PID file: " + self.PIDFILE + " already exists. Exiting.") # Specify folder to load the config file from if o in ('--config',): sickbeard.CONFIG_FILE = ek(os.path.abspath, a) # Specify folder to use as the data dir if o in ('--datadir',): sickbeard.DATA_DIR = ek(os.path.abspath, a) # Prevent resizing of the banner/posters even if PIL is installed if o in ('--noresize',): 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 = ek(os.path.dirname, self.PIDFILE) if not ek(os.access, pid_dir, os.F_OK): sys.exit("PID dir: " + pid_dir + " doesn't exist. Exiting.") if not ek(os.access, pid_dir, os.W_OK): sys.exit("PID dir: " + pid_dir + " must be writable (write permissions). Exiting.") else: if self.consoleLogging: sys.stdout.write("Not running in daemon mode. PID file creation disabled.\n") self.CREATEPID = False # If they don't specify a config file then put it in the data dir if not sickbeard.CONFIG_FILE: sickbeard.CONFIG_FILE = ek(os.path.join, sickbeard.DATA_DIR, "config.ini") # Make sure that we can create the data dir result = ek(os.access, sickbeard.DATA_DIR, os.F_OK) if not ek(os.access, sickbeard.DATA_DIR, os.F_OK): try: ek(os.makedirs, sickbeard.DATA_DIR, 0o744) except os.error as e: raise SystemExit("Unable to create datadir '" + sickbeard.DATA_DIR + "'") # Make sure we can write to the data dir if not ek(os.access, sickbeard.DATA_DIR, os.W_OK): raise SystemExit("Datadir must be writeable '" + sickbeard.DATA_DIR + "'") # Make sure we can write to the config file if not ek(os.access, sickbeard.CONFIG_FILE, os.W_OK): if ek(os.path.isfile, sickbeard.CONFIG_FILE): raise SystemExit("Config file '" + sickbeard.CONFIG_FILE + "' must be writeable.") elif not ek(os.access, ek(os.path.dirname, sickbeard.CONFIG_FILE), os.W_OK): raise SystemExit( "Config file root dir '" + ek(os.path.dirname, sickbeard.CONFIG_FILE) + "' must be writeable.") ek(os.chdir, sickbeard.DATA_DIR) # Check if we need to perform a restore first restoreDir = ek(os.path.join, sickbeard.DATA_DIR, 'restore') if ek(os.path.exists, restoreDir): success = self.restoreDB(restoreDir, sickbeard.DATA_DIR) if self.consoleLogging: sys.stdout.write("Restore: restoring DB and config.ini %s!\n" % ("FAILED", "SUCCESSFUL")[success]) # Load the config and publish it to the sickbeard package if self.consoleLogging and not ek(os.path.isfile, sickbeard.CONFIG_FILE): sys.stdout.write("Unable to find '" + sickbeard.CONFIG_FILE + "' , all settings will be default!" + "\n") sickbeard.CFG = ConfigObj(sickbeard.CONFIG_FILE) # Initialize the config and our threads sickbeard.initialize(consoleLogging=self.consoleLogging) if self.runAsDaemon: sickbeard.DAEMONIZE = True self.daemonize() # Get PID sickbeard.PID = os.getpid() # Build from the DB to start with self.loadShowsFromDB() if self.forcedPort: logging.info("Forcing web server to port " + str(self.forcedPort)) self.startPort = self.forcedPort else: self.startPort = sickbeard.WEB_PORT if sickbeard.WEB_LOG: self.log_dir = sickbeard.LOG_DIR else: self.log_dir = None # sickbeard.WEB_HOST is available as a configuration value in various # places but is not configurable. It is supported here for historic reasons. if sickbeard.WEB_HOST and sickbeard.WEB_HOST != '0.0.0.0': self.webhost = sickbeard.WEB_HOST else: if sickbeard.WEB_IPV6: self.webhost = '::' else: self.webhost = '0.0.0.0' # Clean up after update if sickbeard.GIT_NEWVER: toclean = ek(os.path.join, sickbeard.CACHE_DIR, 'mako') for root, dirs, files in ek(os.walk, toclean, topdown=False): for name in files: ek(os.remove, ek(os.path.join, root, name)) for name in dirs: ek(os.rmdir, ek(os.path.join, root, name)) sickbeard.GIT_NEWVER = False # Fire up all our threads logging.info("Starting SiCKRAGE:[{}] CONFIG:[{}]".format(sickbeard.BRANCH, sickbeard.CONFIG_FILE)) sickbeard.start() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() # Check for metadata indexer updates for shows (Disabled until we use api) # sickbeard.showUpdateScheduler.forceRun() # start tornado web server sickbeard.WEB_SERVER = SRWebServer({ 'port': int(self.startPort), 'host': self.webhost, 'gui_root': sickbeard.GUI_DIR, 'web_root': sickbeard.WEB_ROOT, 'log_dir': self.log_dir, 'username': sickbeard.WEB_USERNAME, 'password': sickbeard.WEB_PASSWORD, 'enable_https': sickbeard.ENABLE_HTTPS, 'handle_reverse_proxy': sickbeard.HANDLE_REVERSE_PROXY, 'https_cert': ek(os.path.join, sickbeard.PROG_DIR, sickbeard.HTTPS_CERT), 'https_key': ek(os.path.join, sickbeard.PROG_DIR, sickbeard.HTTPS_KEY), }).start()
def run(self, force=False): self.amActive = True try: update_datetime = datetime.datetime.now() update_date = update_datetime.date() # refresh network timezones network_timezones.update_network_dict() # update xem id lists sickbeard.scene_exceptions.get_xem_ids() # update scene exceptions sickbeard.scene_exceptions.retrieve_exceptions() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() # clear the data of unused providers sickbeard.helpers.clear_unused_providers() logger.log(u'Doing full update on all shows') # clean out cache directory, remove everything > 12 hours old sickbeard.helpers.clearCache() # select 10 'Ended' tv_shows updated more than 90 days ago and all shows not updated more then 180 days ago to include in this update stale_should_update = [] stale_update_date = (update_date - datetime.timedelta(days=90)).toordinal() stale_update_date_max = (update_date - datetime.timedelta(days=180)).toordinal() # last_update_date <= 90 days, sorted ASC because dates are ordinal myDB = db.DBConnection() sql_results = myDB.mass_action([ [ 'SELECT indexer_id FROM tv_shows WHERE last_update_indexer <= ? AND last_update_indexer >= ? ORDER BY last_update_indexer ASC LIMIT 10;', [stale_update_date, stale_update_date_max] ], [ 'SELECT indexer_id FROM tv_shows WHERE last_update_indexer < ?;', [stale_update_date_max] ] ]) for sql_result in sql_results: for cur_result in sql_result: stale_should_update.append(int(cur_result['indexer_id'])) # start update process piList = [] for curShow in sickbeard.showList: try: # get next episode airdate curShow.nextEpisode() # if should_update returns True (not 'Ended') or show is selected stale 'Ended' then update, otherwise just refresh if curShow.should_update( update_date=update_date ) or curShow.indexerid in stale_should_update: curQueueItem = sickbeard.showQueueScheduler.action.updateShow( curShow, scheduled_update=True) # @UndefinedVariable else: logger.log( u'Not updating episodes for show ' + curShow.name + ' because it\'s marked as ended and last/next episode is not within the grace period.', logger.DEBUG) curQueueItem = sickbeard.showQueueScheduler.action.refreshShow( curShow, True, True) # @UndefinedVariable piList.append(curQueueItem) except (exceptions.CantUpdateException, exceptions.CantRefreshException) as e: logger.log(u'Automatic update failed: ' + ex(e), logger.ERROR) ui.ProgressIndicators.setIndicator( 'dailyUpdate', ui.QueueProgressIndicator('Daily Update', piList)) logger.log(u'Added all shows to show queue for full update') finally: self.amActive = False
def start(self): # pylint: disable=too-many-branches,too-many-statements """ Start SickRage """ # do some preliminary stuff sickbeard.MY_FULLNAME = ek(os.path.normpath, ek(os.path.abspath, __file__)) sickbeard.MY_NAME = ek(os.path.basename, sickbeard.MY_FULLNAME) sickbeard.PROG_DIR = ek(os.path.dirname, sickbeard.MY_FULLNAME) sickbeard.DATA_DIR = sickbeard.PROG_DIR sickbeard.MY_ARGS = sys.argv[1:] try: locale.setlocale(locale.LC_ALL, '') sickbeard.SYS_ENCODING = locale.getpreferredencoding() except (locale.Error, IOError): sickbeard.SYS_ENCODING = 'UTF-8' # pylint: disable=no-member if not sickbeard.SYS_ENCODING or sickbeard.SYS_ENCODING.lower() in ('ansi_x3.4-1968', 'us-ascii', 'ascii', 'charmap') or \ (sys.platform.startswith('win') and sys.getwindowsversion()[0] >= 6 and str(getattr(sys.stdout, 'device', sys.stdout).encoding).lower() in ('cp65001', 'charmap')): sickbeard.SYS_ENCODING = 'UTF-8' # TODO: Continue working on making this unnecessary, this hack creates all sorts of hellish problems if not hasattr(sys, 'setdefaultencoding'): reload(sys) try: # On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError sys.setdefaultencoding(sickbeard.SYS_ENCODING) # pylint: disable=no-member except (AttributeError, LookupError): sys.exit( 'Sorry, you MUST add the SickRage folder to the PYTHONPATH environment variable\n' 'or find another way to force Python to use %s for string encoding.' % sickbeard.SYS_ENCODING) # Need console logging for SickBeard.py and SickBeard-console.exe 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, _ = getopt.getopt(sys.argv[1:], 'hqdp::', [ 'help', 'quiet', 'nolaunch', 'daemon', 'pidfile=', 'port=', 'datadir=', 'config=', 'noresize' ]) except getopt.GetoptError: sys.exit(self.help_message()) for option, value in opts: # Prints help message if option in ('-h', '--help'): sys.exit(self.help_message()) # For now we'll just silence the logging if option in ('-q', '--quiet'): self.console_logging = False # Suppress launching web browser # Needed for OSes without default browser assigned # Prevent duplicate browser window when restarting in the app if option in ('--nolaunch', ): self.no_launch = True # Override default/configured port if option in ('-p', '--port'): try: self.forced_port = int(value) except ValueError: sys.exit( 'Port: {0} is not a number. Exiting.'.format(value)) # Run as a double forked daemon if option in ('-d', '--daemon'): self.run_as_daemon = True # When running as daemon disable console_logging and don't start browser self.console_logging = False self.no_launch = True if sys.platform == 'win32' or sys.platform == 'darwin': self.run_as_daemon = False # Write a pid file if requested if option in ('--pidfile', ): self.create_pid = True self.pid_file = str(value) # If the pid file already exists, SickRage may still be running, so exit if ek(os.path.exists, self.pid_file): sys.exit('PID file: {0} already exists. Exiting.'.format( self.pid_file)) # Specify folder to load the config file from if option in ('--config', ): sickbeard.CONFIG_FILE = ek(os.path.abspath, value) # Specify folder to use as the data directory if option in ('--datadir', ): sickbeard.DATA_DIR = ek(os.path.abspath, value) # Prevent resizing of the banner/posters even if PIL is installed if option in ('--noresize', ): sickbeard.NO_RESIZE = True # The pid file is only useful in daemon mode, make sure we can write the file properly if self.create_pid: if self.run_as_daemon: pid_dir = ek(os.path.dirname, self.pid_file) if not ek(os.access, pid_dir, os.F_OK): sys.exit('PID dir: {0} doesn\'t exist. Exiting.'.format( pid_dir)) if not ek(os.access, pid_dir, os.W_OK): sys.exit( 'PID dir: {0} must be writable (write permissions). Exiting.' .format(pid_dir)) else: if self.console_logging: sys.stdout.write( 'Not running in daemon mode. PID file creation disabled.\n' ) self.create_pid = False # If they don't specify a config file then put it in the data dir if not sickbeard.CONFIG_FILE: sickbeard.CONFIG_FILE = ek(os.path.join, sickbeard.DATA_DIR, 'config.ini') # Make sure that we can create the data dir if not ek(os.access, sickbeard.DATA_DIR, os.F_OK): try: ek(os.makedirs, sickbeard.DATA_DIR, 0o744) except os.error: raise SystemExit('Unable to create data directory: {0}'.format( sickbeard.DATA_DIR)) # Make sure we can write to the data dir if not ek(os.access, sickbeard.DATA_DIR, os.W_OK): raise SystemExit('Data directory must be writeable: {0}'.format( sickbeard.DATA_DIR)) # Make sure we can write to the config file if not ek(os.access, sickbeard.CONFIG_FILE, os.W_OK): if ek(os.path.isfile, sickbeard.CONFIG_FILE): raise SystemExit('Config file must be writeable: {0}'.format( sickbeard.CONFIG_FILE)) elif not ek(os.access, ek(os.path.dirname, sickbeard.CONFIG_FILE), os.W_OK): raise SystemExit( 'Config file root dir must be writeable: {0}'.format( ek(os.path.dirname, sickbeard.CONFIG_FILE))) ek(os.chdir, sickbeard.DATA_DIR) # Check if we need to perform a restore first restore_dir = ek(os.path.join, sickbeard.DATA_DIR, 'restore') if ek(os.path.exists, restore_dir): success = self.restore_db(restore_dir, sickbeard.DATA_DIR) if self.console_logging: sys.stdout.write( 'Restore: restoring DB and config.ini {0}!\n'.format( ('FAILED', 'SUCCESSFUL')[success])) # Load the config and publish it to the sickbeard package if self.console_logging and not ek(os.path.isfile, sickbeard.CONFIG_FILE): sys.stdout.write( 'Unable to find {0}, all settings will be default!\n'.format( sickbeard.CONFIG_FILE)) sickbeard.CFG = ConfigObj(sickbeard.CONFIG_FILE) # Initialize the config and our threads sickbeard.initialize(consoleLogging=self.console_logging) if self.run_as_daemon: self.daemonize() # Get PID sickbeard.PID = os.getpid() # Build from the DB to start with self.load_shows_from_db() logger.log('Starting SickRage [{branch}] using \'{config}\''.format( branch=sickbeard.BRANCH, config=sickbeard.CONFIG_FILE)) self.clear_cache() if self.forced_port: logger.log('Forcing web server to port {port}'.format( port=self.forced_port)) self.start_port = self.forced_port else: self.start_port = sickbeard.WEB_PORT if sickbeard.WEB_LOG: self.log_dir = sickbeard.LOG_DIR else: self.log_dir = None # sickbeard.WEB_HOST is available as a configuration value in various # places but is not configurable. It is supported here for historic reasons. if sickbeard.WEB_HOST and sickbeard.WEB_HOST != '0.0.0.0': self.web_host = sickbeard.WEB_HOST else: self.web_host = '' if sickbeard.WEB_IPV6 else '0.0.0.0' # web server options self.web_options = { 'port': int(self.start_port), 'host': self.web_host, 'data_root': ek(os.path.join, sickbeard.PROG_DIR, 'gui', sickbeard.GUI_NAME), 'web_root': sickbeard.WEB_ROOT, 'log_dir': self.log_dir, 'username': sickbeard.WEB_USERNAME, 'password': sickbeard.WEB_PASSWORD, 'enable_https': sickbeard.ENABLE_HTTPS, 'handle_reverse_proxy': sickbeard.HANDLE_REVERSE_PROXY, 'https_cert': ek(os.path.join, sickbeard.PROG_DIR, sickbeard.HTTPS_CERT), 'https_key': ek(os.path.join, sickbeard.PROG_DIR, sickbeard.HTTPS_KEY), } # start web server self.web_server = SRWebServer(self.web_options) self.web_server.start() # Fire up all our threads sickbeard.start() # Build internal name cache name_cache.buildNameCache() # Pre-populate network timezones, it isn't thread safe network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() # Check for metadata indexer updates for shows (sets the next aired ep!) # sickbeard.showUpdateScheduler.forceRun() # Launch browser if sickbeard.LAUNCH_BROWSER and not (self.no_launch or self.run_as_daemon): sickbeard.launchBrowser( 'https' if sickbeard.ENABLE_HTTPS else 'http', self.start_port, sickbeard.WEB_ROOT) # main loop while True: time.sleep(1)
def start(self): # do some preliminary stuff sickbeard.MY_FULLNAME = os.path.normpath(os.path.abspath(__file__)) sickbeard.MY_NAME = os.path.basename(sickbeard.MY_FULLNAME) sickbeard.PROG_DIR = os.path.dirname(sickbeard.MY_FULLNAME) sickbeard.DATA_DIR = sickbeard.PROG_DIR sickbeard.MY_ARGS = sys.argv[1:] try: locale.setlocale(locale.LC_ALL, "") sickbeard.SYS_ENCODING = locale.getpreferredencoding() except (locale.Error, IOError): sickbeard.SYS_ENCODING = 'UTF-8' # pylint: disable=E1101 if not sickbeard.SYS_ENCODING or sickbeard.SYS_ENCODING.lower() in ('ansi_x3.4-1968', 'us-ascii', 'ascii', 'charmap') or \ (sys.platform.startswith('win') and sys.getwindowsversion()[0] >= 6 and str(getattr(sys.stdout, 'device', sys.stdout).encoding).lower() in ('cp65001', 'charmap')): sickbeard.SYS_ENCODING = 'UTF-8' # TODO: Continue working on making this unnecessary, this hack creates all sorts of hellish problems if not hasattr(sys, "setdefaultencoding"): reload(sys) try: # pylint: disable=E1101 # On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError sys.setdefaultencoding(sickbeard.SYS_ENCODING) except Exception: sys.exit( "Sorry, you MUST add the SickRage folder to the PYTHONPATH environment variable\n" + "or find another way to force Python to use " + sickbeard.SYS_ENCODING + " for string encoding.") # Need console logging for SickBeard.py and SickBeard-console.exe self.consoleLogging = (not hasattr( sys, "frozen")) or (sickbeard.MY_NAME.lower().find('-console') > 0) # Rename the main thread threading.currentThread().name = u"MAIN" try: opts, _ = getopt.getopt(sys.argv[1:], "hqdp::", [ 'help', 'quiet', 'nolaunch', 'daemon', 'pidfile=', 'port=', 'datadir=', 'config=', 'noresize' ]) except getopt.GetoptError: sys.exit(self.help_message()) for o, a in opts: # Prints help message if o in ('-h', '--help'): sys.exit(self.help_message()) # For now we'll just silence the logging if o in ('-q', '--quiet'): self.consoleLogging = False # 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 # Override default/configured port if o in ('-p', '--port'): try: self.forcedPort = int(a) except ValueError: sys.exit("Port: " + str(a) + " is not a number. Exiting.") # Run as a double forked daemon if o in ('-d', '--daemon'): self.runAsDaemon = True # When running as daemon disable consoleLogging and don't start browser self.consoleLogging = False self.noLaunch = True if sys.platform == 'win32' or sys.platform == 'darwin': self.runAsDaemon = False # Write a pidfile if requested if o in ('--pidfile', ): self.CREATEPID = True self.PIDFILE = str(a) # If the pidfile already exists, sickbeard may still be running, so exit if os.path.exists(self.PIDFILE): sys.exit("PID file: " + self.PIDFILE + " already exists. Exiting.") # Specify folder to load the config file from if o in ('--config', ): sickbeard.CONFIG_FILE = os.path.abspath(a) # Specify folder to use as the data dir if o in ('--datadir', ): sickbeard.DATA_DIR = os.path.abspath(a) # Prevent resizing of the banner/posters even if PIL is installed if o in ('--noresize', ): 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 not os.access(pid_dir, os.F_OK): sys.exit("PID dir: " + pid_dir + " doesn't exist. Exiting.") if not os.access(pid_dir, os.W_OK): sys.exit("PID dir: " + pid_dir + " must be writable (write permissions). Exiting.") else: if self.consoleLogging: sys.stdout.write( u"Not running in daemon mode. PID file creation disabled.\n" ) self.CREATEPID = False # If they don't specify a config file then put it in the data dir if not sickbeard.CONFIG_FILE: sickbeard.CONFIG_FILE = os.path.join(sickbeard.DATA_DIR, "config.ini") # Make sure that we can create the data dir if not os.access(sickbeard.DATA_DIR, os.F_OK): try: os.makedirs(sickbeard.DATA_DIR, 0744) except os.error: raise SystemExit("Unable to create datadir '" + sickbeard.DATA_DIR + "'") # Make sure we can write to the data dir if not os.access(sickbeard.DATA_DIR, os.W_OK): raise SystemExit("Datadir must be writeable '" + sickbeard.DATA_DIR + "'") # Make sure we can write to the config file if not os.access(sickbeard.CONFIG_FILE, os.W_OK): if os.path.isfile(sickbeard.CONFIG_FILE): raise SystemExit("Config file '" + sickbeard.CONFIG_FILE + "' must be writeable.") elif not os.access(os.path.dirname(sickbeard.CONFIG_FILE), os.W_OK): raise SystemExit("Config file root dir '" + os.path.dirname(sickbeard.CONFIG_FILE) + "' must be writeable.") os.chdir(sickbeard.DATA_DIR) # Check if we need to perform a restore first restoreDir = os.path.join(sickbeard.DATA_DIR, 'restore') if os.path.exists(restoreDir): success = self.restoreDB(restoreDir, sickbeard.DATA_DIR) if self.consoleLogging: sys.stdout.write( u"Restore: restoring DB and config.ini %s!\n" % ("FAILED", "SUCCESSFUL")[success]) # Load the config and publish it to the sickbeard package if self.consoleLogging and not os.path.isfile(sickbeard.CONFIG_FILE): sys.stdout.write(u"Unable to find '" + sickbeard.CONFIG_FILE + "' , all settings will be default!" + "\n") sickbeard.CFG = ConfigObj(sickbeard.CONFIG_FILE) # Initialize the config and our threads sickbeard.initialize(consoleLogging=self.consoleLogging) if self.runAsDaemon: self.daemonize() # Get PID sickbeard.PID = os.getpid() # Build from the DB to start with self.loadShowsFromDB() if self.forcedPort: logger.log(u"Forcing web server to port " + str(self.forcedPort)) self.startPort = self.forcedPort else: self.startPort = sickbeard.WEB_PORT if sickbeard.WEB_LOG: self.log_dir = sickbeard.LOG_DIR else: self.log_dir = None # sickbeard.WEB_HOST is available as a configuration value in various # places but is not configurable. It is supported here for historic reasons. if sickbeard.WEB_HOST and sickbeard.WEB_HOST != '0.0.0.0': self.webhost = sickbeard.WEB_HOST else: if sickbeard.WEB_IPV6: self.webhost = '::' else: self.webhost = '0.0.0.0' # web server options self.web_options = { 'port': int(self.startPort), 'host': self.webhost, 'data_root': os.path.join(sickbeard.PROG_DIR, 'gui', sickbeard.GUI_NAME), 'web_root': sickbeard.WEB_ROOT, 'log_dir': self.log_dir, 'username': sickbeard.WEB_USERNAME, 'password': sickbeard.WEB_PASSWORD, 'enable_https': sickbeard.ENABLE_HTTPS, 'handle_reverse_proxy': sickbeard.HANDLE_REVERSE_PROXY, 'https_cert': os.path.join(sickbeard.PROG_DIR, sickbeard.HTTPS_CERT), 'https_key': os.path.join(sickbeard.PROG_DIR, sickbeard.HTTPS_KEY), } # start web server self.webserver = SRWebServer(self.web_options) self.webserver.start() if self.consoleLogging: print "Starting up SickRage " + sickbeard.BRANCH + " from " + sickbeard.CONFIG_FILE # Clean up after update if sickbeard.GIT_NEWVER: toclean = os.path.join(sickbeard.CACHE_DIR, 'mako') for root, dirs, files in os.walk(toclean, topdown=False): for name in files: os.remove(os.path.join(root, name)) for name in dirs: os.rmdir(os.path.join(root, name)) sickbeard.GIT_NEWVER = False # Fire up all our threads sickbeard.start() # Build internal name cache name_cache.buildNameCache() # Prepopulate network timezones, it isn't thread safe network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() # # Check for metadata indexer updates for shows (Disabled until we use api) # sickbeard.showUpdateScheduler.forceRun() # Launch browser if sickbeard.LAUNCH_BROWSER and not (self.noLaunch or self.runAsDaemon): sickbeard.launchBrowser( 'https' if sickbeard.ENABLE_HTTPS else 'http', self.startPort, sickbeard.WEB_ROOT) # main loop while True: time.sleep(1)
def start(self): # pylint: disable=too-many-branches,too-many-statements """ Start SickRage """ # do some preliminary stuff sickbeard.MY_FULLNAME = ek(os.path.normpath, ek(os.path.abspath, __file__)) sickbeard.MY_NAME = ek(os.path.basename, sickbeard.MY_FULLNAME) sickbeard.PROG_DIR = ek(os.path.dirname, sickbeard.MY_FULLNAME) sickbeard.DATA_DIR = sickbeard.PROG_DIR sickbeard.MY_ARGS = sys.argv[1:] try: locale.setlocale(locale.LC_ALL, '') sickbeard.SYS_ENCODING = locale.getpreferredencoding() except (locale.Error, IOError): sickbeard.SYS_ENCODING = 'UTF-8' # pylint: disable=no-member if not sickbeard.SYS_ENCODING or sickbeard.SYS_ENCODING.lower() in ('ansi_x3.4-1968', 'us-ascii', 'ascii', 'charmap') or \ (sys.platform.startswith('win') and sys.getwindowsversion()[0] >= 6 and str(getattr(sys.stdout, 'device', sys.stdout).encoding).lower() in ('cp65001', 'charmap')): sickbeard.SYS_ENCODING = 'UTF-8' # TODO: Continue working on making this unnecessary, this hack creates all sorts of hellish problems if not hasattr(sys, 'setdefaultencoding'): reload(sys) try: # On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError sys.setdefaultencoding(sickbeard.SYS_ENCODING) # pylint: disable=no-member except (AttributeError, LookupError): sys.exit('Sorry, you MUST add the SickRage folder to the PYTHONPATH environment variable\n' 'or find another way to force Python to use %s for string encoding.' % sickbeard.SYS_ENCODING) # Need console logging for SickBeard.py and SickBeard-console.exe 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, _ = getopt.getopt( sys.argv[1:], 'hqdp::', ['help', 'quiet', 'nolaunch', 'daemon', 'pidfile=', 'port=', 'datadir=', 'config=', 'noresize'] ) except getopt.GetoptError: sys.exit(self.help_message()) for option, value in opts: # Prints help message if option in ('-h', '--help'): sys.exit(self.help_message()) # For now we'll just silence the logging if option in ('-q', '--quiet'): self.console_logging = False # Suppress launching web browser # Needed for OSes without default browser assigned # Prevent duplicate browser window when restarting in the app if option in ('--nolaunch',): self.no_launch = True # Override default/configured port if option in ('-p', '--port'): try: self.forced_port = int(value) except ValueError: sys.exit('Port: {0} is not a number. Exiting.'.format(value)) # Run as a double forked daemon if option in ('-d', '--daemon'): self.run_as_daemon = True # When running as daemon disable console_logging and don't start browser self.console_logging = False self.no_launch = True if sys.platform == 'win32' or sys.platform == 'darwin': self.run_as_daemon = False # Write a pid file if requested if option in ('--pidfile',): self.create_pid = True self.pid_file = str(value) # If the pid file already exists, SickRage may still be running, so exit if ek(os.path.exists, self.pid_file): sys.exit('PID file: {0} already exists. Exiting.'.format(self.pid_file)) # Specify folder to load the config file from if option in ('--config',): sickbeard.CONFIG_FILE = ek(os.path.abspath, value) # Specify folder to use as the data directory if option in ('--datadir',): sickbeard.DATA_DIR = ek(os.path.abspath, value) # Prevent resizing of the banner/posters even if PIL is installed if option in ('--noresize',): sickbeard.NO_RESIZE = True # The pid file is only useful in daemon mode, make sure we can write the file properly if self.create_pid: if self.run_as_daemon: pid_dir = ek(os.path.dirname, self.pid_file) if not ek(os.access, pid_dir, os.F_OK): sys.exit('PID dir: {0} doesn\'t exist. Exiting.'.format(pid_dir)) if not ek(os.access, pid_dir, os.W_OK): sys.exit('PID dir: {0} must be writable (write permissions). Exiting.'.format(pid_dir)) else: if self.console_logging: sys.stdout.write('Not running in daemon mode. PID file creation disabled.\n') self.create_pid = False # If they don't specify a config file then put it in the data dir if not sickbeard.CONFIG_FILE: sickbeard.CONFIG_FILE = ek(os.path.join, sickbeard.DATA_DIR, 'config.ini') # Make sure that we can create the data dir if not ek(os.access, sickbeard.DATA_DIR, os.F_OK): try: ek(os.makedirs, sickbeard.DATA_DIR, 0o744) except os.error: raise SystemExit('Unable to create data directory: {0}'.format(sickbeard.DATA_DIR)) # Make sure we can write to the data dir if not ek(os.access, sickbeard.DATA_DIR, os.W_OK): raise SystemExit('Data directory must be writeable: {0}'.format(sickbeard.DATA_DIR)) # Make sure we can write to the config file if not ek(os.access, sickbeard.CONFIG_FILE, os.W_OK): if ek(os.path.isfile, sickbeard.CONFIG_FILE): raise SystemExit('Config file must be writeable: {0}'.format(sickbeard.CONFIG_FILE)) elif not ek(os.access, ek(os.path.dirname, sickbeard.CONFIG_FILE), os.W_OK): raise SystemExit('Config file root dir must be writeable: {0}'.format(ek(os.path.dirname, sickbeard.CONFIG_FILE))) ek(os.chdir, sickbeard.DATA_DIR) # Check if we need to perform a restore first restore_dir = ek(os.path.join, sickbeard.DATA_DIR, 'restore') if ek(os.path.exists, restore_dir): success = self.restore_db(restore_dir, sickbeard.DATA_DIR) if self.console_logging: sys.stdout.write('Restore: restoring DB and config.ini {0}!\n'.format(('FAILED', 'SUCCESSFUL')[success])) # Load the config and publish it to the sickbeard package if self.console_logging and not ek(os.path.isfile, sickbeard.CONFIG_FILE): sys.stdout.write('Unable to find {0}, all settings will be default!\n'.format(sickbeard.CONFIG_FILE)) sickbeard.CFG = ConfigObj(sickbeard.CONFIG_FILE) # Initialize the config and our threads sickbeard.initialize(consoleLogging=self.console_logging) if self.run_as_daemon: self.daemonize() # Get PID sickbeard.PID = os.getpid() # Build from the DB to start with self.load_shows_from_db() logger.log('Starting SickRage [{branch}] using \'{config}\''.format (branch=sickbeard.BRANCH, config=sickbeard.CONFIG_FILE)) self.clear_cache() if self.forced_port: logger.log('Forcing web server to port {port}'.format(port=self.forced_port)) self.start_port = self.forced_port else: self.start_port = sickbeard.WEB_PORT if sickbeard.WEB_LOG: self.log_dir = sickbeard.LOG_DIR else: self.log_dir = None # sickbeard.WEB_HOST is available as a configuration value in various # places but is not configurable. It is supported here for historic reasons. if sickbeard.WEB_HOST and sickbeard.WEB_HOST != '0.0.0.0': self.web_host = sickbeard.WEB_HOST else: self.web_host = '' if sickbeard.WEB_IPV6 else '0.0.0.0' # web server options self.web_options = { 'port': int(self.start_port), 'host': self.web_host, 'data_root': ek(os.path.join, sickbeard.PROG_DIR, 'gui', sickbeard.GUI_NAME), 'web_root': sickbeard.WEB_ROOT, 'log_dir': self.log_dir, 'username': sickbeard.WEB_USERNAME, 'password': sickbeard.WEB_PASSWORD, 'enable_https': sickbeard.ENABLE_HTTPS, 'handle_reverse_proxy': sickbeard.HANDLE_REVERSE_PROXY, 'https_cert': ek(os.path.join, sickbeard.PROG_DIR, sickbeard.HTTPS_CERT), 'https_key': ek(os.path.join, sickbeard.PROG_DIR, sickbeard.HTTPS_KEY), } # start web server self.web_server = SRWebServer(self.web_options) self.web_server.start() # Fire up all our threads sickbeard.start() # Build internal name cache name_cache.buildNameCache() # Pre-populate network timezones, it isn't thread safe network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() # Check for metadata indexer updates for shows (sets the next aired ep!) # sickbeard.showUpdateScheduler.forceRun() # Launch browser if sickbeard.LAUNCH_BROWSER and not (self.no_launch or self.run_as_daemon): sickbeard.launchBrowser('https' if sickbeard.ENABLE_HTTPS else 'http', self.start_port, sickbeard.WEB_ROOT) # main loop while True: time.sleep(1)
def run(self, force=False): # pylint: disable=unused-argument, too-many-locals, too-many-branches, too-many-statements self.amActive = True bad_indexer = [INDEXER_TVRAGE] update_datetime = datetime.datetime.now() update_date = update_datetime.date() # update_timestamp = calendar.timegm(update_datetime.timetuple()) update_timestamp = time.mktime(update_datetime.timetuple()) cache_db_con = db.DBConnection('cache.db') result = cache_db_con.select( "SELECT `time` FROM lastUpdate WHERE provider = 'theTVDB'") if result: last_update = int(result[0]['time']) else: last_update = update_timestamp - 86400 cache_db_con.action( "INSERT INTO lastUpdate (provider,`time`) VALUES (?, ?)", ['theTVDB', last_update]) # refresh network timezones network_timezones.update_network_dict() # sure, why not? if sickbeard.USE_FAILED_DOWNLOADS: failed_history.trimHistory() update_delta = update_timestamp - last_update if update_delta >= 691200: # 8 days ( 7 days + 1 day of buffer time) update_file = 'updates_month.xml' elif update_delta >= 90000: # 25 hours ( 1 day + 1 hour of buffer time) update_file = 'updates_week.xml' else: update_file = 'updates_day.xml' # url = 'http://thetvdb.com/api/Updates.php?type=series&time=%s' % last_update url = 'http://thetvdb.com/api/%s/updates/%s' % (sickbeard.indexerApi( INDEXER_TVDB).api_params['apikey'], update_file) data = helpers.getURL(url, session=self.session) if not data: logger.log( u"Could not get the recently updated show data from %s. Retrying later. Url was: %s" % (sickbeard.indexerApi(INDEXER_TVDB).name, url)) self.amActive = False return updated_shows = [] try: tree = ET.fromstring(data) for show in tree.findall("Series"): updated_shows.append(int(show.find('id').text)) except SyntaxError: pass logger.log(u"Doing full update on all shows") pi_list = [] for cur_show in sickbeard.showList: if cur_show.indexer in bad_indexer: logger.log( u"Indexer is no longer available for show [ %s ] " % cur_show.name, logger.WARNING) else: indexer_name = sickbeard.indexerApi(cur_show.indexer).name try: if indexer_name == 'theTVDB': if cur_show.indexerid in updated_shows: pi_list.append( sickbeard.showQueueScheduler.action.updateShow( cur_show, True)) # else: # pi_list.append(sickbeard.showQueueScheduler.action.refreshShow(cur_show, True)) else: cur_show.nextEpisode() if cur_show.should_update(update_date=update_date): try: pi_list.append( sickbeard.showQueueScheduler.action.updateShow( cur_show, True)) except CantUpdateShowException as e: logger.log( u"Unable to update show: {0}".format(str(e)), logger.DEBUG) else: logger.log( u"Not updating episodes for show " + cur_show.name + " because it's last/next episode is not within the grace period.", logger.DEBUG) # pi_list.append(sickbeard.showQueueScheduler.action.refreshShow(cur_show, True)) except (CantUpdateShowException, CantRefreshShowException) as e: logger.log(u"Automatic update failed: " + ex(e), logger.ERROR) ui.ProgressIndicators.setIndicator( 'dailyUpdate', ui.QueueProgressIndicator("Daily Update", pi_list)) cache_db_con.action( "UPDATE lastUpdate SET `time` = ? WHERE provider=?", [update_timestamp, 'theTVDB']) logger.log(u"Completed full update on all shows") self.amActive = False