from fastapi import APIRouter, HTTPException from pydantic import BaseModel from server.errors import call from server.schemas import DeviceBody, device_payload from server.services.downloads import downloads router = APIRouter(prefix="/api/downloads") class DownloadItem(BaseModel): id: int title: str = "" image: str = "" class DownloadStartBody(BaseModel): token: str = "" device: DeviceBody | None = None items: list[DownloadItem] = [] class DirectoryBody(BaseModel): path: str = "" class DownloadSettingsBody(BaseModel): directory: str = "" workers: int | None = None @router.get("") def list_downloads(): return downloads.snapshot() @router.post("") def start_downloads(body: DownloadStartBody): return downloads.enqueue(body.token, device_payload(body.device), [item.model_dump() for item in body.items]) @router.post("/directory") def set_directory(body: DirectoryBody): if not body.path.strip(): raise HTTPException(status_code=400, detail="请选择目录") return {"directory": downloads.set_directory(body.path.strip())} @router.post("/pick") def pick_directory(): return {"directory": downloads.pick_directory()} @router.post("/choose") def choose_directory(): return {"directory": downloads.choose_directory()} @router.get("/settings") def get_download_settings(): return downloads.settings_view() @router.post("/settings") def update_download_settings(body: DownloadSettingsBody): if body.directory.strip(): downloads.set_directory(body.directory.strip()) if body.workers is not None: try: downloads.set_workers(body.workers) except ValueError as exc: raise HTTPException(status_code=400, detail=str(exc)) from exc return downloads.settings_view() @router.post("/pause-all") def pause_all_downloads(): return downloads.pause_all() @router.post("/resume-all") def resume_all_downloads(): return downloads.resume_all() @router.post("/{drama_id}/pause") def pause_download(drama_id: str): return downloads.pause(drama_id) @router.post("/{drama_id}/resume") def resume_download(drama_id: str): return downloads.resume(drama_id) @router.post("/{drama_id}/cancel") def cancel_download(drama_id: str): return downloads.cancel(drama_id) @router.post("/{drama_id}/open") def open_download(drama_id: str): def action(): downloads.open_folder(drama_id) return downloads.snapshot() return call(action) @router.delete("/{drama_id}") def remove_download(drama_id: str): return downloads.remove(drama_id)