Aniworld/src/server/fastapi_app.py
2025-10-22 11:30:04 +02:00

135 lines
4.1 KiB
Python

"""
FastAPI application for Aniworld anime download manager.
This module provides the main FastAPI application with proper CORS
configuration, middleware setup, static file serving, and Jinja2 template
integration.
"""
from pathlib import Path
from typing import Optional
import uvicorn
from fastapi import FastAPI, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from src.config.settings import settings
# Import core functionality
from src.core.SeriesApp import SeriesApp
from src.server.api.anime import router as anime_router
from src.server.api.auth import router as auth_router
from src.server.api.config import router as config_router
from src.server.api.download import router as download_router
from src.server.api.websocket import router as websocket_router
from src.server.controllers.error_controller import (
not_found_handler,
server_error_handler,
)
# Import controllers
from src.server.controllers.health_controller import router as health_router
from src.server.controllers.page_controller import router as page_router
from src.server.middleware.auth import AuthMiddleware
from src.server.middleware.error_handler import register_exception_handlers
from src.server.services.progress_service import get_progress_service
from src.server.services.websocket_service import get_websocket_service
# Initialize FastAPI app
app = FastAPI(
title="Aniworld Download Manager",
description="Modern web interface for Aniworld anime download management",
version="1.0.0",
docs_url="/api/docs",
redoc_url="/api/redoc"
)
# Configure CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Configure appropriately for production
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Configure static files
STATIC_DIR = Path(__file__).parent / "web" / "static"
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
# Attach authentication middleware (token parsing + simple rate limiter)
app.add_middleware(AuthMiddleware, rate_limit_per_minute=5)
# Include routers
app.include_router(health_router)
app.include_router(page_router)
app.include_router(auth_router)
app.include_router(config_router)
app.include_router(anime_router)
app.include_router(download_router)
app.include_router(websocket_router)
# Register exception handlers
register_exception_handlers(app)
# Global variables for application state
series_app: Optional[SeriesApp] = None
@app.on_event("startup")
async def startup_event():
"""Initialize application on startup."""
global series_app
try:
# Initialize SeriesApp with configured directory
if settings.anime_directory:
series_app = SeriesApp(settings.anime_directory)
# Initialize progress service with websocket callback
progress_service = get_progress_service()
ws_service = get_websocket_service()
async def broadcast_callback(
message_type: str, data: dict, room: str
):
"""Broadcast progress updates via WebSocket."""
message = {
"type": message_type,
"data": data,
}
await ws_service.manager.broadcast_to_room(message, room)
progress_service.set_broadcast_callback(broadcast_callback)
print("FastAPI application started successfully")
except Exception as e:
print(f"Error during startup: {e}")
@app.on_event("shutdown")
async def shutdown_event():
"""Cleanup on application shutdown."""
print("FastAPI application shutting down")
@app.exception_handler(404)
async def handle_not_found(request: Request, exc: HTTPException):
"""Custom 404 handler."""
return await not_found_handler(request, exc)
@app.exception_handler(500)
async def handle_server_error(request: Request, exc: Exception):
"""Custom 500 handler."""
return await server_error_handler(request, exc)
if __name__ == "__main__":
uvicorn.run(
"fastapi_app:app",
host="127.0.0.1",
port=8000,
reload=True,
log_level="info"
)