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