Пример #1
0
    def server_checkup(self):
        if self.config.general.server_id:
            server_status = self.api.server.get_status(
                self.config.general.server_id)
            if server_status and not server_status['registered']:
                # re-register server
                server_id = self.api.server.register_server(
                    ip_addresses=','.join([get_internal_ip()]),
                    web_protocol=('http',
                                  'https')[self.config.general.enable_https],
                    web_port=self.config.general.web_port,
                    web_root=self.config.general.web_root,
                    server_version=sickrage.version(),
                )

                if server_id:
                    self.log.info(
                        'Re-registered SiCKRAGE server with SiCKRAGE API')
                    sentry_sdk.set_tag('server_id',
                                       self.config.general.server_id)
                    self.config.general.server_id = server_id
                    self.config.save(mark_dirty=True)
            else:
                self.log.debug('Updating SiCKRAGE server data on SiCKRAGE API')

                # update server information
                self.api.server.update_server(
                    server_id=self.config.general.server_id,
                    ip_addresses=','.join([get_internal_ip()]),
                    web_protocol=('http',
                                  'https')[self.config.general.enable_https],
                    web_port=self.config.general.web_port,
                    web_root=self.config.general.web_root,
                    server_version=sickrage.version(),
                )
Пример #2
0
    def init_sentry(self):
        # sentry log handler
        sentry_logging = LoggingIntegration(
            level=logging.INFO,  # Capture info and above as breadcrumbs
            event_level=logging.ERROR  # Send errors as events
        )

        # init sentry logging
        sentry_sdk.init(
            dsn=
            "https://[email protected]/2?verify_ssl=0",
            integrations=[sentry_logging],
            release=sickrage.version(),
            environment=('master', 'develop')['dev' in sickrage.version()],
            ignore_errors=[
                'KeyboardInterrupt', 'PermissionError', 'FileNotFoundError',
                'EpisodeNotFoundException'
            ])

        # sentry tags
        sentry_tags = {
            'platform': platform.platform(),
            'locale': repr(locale.getdefaultlocale()),
            'python': platform.python_version()
        }

        # set sentry tags
        for tag_key, tag_value in sentry_tags.items():
            sentry_sdk.set_tag(tag_key, tag_value)
Пример #3
0
    def init_sentry(self):
        # sentry log handler
        sentry_logging = LoggingIntegration(
            level=logging.INFO,  # Capture info and above as breadcrumbs
            event_level=logging.ERROR  # Send errors as events
        )

        # init sentry logging
        sentry_sdk.init(
            dsn="https://[email protected]/2?verify_ssl=0",
            integrations=[sentry_logging],
            release=sickrage.version(),
            environment=('master', 'develop')['dev' in sickrage.version()],
            ignore_errors=[
                'KeyboardInterrupt',
                'PermissionError',
                'FileNotFoundError',
                'EpisodeNotFoundException'
            ]
        )

        # sentry tags
        sentry_tags = {
            'platform': platform.platform(),
            'locale': repr(locale.getdefaultlocale()),
            'python': platform.python_version(),
            'install_type': sickrage.install_type()
        }

        # set sentry tags
        for tag_key, tag_value in sentry_tags.items():
            sentry_sdk.set_tag(tag_key, tag_value)

        # set loggers to ignore
        ignored_loggers = [
            'enzyme.parsers.ebml.core',
            'subliminal.core',
            'subliminal.utils',
            'subliminal.refiners.tvdb',
            'subliminal.refiners.metadata',
            'subliminal.providers.tvsubtitles',
            'pika.connection',
            'pika.adapters.base_connection',
            'pika.adapters.utils.io_services_utils',
            'pika.adapters.utils.connection_workflow',
            'pika.adapters.utils.selector_ioloop_adapter'
        ]

        for item in ignored_loggers:
            ignore_logger(item)
Пример #4
0
 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))
