Files
AudiOhm/backend/app/main.py
T
root 801e6a050b prod: UI Optimisée mise en production
- Documentation archivée et réorganisée
- Backend: Ajout tests, migrations, library service, rate limiting
- Frontend: Suppression Flutter, focus sur interface web HTML/JS
- Tailwind CSS ajouté pour le style
- Améliorations UX et corrections bugs

Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-01-20 09:56:39 +00:00

143 lines
3.8 KiB
Python

"""Main FastAPI application entry point."""
import logging
from contextlib import asynccontextmanager
from pathlib import Path
from typing import AsyncGenerator
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse, HTMLResponse
from fastapi.staticfiles import StaticFiles
from slowapi.errors import RateLimitExceeded
from app.core.config import settings
from app.core.database import close_db, init_db
from app.core.rate_limiter import limiter
logger = logging.getLogger(__name__)
# Get the base directory
BASE_DIR = Path(__file__).resolve().parent.parent
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
"""
Lifespan context manager for FastAPI application.
Handles startup and shutdown events.
"""
# Startup
logger.info("Starting up...")
if settings.DEBUG:
logger.debug("Debug mode is ON")
logger.debug(f"Database URL: {settings.DATABASE_URL}")
logger.debug(f"Redis URL: {settings.FULL_REDIS_URL}")
# Initialize database
await init_db()
logger.info("Database initialized")
yield
# Shutdown
logger.info("Shutting down...")
await close_db()
logger.info("Database connections closed")
# Create FastAPI application
app = FastAPI(
title=settings.APP_NAME,
version=settings.APP_VERSION,
description="Alternative to Spotify with YouTube streaming",
docs_url="/api/docs",
redoc_url="/api/redoc",
openapi_url="/api/openapi.json",
lifespan=lifespan,
)
# Set up rate limiting
app.state.limiter = limiter
# Configure CORS
app.add_middleware(
CORSMiddleware,
allow_origins=settings.BACKEND_CORS_ORIGINS,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/", response_class=HTMLResponse)
async def root() -> str:
"""Serve the web application."""
template_path = BASE_DIR / "app" / "templates" / "index.html"
with open(template_path, 'r', encoding='utf-8') as f:
return f.read()
@app.get("/health")
async def health_check() -> dict[str, str]:
"""Health check endpoint."""
return {"status": "healthy"}
@app.get("/api/v1")
async def api_v1_info() -> dict[str, str]:
"""API v1 information endpoint."""
return {
"version": "v1",
"prefix": settings.API_V1_PREFIX,
"docs": "/api/docs",
}
# Exception handlers
@app.exception_handler(Exception)
async def global_exception_handler(request, exc) -> JSONResponse:
"""Global exception handler for unhandled exceptions."""
if settings.DEBUG:
# In debug mode, return full error details
return JSONResponse(
status_code=500,
content={
"detail": str(exc),
"type": type(exc).__name__,
},
)
# In production, return generic error message
return JSONResponse(
status_code=500,
content={"detail": "Internal server error"},
)
# API routes
from app.api.v1 import auth, music, playlists, library
app.include_router(auth.router, prefix=settings.API_V1_PREFIX, tags=["authentication"])
app.include_router(music.router, prefix=settings.API_V1_PREFIX, tags=["music"])
app.include_router(playlists.router, prefix=settings.API_V1_PREFIX, tags=["playlists"])
app.include_router(library.router, prefix=settings.API_V1_PREFIX, tags=["library"])
# Mount static files
static_dir = BASE_DIR / "app" / "static"
static_dir.mkdir(exist_ok=True)
app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"app.main:app",
host=settings.HOST,
port=settings.PORT,
reload=settings.DEBUG,
log_level=settings.LOG_LEVEL.lower(),
)