""" Playlist Monitor Service - Main FastAPI Application """ import asyncio import logging from contextlib import asynccontextmanager from typing import AsyncGenerator import uvicorn from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from .api import playlists, videos, system from .core.config import settings from .core.database import engine, Base from .core.scheduler import scheduler_manager from .services.metube_client import MeTubeClient # Configure logging logging.basicConfig( level=getattr(logging, settings.LOG_LEVEL), format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", handlers=[ logging.StreamHandler(), logging.FileHandler(settings.LOG_FILE) if settings.LOG_FILE else logging.NullHandler() ] ) logger = logging.getLogger(__name__) # Global MeTube client instance metube_client: MeTubeClient | None = None @asynccontextmanager async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: """Application lifespan manager""" global metube_client logger.info("Starting Playlist Monitor Service...") # Create database tables logger.info("Creating database tables...") Base.metadata.create_all(bind=engine) # Initialize MeTube client logger.info("Initializing MeTube client...") metube_client = MeTubeClient(settings.METUBE_URL) await metube_client.connect() # Start scheduler logger.info("Starting scheduler...") scheduler_manager.start() logger.info("Playlist Monitor Service started successfully") yield # Cleanup on shutdown logger.info("Shutting down Playlist Monitor Service...") # Stop scheduler scheduler_manager.shutdown() # Disconnect MeTube client if metube_client: await metube_client.disconnect() logger.info("Playlist Monitor Service shut down complete") # Create FastAPI app app = FastAPI( title="Playlist Monitor Service", description="Automated playlist monitoring service for MeTube", version="0.1.0", lifespan=lifespan ) # Add CORS middleware app.add_middleware( CORSMiddleware, allow_origins=settings.CORS_ORIGINS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Include routers app.include_router(playlists.router, prefix="/api/playlists", tags=["playlists"]) app.include_router(videos.router, prefix="/api/videos", tags=["videos"]) app.include_router(system.router, prefix="/api", tags=["system"]) @app.get("/") async def root(): """Root endpoint""" return { "service": "Playlist Monitor Service", "version": "0.1.0", "status": "running", "docs": "/docs" } @app.get("/health") async def health_check(): """Health check endpoint""" try: # Check database connection from .core.database import SessionLocal db = SessionLocal() db.execute("SELECT 1") db.close() # Check MeTube connection metube_status = await metube_client.health_check() if metube_client else False return { "status": "healthy", "database": "connected", "metube": "connected" if metube_status else "disconnected" } except Exception as e: logger.error(f"Health check failed: {e}") raise HTTPException(status_code=503, detail="Service unhealthy") if __name__ == "__main__": uvicorn.run( "app.main:app", host=settings.HOST, port=settings.PORT, reload=settings.DEBUG, log_level=settings.LOG_LEVEL.lower() )