Пример #5
0
    def start(self):
        # remove all handlers
        self.handlers = []

        # sentry log handler
        sentry_client = raven.Client('https://*****:*****@sentry.sickrage.ca/4?verify_ssl=0', release=sickrage.version(),
                                     repos={'sickrage': {'name': 'sickrage/sickrage'}})

        sentry_handler = SentryHandler(client=sentry_client, tags={'platform': platform.platform()})
        sentry_handler.setLevel(self.logLevels['ERROR'])
        sentry_handler.set_name('sentry')
        self.addHandler(sentry_handler)

        # console log handler
        if self.consoleLogging:
            console_handler = logging.StreamHandler()
            formatter = logging.Formatter('%(asctime)s %(levelname)s::%(threadName)s::%(message)s', '%H:%M:%S')

            console_handler.setFormatter(formatter)
            console_handler.setLevel(self.logLevels['INFO'] if not self.debugLogging else self.logLevels['DEBUG'])
            self.addHandler(console_handler)

        # file log handlers
        if self.logFile:
            # make logs folder if it doesn't exist
            if not os.path.exists(os.path.dirname(self.logFile)):
                if not makeDir(os.path.dirname(self.logFile)):
                    return

            if sickrage.app.developer:
                rfh = FileHandler(
                    filename=self.logFile,
                )
            else:
                rfh = RotatingFileHandler(
                    filename=self.logFile,
                    maxBytes=self.logSize,
                    backupCount=self.logNr
                )

            rfh_errors = RotatingFileHandler(
                filename=self.logFile.replace('.log', '.error.log'),
                maxBytes=self.logSize,
                backupCount=self.logNr
            )

            formatter = logging.Formatter('%(asctime)s %(levelname)s::%(threadName)s::%(message)s', '%Y-%m-%d %H:%M:%S')

            rfh.setFormatter(formatter)
            rfh.setLevel(self.logLevels['INFO'] if not self.debugLogging else self.logLevels['DEBUG'])
            self.addHandler(rfh)

            rfh_errors.setFormatter(formatter)
            rfh_errors.setLevel(self.logLevels['ERROR'])
            self.addHandler(rfh_errors)
Пример #6
0
    def __init__(self):
        super(PLEXNotifier, self).__init__()
        self.name = 'plex'

        self.headers = {
            'X-Plex-Device-Name': 'SiCKRAGE',
            'X-Plex-Product': 'SiCKRAGE Notifier',
            'X-Plex-Client-Identifier': sickrage.app.user_agent,
            'X-Plex-Version': sickrage.version()
        }
Пример #7
0
 def set_default_headers(self):
     self.set_header('X-SiCKRAGE-Server', sickrage.version())
     self.set_header("Access-Control-Allow-Origin", "*")
     self.set_header(
         "Access-Control-Allow-Headers",
         "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With, X-SiCKRAGE-Server"
     )
     self.set_header('Access-Control-Allow-Methods',
                     'POST, GET, PUT, PATCH, DELETE, OPTIONS')
     self.set_header('Cache-Control',
                     'no-store, no-cache, must-revalidate, max-age=0')
Пример #8
0
 def current_branch(self):
     return ("master", "develop")["dev" in sickrage.version()]
Пример #9
0
 def version(self):
     return sickrage.version()
Пример #10
0
    def prepare(self):
        super(APIBaseHandler, self).prepare()

        method_name = self.request.method.lower()
        if method_name == 'options':
            return

        certs = sickrage.app.auth_server.certs()
        auth_header = self.request.headers.get('Authorization')

        if auth_header:
            if 'bearer' in auth_header.lower():
                try:
                    token = auth_header.strip('Bearer').strip()
                    decoded_token = sickrage.app.auth_server.decode_token(token, certs)

                    if not sickrage.app.config.user.sub_id:
                        sickrage.app.config.user.sub_id = decoded_token.get('sub')
                        sickrage.app.config.save(mark_dirty=True)

                    if sickrage.app.config.user.sub_id == decoded_token.get('sub'):
                        save_config = False
                        if not sickrage.app.config.user.username:
                            sickrage.app.config.user.username = decoded_token.get('preferred_username')
                            save_config = True

                        if not sickrage.app.config.user.email:
                            sickrage.app.config.user.email = decoded_token.get('email')
                            save_config = True

                        if not sickrage.app.config.user.permissions == UserPermission.SUPERUSER:
                            sickrage.app.config.user.permissions = UserPermission.SUPERUSER
                            save_config = True

                        if save_config:
                            sickrage.app.config.save()

                    if sickrage.app.config.user.sub_id == decoded_token.get('sub'):
                        sentry_sdk.set_user({
                            'id': sickrage.app.config.user.sub_id,
                            'username': sickrage.app.config.user.username,
                            'email': sickrage.app.config.user.email
                        })

                    if sickrage.app.config.user.sub_id != decoded_token.get('sub'):
                        return self._unauthorized(error='user is not authorized')

                    if not sickrage.app.api.token:
                        exchanged_token = sickrage.app.auth_server.token_exchange(token)
                        if exchanged_token:
                            sickrage.app.api.token = exchanged_token

                    if not sickrage.app.config.general.server_id:
                        server_id = sickrage.app.api.server.register_server(
                            ip_addresses=','.join([get_internal_ip()]),
                            web_protocol=self.request.protocol,
                            web_port=sickrage.app.config.general.web_port,
                            web_root=sickrage.app.config.general.web_root,
                            server_version=sickrage.version()
                        )

                        if server_id:
                            sickrage.app.config.general.server_id = server_id
                            sickrage.app.config.save()

                    if sickrage.app.config.general.server_id:
                        sentry_sdk.set_tag('server_id', sickrage.app.config.general.server_id)

                    method = self.run_async(getattr(self, method_name))
                    setattr(self, method_name, method)
                except Exception:
                    return self._unauthorized(error='failed to decode token')
            else:
                return self._unauthorized(error='invalid authorization request')
        else:
            return self._unauthorized(error='authorization header missing')
