def start(self): self.started = True # thread name threading.currentThread().setName('CORE') # patch modules with encoding kludge patch_modules() # init core classes self.notifier_providers = NotifierProviders() self.metadata_providers = MetadataProviders() self.search_providers = SearchProviders() self.log = Logger() self.config = Config() self.alerts = Notifications() self.main_db = MainDB() self.cache_db = CacheDB() self.scheduler = TornadoScheduler() self.wserver = WebServer() self.name_cache = NameCache() self.show_queue = ShowQueue() self.search_queue = SearchQueue() self.postprocessor_queue = PostProcessorQueue() self.version_updater = VersionUpdater() self.show_updater = ShowUpdater() self.daily_searcher = DailySearcher() self.failed_snatch_searcher = FailedSnatchSearcher() self.backlog_searcher = BacklogSearcher() self.proper_searcher = ProperSearcher() self.trakt_searcher = TraktSearcher() self.subtitle_searcher = SubtitleSearcher() self.auto_postprocessor = AutoPostProcessor() self.upnp_client = UPNPClient() self.quicksearch_cache = QuicksearchCache() # setup oidc client realm = KeycloakRealm(server_url='https://auth.sickrage.ca', realm_name='sickrage') self.oidc_client = realm.open_id_connect( client_id='sickrage-app', client_secret='5d4710b2-ca70-4d39-b5a3-0705e2c5e703') # Check if we need to perform a restore first if os.path.exists( os.path.abspath(os.path.join(self.data_dir, 'restore'))): success = restoreSR( os.path.abspath(os.path.join(self.data_dir, 'restore')), self.data_dir) print("Restoring SiCKRAGE backup: %s!\n" % ("FAILED", "SUCCESSFUL")[success]) if success: shutil.rmtree(os.path.abspath( os.path.join(self.data_dir, 'restore')), ignore_errors=True) # migrate old database file names to new ones if os.path.isfile( os.path.abspath(os.path.join(self.data_dir, 'sickbeard.db'))): if os.path.isfile(os.path.join(self.data_dir, 'sickrage.db')): helpers.moveFile( os.path.join(self.data_dir, 'sickrage.db'), os.path.join( self.data_dir, '{}.bak-{}'.format( 'sickrage.db', datetime.datetime.now().strftime( '%Y%m%d_%H%M%S')))) helpers.moveFile( os.path.abspath(os.path.join(self.data_dir, 'sickbeard.db')), os.path.abspath(os.path.join(self.data_dir, 'sickrage.db'))) # load config self.config.load() # set language self.config.change_gui_lang(self.config.gui_lang) # set socket timeout socket.setdefaulttimeout(self.config.socket_timeout) # setup logger settings self.log.logSize = self.config.log_size self.log.logNr = self.config.log_nr self.log.logFile = os.path.join(self.data_dir, 'logs', 'sickrage.log') self.log.debugLogging = self.config.debug self.log.consoleLogging = not self.quite # start logger self.log.start() # user agent if self.config.random_user_agent: self.user_agent = UserAgent().random urlparse.uses_netloc.append('scgi') urllib.FancyURLopener.version = self.user_agent # set torrent client web url torrent_webui_url(True) # Check available space try: total_space, available_space = getFreeSpace(self.data_dir) if available_space < 100: self.log.error( 'Shutting down as SiCKRAGE needs some space to work. You\'ll get corrupted data ' 'otherwise. Only %sMB left', available_space) return except Exception: self.log.error('Failed getting disk space: %s', traceback.format_exc()) # perform database startup actions for db in [self.main_db, self.cache_db]: # initialize database db.initialize() # check integrity of database db.check_integrity() # migrate database db.migrate() # misc database cleanups db.cleanup() # upgrade database db.upgrade() # compact main database if self.config.last_db_compact < time.time() - 604800: # 7 days self.main_db.compact() self.config.last_db_compact = int(time.time()) # load name cache self.name_cache.load() # load data for shows from database self.load_shows() if self.config.default_page not in ('schedule', 'history', 'IRC'): self.config.default_page = 'home' # cleanup cache folder for folder in ['mako', 'sessions', 'indexers']: try: shutil.rmtree(os.path.join(sickrage.app.cache_dir, folder), ignore_errors=True) except Exception: continue # init anidb connection if self.config.use_anidb: def anidb_logger(msg): return self.log.debug("AniDB: {} ".format(msg)) try: self.adba_connection = adba.Connection(keepAlive=True, log=anidb_logger) self.adba_connection.auth(self.config.anidb_username, self.config.anidb_password) except Exception as e: self.log.warning("AniDB exception msg: %r " % repr(e)) if self.config.web_port < 21 or self.config.web_port > 65535: self.config.web_port = 8081 if not self.config.web_cookie_secret: self.config.web_cookie_secret = generate_secret() # attempt to help prevent users from breaking links by using a bad url if not self.config.anon_redirect.endswith('?'): self.config.anon_redirect = '' if not re.match(r'\d+\|[^|]+(?:\|[^|]+)*', self.config.root_dirs): self.config.root_dirs = '' self.config.naming_force_folders = check_force_season_folders() if self.config.nzb_method not in ('blackhole', 'sabnzbd', 'nzbget'): self.config.nzb_method = 'blackhole' if self.config.torrent_method not in ('blackhole', 'utorrent', 'transmission', 'deluge', 'deluged', 'download_station', 'rtorrent', 'qbittorrent', 'mlnet', 'putio'): self.config.torrent_method = 'blackhole' if self.config.autopostprocessor_freq < self.config.min_autopostprocessor_freq: self.config.autopostprocessor_freq = self.config.min_autopostprocessor_freq if self.config.daily_searcher_freq < self.config.min_daily_searcher_freq: self.config.daily_searcher_freq = self.config.min_daily_searcher_freq self.config.min_backlog_searcher_freq = get_backlog_cycle_time() if self.config.backlog_searcher_freq < self.config.min_backlog_searcher_freq: self.config.backlog_searcher_freq = self.config.min_backlog_searcher_freq if self.config.version_updater_freq < self.config.min_version_updater_freq: self.config.version_updater_freq = self.config.min_version_updater_freq if self.config.subtitle_searcher_freq < self.config.min_subtitle_searcher_freq: self.config.subtitle_searcher_freq = self.config.min_subtitle_searcher_freq if self.config.failed_snatch_age < self.config.min_failed_snatch_age: self.config.failed_snatch_age = self.config.min_failed_snatch_age if self.config.proper_searcher_interval not in ('15m', '45m', '90m', '4h', 'daily'): self.config.proper_searcher_interval = 'daily' if self.config.showupdate_hour < 0 or self.config.showupdate_hour > 23: self.config.showupdate_hour = 0 if self.config.subtitles_languages[0] == '': self.config.subtitles_languages = [] # add version checker job self.scheduler.add_job( self.version_updater.run, IntervalTrigger(hours=self.config.version_updater_freq), name=self.version_updater.name, id=self.version_updater.name) # add network timezones updater job self.scheduler.add_job(update_network_dict, IntervalTrigger(days=1), name="TZUPDATER", id="TZUPDATER") # add show updater job self.scheduler.add_job(self.show_updater.run, IntervalTrigger( days=1, start_date=datetime.datetime.now().replace( hour=self.config.showupdate_hour)), name=self.show_updater.name, id=self.show_updater.name) # add daily search job self.scheduler.add_job( self.daily_searcher.run, IntervalTrigger(minutes=self.config.daily_searcher_freq, start_date=datetime.datetime.now() + datetime.timedelta(minutes=4)), name=self.daily_searcher.name, id=self.daily_searcher.name) # add failed snatch search job self.scheduler.add_job( self.failed_snatch_searcher.run, IntervalTrigger(hours=1, start_date=datetime.datetime.now() + datetime.timedelta(minutes=4)), name=self.failed_snatch_searcher.name, id=self.failed_snatch_searcher.name) # add backlog search job self.scheduler.add_job( self.backlog_searcher.run, IntervalTrigger(minutes=self.config.backlog_searcher_freq, start_date=datetime.datetime.now() + datetime.timedelta(minutes=30)), name=self.backlog_searcher.name, id=self.backlog_searcher.name) # add auto-postprocessing job self.scheduler.add_job( self.auto_postprocessor.run, IntervalTrigger(minutes=self.config.autopostprocessor_freq), name=self.auto_postprocessor.name, id=self.auto_postprocessor.name) # add find proper job self.scheduler.add_job( self.proper_searcher.run, IntervalTrigger(minutes={ '15m': 15, '45m': 45, '90m': 90, '4h': 4 * 60, 'daily': 24 * 60 }[self.config.proper_searcher_interval]), name=self.proper_searcher.name, id=self.proper_searcher.name) # add trakt.tv checker job self.scheduler.add_job(self.trakt_searcher.run, IntervalTrigger(hours=1), name=self.trakt_searcher.name, id=self.trakt_searcher.name) # add subtitles finder job self.scheduler.add_job( self.subtitle_searcher.run, IntervalTrigger(hours=self.config.subtitle_searcher_freq), name=self.subtitle_searcher.name, id=self.subtitle_searcher.name) # add upnp client job self.scheduler.add_job( self.upnp_client.run, IntervalTrigger(seconds=self.upnp_client._nat_portmap_lifetime), name=self.upnp_client.name, id=self.upnp_client.name) # start scheduler service self.scheduler.start() # start queue's self.search_queue.start() self.show_queue.start() self.postprocessor_queue.start() # start webserver self.wserver.start() # start ioloop self.io_loop.start()
class General(base): __tablename__ = 'general' id = Column(Integer, primary_key=True, autoincrement=True) server_id = Column(Text, default='') enable_sickrage_api = Column(Boolean, default=True) log_size = Column(Integer, default=1048576) calendar_unprotected = Column(Boolean, default=False) https_key = Column(Text, default='server.key') https_cert = Column(Text, default='server.crt') allow_high_priority = Column(Boolean, default=False) anon_redirect = Column(Text, default='https://anonym.to/?') series_provider_timeout = Column(Integer, default=20) web_use_gzip = Column(Boolean, default=True) daily_searcher_freq = Column(Integer, default=40) ignore_words = Column(Text, default=','.join(['german', 'french', 'core2hd', 'dutch', 'swedish', 'reenc', 'MrLss'])) api_v1_key = Column(Text, default=generate_api_key()) sso_api_key = Column(Text, default='') sso_auth_enabled = Column(Boolean, default=True) local_auth_enabled = Column(Boolean, default=False) ip_whitelist_enabled = Column(Boolean, default=False) ip_whitelist_localhost_enabled = Column(Boolean, default=False) ip_whitelist = Column(Text, default='') proper_searcher_interval = Column(Enum(CheckPropersInterval), default=CheckPropersInterval.DAILY) nzb_method = Column(Enum(NzbMethod), default=NzbMethod.BLACKHOLE) web_cookie_secret = Column(Text, default=generate_secret()) ssl_verify = Column(Boolean, default=False) enable_upnp = Column(Boolean, default=False) version_notify = Column(Boolean, default=False) web_root = Column(Text, default='') web_log = Column(Text, default='') add_shows_wo_dir = Column(Boolean, default=False) debug = Column(Boolean, default=False) series_provider_default = Column(Enum(SeriesProviderID), default=SeriesProviderID.THETVDB) use_torrents = Column(Boolean, default=True) display_all_seasons = Column(Boolean, default=True) usenet_retention = Column(Integer, default=500) download_propers = Column(Boolean, default=True) pip3_path = Column(Text, default='pip3') del_rar_contents = Column(Boolean, default=False) process_method = Column(Enum(ProcessMethod), default=ProcessMethod.COPY) file_timestamp_timezone = Column(Enum(FileTimestampTimezone), default=FileTimestampTimezone.NETWORK) auto_update = Column(Boolean, default=True) tv_download_dir = Column(Text, default='') naming_custom_abd = Column(Boolean, default=False) scene_default = Column(Boolean, default=False) skip_downloaded_default = Column(Boolean, default=False) add_show_year_default = Column(Boolean, default=False) naming_sports_pattern = Column(Text, default='%SN - %A-D - %EN') create_missing_show_dirs = Column(Boolean, default=False) trash_rotate_logs = Column(Boolean, default=False) airdate_episodes = Column(Boolean, default=False) notify_on_update = Column(Boolean, default=True) backup_on_update = Column(Boolean, default=True) backlog_days = Column(Integer, default=7) root_dirs = Column(Text, default='') naming_pattern = Column(Text, default='Season %0S/%SN - S%0SE%0E - %EN') sort_article = Column(Boolean, default=False) handle_reverse_proxy = Column(Boolean, default=False) postpone_if_sync_files = Column(Boolean, default=True) cpu_preset = Column(Enum(CpuPreset), default=CpuPreset.NORMAL) nfo_rename = Column(Boolean, default=True) naming_anime_multi_ep = Column(Enum(MultiEpNaming), default=MultiEpNaming.REPEAT) use_nzbs = Column(Boolean, default=False) web_ipv6 = Column(Boolean, default=False) anime_default = Column(Boolean, default=False) default_page = Column(Enum(DefaultHomePage), default=DefaultHomePage.HOME) version_updater_freq = Column(Integer, default=1) download_url = Column(Text, default='') show_update_hour = Column(Integer, default=3) enable_rss_cache = Column(Boolean, default=True) torrent_file_to_magnet = Column(Boolean, default=False) torrent_magnet_to_file = Column(Boolean, default=True) download_unverified_magnet_link = Column(Boolean, default=False) status_default = Column(Enum(EpisodeStatus), default=EpisodeStatus.SKIPPED) naming_anime = Column(Integer, default=3) naming_custom_sports = Column(Boolean, default=False) naming_custom_anime = Column(Boolean, default=False) naming_anime_pattern = Column(Text, default='Season %0S/%SN - S%0SE%0E - %EN') randomize_providers = Column(Boolean, default=False) process_automatically = Column(Boolean, default=False) git_path = Column(Text, default='git') sync_files = Column(Text, default=','.join(['!sync', 'lftp-pget-status', 'part', 'bts', '!qb'])) web_port = Column(Integer, default=8081) web_external_port = Column(Integer, default=random.randint(49152, 65536)) launch_browser = Column(Boolean, default=False) unpack = Column(Boolean, default=False) unpack_dir = Column(Text, default='') delete_non_associated_files = Column(Boolean, default=True) move_associated_files = Column(Boolean, default=False) naming_multi_ep = Column(Enum(MultiEpNaming), default=MultiEpNaming.REPEAT) random_user_agent = Column(Boolean, default=False) torrent_method = Column(Enum(TorrentMethod), default=TorrentMethod.BLACKHOLE) trash_remove_show = Column(Boolean, default=False) enable_https = Column(Boolean, default=False) no_delete = Column(Boolean, default=False) naming_abd_pattern = Column(Text, default='%SN - %A.D - %EN') socket_timeout = Column(Integer, default=30) proxy_setting = Column(Text, default='') backlog_searcher_freq = Column(Integer, default=1440) subtitle_searcher_freq = Column(Integer, default=1) auto_postprocessor_freq = Column(Integer, default=10) notify_on_login = Column(Boolean, default=False) rename_episodes = Column(Boolean, default=True) quality_default = Column(IntFlag(Qualities), default=Qualities.SD) extra_scripts = Column(Text, default='') flatten_folders_default = Column(Boolean, default=False) series_provider_default_language = Column(Text, default='eng') show_update_stale = Column(Boolean, default=True) ep_default_deleted_status = Column(Enum(EpisodeStatus), default=EpisodeStatus.ARCHIVED) no_restart = Column(Boolean, default=False) allowed_video_file_exts = Column(Text, default=','.join(['avi', 'mkv', 'mpg', 'mpeg', 'wmv', 'ogm', 'mp4', 'iso', 'img', 'divx', 'm2ts', 'm4v', 'ts', 'flv', 'f4v', 'mov', 'rmvb', 'vob', 'dvr-ms', 'wtv', 'ogv', '3gp', 'webm', 'tp'])) require_words = Column(Text, default='') naming_strip_year = Column(Boolean, default=False) proxy_series_providers = Column(Boolean, default=True) log_nr = Column(Integer, default=5) git_reset = Column(Boolean, default=True) search_format_default = Column(Enum(SearchFormat), default=SearchFormat.STANDARD) skip_removed_files = Column(Boolean, default=False) status_default_after = Column(Enum(EpisodeStatus), default=EpisodeStatus.WANTED) ignored_subs_list = Column(Text, default=','.join(['dk', 'fin', 'heb', 'kor', 'nor', 'nordic', 'pl', 'swe'])) calendar_icons = Column(Boolean, default=False) keep_processed_dir = Column(Boolean, default=True) processor_follow_symlinks = Column(Boolean, default=False) allowed_extensions = Column(Text, default=','.join(['srt', 'nfo', 'srr', 'sfv'])) view_changelog = Column(Boolean, default=False) strip_special_file_bits = Column(Boolean, default=True) max_queue_workers = Column(Integer, default=5)
def start(self): self.started = True self.io_loop = IOLoop.current() # thread name threading.currentThread().setName('CORE') # patch modules with encoding kludge patch_modules() # init core classes self.notifier_providers = NotifierProviders() self.metadata_providers = MetadataProviders() self.search_providers = SearchProviders() self.log = Logger() self.config = Config() self.alerts = Notifications() self.main_db = MainDB() self.cache_db = CacheDB() self.scheduler = TornadoScheduler() self.wserver = WebServer() self.name_cache = NameCache() self.show_queue = ShowQueue() self.search_queue = SearchQueue() self.postprocessor_queue = PostProcessorQueue() self.event_queue = EventQueue() self.version_updater = VersionUpdater() self.show_updater = ShowUpdater() self.tz_updater = TimeZoneUpdater() self.rsscache_updater = RSSCacheUpdater() self.daily_searcher = DailySearcher() self.failed_snatch_searcher = FailedSnatchSearcher() self.backlog_searcher = BacklogSearcher() self.proper_searcher = ProperSearcher() self.trakt_searcher = TraktSearcher() self.subtitle_searcher = SubtitleSearcher() self.auto_postprocessor = AutoPostProcessor() self.upnp_client = UPNPClient() self.quicksearch_cache = QuicksearchCache() # setup oidc client realm = KeycloakRealm(server_url='https://auth.sickrage.ca', realm_name='sickrage') self.oidc_client = realm.open_id_connect(client_id='sickrage-app', client_secret='5d4710b2-ca70-4d39-b5a3-0705e2c5e703') # Check if we need to perform a restore first if os.path.exists(os.path.abspath(os.path.join(self.data_dir, 'restore'))): success = restoreSR(os.path.abspath(os.path.join(self.data_dir, 'restore')), self.data_dir) self.log.info("Restoring SiCKRAGE backup: {}!".format(("FAILED", "SUCCESSFUL")[success])) if success: shutil.rmtree(os.path.abspath(os.path.join(self.data_dir, 'restore')), ignore_errors=True) # migrate old database file names to new ones if os.path.isfile(os.path.abspath(os.path.join(self.data_dir, 'sickbeard.db'))): if os.path.isfile(os.path.join(self.data_dir, 'sickrage.db')): helpers.move_file(os.path.join(self.data_dir, 'sickrage.db'), os.path.join(self.data_dir, '{}.bak-{}' .format('sickrage.db', datetime.datetime.now().strftime( '%Y%m%d_%H%M%S')))) helpers.move_file(os.path.abspath(os.path.join(self.data_dir, 'sickbeard.db')), os.path.abspath(os.path.join(self.data_dir, 'sickrage.db'))) # load config self.config.load() # set language self.config.change_gui_lang(self.config.gui_lang) # set socket timeout socket.setdefaulttimeout(self.config.socket_timeout) # setup logger settings self.log.logSize = self.config.log_size self.log.logNr = self.config.log_nr self.log.logFile = os.path.join(self.data_dir, 'logs', 'sickrage.log') self.log.debugLogging = self.config.debug self.log.consoleLogging = not self.quiet # start logger self.log.start() # user agent if self.config.random_user_agent: self.user_agent = UserAgent().random urlparse.uses_netloc.append('scgi') urllib.FancyURLopener.version = self.user_agent # set torrent client web url torrent_webui_url(True) # Check available space try: total_space, available_space = getFreeSpace(self.data_dir) if available_space < 100: self.log.error('Shutting down as SiCKRAGE needs some space to work. You\'ll get corrupted data ' 'otherwise. Only %sMB left', available_space) return except Exception: self.log.error('Failed getting disk space: %s', traceback.format_exc()) # perform database startup actions for db in [self.main_db, self.cache_db]: # initialize database db.initialize() # check integrity of database db.check_integrity() # migrate database db.migrate() # misc database cleanups db.cleanup() # upgrade database db.upgrade() # compact main database if self.config.last_db_compact < time.time() - 604800: # 7 days self.main_db.compact() self.config.last_db_compact = int(time.time()) # load name cache self.name_cache.load() # load data for shows from database self.load_shows() if self.config.default_page not in ('schedule', 'history', 'IRC'): self.config.default_page = 'home' # cleanup cache folder for folder in ['mako', 'sessions', 'indexers']: try: shutil.rmtree(os.path.join(sickrage.app.cache_dir, folder), ignore_errors=True) except Exception: continue if self.config.web_port < 21 or self.config.web_port > 65535: self.config.web_port = 8081 if not self.config.web_cookie_secret: self.config.web_cookie_secret = generate_secret() # attempt to help prevent users from breaking links by using a bad url if not self.config.anon_redirect.endswith('?'): self.config.anon_redirect = '' if not re.match(r'\d+\|[^|]+(?:\|[^|]+)*', self.config.root_dirs): self.config.root_dirs = '' self.config.naming_force_folders = check_force_season_folders() if self.config.nzb_method not in ('blackhole', 'sabnzbd', 'nzbget'): self.config.nzb_method = 'blackhole' if self.config.torrent_method not in ('blackhole', 'utorrent', 'transmission', 'deluge', 'deluged', 'download_station', 'rtorrent', 'qbittorrent', 'mlnet', 'putio'): self.config.torrent_method = 'blackhole' if self.config.autopostprocessor_freq < self.config.min_autopostprocessor_freq: self.config.autopostprocessor_freq = self.config.min_autopostprocessor_freq if self.config.daily_searcher_freq < self.config.min_daily_searcher_freq: self.config.daily_searcher_freq = self.config.min_daily_searcher_freq if self.config.backlog_searcher_freq < self.config.min_backlog_searcher_freq: self.config.backlog_searcher_freq = self.config.min_backlog_searcher_freq if self.config.version_updater_freq < self.config.min_version_updater_freq: self.config.version_updater_freq = self.config.min_version_updater_freq if self.config.subtitle_searcher_freq < self.config.min_subtitle_searcher_freq: self.config.subtitle_searcher_freq = self.config.min_subtitle_searcher_freq if self.config.failed_snatch_age < self.config.min_failed_snatch_age: self.config.failed_snatch_age = self.config.min_failed_snatch_age if self.config.proper_searcher_interval not in ('15m', '45m', '90m', '4h', 'daily'): self.config.proper_searcher_interval = 'daily' if self.config.showupdate_hour < 0 or self.config.showupdate_hour > 23: self.config.showupdate_hour = 0 # add version checker job self.scheduler.add_job( self.version_updater.run, IntervalTrigger( hours=self.config.version_updater_freq, ), name=self.version_updater.name, id=self.version_updater.name ) # add network timezones updater job self.scheduler.add_job( self.tz_updater.run, IntervalTrigger( days=1, ), name=self.tz_updater.name, id=self.tz_updater.name ) # add show updater job self.scheduler.add_job( self.show_updater.run, IntervalTrigger( days=1, start_date=datetime.datetime.now().replace(hour=self.config.showupdate_hour) ), name=self.show_updater.name, id=self.show_updater.name ) # add rss cache updater job self.scheduler.add_job( self.rsscache_updater.run, IntervalTrigger( minutes=15, ), name=self.rsscache_updater.name, id=self.rsscache_updater.name ) # add daily search job self.scheduler.add_job( self.daily_searcher.run, IntervalTrigger( minutes=self.config.daily_searcher_freq, start_date=datetime.datetime.now() + datetime.timedelta(minutes=4) ), name=self.daily_searcher.name, id=self.daily_searcher.name ) # add failed snatch search job self.scheduler.add_job( self.failed_snatch_searcher.run, IntervalTrigger( hours=1, start_date=datetime.datetime.now() + datetime.timedelta(minutes=4) ), name=self.failed_snatch_searcher.name, id=self.failed_snatch_searcher.name ) # add backlog search job self.scheduler.add_job( self.backlog_searcher.run, IntervalTrigger( minutes=self.config.backlog_searcher_freq, start_date=datetime.datetime.now() + datetime.timedelta(minutes=30) ), name=self.backlog_searcher.name, id=self.backlog_searcher.name ) # add auto-postprocessing job self.scheduler.add_job( self.auto_postprocessor.run, IntervalTrigger( minutes=self.config.autopostprocessor_freq ), name=self.auto_postprocessor.name, id=self.auto_postprocessor.name ) # add find proper job self.scheduler.add_job( self.proper_searcher.run, IntervalTrigger( minutes={ '15m': 15, '45m': 45, '90m': 90, '4h': 4 * 60, 'daily': 24 * 60 }[self.config.proper_searcher_interval] ), name=self.proper_searcher.name, id=self.proper_searcher.name ) # add trakt.tv checker job self.scheduler.add_job( self.trakt_searcher.run, IntervalTrigger( hours=1 ), name=self.trakt_searcher.name, id=self.trakt_searcher.name ) # add subtitles finder job self.scheduler.add_job( self.subtitle_searcher.run, IntervalTrigger( hours=self.config.subtitle_searcher_freq ), name=self.subtitle_searcher.name, id=self.subtitle_searcher.name ) # add upnp client job self.scheduler.add_job( self.upnp_client.run, IntervalTrigger( seconds=self.upnp_client._nat_portmap_lifetime ), name=self.upnp_client.name, id=self.upnp_client.name ) # add namecache update job self.scheduler.add_job( self.name_cache.build_all, IntervalTrigger( days=1, ), name=self.name_cache.name, id=self.name_cache.name ) # start scheduler service self.scheduler.start() # start queue's self.search_queue.start() self.show_queue.start() self.postprocessor_queue.start() self.event_queue.start() # fire off startup events self.event_queue.fire_event(self.name_cache.build_all) self.event_queue.fire_event(self.version_updater.run) self.event_queue.fire_event(self.tz_updater.run) # start webserver self.wserver.start() # launch browser window if all([not sickrage.app.no_launch, sickrage.app.config.launch_browser]): self.event_queue.fire_event(lambda: launch_browser(('http', 'https')[sickrage.app.config.enable_https], sickrage.app.config.web_host, sickrage.app.config.web_port)) # start ioloop self.io_loop.start()
def start(self): self.started = True self.io_loop = IOLoop.current() # thread name threading.currentThread().setName('CORE') # init core classes self.main_db = MainDB(self.db_type, self.db_prefix, self.db_host, self.db_port, self.db_username, self.db_password) self.cache_db = CacheDB(self.db_type, self.db_prefix, self.db_host, self.db_port, self.db_username, self.db_password) self.notifier_providers = NotifierProviders() self.metadata_providers = MetadataProviders() self.search_providers = SearchProviders() self.log = Logger() self.config = Config() self.alerts = Notifications() self.scheduler = TornadoScheduler({'apscheduler.timezone': 'UTC'}) self.wserver = WebServer() self.name_cache = NameCache() self.show_queue = ShowQueue() self.search_queue = SearchQueue() self.postprocessor_queue = PostProcessorQueue() self.version_updater = VersionUpdater() self.show_updater = ShowUpdater() self.tz_updater = TimeZoneUpdater() self.rsscache_updater = RSSCacheUpdater() self.daily_searcher = DailySearcher() self.failed_snatch_searcher = FailedSnatchSearcher() self.backlog_searcher = BacklogSearcher() self.proper_searcher = ProperSearcher() self.trakt_searcher = TraktSearcher() self.subtitle_searcher = SubtitleSearcher() self.auto_postprocessor = AutoPostProcessor() self.upnp_client = UPNPClient() self.quicksearch_cache = QuicksearchCache() # setup oidc client realm = KeycloakRealm(server_url='https://auth.sickrage.ca', realm_name='sickrage') self.oidc_client = realm.open_id_connect(client_id=self.oidc_client_id, client_secret=self.oidc_client_secret) # Check if we need to perform a restore first if os.path.exists(os.path.abspath(os.path.join(self.data_dir, 'restore'))): success = restore_app_data(os.path.abspath(os.path.join(self.data_dir, 'restore')), self.data_dir) self.log.info("Restoring SiCKRAGE backup: %s!" % ("FAILED", "SUCCESSFUL")[success]) if success: shutil.rmtree(os.path.abspath(os.path.join(self.data_dir, 'restore')), ignore_errors=True) # migrate old database file names to new ones if os.path.isfile(os.path.abspath(os.path.join(self.data_dir, 'sickbeard.db'))): if os.path.isfile(os.path.join(self.data_dir, 'sickrage.db')): helpers.move_file(os.path.join(self.data_dir, 'sickrage.db'), os.path.join(self.data_dir, '{}.bak-{}' .format('sickrage.db', datetime.datetime.now().strftime( '%Y%m%d_%H%M%S')))) helpers.move_file(os.path.abspath(os.path.join(self.data_dir, 'sickbeard.db')), os.path.abspath(os.path.join(self.data_dir, 'sickrage.db'))) # init encryption public and private keys encryption.initialize() # load config self.config.load() # set language self.config.change_gui_lang(self.config.gui_lang) # set socket timeout socket.setdefaulttimeout(self.config.socket_timeout) # setup logger settings self.log.logSize = self.config.log_size self.log.logNr = self.config.log_nr self.log.logFile = os.path.join(self.data_dir, 'logs', 'sickrage.log') self.log.debugLogging = self.config.debug self.log.consoleLogging = not self.quiet # start logger self.log.start() # user agent if self.config.random_user_agent: self.user_agent = UserAgent().random uses_netloc.append('scgi') FancyURLopener.version = self.user_agent # set torrent client web url torrent_webui_url(True) # Check available space try: total_space, available_space = get_free_space(self.data_dir) if available_space < 100: self.log.warning('Shutting down as SiCKRAGE needs some space to work. You\'ll get corrupted data otherwise. Only %sMB left', available_space) return except Exception: self.log.error('Failed getting disk space: %s', traceback.format_exc()) # perform database startup actions for db in [self.main_db, self.cache_db]: # perform integrity check db.integrity_check() # migrate database db.migrate() # sync database repo db.sync_db_repo() # cleanup db.cleanup() # load name cache self.name_cache.load() if self.config.default_page not in ('schedule', 'history', 'IRC'): self.config.default_page = 'home' # cleanup cache folder for folder in ['mako', 'sessions', 'indexers']: try: shutil.rmtree(os.path.join(sickrage.app.cache_dir, folder), ignore_errors=True) except Exception: continue if self.config.web_port < 21 or self.config.web_port > 65535: self.config.web_port = 8081 if not self.config.web_cookie_secret: self.config.web_cookie_secret = generate_secret() # attempt to help prevent users from breaking links by using a bad url if not self.config.anon_redirect.endswith('?'): self.config.anon_redirect = '' if not re.match(r'\d+\|[^|]+(?:\|[^|]+)*', self.config.root_dirs): self.config.root_dirs = '' self.config.naming_force_folders = check_force_season_folders() if self.config.nzb_method not in ('blackhole', 'sabnzbd', 'nzbget'): self.config.nzb_method = 'blackhole' if self.config.torrent_method not in ('blackhole', 'utorrent', 'transmission', 'deluge', 'deluged', 'download_station', 'rtorrent', 'qbittorrent', 'mlnet', 'putio'): self.config.torrent_method = 'blackhole' if self.config.autopostprocessor_freq < self.config.min_autopostprocessor_freq: self.config.autopostprocessor_freq = self.config.min_autopostprocessor_freq if self.config.daily_searcher_freq < self.config.min_daily_searcher_freq: self.config.daily_searcher_freq = self.config.min_daily_searcher_freq if self.config.backlog_searcher_freq < self.config.min_backlog_searcher_freq: self.config.backlog_searcher_freq = self.config.min_backlog_searcher_freq if self.config.version_updater_freq < self.config.min_version_updater_freq: self.config.version_updater_freq = self.config.min_version_updater_freq if self.config.subtitle_searcher_freq < self.config.min_subtitle_searcher_freq: self.config.subtitle_searcher_freq = self.config.min_subtitle_searcher_freq if self.config.failed_snatch_age < self.config.min_failed_snatch_age: self.config.failed_snatch_age = self.config.min_failed_snatch_age if self.config.proper_searcher_interval not in ('15m', '45m', '90m', '4h', 'daily'): self.config.proper_searcher_interval = 'daily' if self.config.showupdate_hour < 0 or self.config.showupdate_hour > 23: self.config.showupdate_hour = 0 # add API token refresh job self.scheduler.add_job( API().refresh_token, IntervalTrigger( hours=1, ), name='SR-API', id='SR-API' ) # add version checker job self.scheduler.add_job( self.version_updater.run, IntervalTrigger( hours=self.config.version_updater_freq, ), name=self.version_updater.name, id=self.version_updater.name ) # add network timezones updater job self.scheduler.add_job( self.tz_updater.run, IntervalTrigger( days=1, ), name=self.tz_updater.name, id=self.tz_updater.name ) # add show updater job self.scheduler.add_job( self.show_updater.run, IntervalTrigger( days=1, start_date=datetime.datetime.now().replace(hour=self.config.showupdate_hour) ), name=self.show_updater.name, id=self.show_updater.name ) # add rss cache updater job self.scheduler.add_job( self.rsscache_updater.run, IntervalTrigger( minutes=15, ), name=self.rsscache_updater.name, id=self.rsscache_updater.name ) # add daily search job self.scheduler.add_job( self.daily_searcher.run, IntervalTrigger( minutes=self.config.daily_searcher_freq, start_date=datetime.datetime.now() + datetime.timedelta(minutes=4) ), name=self.daily_searcher.name, id=self.daily_searcher.name ) # add failed snatch search job self.scheduler.add_job( self.failed_snatch_searcher.run, IntervalTrigger( hours=1, start_date=datetime.datetime.now() + datetime.timedelta(minutes=4) ), name=self.failed_snatch_searcher.name, id=self.failed_snatch_searcher.name ) # add backlog search job self.scheduler.add_job( self.backlog_searcher.run, IntervalTrigger( minutes=self.config.backlog_searcher_freq, start_date=datetime.datetime.now() + datetime.timedelta(minutes=30) ), name=self.backlog_searcher.name, id=self.backlog_searcher.name ) # add auto-postprocessing job self.scheduler.add_job( self.auto_postprocessor.run, IntervalTrigger( minutes=self.config.autopostprocessor_freq ), name=self.auto_postprocessor.name, id=self.auto_postprocessor.name ) # add find proper job self.scheduler.add_job( self.proper_searcher.run, IntervalTrigger( minutes={ '15m': 15, '45m': 45, '90m': 90, '4h': 4 * 60, 'daily': 24 * 60 }[self.config.proper_searcher_interval] ), name=self.proper_searcher.name, id=self.proper_searcher.name ) # add trakt.tv checker job self.scheduler.add_job( self.trakt_searcher.run, IntervalTrigger( hours=1 ), name=self.trakt_searcher.name, id=self.trakt_searcher.name ) # add subtitles finder job self.scheduler.add_job( self.subtitle_searcher.run, IntervalTrigger( hours=self.config.subtitle_searcher_freq ), name=self.subtitle_searcher.name, id=self.subtitle_searcher.name ) # add upnp client job self.scheduler.add_job( self.upnp_client.run, IntervalTrigger( seconds=self.upnp_client._nat_portmap_lifetime ), name=self.upnp_client.name, id=self.upnp_client.name ) # add namecache update job self.scheduler.add_job( self.name_cache.build_all, IntervalTrigger( days=1, ), name=self.name_cache.name, id=self.name_cache.name ) # start scheduler service self.scheduler.start() # start queue's self.io_loop.add_callback(self.search_queue.watch) self.io_loop.add_callback(self.show_queue.watch) self.io_loop.add_callback(self.postprocessor_queue.watch) # fire off startup events self.io_loop.run_in_executor(None, self.quicksearch_cache.run) self.io_loop.run_in_executor(None, self.name_cache.run) self.io_loop.run_in_executor(None, self.version_updater.run) self.io_loop.run_in_executor(None, self.tz_updater.run) # start web server self.wserver.start() # launch browser window if all([not sickrage.app.no_launch, sickrage.app.config.launch_browser]): self.io_loop.run_in_executor(None, functools.partial(launch_browser, ('http', 'https')[sickrage.app.config.enable_https], sickrage.app.config.web_host, sickrage.app.config.web_port)) def started(): self.log.info("SiCKRAGE :: STARTED") self.log.info("SiCKRAGE :: APP VERSION:[{}]".format(sickrage.version())) self.log.info("SiCKRAGE :: CONFIG VERSION:[v{}]".format(self.config.config_version)) self.log.info("SiCKRAGE :: DATABASE VERSION:[v{}]".format(self.main_db.version)) self.log.info("SiCKRAGE :: DATABASE TYPE:[{}]".format(self.db_type)) self.log.info("SiCKRAGE :: URL:[{}://{}:{}{}]".format(('http', 'https')[self.config.enable_https], self.config.web_host, self.config.web_port, self.config.web_root)) # start io_loop self.io_loop.add_callback(started) self.io_loop.start()
def start(self): self.started = True # load languages tornado.locale.load_gettext_translations(sickrage.LOCALE_DIR, 'messages') # clear mako cache folder mako_cache = os.path.join(sickrage.app.cache_dir, 'mako') if os.path.isdir(mako_cache): shutil.rmtree(mako_cache) # video root if sickrage.app.config.root_dirs: root_dirs = sickrage.app.config.root_dirs.split('|') self.video_root = root_dirs[int(root_dirs[0]) + 1] # web root if sickrage.app.config.web_root: sickrage.app.config.web_root = sickrage.app.config.web_root = ( '/' + sickrage.app.config.web_root.lstrip('/').strip('/')) # api root self.api_root = r'%s/api/%s' % (sickrage.app.config.web_root, sickrage.app.config.api_key) # tornado setup if sickrage.app.config.enable_https: # If either the HTTPS certificate or key do not exist, make some self-signed ones. if not create_https_certificates(sickrage.app.config.https_cert, sickrage.app.config.https_key): sickrage.app.log.info( "Unable to create CERT/KEY files, disabling HTTPS") sickrage.app.config.enable_https = False if not (os.path.exists(sickrage.app.config.https_cert) and os.path.exists(sickrage.app.config.https_key)): sickrage.app.log.warning( "Disabled HTTPS because of missing CERT and KEY files") sickrage.app.config.enable_https = False # Load the app self.app = Application( debug=True, autoreload=False, gzip=sickrage.app.config.web_use_gzip, cookie_secret=sickrage.app.config.web_cookie_secret, login_url='%s/login/' % sickrage.app.config.web_root, httpclient_secret=generate_secret()) # Websocket handler self.app.add_handlers( '.*$', [(r'%s/ws/ui' % sickrage.app.config.web_root, WebSocketUIHandler)]) # Static File Handlers self.app.add_handlers( '.*$', [ # api (r'%s/api/(\w{32})(/?.*)' % sickrage.app.config.web_root, ApiHandler), # redirect to home (r"(%s)(/?)" % sickrage.app.config.web_root, RedirectHandler, { "url": "%s/home" % sickrage.app.config.web_root }), # api builder (r'%s/api/builder' % sickrage.app.config.web_root, RedirectHandler, { "url": sickrage.app.config.web_root + '/apibuilder/' }), # login (r'%s/login(/?)' % sickrage.app.config.web_root, LoginHandler), # logout (r'%s/logout(/?)' % sickrage.app.config.web_root, LogoutHandler ), # favicon (r'%s/(favicon\.ico)' % sickrage.app.config.web_root, StaticNoCacheFileHandler, { "path": os.path.join(sickrage.app.config.gui_static_dir, 'images/favicon.ico') }), # images (r'%s/images/(.*)' % sickrage.app.config.web_root, StaticImageHandler, { "path": os.path.join(sickrage.app.config.gui_static_dir, 'images') }), # css (r'%s/css/(.*)' % sickrage.app.config.web_root, StaticNoCacheFileHandler, { "path": os.path.join(sickrage.app.config.gui_static_dir, 'css') }), # scss (r'%s/scss/(.*)' % sickrage.app.config.web_root, StaticNoCacheFileHandler, { "path": os.path.join(sickrage.app.config.gui_static_dir, 'scss') }), # fonts (r'%s/fonts/(.*)' % sickrage.app.config.web_root, StaticNoCacheFileHandler, { "path": os.path.join(sickrage.app.config.gui_static_dir, 'fonts') }), # javascript (r'%s/js/(.*)' % sickrage.app.config.web_root, StaticNoCacheFileHandler, { "path": os.path.join(sickrage.app.config.gui_static_dir, 'js') }), # videos (r'%s/videos/(.*)' % sickrage.app.config.web_root, StaticNoCacheFileHandler, { "path": self.video_root }), ]) # Handlers self.app.add_handlers('.*$', [ (r'%s/robots.txt' % sickrage.app.config.web_root, RobotsDotTxtHandler), (r'%s/messages.po' % sickrage.app.config.web_root, MessagesDotPoHandler), (r'%s/quicksearch.json' % sickrage.app.config.web_root, QuicksearchDotJsonHandler), (r'%s/apibuilder(/?)' % sickrage.app.config.web_root, APIBulderHandler), (r'%s/setHomeLayout(/?)' % sickrage.app.config.web_root, SetHomeLayoutHandler), (r'%s/setPosterSortBy(/?)' % sickrage.app.config.web_root, SetPosterSortByHandler), (r'%s/setPosterSortDir(/?)' % sickrage.app.config.web_root, SetPosterSortDirHandler), (r'%s/setHistoryLayout(/?)' % sickrage.app.config.web_root, SetHistoryLayoutHandler), (r'%s/toggleDisplayShowSpecials(/?)' % sickrage.app.config.web_root, ToggleDisplayShowSpecialsHandler), (r'%s/toggleScheduleDisplayPaused(/?)' % sickrage.app.config.web_root, ToggleScheduleDisplayPausedHandler), (r'%s/setScheduleSort(/?)' % sickrage.app.config.web_root, SetScheduleSortHandler), (r'%s/schedule(/?)' % sickrage.app.config.web_root, ScheduleHandler), (r'%s/unlink(/?)' % sickrage.app.config.web_root, UnlinkHandler), (r'%s/setScheduleLayout(/?)' % sickrage.app.config.web_root, SetScheduleLayoutHandler), (r'%s/calendar(/?)' % sickrage.app.config.web_root, CalendarHandler), (r'%s/changelog(/?)' % sickrage.app.config.web_root, ChangelogHandler), (r'%s/history(/?)' % sickrage.app.config.web_root, HistoryHandler), (r'%s/history/clear(/?)' % sickrage.app.config.web_root, HistoryClearHandler), (r'%s/history/trim(/?)' % sickrage.app.config.web_root, HistoryTrimHandler), (r'%s/irc(/?)' % sickrage.app.config.web_root, IRCHandler), (r'%s/logs(/?)' % sickrage.app.config.web_root, LogsHandler), (r'%s/logs/view(/?)' % sickrage.app.config.web_root, LogsViewHandler), (r'%s/logs/clearAll(/?)' % sickrage.app.config.web_root, LogsClearAllHanlder), (r'%s/logs/clearWarnings(/?)' % sickrage.app.config.web_root, LogsClearWarningsHanlder), (r'%s/logs/clearErrors(/?)' % sickrage.app.config.web_root, LogsClearErrorsHanlder), (r'%s/browser(/?)' % sickrage.app.config.web_root, WebFileBrowserHandler), (r'%s/browser/complete(/?)' % sickrage.app.config.web_root, WebFileBrowserCompleteHandler), (r'%s/home(/?)' % sickrage.app.config.web_root, HomeHandler), (r'%s/home/is_alive(/?)' % sickrage.app.config.web_root, IsAliveHandler), (r'%s/home/testSABnzbd(/?)' % sickrage.app.config.web_root, TestSABnzbdHandler), (r'%s/home/testTorrent(/?)' % sickrage.app.config.web_root, TestTorrentHandler), (r'%s/home/testFreeMobile(/?)' % sickrage.app.config.web_root, TestFreeMobileHandler), (r'%s/home/testTelegram(/?)' % sickrage.app.config.web_root, TestTelegramHandler), (r'%s/home/testJoin(/?)' % sickrage.app.config.web_root, TestJoinHandler), (r'%s/home/testGrowl(/?)' % sickrage.app.config.web_root, TestGrowlHandler), (r'%s/home/testProwl(/?)' % sickrage.app.config.web_root, TestProwlHandler), (r'%s/home/testBoxcar2(/?)' % sickrage.app.config.web_root, TestBoxcar2Handler), (r'%s/home/testPushover(/?)' % sickrage.app.config.web_root, TestPushoverHandler), (r'%s/home/twitterStep1(/?)' % sickrage.app.config.web_root, TwitterStep1Handler), (r'%s/home/twitterStep2(/?)' % sickrage.app.config.web_root, TwitterStep2Handler), (r'%s/home/testTwitter(/?)' % sickrage.app.config.web_root, TestTwitterHandler), (r'%s/home/testTwilio(/?)' % sickrage.app.config.web_root, TestTwilioHandler), (r'%s/home/testSlack(/?)' % sickrage.app.config.web_root, TestSlackHandler), (r'%s/home/testDiscord(/?)' % sickrage.app.config.web_root, TestDiscordHandler), (r'%s/home/testKODI(/?)' % sickrage.app.config.web_root, TestKODIHandler), (r'%s/home/testPMC(/?)' % sickrage.app.config.web_root, TestPMCHandler), (r'%s/home/testPMS(/?)' % sickrage.app.config.web_root, TestPMSHandler), (r'%s/home/testLibnotify(/?)' % sickrage.app.config.web_root, TestLibnotifyHandler), (r'%s/home/testEMBY(/?)' % sickrage.app.config.web_root, TestEMBYHandler), (r'%s/home/testNMJ(/?)' % sickrage.app.config.web_root, TestNMJHandler), (r'%s/home/settingsNMJ(/?)' % sickrage.app.config.web_root, SettingsNMJHandler), (r'%s/home/testNMJv2(/?)' % sickrage.app.config.web_root, TestNMJv2Handler), (r'%s/home/settingsNMJv2(/?)' % sickrage.app.config.web_root, SettingsNMJv2Handler), (r'%s/home/getTraktToken(/?)' % sickrage.app.config.web_root, GetTraktTokenHandler), (r'%s/home/testTrakt(/?)' % sickrage.app.config.web_root, TestTraktHandler), (r'%s/home/loadShowNotifyLists(/?)' % sickrage.app.config.web_root, LoadShowNotifyListsHandler), (r'%s/home/saveShowNotifyList(/?)' % sickrage.app.config.web_root, SaveShowNotifyListHandler), (r'%s/home/testEmail(/?)' % sickrage.app.config.web_root, TestEmailHandler), (r'%s/home/testNMA(/?)' % sickrage.app.config.web_root, TestNMAHandler), (r'%s/home/testPushalot(/?)' % sickrage.app.config.web_root, TestPushalotHandler), (r'%s/home/testPushbullet(/?)' % sickrage.app.config.web_root, TestPushbulletHandler), (r'%s/home/getPushbulletDevices(/?)' % sickrage.app.config.web_root, GetPushbulletDevicesHandler), (r'%s/home/status(/?)' % sickrage.app.config.web_root, StatusHandler), (r'%s/home/shutdown(/?)' % sickrage.app.config.web_root, ShutdownHandler), (r'%s/home/restart(/?)' % sickrage.app.config.web_root, RestartHandler), (r'%s/home/updateCheck(/?)' % sickrage.app.config.web_root, UpdateCheckHandler), (r'%s/home/update(/?)' % sickrage.app.config.web_root, UpdateHandler), (r'%s/home/verifyPath(/?)' % sickrage.app.config.web_root, VerifyPathHandler), (r'%s/home/installRequirements(/?)' % sickrage.app.config.web_root, InstallRequirementsHandler), (r'%s/home/branchCheckout(/?)' % sickrage.app.config.web_root, BranchCheckoutHandler), (r'%s/home/displayShow(/?)' % sickrage.app.config.web_root, DisplayShowHandler), (r'%s/home/editShow(/?)' % sickrage.app.config.web_root, EditShowHandler), (r'%s/home/togglePause(/?)' % sickrage.app.config.web_root, TogglePauseHandler), (r'%s/home/deleteShow' % sickrage.app.config.web_root, DeleteShowHandler), (r'%s/home/refreshShow(/?)' % sickrage.app.config.web_root, RefreshShowHandler), (r'%s/home/updateShow(/?)' % sickrage.app.config.web_root, UpdateShowHandler), (r'%s/home/subtitleShow(/?)' % sickrage.app.config.web_root, SubtitleShowHandler), (r'%s/home/updateKODI(/?)' % sickrage.app.config.web_root, UpdateKODIHandler), (r'%s/home/updatePLEX(/?)' % sickrage.app.config.web_root, UpdatePLEXHandler), (r'%s/home/updateEMBY(/?)' % sickrage.app.config.web_root, UpdateEMBYHandler), (r'%s/home/syncTrakt(/?)' % sickrage.app.config.web_root, SyncTraktHandler), (r'%s/home/deleteEpisode(/?)' % sickrage.app.config.web_root, DeleteEpisodeHandler), (r'%s/home/setStatus(/?)' % sickrage.app.config.web_root, SetStatusHandler), (r'%s/home/testRename(/?)' % sickrage.app.config.web_root, TestRenameHandler), (r'%s/home/doRename(/?)' % sickrage.app.config.web_root, DoRenameHandler), (r'%s/home/searchEpisode(/?)' % sickrage.app.config.web_root, SearchEpisodeHandler), (r'%s/home/getManualSearchStatus(/?)' % sickrage.app.config.web_root, GetManualSearchStatusHandler), (r'%s/home/searchEpisodeSubtitles(/?)' % sickrage.app.config.web_root, SearchEpisodeSubtitlesHandler), (r'%s/home/setSceneNumbering(/?)' % sickrage.app.config.web_root, SetSceneNumberingHandler), (r'%s/home/retryEpisode(/?)' % sickrage.app.config.web_root, RetryEpisodeHandler), (r'%s/home/fetch_releasegroups(/?)' % sickrage.app.config.web_root, FetchReleasegroupsHandler), (r'%s/home/postprocess(/?)' % sickrage.app.config.web_root, HomePostProcessHandler), (r'%s/home/postprocess/processEpisode(/?)' % sickrage.app.config.web_root, HomeProcessEpisodeHandler), (r'%s/home/addShows(/?)' % sickrage.app.config.web_root, HomeAddShowsHandler), (r'%s/home/addShows/searchIndexersForShowName(/?)' % sickrage.app.config.web_root, SearchIndexersForShowNameHandler), (r'%s/home/addShows/massAddTable(/?)' % sickrage.app.config.web_root, MassAddTableHandler), (r'%s/home/addShows/newShow(/?)' % sickrage.app.config.web_root, NewShowHandler), (r'%s/home/addShows/traktShows(/?)' % sickrage.app.config.web_root, TraktShowsHandler), (r'%s/home/addShows/popularShows(/?)' % sickrage.app.config.web_root, PopularShowsHandler), (r'%s/home/addShows/addShowToBlacklist(/?)' % sickrage.app.config.web_root, AddShowToBlacklistHandler), (r'%s/home/addShows/existingShows(/?)' % sickrage.app.config.web_root, ExistingShowsHandler), (r'%s/home/addShows/addShowByID(/?)' % sickrage.app.config.web_root, AddShowByIDHandler), (r'%s/home/addShows/addNewShow(/?)' % sickrage.app.config.web_root, AddNewShowHandler), (r'%s/home/addShows/addExistingShows(/?)' % sickrage.app.config.web_root, AddExistingShowsHandler), (r'%s/manage(/?)' % sickrage.app.config.web_root, ManageHandler), (r'%s/manage/showEpisodeStatuses(/?)' % sickrage.app.config.web_root, ShowEpisodeStatusesHandler), (r'%s/manage/episodeStatuses(/?)' % sickrage.app.config.web_root, EpisodeStatusesHandler), (r'%s/manage/changeEpisodeStatuses(/?)' % sickrage.app.config.web_root, ChangeEpisodeStatusesHandler), (r'%s/manage/showSubtitleMissed(/?)' % sickrage.app.config.web_root, ShowSubtitleMissedHandler), (r'%s/manage/subtitleMissed(/?)' % sickrage.app.config.web_root, SubtitleMissedHandler), (r'%s/manage/downloadSubtitleMissed(/?)' % sickrage.app.config.web_root, DownloadSubtitleMissedHandler), (r'%s/manage/backlogShow(/?)' % sickrage.app.config.web_root, BacklogShowHandler), (r'%s/manage/backlogOverview(/?)' % sickrage.app.config.web_root, BacklogOverviewHandler), (r'%s/manage/massEdit(/?)' % sickrage.app.config.web_root, MassEditHandler), (r'%s/manage/massUpdate(/?)' % sickrage.app.config.web_root, MassUpdateHandler), (r'%s/manage/failedDownloads(/?)' % sickrage.app.config.web_root, FailedDownloadsHandler), (r'%s/manage/manageQueues(/?)' % sickrage.app.config.web_root, ManageQueuesHandler), (r'%s/manage/manageQueues/forceBacklogSearch(/?)' % sickrage.app.config.web_root, ForceBacklogSearchHandler), (r'%s/manage/manageQueues/forceDailySearch(/?)' % sickrage.app.config.web_root, ForceDailySearchHandler), (r'%s/manage/manageQueues/forceFindPropers(/?)' % sickrage.app.config.web_root, ForceFindPropersHandler), (r'%s/manage/manageQueues/pauseDailySearcher(/?)' % sickrage.app.config.web_root, PauseDailySearcherHandler), (r'%s/manage/manageQueues/pauseBacklogSearcher(/?)' % sickrage.app.config.web_root, PauseBacklogSearcherHandler), (r'%s/manage/manageQueues/pausePostProcessor(/?)' % sickrage.app.config.web_root, PausePostProcessorHandler), (r'%s/config(/?)' % sickrage.app.config.web_root, ConfigHandler), (r'%s/config/reset(/?)' % sickrage.app.config.web_root, ConfigResetHandler), (r'%s/config/anime(/?)' % sickrage.app.config.web_root, ConfigAnimeHandler), (r'%s/config/anime/saveAnime(/?)' % sickrage.app.config.web_root, ConfigSaveAnimeHandler), (r'%s/config/backuprestore(/?)' % sickrage.app.config.web_root, ConfigBackupRestoreHandler), (r'%s/config/backuprestore/backup(/?)' % sickrage.app.config.web_root, ConfigBackupHandler), (r'%s/config/backuprestore/restore(/?)' % sickrage.app.config.web_root, ConfigRestoreHandler), (r'%s/config/backuprestore/saveBackupRestore(/?)' % sickrage.app.config.web_root, SaveBackupRestoreHandler), (r'%s/config/general(/?)' % sickrage.app.config.web_root, ConfigGeneralHandler), (r'%s/config/general/generateApiKey(/?)' % sickrage.app.config.web_root, GenerateApiKeyHandler), (r'%s/config/general/saveRootDirs(/?)' % sickrage.app.config.web_root, SaveRootDirsHandler), (r'%s/config/general/saveAddShowDefaults(/?)' % sickrage.app.config.web_root, SaveAddShowDefaultsHandler), (r'%s/config/general/saveGeneral(/?)' % sickrage.app.config.web_root, SaveGeneralHandler), (r'%s/config/notifications(/?)' % sickrage.app.config.web_root, ConfigNotificationsHandler), (r'%s/config/notifications/saveNotifications(/?)' % sickrage.app.config.web_root, SaveNotificationsHandler), (r'%s/config/postProcessing(/?)' % sickrage.app.config.web_root, ConfigPostProcessingHandler), (r'%s/config/postProcessing/savePostProcessing(/?)' % sickrage.app.config.web_root, SavePostProcessingHandler), (r'%s/config/postProcessing/testNaming(/?)' % sickrage.app.config.web_root, TestNamingHandler), (r'%s/config/postProcessing/isNamingValid(/?)' % sickrage.app.config.web_root, IsNamingValidHandler), (r'%s/config/postProcessing/isRarSupported(/?)' % sickrage.app.config.web_root, IsRarSupportedHandler), (r'%s/config/providers(/?)' % sickrage.app.config.web_root, ConfigProvidersHandler), (r'%s/config/providers/canAddNewznabProvider(/?)' % sickrage.app.config.web_root, CanAddNewznabProviderHandler), (r'%s/config/providers/canAddTorrentRssProvider(/?)' % sickrage.app.config.web_root, CanAddTorrentRssProviderHandler), (r'%s/config/providers/getNewznabCategories(/?)' % sickrage.app.config.web_root, GetNewznabCategoriesHandler), (r'%s/config/providers/saveProviders(/?)' % sickrage.app.config.web_root, SaveProvidersHandler), (r'%s/config/qualitySettings(/?)' % sickrage.app.config.web_root, ConfigQualitySettingsHandler), (r'%s/config/qualitySettings/saveQualities(/?)' % sickrage.app.config.web_root, SaveQualitiesHandler), (r'%s/config/search(/?)' % sickrage.app.config.web_root, ConfigSearchHandler), (r'%s/config/search/saveSearch(/?)' % sickrage.app.config.web_root, SaveSearchHandler), (r'%s/config/subtitles(/?)' % sickrage.app.config.web_root, ConfigSubtitlesHandler), (r'%s/config/subtitles/get_code(/?)' % sickrage.app.config.web_root, ConfigSubtitleGetCodeHandler), (r'%s/config/subtitles/wanted_languages(/?)' % sickrage.app.config.web_root, ConfigSubtitlesWantedLanguagesHandler), (r'%s/config/subtitles/saveSubtitles(/?)' % sickrage.app.config.web_root, SaveSubtitlesHandler), ]) # HTTPS Cert/Key object ssl_ctx = None if sickrage.app.config.enable_https: ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) ssl_ctx.load_cert_chain(sickrage.app.config.https_cert, sickrage.app.config.https_key) # Web Server self.server = HTTPServer( self.app, ssl_options=ssl_ctx, xheaders=sickrage.app.config.handle_reverse_proxy) try: self.server.listen(sickrage.app.config.web_port) except socket.error as e: sickrage.app.log.warning(e.strerror) raise SystemExit