Exemplo n.º 1
0
def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, Env = None, desktop = None):

    try:
        locale.setlocale(locale.LC_ALL, "")
        encoding = locale.getpreferredencoding()
    except (locale.Error, IOError):
        encoding = None

    # for OSes that are poorly configured I'll just force UTF-8
    if not encoding or encoding in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
        encoding = 'UTF-8'

    Env.set('encoding', encoding)

    # Do db stuff
    db_path = toUnicode(os.path.join(data_dir, 'couchpotato.db'))

    # Backup before start and cleanup old databases
    new_backup = toUnicode(os.path.join(data_dir, 'db_backup', str(int(time.time()))))

    # Create path and copy
    if not os.path.isdir(new_backup): os.makedirs(new_backup)
    src_files = [options.config_file, db_path, db_path + '-shm', db_path + '-wal']
    for src_file in src_files:
        if os.path.isfile(src_file):
            dst_file = toUnicode(os.path.join(new_backup, os.path.basename(src_file)))
            shutil.copyfile(src_file, dst_file)

            # Try and copy stats seperately
            try: shutil.copystat(src_file, dst_file)
            except: pass

    # Remove older backups, keep backups 3 days or at least 3
    backups = []
    for directory in os.listdir(os.path.dirname(new_backup)):
        backup = toUnicode(os.path.join(os.path.dirname(new_backup), directory))
        if os.path.isdir(backup):
            backups.append(backup)

    total_backups = len(backups)
    for backup in backups:
        if total_backups > 3:
            if tryInt(os.path.basename(backup)) < time.time() - 259200:
                for the_file in os.listdir(backup):
                    file_path = os.path.join(backup, the_file)
                    try:
                        if os.path.isfile(file_path):
                            os.remove(file_path)
                    except:
                        raise

                os.rmdir(backup)
                total_backups -= 1


    # Register environment settings
    Env.set('app_dir', toUnicode(base_path))
    Env.set('data_dir', toUnicode(data_dir))
    Env.set('log_path', toUnicode(os.path.join(log_dir, 'CouchPotato.log')))
    Env.set('db_path', toUnicode('sqlite:///' + db_path))
    Env.set('cache_dir', toUnicode(os.path.join(data_dir, 'cache')))
    Env.set('cache', FileSystemCache(toUnicode(os.path.join(Env.get('cache_dir'), 'python'))))
    Env.set('console_log', options.console_log)
    Env.set('quiet', options.quiet)
    Env.set('desktop', desktop)
    Env.set('daemonized', options.daemon)
    Env.set('args', args)
    Env.set('options', options)

    # Determine debug
    debug = options.debug or Env.setting('debug', default = False, type = 'bool')
    Env.set('debug', debug)

    # Development
    development = Env.setting('development', default = False, type = 'bool')
    Env.set('dev', development)

    # Disable logging for some modules
    for logger_name in ['enzyme', 'guessit', 'subliminal', 'apscheduler']:
        logging.getLogger(logger_name).setLevel(logging.ERROR)

    for logger_name in ['gntp', 'migrate']:
        logging.getLogger(logger_name).setLevel(logging.WARNING)

    # Use reloader
    reloader = debug is True and development and not Env.get('desktop') and not options.daemon

    # Logger
    logger = logging.getLogger()
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%m-%d %H:%M:%S')
    level = logging.DEBUG if debug else logging.INFO
    logger.setLevel(level)
    logging.addLevelName(19, 'INFO')

    # To screen
    if (debug or options.console_log) and not options.quiet and not options.daemon:
        hdlr = logging.StreamHandler(sys.stderr)
        hdlr.setFormatter(formatter)
        logger.addHandler(hdlr)

    # To file
    hdlr2 = handlers.RotatingFileHandler(Env.get('log_path'), 'a', 500000, 10)
    hdlr2.setFormatter(formatter)
    logger.addHandler(hdlr2)

    # Start logging & enable colors
    import color_logs
    from couchpotato.core.logger import CPLog
    log = CPLog(__name__)
    log.debug('Started with options %s', options)

    def customwarn(message, category, filename, lineno, file = None, line = None):
        log.warning('%s %s %s line:%s', (category, message, filename, lineno))
    warnings.showwarning = customwarn

    # Check if database exists
    db = Env.get('db_path')
    db_exists = os.path.isfile(toUnicode(db_path))

    # Load migrations
    if db_exists:

        from migrate.versioning.api import version_control, db_version, version, upgrade
        repo = os.path.join(base_path, 'couchpotato', 'core', 'migration')

        latest_db_version = version(repo)
        try:
            current_db_version = db_version(db, repo)
        except:
            version_control(db, repo, version = latest_db_version)
            current_db_version = db_version(db, repo)

        if current_db_version < latest_db_version:
            if development:
                log.error('There is a database migration ready, but you are running development mode, so it won\'t be used. If you see this, you are stupid. Please disable development mode.')
            else:
                log.info('Doing database upgrade. From %d to %d', (current_db_version, latest_db_version))
                upgrade(db, repo)

    # Configure Database
    from couchpotato.core.settings.model import setup
    setup()

    # Create app
    from couchpotato import WebHandler
    web_base = ('/' + Env.setting('url_base').lstrip('/') + '/') if Env.setting('url_base') else '/'
    Env.set('web_base', web_base)

    api_key = Env.setting('api_key')
    api_base = r'%sapi/%s/' % (web_base, api_key)
    Env.set('api_base', api_base)

    # Basic config
    host = Env.setting('host', default = '0.0.0.0')
    # app.debug = development
    config = {
        'use_reloader': reloader,
        'port': tryInt(Env.setting('port', default = 5050)),
        'host': host if host and len(host) > 0 else '0.0.0.0',
        'ssl_cert': Env.setting('ssl_cert', default = None),
        'ssl_key': Env.setting('ssl_key', default = None),
    }


    # Load the app
    application = Application([],
        log_function = lambda x : None,
        debug = config['use_reloader'],
        gzip = True,
        cookie_secret = api_key,
        login_url = '%slogin/' % web_base,
    )
    Env.set('app', application)

    # Request handlers
    application.add_handlers(".*$", [
        (r'%snonblock/(.*)(/?)' % api_base, NonBlockHandler),

        # API handlers
        (r'%s(.*)(/?)' % api_base, ApiHandler), # Main API handler
        (r'%sgetkey(/?)' % web_base, KeyHandler), # Get API key
        (r'%s' % api_base, RedirectHandler, {"url": web_base + 'docs/'}), # API docs

        # Login handlers
        (r'%slogin(/?)' % web_base, LoginHandler),
        (r'%slogout(/?)' % web_base, LogoutHandler),

        # Catch all webhandlers
        (r'%s(.*)(/?)' % web_base, WebHandler),
        (r'(.*)', WebHandler),
    ])

    # Static paths
    static_path = '%sstatic/' % web_base
    for dir_name in ['fonts', 'images', 'scripts', 'style']:
        application.add_handlers(".*$", [
             ('%s%s/(.*)' % (static_path, dir_name), StaticFileHandler, {'path': toUnicode(os.path.join(base_path, 'couchpotato', 'static', dir_name))})
        ])
    Env.set('static_path', static_path)


    # Load configs & plugins
    loader = Env.get('loader')
    loader.preload(root = toUnicode(base_path))
    loader.run()


    # Fill database with needed stuff
    if not db_exists:
        fireEvent('app.initialize', in_order = True)


    # Go go go!
    from tornado.ioloop import IOLoop
    loop = IOLoop.current()


    # Some logging and fire load event
    try: log.info('Starting server on port %(port)s', config)
    except: pass
    fireEventAsync('app.load')


    if config['ssl_cert'] and config['ssl_key']:
        server = HTTPServer(application, no_keep_alive = True, ssl_options = {
           "certfile": config['ssl_cert'],
           "keyfile": config['ssl_key'],
        })
    else:
        server = HTTPServer(application, no_keep_alive = True)

    try_restart = True
    restart_tries = 5

    while try_restart:
        try:
            server.listen(config['port'], config['host'])
            loop.start()
        except Exception, e:
            log.error('Failed starting: %s', traceback.format_exc())
            try:
                nr, msg = e
                if nr == 48:
                    log.info('Port (%s) needed for CouchPotato is already in use, try %s more time after few seconds', (config.get('port'), restart_tries))
                    time.sleep(1)
                    restart_tries -= 1

                    if restart_tries > 0:
                        continue
                    else:
                        return
            except:
                pass

            raise

        try_restart = False