Пример #11
0
 def _find_installed_version():
     return sickrage.version() or ""
Пример #12
0
    def start(self):
        # remove all handlers
        self.handlers = []

        # sentry log handler
        sentry_client = raven.Client(
            'https://*****:*****@sentry.sickrage.ca/4?verify_ssl=0',
            release=sickrage.version(),
            repos={'sickrage': {
                'name': 'sickrage/sickrage'
            }})

        sentry_handler = SentryHandler(client=sentry_client,
                                       tags={'platform': platform.platform()})
        sentry_handler.setLevel(self.logLevels['ERROR'])
        sentry_handler.set_name('sentry')
        self.addHandler(sentry_handler)

        # console log handler
        if self.consoleLogging:
            console_handler = logging.StreamHandler()
            formatter = logging.Formatter(
                '%(asctime)s %(levelname)s::%(threadName)s::%(message)s',
                '%H:%M:%S')

            console_handler.setFormatter(formatter)
            console_handler.setLevel(self.logLevels['INFO'] if not self.
                                     debugLogging else self.logLevels['DEBUG'])
            self.addHandler(console_handler)

        # file log handlers
        if self.logFile:
            # make logs folder if it doesn't exist
            if not os.path.exists(os.path.dirname(self.logFile)):
                if not makeDir(os.path.dirname(self.logFile)):
                    return

            if sickrage.app.developer:
                rfh = FileHandler(filename=self.logFile, )
            else:
                rfh = RotatingFileHandler(filename=self.logFile,
                                          maxBytes=self.logSize,
                                          backupCount=self.logNr)

            rfh_errors = RotatingFileHandler(filename=self.logFile.replace(
                '.log', '.error.log'),
                                             maxBytes=self.logSize,
                                             backupCount=self.logNr)

            formatter = logging.Formatter(
                '%(asctime)s %(levelname)s::%(threadName)s::%(message)s',
                '%Y-%m-%d %H:%M:%S')

            rfh.setFormatter(formatter)
            rfh.setLevel(self.logLevels['INFO']
                         if not self.debugLogging else self.logLevels['DEBUG'])
            self.addHandler(rfh)

            rfh_errors.setFormatter(formatter)
            rfh_errors.setLevel(self.logLevels['ERROR'])
            self.addHandler(rfh_errors)
Пример #13
0
    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 (
                    sickrage.app.config.https_cert and os.path.exists(
                sickrage.app.config.https_cert)) or not (
                    sickrage.app.config.https_key and os.path.exists(sickrage.app.config.https_key)):
                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)

        # 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),

            # calendar
            (r'%s/calendar' % sickrage.app.config.web_root, CalendarHandler),

            # 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}),
        ])

        # Web Handlers
        self.app.add_handlers('.*$', Route.get_routes(sickrage.app.config.web_root))

        # 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)

            sickrage.app.log.info(
                "SiCKRAGE :: STARTED")
            sickrage.app.log.info(
                "SiCKRAGE :: VERSION:[{}]".format(sickrage.version()))
            sickrage.app.log.info(
                "SiCKRAGE :: CONFIG:[{}] [v{}]".format(sickrage.app.config_file, sickrage.app.config.config_version))
            sickrage.app.log.info(
                "SiCKRAGE :: DATABASE:[v{}]".format(sickrage.app.main_db.version))
            sickrage.app.log.info(
                "SiCKRAGE :: URL:[{}://{}:{}{}]".format(('http', 'https')[sickrage.app.config.enable_https],
                                                        sickrage.app.config.web_host, sickrage.app.config.web_port,
                                                        sickrage.app.config.web_root))
        except socket.error as e:
            sickrage.app.log.warning(e.strerror)
            raise SystemExit
Пример #14
0
 def _find_installed_version():
     return sickrage.version() or ""
