""" Download management routes for Ohm Stream Downloader API. """ import os from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException from fastapi.responses import FileResponse from app.download_manager import DownloadManager from app.models import DownloadRequest, DownloadStatus from app.utils import is_safe_filename, sanitize_filename router = APIRouter(prefix="/api/download", tags=["downloads"]) def get_download_manager() -> DownloadManager: from main import download_manager return download_manager @router.post("") async def create_download( request: DownloadRequest, background_tasks: BackgroundTasks, download_manager: DownloadManager = Depends(get_download_manager), ): """Create a new download task""" if request.filename: request.filename = sanitize_filename(request.filename) if not is_safe_filename(request.filename): raise HTTPException( status_code=400, detail="Invalid filename. Path traversal attempts are not allowed.", ) task = download_manager.create_task(request) background_tasks.add_task(download_manager.start_download, task.id) return {"task_id": task.id, "task": task} @router.get("/direct") async def direct_download( url: str, filename: str, background_tasks: BackgroundTasks, download_manager: DownloadManager = Depends(get_download_manager), ): """Download directly from a video URL with custom filename""" request = DownloadRequest(url=url, filename=filename) task = download_manager.create_task(request) background_tasks.add_task(download_manager.start_download, task.id) return {"task_id": task.id, "task": task} @router.get("/{task_id}") async def get_download_status( task_id: str, download_manager: DownloadManager = Depends(get_download_manager), ): """Get status of a specific download""" task = download_manager.get_task(task_id) if not task: raise HTTPException(status_code=404, detail="Task not found") return task @router.post("/{task_id}/pause") async def pause_download( task_id: str, download_manager: DownloadManager = Depends(get_download_manager), ): """Pause a download""" task = download_manager.get_task(task_id) if not task: raise HTTPException(status_code=404, detail="Task not found") await download_manager.pause_download(task_id) return {"status": "paused"} @router.post("/{task_id}/resume") async def resume_download( task_id: str, background_tasks: BackgroundTasks, download_manager: DownloadManager = Depends(get_download_manager), ): """Resume a paused download""" task = download_manager.get_task(task_id) if not task: raise HTTPException(status_code=404, detail="Task not found") if task.status == DownloadStatus.PAUSED: background_tasks.add_task(download_manager.start_download, task_id) return {"status": "resumed"} return {"status": "already running or completed"} @router.delete("/{task_id}") async def delete_download( task_id: str, download_manager: DownloadManager = Depends(get_download_manager), ): """Delete/cancel a download""" task = download_manager.get_task(task_id) if not task: raise HTTPException(status_code=404, detail="Task not found") await download_manager.delete_task(task_id) return {"status": "deleted"} @router.get("/{task_id}/file") async def download_file( task_id: str, download_manager: DownloadManager = Depends(get_download_manager), ): """Download the completed file""" task = download_manager.get_task(task_id) if not task: raise HTTPException(status_code=404, detail="Task not found") if task.status != DownloadStatus.COMPLETED: raise HTTPException(status_code=400, detail="Download not completed") if not task.file_path or not os.path.exists(task.file_path): raise HTTPException(status_code=404, detail="File not found") return FileResponse( task.file_path, filename=task.filename, media_type="application/octet-stream" ) @router.get("/") async def list_downloads( download_manager: DownloadManager = Depends(get_download_manager), ): """List all download tasks""" return {"downloads": download_manager.get_all_tasks()} # Legacy endpoint for /api/downloads legacy_router = APIRouter(prefix="/api", tags=["downloads-legacy"]) @legacy_router.get("/downloads") async def list_all_downloads( download_manager: DownloadManager = Depends(get_download_manager), ): """List all download tasks (legacy endpoint at /api/downloads)""" return {"downloads": download_manager.get_all_tasks()}