Exemplo n.º 2
0
def runCouchPotato(options, base_path, args, desktop = None):

    # Load settings
    from couchpotato.environment import Env
    settings = Env.get('settings')
    settings.setFile(options.config_file)

    # Create data dir if needed
    data_dir = os.path.expanduser(Env.setting('data_dir'))
    if data_dir == '':
        data_dir = getDataDir()

    if not os.path.isdir(data_dir):
        os.makedirs(data_dir)

    # Create logging dir
    log_dir = os.path.join(data_dir, 'logs');
    if not os.path.isdir(log_dir):
        os.mkdir(log_dir)

    try:
        locale.setlocale(locale.LC_ALL, "")
        encoding = locale.getpreferredencoding()
    except (locale.Error, IOError):
        pass

    # for OSes that are poorly configured I'll just force UTF-8
    if not encoding or encoding in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
        encoding = 'UTF-8'

    # Register environment settings
    Env.set('encoding', encoding)
    Env.set('uses_git', not options.nogit)
    Env.set('app_dir', base_path)
    Env.set('data_dir', data_dir)
    Env.set('log_path', os.path.join(log_dir, 'CouchPotato.log'))
    Env.set('db_path', 'sqlite:///' + os.path.join(data_dir, 'couchpotato.db'))
    Env.set('cache_dir', os.path.join(data_dir, 'cache'))
    Env.set('cache', FileSystemCache(os.path.join(Env.get('cache_dir'), 'python')))
    Env.set('console_log', options.console_log)
    Env.set('quiet', options.quiet)
    Env.set('desktop', desktop)
    Env.set('args', args)
    Env.set('options', options)

    # Determine debug
    debug = options.debug or Env.setting('debug', default = False, type = 'bool')
    Env.set('debug', debug)

    # Disable server access log
    server_log = logging.getLogger('werkzeug')
    server_log.disabled = True

    # Only run once when debugging
    fire_load = False
    if os.environ.get('WERKZEUG_RUN_MAIN') or not debug or Env.get('desktop') or options.daemon:

        # Logger
        logger = logging.getLogger()
        formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%H:%M:%S')
        level = logging.DEBUG if debug else logging.INFO
        logger.setLevel(level)

        # To screen
        if (debug or options.console_log) and not options.quiet and not options.daemon:
            hdlr = logging.StreamHandler(sys.stderr)
            hdlr.setFormatter(formatter)
            logger.addHandler(hdlr)

        # To file
        hdlr2 = handlers.RotatingFileHandler(Env.get('log_path'), 'a', 500000, 10)
        hdlr2.setFormatter(formatter)
        logger.addHandler(hdlr2)

        # Start logging & enable colors
        import color_logs
        from couchpotato.core.logger import CPLog
        log = CPLog(__name__)
        log.debug('Started with options %s' % options)


        # Load configs & plugins
        loader = Env.get('loader')
        loader.preload(root = base_path)
        loader.run()


        # Load migrations
        from migrate.versioning.api import version_control, db_version, version, upgrade
        db = Env.get('db_path')
        repo = os.path.join(base_path, 'couchpotato', 'core', 'migration')
        logging.getLogger('migrate').setLevel(logging.WARNING) # Disable logging for migration

        latest_db_version = version(repo)

        initialize = True
        try:
            current_db_version = db_version(db, repo)
            initialize = False
        except:
            version_control(db, repo, version = latest_db_version)
            current_db_version = db_version(db, repo)

        if current_db_version < latest_db_version and not debug:
            log.info('Doing database upgrade. From %d to %d' % (current_db_version, latest_db_version))
            upgrade(db, repo)

        # Configure Database
        from couchpotato.core.settings.model import setup
        setup()

        if initialize:
            fireEvent('app.initialize')

        fire_load = True

    # Create app
    from couchpotato import app
    api_key = Env.setting('api_key')
    url_base = '/' + Env.setting('url_base').lstrip('/') if Env.setting('url_base') else ''
    reloader = debug is True and not Env.get('desktop') and not options.daemon

    # Basic config
    app.secret_key = api_key
    config = {
        'use_reloader': reloader,
        'host': Env.setting('host', default = '0.0.0.0'),
        'port': tryInt(Env.setting('port', default = 5000))
    }

    # Static path
    web.add_url_rule('static/<path:filename>',
                      endpoint = 'static',
                      view_func = app.send_static_file)

    # Register modules
    app.register_blueprint(web, url_prefix = '%s/' % url_base)
    app.register_blueprint(api, url_prefix = '%s/%s/' % (url_base, api_key))

    # Some logging and fire load event
    try: log.info('Starting server on port %(port)s' % config)
    except: pass
    if fire_load: fireEventAsync('app.load')

    # Go go go!
    try:
        app.run(**config)
    except (KeyboardInterrupt, SystemExit):
        raise
    except:
        log.error('Failed starting: %s' % traceback.format_exc())
        raise