Пример #15
0
    def handle_sso_auth_get(self):
        code = self.get_argument('code', None)

        redirect_uri = f"{self.request.protocol}://{self.request.host}{sickrage.app.config.general.web_root}/login"

        if code:
            try:
                token = sickrage.app.auth_server.authorization_code(
                    code, redirect_uri)
                if not token:
                    return self.redirect('/logout')

                certs = sickrage.app.auth_server.certs()
                if not certs:
                    return self.redirect('/logout')

                decoded_token = sickrage.app.auth_server.decode_token(
                    token['access_token'], certs)
                if not decoded_token:
                    return self.redirect('/logout')

                if not decoded_token.get('sub'):
                    return self.redirect('/logout')

                self.set_secure_cookie('_sr_access_token',
                                       token['access_token'])
                self.set_secure_cookie('_sr_refresh_token',
                                       token['refresh_token'])

                if not sickrage.app.config.user.sub_id:
                    sickrage.app.config.user.sub_id = decoded_token.get('sub')
                    sickrage.app.config.save(mark_dirty=True)

                if sickrage.app.config.user.sub_id == decoded_token.get('sub'):
                    save_config = False
                    if not sickrage.app.config.user.username:
                        sickrage.app.config.user.username = decoded_token.get(
                            'preferred_username')
                        save_config = True

                    if not sickrage.app.config.user.email:
                        sickrage.app.config.user.email = decoded_token.get(
                            'email')
                        save_config = True

                    if not sickrage.app.config.user.permissions == UserPermission.SUPERUSER:
                        sickrage.app.config.user.permissions = UserPermission.SUPERUSER
                        save_config = True

                    if save_config:
                        sickrage.app.config.save()

                if sickrage.app.config.user.sub_id == decoded_token.get('sub'):
                    sentry_sdk.set_user({
                        'id': sickrage.app.config.user.sub_id,
                        'username': sickrage.app.config.user.username,
                        'email': sickrage.app.config.user.email
                    })

                if sickrage.app.config.user.sub_id != decoded_token.get('sub'):
                    if sickrage.app.api.token:
                        allowed_usernames = sickrage.app.api.allowed_usernames(
                        )['data']
                        if not decoded_token.get(
                                'preferred_username') in allowed_usernames:
                            sickrage.app.log.debug(
                                "USERNAME:{} IP:{} - WEB-UI ACCESS DENIED".
                                format(decoded_token.get('preferred_username'),
                                       self.request.remote_ip))
                            return self.redirect('/logout')
                    else:
                        return self.redirect('/logout')
                elif not sickrage.app.api.token:
                    exchanged_token = sickrage.app.auth_server.token_exchange(
                        token['access_token'])
                    if exchanged_token:
                        sickrage.app.api.token = exchanged_token
            except Exception as e:
                sickrage.app.log.debug('{!r}'.format(e))
                return self.redirect('/logout')

            if not sickrage.app.config.general.server_id:
                server_id = sickrage.app.api.server.register_server(
                    ip_addresses=','.join([get_internal_ip()]),
                    web_protocol=self.request.protocol,
                    web_port=sickrage.app.config.general.web_port,
                    web_root=sickrage.app.config.general.web_root,
                    server_version=sickrage.version())

                if server_id:
                    sickrage.app.config.general.server_id = server_id
                    sickrage.app.config.save()

            if sickrage.app.config.general.server_id:
                sentry_sdk.set_tag('server_id',
                                   sickrage.app.config.general.server_id)

            redirect_uri = self.get_argument(
                'next',
                "/{}/".format(sickrage.app.config.general.default_page.value))
            return self.redirect("{}".format(redirect_uri))
        else:
            authorization_url = sickrage.app.auth_server.authorization_url(
                redirect_uri=redirect_uri, scope="profile email")
            if authorization_url:
                return self.redirect(authorization_url, add_web_root=False)

        return self.redirect('/logout')
