"""Scheduler API endpoints for Aniworld. This module provides endpoints for managing scheduled tasks such as automatic anime library rescans. """ import logging from typing import Dict, Optional from fastapi import APIRouter, Depends, HTTPException, status from src.server.models.config import SchedulerConfig from src.server.services.config_service import ConfigServiceError, get_config_service from src.server.utils.dependencies import require_auth logger = logging.getLogger(__name__) router = APIRouter(prefix="/api/scheduler", tags=["scheduler"]) @router.get("/config", response_model=SchedulerConfig) def get_scheduler_config( auth: Optional[dict] = Depends(require_auth) ) -> SchedulerConfig: """Get current scheduler configuration. Args: auth: Authentication token (optional for read operations) Returns: SchedulerConfig: Current scheduler configuration Raises: HTTPException: If configuration cannot be loaded """ try: config_service = get_config_service() app_config = config_service.load_config() return app_config.scheduler except ConfigServiceError as e: logger.error(f"Failed to load scheduler config: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to load scheduler configuration: {e}", ) from e @router.post("/config", response_model=SchedulerConfig) def update_scheduler_config( scheduler_config: SchedulerConfig, auth: dict = Depends(require_auth), ) -> SchedulerConfig: """Update scheduler configuration. Args: scheduler_config: New scheduler configuration auth: Authentication token (required) Returns: SchedulerConfig: Updated scheduler configuration Raises: HTTPException: If configuration update fails """ try: config_service = get_config_service() app_config = config_service.load_config() # Update scheduler section app_config.scheduler = scheduler_config # Save and return config_service.save_config(app_config) logger.info( f"Scheduler config updated by {auth.get('username', 'unknown')}" ) return scheduler_config except ConfigServiceError as e: logger.error(f"Failed to update scheduler config: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to update scheduler configuration: {e}", ) from e @router.post("/trigger-rescan", response_model=Dict[str, str]) async def trigger_rescan(auth: dict = Depends(require_auth)) -> Dict[str, str]: """Manually trigger a library rescan. This endpoint triggers an immediate anime library rescan, bypassing the scheduler interval. Args: auth: Authentication token (required) Returns: Dict with success message Raises: HTTPException: If rescan cannot be triggered """ try: # Import here to avoid circular dependency from src.server.fastapi_app import get_series_app series_app = get_series_app() if not series_app: raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="SeriesApp not initialized", ) # Trigger the rescan logger.info( f"Manual rescan triggered by {auth.get('username', 'unknown')}" ) # Use existing rescan logic from anime API from src.server.api.anime import trigger_rescan as do_rescan return await do_rescan() except HTTPException: raise except Exception as e: logger.exception("Failed to trigger manual rescan") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to trigger rescan: {str(e)}", ) from e