Exemplo n.º 3
0
def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, Env = None, desktop = None):

    try:
        locale.setlocale(locale.LC_ALL, "")
        encoding = locale.getpreferredencoding()
    except (locale.Error, IOError):
        encoding = None

    # for OSes that are poorly configured I'll just force UTF-8
    if not encoding or encoding in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
        encoding = 'UTF-8'

    # Do db stuff
    db_path = os.path.join(data_dir, 'couchpotato.db')

    # Backup before start and cleanup old databases
    new_backup = os.path.join(data_dir, 'db_backup', str(int(time.time())))

    # Create path and copy
    if not os.path.isdir(new_backup): os.makedirs(new_backup)
    src_files = [options.config_file, db_path, db_path + '-shm', db_path + '-wal']
    for src_file in src_files:
        if os.path.isfile(src_file):
            shutil.copy2(src_file, os.path.join(new_backup, os.path.basename(src_file)))

    # Remove older backups, keep backups 3 days or at least 3
    backups = []
    for directory in os.listdir(os.path.dirname(new_backup)):
        backup = os.path.join(os.path.dirname(new_backup), directory)
        if os.path.isdir(backup):
            backups.append(backup)

    total_backups = len(backups)
    for backup in backups:
        if total_backups > 3:
            if tryInt(os.path.basename(backup)) < time.time() - 259200:
                for src_file in src_files:
                    b_file = os.path.join(backup, os.path.basename(src_file))
                    if os.path.isfile(b_file):
                        os.remove(b_file)
                os.rmdir(backup)
                total_backups -= 1


    # Register environment settings
    Env.set('encoding', encoding)
    Env.set('app_dir', base_path)
    Env.set('data_dir', data_dir)
    Env.set('log_path', os.path.join(log_dir, 'CouchPotato.log'))
    Env.set('db_path', 'sqlite:///' + db_path)
    Env.set('cache_dir', os.path.join(data_dir, 'cache'))
    Env.set('cache', FileSystemCache(os.path.join(Env.get('cache_dir'), 'python')))
    Env.set('console_log', options.console_log)
    Env.set('quiet', options.quiet)
    Env.set('desktop', desktop)
    Env.set('daemonized', options.daemon)
    Env.set('args', args)
    Env.set('options', options)

    # Determine debug
    debug = options.debug or Env.setting('debug', default = False, type = 'bool')
    Env.set('debug', debug)

    # Development
    development = Env.setting('development', default = False, type = 'bool')
    Env.set('dev', development)

    # Disable logging for some modules
    for logger_name in ['enzyme', 'guessit', 'subliminal', 'apscheduler']:
        logging.getLogger(logger_name).setLevel(logging.ERROR)

    for logger_name in ['gntp', 'migrate']:
        logging.getLogger(logger_name).setLevel(logging.WARNING)

    # Use reloader
    reloader = debug is True and development and not Env.get('desktop') and not options.daemon

    # Logger
    logger = logging.getLogger()
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%m-%d %H:%M:%S')
    level = logging.DEBUG if debug else logging.INFO
    logger.setLevel(level)
    logging.addLevelName(19, 'INFO')

    # To screen
    if (debug or options.console_log) and not options.quiet and not options.daemon:
        hdlr = logging.StreamHandler(sys.stderr)
        hdlr.setFormatter(formatter)
        logger.addHandler(hdlr)

    # To file
    hdlr2 = handlers.RotatingFileHandler(Env.get('log_path'), 'a', 500000, 10)
    hdlr2.setFormatter(formatter)
    logger.addHandler(hdlr2)

    # Start logging & enable colors
    import color_logs
    from couchpotato.core.logger import CPLog
    log = CPLog(__name__)
    log.debug('Started with options %s', options)

    def customwarn(message, category, filename, lineno, file = None, line = None):
        log.warning('%s %s %s line:%s', (category, message, filename, lineno))
    warnings.showwarning = customwarn

    # Check if database exists
    db = Env.get('db_path')
    db_exists = os.path.isfile(db_path)

    # Load configs & plugins
    loader = Env.get('loader')
    loader.preload(root = base_path)
    loader.run()

    # Load migrations
    if db_exists:

        from migrate.versioning.api import version_control, db_version, version, upgrade
        repo = os.path.join(base_path, 'couchpotato', 'core', 'migration')

        latest_db_version = version(repo)
        try:
            current_db_version = db_version(db, repo)
        except:
            version_control(db, repo, version = latest_db_version)
            current_db_version = db_version(db, repo)

        if current_db_version < latest_db_version:
            if development:
                log.error('There is a database migration ready, but you are running development mode, so it won\'t be used. If you see this, you are stupid. Please disable development mode.')
            else:
                log.info('Doing database upgrade. From %d to %d', (current_db_version, latest_db_version))
                upgrade(db, repo)

    # Configure Database
    from couchpotato.core.settings.model import setup
    setup()

    # Fill database with needed stuff
    if not db_exists:
        fireEvent('app.initialize', in_order = True)

    # Create app
    from couchpotato import app
    api_key = Env.setting('api_key')
    url_base = '/' + Env.setting('url_base').lstrip('/') if Env.setting('url_base') else ''

    # Basic config
    app.secret_key = api_key
    host = Env.setting('host', default = '0.0.0.0')
    # app.debug = development
    config = {
        'use_reloader': reloader,
        'port': tryInt(Env.setting('port', default = 5000)),
        'host': host if host and len(host) > 0 else '0.0.0.0',
        'ssl_cert': Env.setting('ssl_cert', default = None),
        'ssl_key': Env.setting('ssl_key', default = None),
    }

    # Static path
    app.static_folder = os.path.join(base_path, 'couchpotato', 'static')
    web.add_url_rule('api/%s/static/<path:filename>' % api_key,
                      endpoint = 'static',
                      view_func = app.send_static_file)

    # Register modules
    app.register_blueprint(web, url_prefix = '%s/' % url_base)
    app.register_blueprint(api, url_prefix = '%s/api/%s/' % (url_base, api_key))

    # Some logging and fire load event
    try: log.info('Starting server on port %(port)s', config)
    except: pass
    fireEventAsync('app.load')

    # Go go go!
    from tornado.ioloop import IOLoop
    web_container = WSGIContainer(app)
    web_container._log = _log
    loop = IOLoop.current()


    application = Application([
        (r'%s/api/%s/nonblock/(.*)/' % (url_base, api_key), NonBlockHandler),
        (r'.*', FallbackHandler, dict(fallback = web_container)),
    ],
        log_function = lambda x : None,
        debug = config['use_reloader'],
        gzip = True,
    )

    if config['ssl_cert'] and config['ssl_key']:
        server = HTTPServer(application, no_keep_alive = True, ssl_options = {
           "certfile": config['ssl_cert'],
           "keyfile": config['ssl_key'],
        })
    else:
        server = HTTPServer(application, no_keep_alive = True)

    try_restart = True
    restart_tries = 5

    while try_restart:
        try:
            server.listen(config['port'], config['host'])
            loop.start()
        except Exception, e:
            try:
                nr, msg = e
                if nr == 48:
                    log.info('Already in use, try %s more time after few seconds', restart_tries)
                    time.sleep(1)
                    restart_tries -= 1

                    if restart_tries > 0:
                        continue
                    else:
                        return
            except:
                pass

            raise

        try_restart = False