Пример #16
0
    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 (
                    sickrage.app.config.https_cert and os.path.exists(
                sickrage.app.config.https_cert)) or not (
                    sickrage.app.config.https_key and os.path.exists(sickrage.app.config.https_key)):
                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)

        # 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(/?.*)' % self.api_root, ApiHandler),

            # redirect to home
            (r"(%s)" % sickrage.app.config.web_root, RedirectHandler,
             {"url": "%s/home" % sickrage.app.config.web_root}),

            # api key
            (r'%s/getkey(/?.*)' % sickrage.app.config.web_root, KeyHandler),

            # 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),

            # calendar
            (r'%s/calendar' % sickrage.app.config.web_root, CalendarHandler),

            # 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}),
        ])

        # Web Handlers
        self.app.add_handlers('.*$', Route.get_routes(sickrage.app.config.web_root))

        self.server = HTTPServer(self.app, xheaders=sickrage.app.config.handle_reverse_proxy)
        if sickrage.app.config.enable_https: self.server.ssl_options = {
            "certfile": sickrage.app.config.https_cert,
            "keyfile": sickrage.app.config.https_key
        }

        try:
            self.server.listen(sickrage.app.config.web_port)

            sickrage.app.log.info(
                "SiCKRAGE :: STARTED")
            sickrage.app.log.info(
                "SiCKRAGE :: VERSION:[{}]".format(sickrage.version()))
            sickrage.app.log.info(
                "SiCKRAGE :: CONFIG:[{}] [v{}]".format(sickrage.app.config_file, sickrage.app.config.config_version))
            sickrage.app.log.info(
                "SiCKRAGE :: DATABASE:[v{}]".format(sickrage.app.main_db.version))
            sickrage.app.log.info(
                "SiCKRAGE :: URL:[{}://{}:{}{}]".format(('http', 'https')[sickrage.app.config.enable_https],
                                                        sickrage.app.config.web_host, sickrage.app.config.web_port,
                                                        sickrage.app.config.web_root))

            # launch browser window
            if all([not sickrage.app.no_launch,
                    sickrage.app.config.launch_browser]) or sickrage.app.config.view_changelog:
                threading.Thread(None, lambda: launch_browser(
                    ('http', 'https')[sickrage.app.config.enable_https],
                    sickrage.app.config.web_host,
                    sickrage.app.config.web_port
                ), name="LAUNCH-BROWSER").start()
        except socket.error as e:
            sickrage.app.log.warning(e.strerror)
            raise SystemExit
Пример #17
0
    def get(self, *args, **kwargs):
        code = self.get_argument('code', None)

        redirect_uri = "{}://{}{}/account/link".format(self.request.protocol, self.request.host, sickrage.app.config.general.web_root)

        if code:
            token = sickrage.app.auth_server.authorization_code(code, redirect_uri)
            if not token:
                return self.redirect('/account/link')

            certs = sickrage.app.auth_server.certs()
            if not certs:
                return self.redirect('/account/link')

            decoded_token = sickrage.app.auth_server.decode_token(token['access_token'], certs)
            if not decoded_token:
                return self.redirect('/account/link')

            # if sickrage.app.api.token:
            #     sickrage.app.api.logout()

            exchanged_token = sickrage.app.auth_server.token_exchange(token['access_token'])
            if exchanged_token:
                sickrage.app.api.token = exchanged_token

            sickrage.app.config.general.enable_sickrage_api = True

            if not sickrage.app.config.user.sub_id:
                sickrage.app.config.user.sub_id = decoded_token.get('sub_id')
                sickrage.app.config.user.username = decoded_token.get('preferred_username')
                sickrage.app.config.user.email = decoded_token.get('email')
                sickrage.app.config.user.permissions = UserPermission.SUPERUSER

                sentry_sdk.set_user({
                    'id': sickrage.app.config.user.sub_id,
                    'username': sickrage.app.config.user.username,
                    'email': sickrage.app.config.user.email
                })

            if not sickrage.app.config.general.server_id:
                server_id = sickrage.app.api.server.register_server(
                    ip_addresses=','.join([get_internal_ip()]),
                    web_protocol=self.request.protocol,
                    web_port=sickrage.app.config.general.web_port,
                    web_root=sickrage.app.config.general.web_root,
                    server_version=sickrage.version()
                )

                if server_id:
                    sickrage.app.config.general.server_id = server_id

            if sickrage.app.config.general.server_id:
                sentry_sdk.set_tag('server_id', sickrage.app.config.general.server_id)

            sickrage.app.config.save(mark_dirty=True)

            sickrage.app.alerts.message(_('Linked SiCKRAGE account to SiCKRAGE API'))
        else:
            authorization_url = sickrage.app.auth_server.authorization_url(redirect_uri=redirect_uri, scope="profile email")
            if authorization_url:
                return self.redirect(authorization_url, add_web_root=False)

        return self.redirect('/account/link')
