Example #1
0
def run_forever(args, config):
    # ensure requiresments, raise SystemExit if failed
    os.chdir(os.path.join(os.path.dirname(__file__), '../..'))
    ensure_dirs()

    # In an ideal world, users are capable to do anything in rcfile,
    # including monkeypatch, so we should load rcfile as early as possible
    fuoexec_load_rcfile(config)

    # Extract config items from args and setup config object,
    # since then, no more `args` object, only `config`.
    setup_config(args, config)

    setup_logger(config)

    # create app instance with config
    #
    # nothing should happen except all objects are created
    app = create_app(config)

    # do fuoexec initialization before app inits
    fuoexec_init(app)

    # initialize app with config
    #
    # all objects can do initialization here. some objects may emit signal,
    # some objects may connect with others signals.
    init_app(app)

    app.initialized.emit(app)

    run_app(app)
Example #2
0
def main():
    parser = setup_argparse()
    args = parser.parse_args()

    if args.version:
        print('feeluown {}, fuocore {}'.format(feeluown_version,
                                               fuocore_version))
        return

    if is_port_used(23333) or is_port_used(23334):
        print('\033[0;31m', end='')
        print(
            'Port(23333 or 23334) is used, maybe another feeluown is running?')
        print('\033[0m', end='')
        sys.exit(1)

    debug = args.debug
    mpv_audio_device = args.mpv_audio_device
    cli_only = args.no_window
    logger_config(debug, to_file=args.log_to_file)

    load_rcfile()

    player_kwargs = dict(audio_device=bytes(mpv_audio_device, 'utf-8'))

    # 设置 exception hook
    sys.excepthook = excepthook

    if not cli_only:
        try:
            import PyQt5  # noqa
        except ImportError:
            logger.warning('PyQt5 is not installed,can only use CLI mode.')
            cli_only = True

    if not cli_only:
        from PyQt5.QtWidgets import QApplication
        from quamash import QEventLoop

        q_app = QApplication(sys.argv)
        q_app.setQuitOnLastWindowClosed(True)
        q_app.setApplicationName('FeelUOwn')

        app_event_loop = QEventLoop(q_app)
        asyncio.set_event_loop(app_event_loop)

    mode = App.CliMode if cli_only else App.GuiMode
    app = create_app(mode, **player_kwargs)
    bind_signals(app)

    event_loop = asyncio.get_event_loop()
    try:
        event_loop.run_forever()
        logger.info('Event loop stopped.')
    except KeyboardInterrupt:
        # NOTE: gracefully shutdown?
        app.shutdown()
    finally:
        event_loop.close()
Example #3
0
def setup_app(args, config):
    if config.DEBUG:
        verbose = 3
    else:
        verbose = args.verbose or 0
    logger_config(verbose=verbose, to_file=config.LOG_TO_FILE)
    Signal.setup_aio_support()
    app = create_app(config)
    return app
Example #4
0
async def start_app(args, config, sentinal=None):
    """
    The param sentinal is currently only used for unittest.
    """
    Signal.setup_aio_support()

    app = create_app(args, config)

    # Do fuoexec initialization before app initialization.
    fuoexec_init(app)

    # Initialize app with config.
    #
    # all objects can do initialization here. some objects may emit signal,
    # some objects may connect with others signals.
    app.initialize()
    app.initialized.emit(app)

    # Load last state.
    app.load_state()

    def sighanlder(signum, _):
        logger.info('Signal %d is received', signum)
        app.exit()

    # Handle signals.
    signal.signal(signal.SIGTERM, sighanlder)
    signal.signal(signal.SIGINT, sighanlder)

    if sentinal is None:
        sentinal: asyncio.Future = asyncio.Future()

    def shutdown(_):
        # Since about_to_shutdown signal may emit multiple times
        # (QApplication.aboutToQuit emits multiple times),
        # we should check if it is already done firstly.
        if not sentinal.done():
            sentinal.set_result(0)

    app.about_to_shutdown.connect(shutdown, weak=False)

    # App can exit in several ways.
    #
    # GUI mode:
    # 1. QApplication.quit. QApplication.quit can be called under several circumstances
    #    1. User press CMD-Q on macOS.
    #    2. User clicks the tray icon exit button.
    # 2. SIGTERM is received.
    #
    # Daemon mode:
    # 1. Ctrl-C
    # 2. SIGTERM
    app.run()
    await sentinal

    Signal.teardown_aio_support()
Example #5
0
def main():
    # 让程序能正确的找到图标等资源
    os.chdir(os.path.join(os.path.dirname(__file__), '..'))
    sys.excepthook = excepthook

    parser = setup_argparse()
    args = parser.parse_args()

    if args.version:
        print('feeluown {}, fuocore {}'.format(feeluown_version,
                                               fuocore_version))
        return

    check_ports()
    ensure_dirs()
    config = create_config()
    load_rcfile(config)
    map_args_to_config(args, config)
    logger_config(config.DEBUG, to_file=args.log_to_file)

    if config.MODE & App.GuiMode:
        try:
            import PyQt5  # noqa
        except ImportError:
            logger.warning('PyQt5 is not installed,can only use CLI mode.')
            config.MODE = App.CliMode

    if config.MODE & App.GuiMode:
        from PyQt5.QtWidgets import QApplication
        from quamash import QEventLoop

        q_app = QApplication(sys.argv)
        q_app.setQuitOnLastWindowClosed(True)
        q_app.setApplicationName('FeelUOwn')

        app_event_loop = QEventLoop(q_app)
        asyncio.set_event_loop(app_event_loop)

    event_loop = asyncio.get_event_loop()
    Signal.setup_aio_support(loop=event_loop)
    app = create_app(config)
    bind_signals(app)
    if sys.platform.lower() == 'darwin':
        enable_mac_hotkey(force=config.FORCE_MAC_HOTKEY)
    try:
        event_loop.run_forever()
    except KeyboardInterrupt:
        # NOTE: gracefully shutdown?
        pass
    finally:
        event_loop.stop()
        app.shutdown()
        event_loop.close()
Example #6
0
def run_once(args, config):
    # ignore all warnings since it will pollute the output
    warnings.filterwarnings("ignore")

    fuoexec_load_rcfile(config)
    setup_config(args, config)
    app = create_app(config)
    fuoexec_init(app)
    init_app(app)
    app.initialized.emit(app)

    future = oncemain(app, args)
    if future is not None:
        run_app_once(app, future)
Example #7
0
def setup_app(args, config):
    logger_config(config.DEBUG, to_file=config.LOG_TO_FILE)
    Signal.setup_aio_support()
    app = create_app(config)
    bind_signals(app)
    return app
Example #8
0
async def test_create_cli_app(args_test, config, noharm):
    config.MODE = AppMode.cli
    app = create_app(args_test, config=config)
    assert not app.has_server and not app.has_gui
Example #9
0
async def test_create_server_app(args, config, noharm):
    config.MODE = AppMode.server
    app = create_app(args, config=config)
    assert app.has_server and not app.has_gui