Exemplo n.º 4
0
def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, Env = None, desktop = None):

    try:
        locale.setlocale(locale.LC_ALL, "")
        encoding = locale.getpreferredencoding()
    except (locale.Error, IOError):
        pass

    # for OSes that are poorly configured I'll just force UTF-8
    if not encoding or encoding in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
        encoding = 'UTF-8'

    # Register environment settings
    Env.set('encoding', encoding)
    Env.set('uses_git', not options.nogit)
    Env.set('app_dir', base_path)
    Env.set('data_dir', data_dir)
    Env.set('log_path', os.path.join(log_dir, 'CouchPotato.log'))
    Env.set('db_path', 'sqlite:///' + os.path.join(data_dir, 'couchpotato.db'))
    Env.set('cache_dir', os.path.join(data_dir, 'cache'))
    Env.set('cache', FileSystemCache(os.path.join(Env.get('cache_dir'), 'python')))
    Env.set('console_log', options.console_log)
    Env.set('quiet', options.quiet)
    Env.set('desktop', desktop)
    Env.set('args', args)
    Env.set('options', options)

    # Determine debug
    debug = options.debug or Env.setting('debug', default = False, type = 'bool')
    Env.set('debug', debug)

    # Development
    development = Env.setting('development', default = False, type = 'bool')
    Env.set('dev', development)
    if not development:
        atexit.register(cleanup)

    # Use reloader
    reloader = debug is True and development and not Env.get('desktop') and not options.daemon

    # Disable server access log
    logging.getLogger('werkzeug').setLevel(logging.WARNING)

    # Only run once when debugging
    fire_load = False
    if os.environ.get('WERKZEUG_RUN_MAIN') or not reloader:

        # Logger
        logger = logging.getLogger()
        formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%H:%M:%S')
        level = logging.DEBUG if debug else logging.INFO
        logger.setLevel(level)

        # To screen
        if (debug or options.console_log) and not options.quiet and not options.daemon:
            hdlr = logging.StreamHandler(sys.stderr)
            hdlr.setFormatter(formatter)
            logger.addHandler(hdlr)

        # To file
        hdlr2 = handlers.RotatingFileHandler(Env.get('log_path'), 'a', 500000, 10)
        hdlr2.setFormatter(formatter)
        logger.addHandler(hdlr2)

        # Start logging & enable colors
        import color_logs
        from couchpotato.core.logger import CPLog
        log = CPLog(__name__)
        log.debug('Started with options %s' % options)

        def customwarn(message, category, filename, lineno, file = None, line = None):
            log.warning('%s %s %s line:%s' % (category, message, filename, lineno))
        warnings.showwarning = customwarn


        # Load configs & plugins
        loader = Env.get('loader')
        loader.preload(root = base_path)
        loader.run()


        # Load migrations
        initialize = True
        db = Env.get('db_path')
        if os.path.isfile(db.replace('sqlite:///', '')):
            initialize = False

            from migrate.versioning.api import version_control, db_version, version, upgrade
            repo = os.path.join(base_path, 'couchpotato', 'core', 'migration')
            logging.getLogger('migrate').setLevel(logging.WARNING) # Disable logging for migration

            latest_db_version = version(repo)
            try:
                current_db_version = db_version(db, repo)
            except:
                version_control(db, repo, version = latest_db_version)
                current_db_version = db_version(db, repo)

            if current_db_version < latest_db_version and not debug:
                log.info('Doing database upgrade. From %d to %d' % (current_db_version, latest_db_version))
                upgrade(db, repo)

        # Configure Database
        from couchpotato.core.settings.model import setup
        setup()

        if initialize:
            fireEvent('app.initialize', in_order = True)

        fire_load = True

    # Create app
    from couchpotato import app
    api_key = Env.setting('api_key')
    url_base = '/' + Env.setting('url_base').lstrip('/') if Env.setting('url_base') else ''

    # Basic config
    app.secret_key = api_key
    config = {
        'use_reloader': reloader,
        'host': Env.setting('host', default = '0.0.0.0'),
        'port': tryInt(Env.setting('port', default = 5000))
    }

    # Static path
    app.static_folder = os.path.join(base_path, 'couchpotato', 'static')
    web.add_url_rule('%s/static/<path:filename>' % api_key,
                      endpoint = 'static',
                      view_func = app.send_static_file)

    # Register modules
    app.register_blueprint(web, url_prefix = '%s/' % url_base)
    app.register_blueprint(api, url_prefix = '%s/%s/' % (url_base, api_key))

    # Some logging and fire load event
    try: log.info('Starting server on port %(port)s' % config)
    except: pass
    if fire_load: fireEventAsync('app.load')

    # Go go go!
    try_restart = True
    restart_tries = 5
    while try_restart:
        try:
            app.run(**config)
        except Exception, e:
            try:
                nr, msg = e
                if nr == 48:
                    log.info('Already in use, try %s more time after few seconds' % restart_tries)
                    time.sleep(1)
                    restart_tries -= 1

                    if restart_tries > 0:
                        continue
                    else:
                        return
            except:
                pass

            raise

        try_restart = False
Exemplo n.º 5
0
def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, Env = None, desktop = None):

    try:
        locale.setlocale(locale.LC_ALL, "")
        encoding = locale.getpreferredencoding()
    except (locale.Error, IOError):
        encoding = None

    # for OSes that are poorly configured I'll just force UTF-8
    if not encoding or encoding in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
        encoding = 'UTF-8'

    # Do db stuff
    db_path = os.path.join(data_dir, 'couchpotato.db')

    # Backup before start and cleanup old databases
    new_backup = os.path.join(data_dir, 'db_backup', str(int(time.time())))

    # Create path and copy
    if not os.path.isdir(new_backup): os.makedirs(new_backup)
    src_files = [options.config_file, db_path, db_path + '-shm', db_path + '-wal']
    for src_file in src_files:
        if os.path.isfile(src_file):
            shutil.copy2(src_file, os.path.join(new_backup, os.path.basename(src_file)))

    # Remove older backups, keep backups 3 days or at least 3
    backups = []
    for directory in os.listdir(os.path.dirname(new_backup)):
        backup = os.path.join(os.path.dirname(new_backup), directory)
        if os.path.isdir(backup):
            backups.append(backup)

    total_backups = len(backups)
    for backup in backups:
        if total_backups > 3:
            if int(os.path.basename(backup)) < time.time() - 259200:
                for src_file in src_files:
                    b_file = os.path.join(backup, os.path.basename(src_file))
                    if os.path.isfile(b_file):
                        os.remove(b_file)
                os.rmdir(backup)
                total_backups -= 1


    # Register environment settings
    Env.set('encoding', encoding)
    Env.set('app_dir', base_path)
    Env.set('data_dir', data_dir)
    Env.set('log_path', os.path.join(log_dir, 'CouchPotato.log'))
    Env.set('db_path', 'sqlite:///' + db_path)
    Env.set('cache_dir', os.path.join(data_dir, 'cache'))
    Env.set('cache', FileSystemCache(os.path.join(Env.get('cache_dir'), 'python')))
    Env.set('console_log', options.console_log)
    Env.set('quiet', options.quiet)
    Env.set('desktop', desktop)
    Env.set('args', args)
    Env.set('options', options)

    # Determine debug
    debug = options.debug or Env.setting('debug', default = False, type = 'bool')
    Env.set('debug', debug)

    # Development
    development = Env.setting('development', default = False, type = 'bool')
    Env.set('dev', development)

    # Disable logging for some modules
    for logger_name in ['enzyme', 'guessit', 'subliminal', 'apscheduler']:
        logging.getLogger(logger_name).setLevel(logging.ERROR)

    for logger_name in ['gntp', 'migrate']:
        logging.getLogger(logger_name).setLevel(logging.WARNING)

    # Use reloader
    reloader = debug is True and development and not Env.get('desktop') and not options.daemon

    # Logger
    logger = logging.getLogger()
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%m-%d %H:%M:%S')
    level = logging.DEBUG if debug else logging.INFO
    logger.setLevel(level)
    logging.addLevelName(19, 'INFO')

    # To screen
    if (debug or options.console_log) and not options.quiet and not options.daemon:
        hdlr = logging.StreamHandler(sys.stderr)
        hdlr.setFormatter(formatter)
        logger.addHandler(hdlr)

    # To file
    hdlr2 = handlers.RotatingFileHandler(Env.get('log_path'), 'a', 500000, 10)
    hdlr2.setFormatter(formatter)
    logger.addHandler(hdlr2)

    # Start logging & enable colors
    import color_logs
    from couchpotato.core.logger import CPLog
    log = CPLog(__name__)
    log.debug('Started with options %s', options)

    def customwarn(message, category, filename, lineno, file = None, line = None):
        log.warning('%s %s %s line:%s', (category, message, filename, lineno))
    warnings.showwarning = customwarn

    # Check if database exists
    db = Env.get('db_path')
    db_exists = os.path.isfile(db_path)

    # Load configs & plugins
    loader = Env.get('loader')
    loader.preload(root = base_path)
    loader.run()

    # Load migrations
    if db_exists:

        from migrate.versioning.api import version_control, db_version, version, upgrade
        repo = os.path.join(base_path, 'couchpotato', 'core', 'migration')

        latest_db_version = version(repo)
        try:
            current_db_version = db_version(db, repo)
        except:
            version_control(db, repo, version = latest_db_version)
            current_db_version = db_version(db, repo)

        if current_db_version < latest_db_version and not development:
            log.info('Doing database upgrade. From %d to %d', (current_db_version, latest_db_version))
            upgrade(db, repo)

    # Configure Database
    from couchpotato.core.settings.model import setup
    setup()

    # Fill database with needed stuff
    if not db_exists:
        fireEvent('app.initialize', in_order = True)

    # Create app
    from couchpotato import app
    api_key = Env.setting('api_key')
    url_base = '/' + Env.setting('url_base').lstrip('/') if Env.setting('url_base') else ''

    # Basic config
    app.secret_key = api_key
    # app.debug = development
    config = {
        'use_reloader': reloader,
        'host': Env.setting('host', default = '0.0.0.0'),
        'port': tryInt(Env.setting('port', default = 5000))
    }

    # Static path
    app.static_folder = os.path.join(base_path, 'couchpotato', 'static')
    web.add_url_rule('api/%s/static/<path:filename>' % api_key,
                      endpoint = 'static',
                      view_func = app.send_static_file)

    # Register modules
    app.register_blueprint(web, url_prefix = '%s/' % url_base)
    app.register_blueprint(api, url_prefix = '%s/api/%s/' % (url_base, api_key))

    # Some logging and fire load event
    try: log.info('Starting server on port %(port)s', config)
    except: pass
    fireEventAsync('app.load')

    # Go go go!
    from tornado.ioloop import IOLoop
    web_container = WSGIContainer(app)
    web_container._log = _log
    loop = IOLoop.instance()

    application = Application([
        (r'%s/api/%s/nonblock/(.*)/' % (url_base, api_key), NonBlockHandler),
        (r'.*', FallbackHandler, dict(fallback = web_container)),
    ],
        log_function = lambda x : None,
        debug = config['use_reloader']
    )

    try_restart = True
    restart_tries = 5

    while try_restart:
        try:
            application.listen(config['port'], config['host'], no_keep_alive = True)
            loop.start()
        except Exception, e:
            try:
                nr, msg = e
                if nr == 48:
                    log.info('Already in use, try %s more time after few seconds', restart_tries)
                    time.sleep(1)
                    restart_tries -= 1

                    if restart_tries > 0:
                        continue
                    else:
                        return
            except:
                pass

            raise

        try_restart = False