Пример #18
0
    def handle_jwt_auth_get(self):
        certs = sickrage.app.auth_server.certs()
        auth_token = self.request.headers['Authorization'].strip(
            'Bearer').strip()

        try:
            decoded_token = sickrage.app.auth_server.decode_token(
                auth_token, certs)
        except ExpiredSignatureError:
            self.set_status(401)
            return {'error': 'Token expired'}
        except JWTError as e:
            self.set_status(401)
            return {'error': f'Improper JWT token supplied, {e!r}'}

        if not sickrage.app.config.user.sub_id:
            sickrage.app.config.user.sub_id = decoded_token.get('sub')
            sickrage.app.config.save(mark_dirty=True)

        if sickrage.app.config.user.sub_id == decoded_token.get('sub'):
            save_config = False
            if not sickrage.app.config.user.username:
                sickrage.app.config.user.username = decoded_token.get(
                    'preferred_username')
                save_config = True

            if not sickrage.app.config.user.email:
                sickrage.app.config.user.email = decoded_token.get('email')
                save_config = True

            if not sickrage.app.config.user.permissions == UserPermission.SUPERUSER:
                sickrage.app.config.user.permissions = UserPermission.SUPERUSER
                save_config = True

            if save_config:
                sickrage.app.config.save()

        if sickrage.app.config.user.sub_id == decoded_token.get('sub'):
            sentry_sdk.set_user({
                'id': sickrage.app.config.user.sub_id,
                'username': sickrage.app.config.user.username,
                'email': sickrage.app.config.user.email
            })

        if sickrage.app.config.user.sub_id != decoded_token.get('sub'):
            return

        if not sickrage.app.api.token:
            exchanged_token = sickrage.app.auth_server.token_exchange(
                auth_token)
            if exchanged_token:
                sickrage.app.api.token = exchanged_token

        if not sickrage.app.config.general.server_id:
            server_id = sickrage.app.api.server.register_server(
                ip_addresses=','.join([get_internal_ip()]),
                web_protocol=self.request.protocol,
                web_port=sickrage.app.config.general.web_port,
                web_root=sickrage.app.config.general.web_root,
                server_version=sickrage.version())

            if server_id:
                sickrage.app.config.general.server_id = server_id
                sickrage.app.config.save()

        if sickrage.app.config.general.server_id:
            sentry_sdk.set_tag('server_id',
                               sickrage.app.config.general.server_id)
