syllabus/app/routes/scheduler.py
2026-01-08 13:26:15 -05:00

130 lines
4.4 KiB
Python

"""Scheduler API Routes - Manage scheduled tasks."""
import logging
from typing import Optional, List, Dict, Any
from fastapi import APIRouter, Form
from fastapi.responses import JSONResponse
from core.scheduler import add_job, remove_job, get_jobs
logger = logging.getLogger("syllabus")
router = APIRouter(prefix="/api/schedule", tags=["Scheduler"])
@router.post("/add", description="Add a scheduled task")
async def add_scheduled_task(
job_id: str = Form(...),
task: str = Form(...),
cron: str = Form(...),
show: Optional[str] = Form(None),
season: Optional[int] = Form(None),
specials: bool = Form(False)
) -> JSONResponse:
"""
Add a scheduled task.
**Tasks:**
- `download_show`: Download specific show/season (requires: show, season)
- `download_latest`: Download latest season (requires: show)
- `update_series`: Update series list (no params needed)
- `update_posters`: Force re-download all show posters (no params needed)
**Cron Format:** (minute hour day month day_of_week)
- `0 2 * * *` = Daily at 2 AM
- `0 */6 * * *` = Every 6 hours
- `0 0 * * 0` = Weekly on Sunday at midnight
"""
try:
# Validate task type
valid_tasks = ["download_show", "download_latest", "update_series", "update_posters"]
if task not in valid_tasks:
return JSONResponse(
status_code=400,
content={"status": "error", "message": f"Invalid task. Must be one of: {valid_tasks}"}
)
# Build kwargs based on task
kwargs = {}
if task == "download_show":
if not show or season is None:
return JSONResponse(
status_code=400,
content={"status": "error", "message": "download_show requires 'show' and 'season'"}
)
kwargs = {"show": show, "season": season, "specials": specials}
elif task == "download_latest":
if not show:
return JSONResponse(
status_code=400,
content={"status": "error", "message": "download_latest requires 'show'"}
)
kwargs = {"show": show}
# Add the job
success = add_job(job_id, task, cron, kwargs)
if success:
return JSONResponse(
status_code=201,
content={
"status": "success",
"message": f"Job '{job_id}' scheduled",
"job_id": job_id,
"task": task,
"cron": cron
}
)
else:
return JSONResponse(
status_code=500,
content={"status": "error", "message": "Failed to add job"}
)
except Exception as e:
logger.error(f"Error adding scheduled task: {e}")
return JSONResponse(
status_code=500,
content={"status": "error", "message": str(e)}
)
@router.delete("/remove/{job_id}", description="Remove a scheduled task")
async def remove_scheduled_task(job_id: str) -> JSONResponse:
"""Remove a scheduled task by ID."""
try:
success = remove_job(job_id)
if success:
return JSONResponse(
status_code=200,
content={"status": "success", "message": f"Job '{job_id}' removed"}
)
else:
return JSONResponse(
status_code=404,
content={"status": "error", "message": f"Job '{job_id}' not found"}
)
except Exception as e:
logger.error(f"Error removing scheduled task: {e}")
return JSONResponse(
status_code=500,
content={"status": "error", "message": str(e)}
)
@router.get("/list", description="List all scheduled tasks")
async def list_scheduled_tasks() -> JSONResponse:
"""Get list of all scheduled tasks."""
try:
jobs = get_jobs()
return JSONResponse(
status_code=200,
content={
"status": "success",
"count": len(jobs),
"jobs": jobs
}
)
except Exception as e:
logger.error(f"Error listing scheduled tasks: {e}")
return JSONResponse(
status_code=500,
content={"status": "error", "message": str(e)}
)