Exemplo n.º 6
0
def cmd_couchpotato(base_path, args):
    '''Commandline entry point.'''

    # Options
    parser = ArgumentParser()
    parser.add_argument('-s', '--datadir', default = os.path.join(base_path, '_data'),
                        dest = 'data_dir', help = 'Absolute or ~/ path, where settings/logs/database data is saved (default ./_data)')
    parser.add_argument('-t', '--test', '--debug', action = 'store_true',
                        dest = 'debug', help = 'Debug mode')
    parser.add_argument('-q', '--quiet', action = 'store_true',
                        dest = 'quiet', help = "Don't log to console")
    parser.add_argument('-d', '--daemon', action = 'store_true',
                        dest = 'daemonize', help = 'Daemonize the app')

    options = parser.parse_args(args)


    # Create data dir if needed
    if not os.path.isdir(options.data_dir):
        options.data_dir = os.path.expanduser(options.data_dir)
        os.makedirs(options.data_dir)

    # Create logging dir
    log_dir = os.path.join(options.data_dir, 'logs');
    if not os.path.isdir(log_dir):
        os.mkdir(log_dir)


    # Daemonize app
    if options.daemonize:
        createDaemon()


    # Register environment settings
    from couchpotato.environment import Env
    Env.get('settings').setFile(os.path.join(options.data_dir, 'settings.conf'))
    Env.set('app_dir', base_path)
    Env.set('data_dir', options.data_dir)
    Env.set('db_path', 'sqlite:///' + os.path.join(options.data_dir, 'couchpotato.db'))
    Env.set('cache_dir', os.path.join(options.data_dir, 'cache'))
    Env.set('cache', FileSystemCache(os.path.join(Env.get('cache_dir'), 'python')))
    Env.set('quiet', options.quiet)
    Env.set('daemonize', options.daemonize)
    Env.set('args', args)

    # Determine debug
    debug = options.debug or Env.setting('debug', default = False)
    Env.set('debug', debug)


    # Logger
    logger = logging.getLogger()
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%H:%M:%S')
    level = logging.DEBUG if debug else logging.INFO
    logger.setLevel(level)

    # To screen
    if debug and not options.quiet and not options.daemonize:
        hdlr = logging.StreamHandler(sys.stderr)
        hdlr.setFormatter(formatter)
        logger.addHandler(hdlr)

    # To file
    hdlr2 = handlers.RotatingFileHandler(os.path.join(log_dir, 'CouchPotato.log'), 'a', 5000000, 4)
    hdlr2.setFormatter(formatter)
    logger.addHandler(hdlr2)

    # Disable server access log
    server_log = logging.getLogger('werkzeug')
    server_log.disabled = True

    # Start logging
    from couchpotato.core.logger import CPLog
    log = CPLog(__name__)
    log.debug('Started with options %s' % options)


    # Load configs & plugins
    loader = Env.get('loader')
    loader.preload(root = base_path)
    loader.addModule('core', 'couchpotato.core', 'core')
    loader.run()


    # Load migrations
    from migrate.versioning.api import version_control, db_version, version, upgrade
    db = Env.get('db_path')
    repo = os.path.join('couchpotato', 'core', 'migration')
    logging.getLogger('migrate').setLevel(logging.WARNING) # Disable logging for migration

    latest_db_version = version(repo)

    try:
        current_db_version = db_version(db, repo)
    except:
        version_control(db, repo, version = latest_db_version)
        current_db_version = db_version(db, repo)

    if current_db_version < latest_db_version and not debug:
        log.info('Doing database upgrade. From %d to %d' % (current_db_version, latest_db_version))
        upgrade(db, repo)

    # Configure Database
    from couchpotato.core.settings.model import setup
    setup()

    fireEvent('app.load')

    # Create app
    from couchpotato import app
    api_key = Env.setting('api_key')
    url_base = '/' + Env.setting('url_base') if Env.setting('url_base') else ''
    reloader = debug and not options.daemonize

    # Basic config
    app.host = Env.setting('host', default = '0.0.0.0')
    app.port = Env.setting('port', default = 5000)
    app.debug = debug
    app.secret_key = api_key
    app.static_path = url_base + '/static'

    # Register modules
    app.register_module(web, url_prefix = '%s/' % url_base)
    app.register_module(api, url_prefix = '%s/%s/' % (url_base, api_key))

    # Go go go!
    app.run(use_reloader = reloader)