Пример #19
0
    def start(self):
        self.started = True

        # thread name
        threading.currentThread().setName('CORE')

        # event loop policy that allows loop creation on any thread.
        asyncio.set_event_loop_policy(AnyThreadEventLoopPolicy())

        # scheduler
        self.scheduler = BackgroundScheduler({'apscheduler.timezone': 'UTC'})

        # init core classes
        self.api = API()
        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.wserver = WebServer()
        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.announcements = Announcements()

        # authorization sso client
        self.auth_server = AuthServer()

        # check available space
        try:
            self.log.info("Performing disk space checks")
            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())

        # check if we need to perform a restore first
        if os.path.exists(os.path.abspath(os.path.join(self.data_dir, 'restore'))):
            self.log.info('Performing restore of backup files')
            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:
                # 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)
                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()

        # perform database startup actions
        for db in [self.main_db, self.cache_db]:
            # perform integrity check
            self.log.info("Performing integrity check on {} database".format(db.name))
            db.integrity_check()

            # migrate database
            self.log.info("Performing migrations on {} database".format(db.name))
            db.migrate()

            # upgrade database
            self.log.info("Performing upgrades on {} database".format(db.name))
            db.upgrade()

            # cleanup
            self.log.info("Performing cleanup on {} database".format(db.name))
            db.cleanup()

        # 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)

        if self.config.default_page not in ('schedule', 'history', 'IRC'):
            self.config.default_page = 'home'

        # 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.task,
            IntervalTrigger(
                hours=self.config.version_updater_freq,
                timezone='utc'
            ),
            name=self.version_updater.name,
            id=self.version_updater.name
        )

        # add network timezones updater job
        self.scheduler.add_job(
            self.tz_updater.task,
            IntervalTrigger(
                days=1,
                timezone='utc'
            ),
            name=self.tz_updater.name,
            id=self.tz_updater.name
        )

        # add show updater job
        self.scheduler.add_job(
            self.show_updater.task,
            IntervalTrigger(
                days=1,
                start_date=datetime.datetime.now().replace(hour=self.config.showupdate_hour),
                timezone='utc'
            ),
            name=self.show_updater.name,
            id=self.show_updater.name
        )

        # add rss cache updater job
        self.scheduler.add_job(
            self.rsscache_updater.task,
            IntervalTrigger(
                minutes=15,
                timezone='utc'
            ),
            name=self.rsscache_updater.name,
            id=self.rsscache_updater.name
        )

        # add daily search job
        self.scheduler.add_job(
            self.daily_searcher.task,
            IntervalTrigger(
                minutes=self.config.daily_searcher_freq,
                start_date=datetime.datetime.now() + datetime.timedelta(minutes=4),
                timezone='utc'
            ),
            name=self.daily_searcher.name,
            id=self.daily_searcher.name
        )

        # add failed snatch search job
        self.scheduler.add_job(
            self.failed_snatch_searcher.task,
            IntervalTrigger(
                hours=1,
                start_date=datetime.datetime.now() + datetime.timedelta(minutes=4),
                timezone='utc'
            ),
            name=self.failed_snatch_searcher.name,
            id=self.failed_snatch_searcher.name
        )

        # add backlog search job
        self.scheduler.add_job(
            self.backlog_searcher.task,
            IntervalTrigger(
                minutes=self.config.backlog_searcher_freq,
                start_date=datetime.datetime.now() + datetime.timedelta(minutes=30),
                timezone='utc'
            ),
            name=self.backlog_searcher.name,
            id=self.backlog_searcher.name
        )

        # add auto-postprocessing job
        self.scheduler.add_job(
            self.auto_postprocessor.task,
            IntervalTrigger(
                minutes=self.config.autopostprocessor_freq,
                timezone='utc'
            ),
            name=self.auto_postprocessor.name,
            id=self.auto_postprocessor.name
        )

        # add find proper job
        self.scheduler.add_job(
            self.proper_searcher.task,
            IntervalTrigger(
                minutes={
                    '15m': 15,
                    '45m': 45,
                    '90m': 90,
                    '4h': 4 * 60,
                    'daily': 24 * 60
                }[self.config.proper_searcher_interval],
                timezone='utc'
            ),
            name=self.proper_searcher.name,
            id=self.proper_searcher.name
        )

        # add trakt.tv checker job
        self.scheduler.add_job(
            self.trakt_searcher.task,
            IntervalTrigger(
                hours=1,
                timezone='utc'
            ),
            name=self.trakt_searcher.name,
            id=self.trakt_searcher.name
        )

        # add subtitles finder job
        self.scheduler.add_job(
            self.subtitle_searcher.task,
            IntervalTrigger(
                hours=self.config.subtitle_searcher_freq,
                timezone='utc'
            ),
            name=self.subtitle_searcher.name,
            id=self.subtitle_searcher.name
        )

        # add upnp client job
        self.scheduler.add_job(
            self.upnp_client.task,
            IntervalTrigger(
                seconds=self.upnp_client._nat_portmap_lifetime,
                timezone='utc'
            ),
            name=self.upnp_client.name,
            id=self.upnp_client.name
        )

        # add announcements job
        self.scheduler.add_job(
            self.announcements.task,
            IntervalTrigger(
                minutes=15,
                timezone='utc'
            ),
            name=self.announcements.name,
            id=self.announcements.name
        )

        # add provider URL update job
        self.scheduler.add_job(
            self.search_providers.task,
            IntervalTrigger(
                hours=1,
                timezone='utc'
            ),
            name=self.search_providers.name,
            id=self.search_providers.name
        )

        # start queues
        self.search_queue.start_worker(self.config.max_queue_workers)
        self.show_queue.start_worker(self.config.max_queue_workers)
        self.postprocessor_queue.start_worker(self.config.max_queue_workers)

        # start web server
        self.wserver.start()

        # fire off jobs now
        self.scheduler.get_job(self.version_updater.name).modify(next_run_time=datetime.datetime.utcnow())
        self.scheduler.get_job(self.tz_updater.name).modify(next_run_time=datetime.datetime.utcnow())
        self.scheduler.get_job(self.announcements.name).modify(next_run_time=datetime.datetime.utcnow())
        self.scheduler.get_job(self.search_providers.name).modify(next_run_time=datetime.datetime.utcnow())

        # start scheduler service
        self.scheduler.start()

        # load shows
        self.scheduler.add_job(self.load_shows)

        # launch browser window
        if all([not sickrage.app.no_launch, sickrage.app.config.launch_browser]):
            self.scheduler.add_job(launch_browser, args=[('http', 'https')[sickrage.app.config.enable_https],
                                                         sickrage.app.config.web_host, sickrage.app.config.web_port])

        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, get_lan_ip())[self.config.web_host == '0.0.0.0'],
                                                               self.config.web_port,
                                                               self.config.web_root))
