from __future__ import annotations import argparse import asyncio import logging import signal import sys from typing import List from src.config import AppConfig from src.jellyfin.client import JellyfinClient from src.player.mpv_controller import MpvController from src.remotes.kodi_rpc import KodiRpcServer from src.remotes.rest_api import RestApiServer logger = logging.getLogger("jellyfin_client") def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="Jellyfin HTPC Client & YouTube Player") parser.add_argument("-c", "--config", help="Path to config.yaml file") parser.add_argument("-d", "--debug", action="store_true", help="Enable debug logging") return parser.parse_args() async def run_app(config: AppConfig) -> None: player = MpvController(config.player) jellyfin = JellyfinClient(config.jellyfin, player) kodi_rpc = KodiRpcServer(config.kodi_rpc, player) rest_api = RestApiServer(config.web_api, player) # Start services await player.start() await jellyfin.start() await kodi_rpc.start() await rest_api.start() logger.info("Jellyfin HTPC Client is fully initialized and ready.") # Setup signal handling for graceful shutdown loop = asyncio.get_running_loop() stop_event = asyncio.Event() def _sig_handler() -> None: logger.info("Shutdown signal received") stop_event.set() for sig in (signal.SIGINT, signal.SIGTERM): try: loop.add_signal_handler(sig, _sig_handler) except NotImplementedError: pass # Windows or non-main thread await stop_event.wait() logger.info("Shutting down services...") await rest_api.shutdown() await kodi_rpc.shutdown() await jellyfin.shutdown() await player.shutdown() logger.info("Graceful shutdown complete.") def main() -> None: args = parse_args() log_level = logging.DEBUG if args.debug else logging.INFO logging.basicConfig( level=log_level, format="%(asctime)s [%(levelname)s] (%(name)s) %(message)s", datefmt="%Y-%m-%d %H:%M:%S", ) config = AppConfig.load(args.config) try: asyncio.run(run_app(config)) except KeyboardInterrupt: pass except Exception as e: logger.critical("Fatal error: %s", e, exc_info=True) sys.exit(1) if __name__ == "__main__": main()