Exemplo n.º 7
0
def runCouchPotato(options, base_path, args):

    # Load settings
    from couchpotato.environment import Env
    settings = Env.get('settings')
    settings.setFile(options.config_file)

    # Create data dir if needed
    data_dir = os.path.expanduser(Env.setting('data_dir'))
    if data_dir == '':
        data_dir = os.path.join(base_path, '_data')
    if not os.path.isdir(data_dir):
        os.makedirs(data_dir)

    # Create logging dir
    log_dir = os.path.join(data_dir, 'logs')
    if not os.path.isdir(log_dir):
        os.mkdir(log_dir)

    # Daemonize app
    if options.daemonize:
        createDaemon()

    # Register environment settings
    Env.set('uses_git', not options.git)
    Env.set('app_dir', base_path)
    Env.set('data_dir', data_dir)
    Env.set('log_path', os.path.join(log_dir, 'CouchPotato.log'))
    Env.set('db_path', 'sqlite:///' + os.path.join(data_dir, 'couchpotato.db'))
    Env.set('cache_dir', os.path.join(data_dir, 'cache'))
    Env.set('cache',
            FileSystemCache(os.path.join(Env.get('cache_dir'), 'python')))
    Env.set('quiet', options.quiet)
    Env.set('daemonize', options.daemonize)
    Env.set('args', args)

    # Determine debug
    debug = options.debug or Env.setting('debug', default=False)
    Env.set('debug', debug)

    # Only run once when debugging
    if os.environ.get('WERKZEUG_RUN_MAIN') or not debug:

        # Logger
        logger = logging.getLogger()
        formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s',
                                      '%H:%M:%S')
        level = logging.DEBUG if debug else logging.INFO
        logger.setLevel(level)

        # To screen
        if debug and not options.quiet and not options.daemonize:
            hdlr = logging.StreamHandler(sys.stderr)
            hdlr.setFormatter(formatter)
            logger.addHandler(hdlr)

        # To file
        hdlr2 = handlers.RotatingFileHandler(Env.get('log_path'), 'a', 500000,
                                             10)
        hdlr2.setFormatter(formatter)
        logger.addHandler(hdlr2)

        # Disable server access log
        server_log = logging.getLogger('werkzeug')
        server_log.disabled = True

        # Start logging
        from couchpotato.core.logger import CPLog
        log = CPLog(__name__)
        log.debug('Started with options %s' % options)

        # Load configs & plugins
        loader = Env.get('loader')
        loader.preload(root=base_path)
        loader.run()

        # Load migrations
        from migrate.versioning.api import version_control, db_version, version, upgrade
        db = Env.get('db_path')
        repo = os.path.join(base_path, 'couchpotato', 'core', 'migration')
        logging.getLogger('migrate').setLevel(
            logging.WARNING)  # Disable logging for migration

        latest_db_version = version(repo)

        initialize = True
        try:
            current_db_version = db_version(db, repo)
            initialize = False
        except:
            version_control(db, repo, version=latest_db_version)
            current_db_version = db_version(db, repo)

        if current_db_version < latest_db_version and not debug:
            log.info('Doing database upgrade. From %d to %d' %
                     (current_db_version, latest_db_version))
            upgrade(db, repo)

        # Configure Database
        from couchpotato.core.settings.model import setup
        setup()

        fireEventAsync('app.load')

        if initialize:
            fireEventAsync('app.initialize')

    # Create app
    from couchpotato import app
    api_key = Env.setting('api_key')
    url_base = '/' + Env.setting('url_base').lstrip('/') if Env.setting(
        'url_base') else ''
    reloader = debug and not options.daemonize

    # Basic config
    app.secret_key = api_key
    config = {
        'use_reloader': reloader,
        'host': Env.setting('host', default='0.0.0.0'),
        'port': Env.setting('port', default=5000)
    }

    # Static path
    web.add_url_rule(url_base + '/static/<path:filename>',
                     endpoint='static',
                     view_func=app.send_static_file)

    # Register modules
    app.register_blueprint(web, url_prefix='%s/' % url_base)
    app.register_blueprint(api, url_prefix='%s/%s/' % (url_base, api_key))

    # Go go go!
    app.run(**config)
Exemplo n.º 8
0
def runCouchPotato(options, base_path, args, data_dir=None, log_dir=None, Env=None, desktop=None):

    try:
        locale.setlocale(locale.LC_ALL, "")
        encoding = locale.getpreferredencoding()
    except (locale.Error, IOError):
        encoding = None

    # for OSes that are poorly configured I'll just force UTF-8
    if not encoding or encoding in ("ANSI_X3.4-1968", "US-ASCII", "ASCII"):
        encoding = "UTF-8"

    # Do db stuff
    db_path = os.path.join(data_dir, "couchpotato.db")

    # Backup before start and cleanup old databases
    new_backup = os.path.join(data_dir, "db_backup", str(int(time.time())))

    # Create path and copy
    if not os.path.isdir(new_backup):
        os.makedirs(new_backup)
    src_files = [options.config_file, db_path, db_path + "-shm", db_path + "-wal"]
    for src_file in src_files:
        if os.path.isfile(src_file):
            shutil.copy2(src_file, os.path.join(new_backup, os.path.basename(src_file)))

    # Remove older backups, keep backups 3 days or at least 3
    backups = []
    for directory in os.listdir(os.path.dirname(new_backup)):
        backup = os.path.join(os.path.dirname(new_backup), directory)
        if os.path.isdir(backup):
            backups.append(backup)

    total_backups = len(backups)
    for backup in backups:
        if total_backups > 3:
            if int(os.path.basename(backup)) < time.time() - 259200:
                for src_file in src_files:
                    b_file = os.path.join(backup, os.path.basename(src_file))
                    if os.path.isfile(b_file):
                        os.remove(b_file)
                os.rmdir(backup)
                total_backups -= 1

    # Register environment settings
    Env.set("encoding", encoding)
    Env.set("app_dir", base_path)
    Env.set("data_dir", data_dir)
    Env.set("log_path", os.path.join(log_dir, "CouchPotato.log"))
    Env.set("db_path", "sqlite:///" + db_path)
    Env.set("cache_dir", os.path.join(data_dir, "cache"))
    Env.set("cache", FileSystemCache(os.path.join(Env.get("cache_dir"), "python")))
    Env.set("console_log", options.console_log)
    Env.set("quiet", options.quiet)
    Env.set("desktop", desktop)
    Env.set("args", args)
    Env.set("options", options)

    # Determine debug
    debug = options.debug or Env.setting("debug", default=False, type="bool")
    Env.set("debug", debug)

    # Development
    development = Env.setting("development", default=False, type="bool")
    Env.set("dev", development)

    # Disable logging for some modules
    for logger_name in ["enzyme", "guessit", "subliminal", "apscheduler"]:
        logging.getLogger(logger_name).setLevel(logging.ERROR)

    for logger_name in ["gntp", "migrate"]:
        logging.getLogger(logger_name).setLevel(logging.WARNING)

    # Use reloader
    reloader = debug is True and development and not Env.get("desktop") and not options.daemon

    # Logger
    logger = logging.getLogger()
    formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s", "%m-%d %H:%M:%S")
    level = logging.DEBUG if debug else logging.INFO
    logger.setLevel(level)
    logging.addLevelName(19, "INFO")

    # To screen
    if (debug or options.console_log) and not options.quiet and not options.daemon:
        hdlr = logging.StreamHandler(sys.stderr)
        hdlr.setFormatter(formatter)
        logger.addHandler(hdlr)

    # To file
    hdlr2 = handlers.RotatingFileHandler(Env.get("log_path"), "a", 500000, 10)
    hdlr2.setFormatter(formatter)
    logger.addHandler(hdlr2)

    # Start logging & enable colors
    import color_logs
    from couchpotato.core.logger import CPLog

    log = CPLog(__name__)
    log.debug("Started with options %s", options)

    def customwarn(message, category, filename, lineno, file=None, line=None):
        log.warning("%s %s %s line:%s", (category, message, filename, lineno))

    warnings.showwarning = customwarn

    # Check if database exists
    db = Env.get("db_path")
    db_exists = os.path.isfile(db_path)

    # Load configs & plugins
    loader = Env.get("loader")
    loader.preload(root=base_path)
    loader.run()

    # Load migrations
    if db_exists:

        from migrate.versioning.api import version_control, db_version, version, upgrade

        repo = os.path.join(base_path, "couchpotato", "core", "migration")

        latest_db_version = version(repo)
        try:
            current_db_version = db_version(db, repo)
        except:
            version_control(db, repo, version=latest_db_version)
            current_db_version = db_version(db, repo)

        if current_db_version < latest_db_version and not debug:
            log.info("Doing database upgrade. From %d to %d", (current_db_version, latest_db_version))
            upgrade(db, repo)

    # Configure Database
    from couchpotato.core.settings.model import setup

    setup()

    # Fill database with needed stuff
    if not db_exists:
        fireEvent("app.initialize", in_order=True)

    # Create app
    from couchpotato import app

    api_key = Env.setting("api_key")
    url_base = "/" + Env.setting("url_base").lstrip("/") if Env.setting("url_base") else ""

    # Basic config
    app.secret_key = api_key
    # app.debug = development
    config = {
        "use_reloader": reloader,
        "host": Env.setting("host", default="0.0.0.0"),
        "port": tryInt(Env.setting("port", default=5000)),
    }

    # Static path
    app.static_folder = os.path.join(base_path, "couchpotato", "static")
    web.add_url_rule("api/%s/static/<path:filename>" % api_key, endpoint="static", view_func=app.send_static_file)

    # Register modules
    app.register_blueprint(web, url_prefix="%s/" % url_base)
    app.register_blueprint(api, url_prefix="%s/api/%s/" % (url_base, api_key))

    # Some logging and fire load event
    try:
        log.info("Starting server on port %(port)s", config)
    except:
        pass
    fireEventAsync("app.load")

    # Go go go!
    web_container = WSGIContainer(app)
    web_container._log = _log
    loop = IOLoop.instance()

    application = Application(
        [
            (r"%s/api/%s/nonblock/(.*)/" % (url_base, api_key), NonBlockHandler),
            (r".*", FallbackHandler, dict(fallback=web_container)),
        ],
        log_function=lambda x: None,
        debug=config["use_reloader"],
    )

    try_restart = True
    restart_tries = 5

    while try_restart:
        try:
            application.listen(config["port"], config["host"], no_keep_alive=True)
            loop.start()
        except Exception, e:
            try:
                nr, msg = e
                if nr == 48:
                    log.info("Already in use, try %s more time after few seconds", restart_tries)
                    time.sleep(1)
                    restart_tries -= 1

                    if restart_tries > 0:
                        continue
                    else:
                        return
            except:
                pass

            raise

        try_restart = False