Пример #20
0
    def start(self):
        # remove all handlers
        self.handlers.clear()

        sentry_ignore_exceptions = [
            'KeyboardInterrupt',
            'PermissionError',
            'FileNotFoundError',
            'EpisodeNotFoundException'
        ]

        # sentry log handler
        sentry_client = raven.Client(
            'https://[email protected]/2?verify_ssl=0',
            release=sickrage.version(),
            repos={'sickrage': {'name': 'sickrage/sickrage'}},
            ignore_exceptions=sentry_ignore_exceptions
        )

        sentry_tags = {
            'platform': platform.platform(),
            'locale': locale.getdefaultlocale(),
            'python': platform.python_version()
        }

        if sickrage.app.config and sickrage.app.config.sub_id:
            sentry_tags.update({'sub_id': sickrage.app.config.sub_id})
        if sickrage.app.config and sickrage.app.config.server_id:
            sentry_tags.update({'server_id': sickrage.app.config.server_id})

        sentry_handler = SentryHandler(client=sentry_client, ignore_exceptions=sentry_ignore_exceptions, tags=sentry_tags)

        sentry_handler.setLevel(self.logLevels['ERROR'])
        sentry_handler.set_name('sentry')
        self.addHandler(sentry_handler)

        # console log handler
        if self.consoleLogging:
            console_handler = logging.StreamHandler()
            formatter = logging.Formatter('%(asctime)s %(levelname)s::%(threadName)s::%(message)s', '%H:%M:%S')

            console_handler.setFormatter(formatter)
            console_handler.setLevel(self.logLevels['INFO'] if not self.debugLogging else self.logLevels['DEBUG'])
            self.addHandler(console_handler)

        # file log handlers
        if self.logFile:
            # make logs folder if it doesn't exist
            if not os.path.exists(os.path.dirname(self.logFile)):
                if not make_dir(os.path.dirname(self.logFile)):
                    return

            if sickrage.app.developer:
                rfh = FileHandler(
                    filename=self.logFile,
                )
            else:
                rfh = RotatingFileHandler(
                    filename=self.logFile,
                    maxBytes=self.logSize,
                    backupCount=self.logNr
                )

            rfh_errors = RotatingFileHandler(
                filename=self.logFile.replace('.log', '.error.log'),
                maxBytes=self.logSize,
                backupCount=self.logNr
            )

            formatter = logging.Formatter('%(asctime)s %(levelname)s::%(threadName)s::%(message)s', '%Y-%m-%d %H:%M:%S')

            rfh.setFormatter(formatter)
            rfh.setLevel(self.logLevels['INFO'] if not self.debugLogging else self.logLevels['DEBUG'])
            self.addHandler(rfh)

            rfh_errors.setFormatter(formatter)
            rfh_errors.setLevel(self.logLevels['ERROR'])
            self.addHandler(rfh_errors)
Пример #21
0
    def start(self):
        # remove all handlers
        self.handlers = []

        # sentry log handler
        sentry_client = raven.Client(
            'https://*****:*****@sentry.sickrage.ca/5?verify_ssl=0',
            release=sickrage.version(),
            repos={'sickrage': {
                'name': 'sickrage/sickrage'
            }})

        sentry_tags = {
            'platform': platform.platform(),
            'locale': sys.getdefaultencoding(),
            'python': sys.version_info
        }

        if sickrage.app.config and sickrage.app.config.sub_id:
            sentry_tags.update({'sub_id': sickrage.app.config.sub_id})
        if sickrage.app.config and sickrage.app.config.app_id:
            sentry_tags.update({'app_id': sickrage.app.config.app_id})

        sentry_handler = SentryHandler(client=sentry_client, tags=sentry_tags)

        sentry_handler.setLevel(self.logLevels['ERROR'])
        sentry_handler.set_name('sentry')
        self.addHandler(sentry_handler)

        # console log handler
        if self.consoleLogging:
            console_handler = logging.StreamHandler()
            formatter = logging.Formatter(
                '%(asctime)s %(levelname)s::%(threadName)s::%(message)s',
                '%H:%M:%S')

            console_handler.setFormatter(formatter)
            console_handler.setLevel(self.logLevels['INFO'] if not self.
                                     debugLogging else self.logLevels['DEBUG'])
            self.addHandler(console_handler)

        # file log handlers
        if self.logFile:
            # make logs folder if it doesn't exist
            if not os.path.exists(os.path.dirname(self.logFile)):
                if not make_dir(os.path.dirname(self.logFile)):
                    return

            if sickrage.app.developer:
                rfh = FileHandler(filename=self.logFile, )
            else:
                rfh = RotatingFileHandler(filename=self.logFile,
                                          maxBytes=self.logSize,
                                          backupCount=self.logNr)

            rfh_errors = RotatingFileHandler(filename=self.logFile.replace(
                '.log', '.error.log'),
                                             maxBytes=self.logSize,
                                             backupCount=self.logNr)

            formatter = logging.Formatter(
                '%(asctime)s %(levelname)s::%(threadName)s::%(message)s',
                '%Y-%m-%d %H:%M:%S')

            rfh.setFormatter(formatter)
            rfh.setLevel(self.logLevels['INFO']
                         if not self.debugLogging else self.logLevels['DEBUG'])
            self.addHandler(rfh)

            rfh_errors.setFormatter(formatter)
            rfh_errors.setLevel(self.logLevels['ERROR'])
            self.addHandler(rfh_errors)