Exemplo n.º 9
0
def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, Env = None, desktop = None):

    try:
        locale.setlocale(locale.LC_ALL, "")
        encoding = locale.getpreferredencoding()
    except (locale.Error, IOError):
        encoding = None

    # for OSes that are poorly configured I'll just force UTF-8
    if not encoding or encoding in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
        encoding = 'UTF-8'

    Env.set('encoding', encoding)

    # Do db stuff
    db_path = toUnicode(os.path.join(data_dir, 'couchpotato.db'))

    # Backup before start and cleanup old databases
    new_backup = toUnicode(os.path.join(data_dir, 'db_backup', str(int(time.time()))))
    if not os.path.isdir(new_backup): os.makedirs(new_backup)

    # Remove older backups, keep backups 3 days or at least 3
    backups = []
    for directory in os.listdir(os.path.dirname(new_backup)):
        backup = toUnicode(os.path.join(os.path.dirname(new_backup), directory))
        if os.path.isdir(backup):
            backups.append(backup)

    latest_backup = tryInt(os.path.basename(sorted(backups)[-1])) if len(backups) > 0 else 0
    if latest_backup < time.time() - 3600:
        # Create path and copy
        src_files = [options.config_file, db_path, db_path + '-shm', db_path + '-wal']
        for src_file in src_files:
            if os.path.isfile(src_file):
                dst_file = toUnicode(os.path.join(new_backup, os.path.basename(src_file)))
                shutil.copyfile(src_file, dst_file)

                # Try and copy stats seperately
                try: shutil.copystat(src_file, dst_file)
                except: pass

    total_backups = len(backups)
    for backup in backups:
        if total_backups > 3:
            if tryInt(os.path.basename(backup)) < time.time() - 259200:
                for the_file in os.listdir(backup):
                    file_path = os.path.join(backup, the_file)
                    try:
                        if os.path.isfile(file_path):
                            os.remove(file_path)
                    except:
                        raise

                os.rmdir(backup)
                total_backups -= 1


    # Register environment settings
    Env.set('app_dir', toUnicode(base_path))
    Env.set('data_dir', toUnicode(data_dir))
    Env.set('log_path', toUnicode(os.path.join(log_dir, 'CouchPotato.log')))
    Env.set('db_path', toUnicode('sqlite:///' + db_path))
    Env.set('cache_dir', toUnicode(os.path.join(data_dir, 'cache')))
    Env.set('cache', FileSystemCache(toUnicode(os.path.join(Env.get('cache_dir'), 'python'))))
    Env.set('console_log', options.console_log)
    Env.set('quiet', options.quiet)
    Env.set('desktop', desktop)
    Env.set('daemonized', options.daemon)
    Env.set('args', args)
    Env.set('options', options)

    # Determine debug
    debug = options.debug or Env.setting('debug', default = False, type = 'bool')
    Env.set('debug', debug)

    # Development
    development = Env.setting('development', default = False, type = 'bool')
    Env.set('dev', development)

    # Disable logging for some modules
    for logger_name in ['enzyme', 'guessit', 'subliminal', 'apscheduler', 'tornado', 'requests']:
        logging.getLogger(logger_name).setLevel(logging.ERROR)

    for logger_name in ['gntp', 'migrate']:
        logging.getLogger(logger_name).setLevel(logging.WARNING)

    # Use reloader
    reloader = debug is True and development and not Env.get('desktop') and not options.daemon

    # Logger
    logger = logging.getLogger()
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%m-%d %H:%M:%S')
    level = logging.DEBUG if debug else logging.INFO
    logger.setLevel(level)
    logging.addLevelName(19, 'INFO')

    # To screen
    if (debug or options.console_log) and not options.quiet and not options.daemon:
        hdlr = logging.StreamHandler(sys.stderr)
        hdlr.setFormatter(formatter)
        logger.addHandler(hdlr)

    # To file
    hdlr2 = handlers.RotatingFileHandler(Env.get('log_path'), 'a', 500000, 10, encoding = Env.get('encoding'))
    hdlr2.setFormatter(formatter)
    logger.addHandler(hdlr2)

    # Start logging & enable colors
    import color_logs
    from couchpotato.core.logger import CPLog
    log = CPLog(__name__)
    log.debug('Started with options %s', options)

    def customwarn(message, category, filename, lineno, file = None, line = None):
        log.warning('%s %s %s line:%s', (category, message, filename, lineno))
    warnings.showwarning = customwarn

    # Check if database exists
    db = Env.get('db_path')
    db_exists = os.path.isfile(toUnicode(db_path))

    # Load migrations
    if db_exists:

        from migrate.versioning.api import version_control, db_version, version, upgrade
        repo = os.path.join(base_path, 'couchpotato', 'core', 'migration')

        latest_db_version = version(repo)
        try:
            current_db_version = db_version(db, repo)
        except:
            version_control(db, repo, version = latest_db_version)
            current_db_version = db_version(db, repo)

        if current_db_version < latest_db_version:
            if development:
                log.error('There is a database migration ready, but you are running development mode, so it won\'t be used. If you see this, you are stupid. Please disable development mode.')
            else:
                log.info('Doing database upgrade. From %d to %d', (current_db_version, latest_db_version))
                upgrade(db, repo)

    # Configure Database
    from couchpotato.core.settings.model import setup
    setup()

    # Create app
    from couchpotato import WebHandler
    web_base = ('/' + Env.setting('url_base').lstrip('/') + '/') if Env.setting('url_base') else '/'
    Env.set('web_base', web_base)

    api_key = Env.setting('api_key')
    if not api_key:
        api_key = uuid4().hex
        Env.setting('api_key', value = api_key)

    api_base = r'%sapi/%s/' % (web_base, api_key)
    Env.set('api_base', api_base)

    # Basic config
    host = Env.setting('host', default = '0.0.0.0')
    # app.debug = development
    config = {
        'use_reloader': reloader,
        'port': tryInt(Env.setting('port', default = 5050)),
        'host': host if host and len(host) > 0 else '0.0.0.0',
        'ssl_cert': Env.setting('ssl_cert', default = None),
        'ssl_key': Env.setting('ssl_key', default = None),
    }


    # Load the app
    application = Application([],
        log_function = lambda x : None,
        debug = config['use_reloader'],
        gzip = True,
        cookie_secret = api_key,
        login_url = '%slogin/' % web_base,
    )
    Env.set('app', application)

    # Request handlers
    application.add_handlers(".*$", [
        (r'%snonblock/(.*)(/?)' % api_base, NonBlockHandler),

        # API handlers
        (r'%s(.*)(/?)' % api_base, ApiHandler), # Main API handler
        (r'%sgetkey(/?)' % web_base, KeyHandler), # Get API key
        (r'%s' % api_base, RedirectHandler, {"url": web_base + 'docs/'}), # API docs

        # Login handlers
        (r'%slogin(/?)' % web_base, LoginHandler),
        (r'%slogout(/?)' % web_base, LogoutHandler),

        # Catch all webhandlers
        (r'%s(.*)(/?)' % web_base, WebHandler),
        (r'(.*)', WebHandler),
    ])

    # Static paths
    static_path = '%sstatic/' % web_base
    for dir_name in ['fonts', 'images', 'scripts', 'style']:
        application.add_handlers(".*$", [
             ('%s%s/(.*)' % (static_path, dir_name), StaticFileHandler, {'path': toUnicode(os.path.join(base_path, 'couchpotato', 'static', dir_name))})
        ])
    Env.set('static_path', static_path)


    # Load configs & plugins
    loader = Env.get('loader')
    loader.preload(root = toUnicode(base_path))
    loader.run()


    # Fill database with needed stuff
    if not db_exists:
        fireEvent('app.initialize', in_order = True)


    # Go go go!
    from tornado.ioloop import IOLoop
    loop = IOLoop.current()


    # Some logging and fire load event
    try: log.info('Starting server on port %(port)s', config)
    except: pass
    fireEventAsync('app.load')


    if config['ssl_cert'] and config['ssl_key']:
        server = HTTPServer(application, no_keep_alive = True, ssl_options = {
           "certfile": config['ssl_cert'],
           "keyfile": config['ssl_key'],
        })
    else:
        server = HTTPServer(application, no_keep_alive = True)

    try_restart = True
    restart_tries = 5

    while try_restart:
        try:
            server.listen(config['port'], config['host'])
            loop.start()
        except Exception, e:
            log.error('Failed starting: %s', traceback.format_exc())
            try:
                nr, msg = e
                if nr == 48:
                    log.info('Port (%s) needed for CouchPotato is already in use, try %s more time after few seconds', (config.get('port'), restart_tries))
                    time.sleep(1)
                    restart_tries -= 1

                    if restart_tries > 0:
                        continue
                    else:
                        return
            except:
                pass

            raise

        try_restart = False
Exemplo n.º 10
0
def runCouchPotato(options, base_path, args):

    # Load settings
    from couchpotato.environment import Env
    settings = Env.get('settings')
    settings.setFile(options.config_file)

    # Create data dir if needed
    data_dir = os.path.expanduser(Env.setting('data_dir'))
    if data_dir == '':
        data_dir = os.path.join(base_path, '_data')
    if not os.path.isdir(data_dir):
        os.makedirs(data_dir)

    # Create logging dir
    log_dir = os.path.join(data_dir, 'logs');
    if not os.path.isdir(log_dir):
        os.mkdir(log_dir)

    # Daemonize app
    if options.daemonize:
        createDaemon()


    # Register environment settings
    Env.set('uses_git', not options.git)
    Env.set('app_dir', base_path)
    Env.set('data_dir', data_dir)
    Env.set('log_path', os.path.join(log_dir, 'CouchPotato.log'))
    Env.set('db_path', 'sqlite:///' + os.path.join(data_dir, 'couchpotato.db'))
    Env.set('cache_dir', os.path.join(data_dir, 'cache'))
    Env.set('cache', FileSystemCache(os.path.join(Env.get('cache_dir'), 'python')))
    Env.set('quiet', options.quiet)
    Env.set('daemonize', options.daemonize)
    Env.set('args', args)

    # Determine debug
    debug = options.debug or Env.setting('debug', default = False)
    Env.set('debug', debug)

    # Only run once when debugging
    if os.environ.get('WERKZEUG_RUN_MAIN') or not debug:

        # Logger
        logger = logging.getLogger()
        formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%H:%M:%S')
        level = logging.DEBUG if debug else logging.INFO
        logger.setLevel(level)

        # To screen
        if debug and not options.quiet and not options.daemonize:
            hdlr = logging.StreamHandler(sys.stderr)
            hdlr.setFormatter(formatter)
            logger.addHandler(hdlr)

        # To file
        hdlr2 = handlers.RotatingFileHandler(Env.get('log_path'), 'a', 500000, 10)
        hdlr2.setFormatter(formatter)
        logger.addHandler(hdlr2)

        # Disable server access log
        server_log = logging.getLogger('werkzeug')
        server_log.disabled = True

        # Start logging
        from couchpotato.core.logger import CPLog
        log = CPLog(__name__)
        log.debug('Started with options %s' % options)


        # Load configs & plugins
        loader = Env.get('loader')
        loader.preload(root = base_path)
        loader.run()


        # Load migrations
        from migrate.versioning.api import version_control, db_version, version, upgrade
        db = Env.get('db_path')
        repo = os.path.join(base_path, 'couchpotato', 'core', 'migration')
        logging.getLogger('migrate').setLevel(logging.WARNING) # Disable logging for migration

        latest_db_version = version(repo)

        initialize = True
        try:
            current_db_version = db_version(db, repo)
            initialize = False
        except:
            version_control(db, repo, version = latest_db_version)
            current_db_version = db_version(db, repo)

        if current_db_version < latest_db_version and not debug:
            log.info('Doing database upgrade. From %d to %d' % (current_db_version, latest_db_version))
            upgrade(db, repo)

        # Configure Database
        from couchpotato.core.settings.model import setup
        setup()

        fireEventAsync('app.load')

        if initialize:
            fireEventAsync('app.initialize')

    # Create app
    from couchpotato import app
    api_key = Env.setting('api_key')
    url_base = '/' + Env.setting('url_base').lstrip('/') if Env.setting('url_base') else ''
    reloader = debug and not options.daemonize

    # Basic config
    app.secret_key = api_key
    config = {
        'use_reloader': reloader,
        'host': Env.setting('host', default = '0.0.0.0'),
        'port': Env.setting('port', default = 5000)
    }

    # Static path
    web.add_url_rule(url_base + '/static/<path:filename>',
                      endpoint = 'static',
                      view_func = app.send_static_file)

    # Register modules
    app.register_blueprint(web, url_prefix = '%s/' % url_base)
    app.register_blueprint(api, url_prefix = '%s/%s/' % (url_base, api_key))

    # Go go go!
    app.run(**config)