78 lines
2.4 KiB
Python
78 lines
2.4 KiB
Python
import logging
|
|
import uuid
|
|
from pathlib import Path
|
|
|
|
import aiofiles
|
|
from fastapi import APIRouter, UploadFile, File, HTTPException
|
|
from fastapi.responses import FileResponse
|
|
|
|
from app.models.video import VideoUploadResponse
|
|
from app.services.video_service import VideoService
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter(tags=["video"])
|
|
|
|
|
|
def _get_video_service() -> VideoService:
|
|
from app.core.config import get_settings
|
|
|
|
s = get_settings()
|
|
return VideoService(
|
|
upload_dir=s.video_upload_dir,
|
|
max_size_mb=s.max_video_size_mb,
|
|
supported_formats=s.supported_video_formats,
|
|
)
|
|
|
|
|
|
@router.post("/video/upload", response_model=VideoUploadResponse)
|
|
async def upload_video(file: UploadFile = File(...)):
|
|
service = _get_video_service()
|
|
filename = file.filename or "unknown"
|
|
ext = Path(filename).suffix.lower()
|
|
|
|
total_size = 0
|
|
video_id = uuid.uuid4().hex[:12]
|
|
dest_path = service.upload_dir / f"{video_id}{ext}"
|
|
|
|
try:
|
|
async with aiofiles.open(dest_path, "wb") as out:
|
|
while chunk := await file.read(1024 * 1024):
|
|
total_size += len(chunk)
|
|
if total_size > service.max_size_bytes:
|
|
raise HTTPException(
|
|
status_code=413,
|
|
detail=f"File exceeds {service.max_size_bytes // 1024 // 1024}MB limit",
|
|
)
|
|
await out.write(chunk)
|
|
except HTTPException:
|
|
dest_path.unlink(missing_ok=True)
|
|
raise
|
|
except Exception:
|
|
dest_path.unlink(missing_ok=True)
|
|
raise HTTPException(status_code=500, detail="Upload failed")
|
|
|
|
service.validate_video(filename, file.content_type, total_size)
|
|
logger.info("Video uploaded: id=%s filename=%s size=%d", video_id, filename, total_size)
|
|
|
|
return VideoUploadResponse(
|
|
video_id=video_id,
|
|
filename=filename,
|
|
size_bytes=total_size,
|
|
url=f"/api/v1/video/{video_id}",
|
|
)
|
|
|
|
|
|
@router.get("/video/{video_id}")
|
|
async def serve_video(video_id: str):
|
|
service = _get_video_service()
|
|
video_path = service.get_video_path(video_id)
|
|
ext = video_path.suffix.lower()
|
|
media_types = {
|
|
".mp4": "video/mp4",
|
|
".webm": "video/webm",
|
|
".mov": "video/quicktime",
|
|
".avi": "video/x-msvideo",
|
|
".mkv": "video/x-matroska",
|
|
}
|
|
return FileResponse(str(video_path), media_type=media_types.get(ext, "application/octet-stream"))
|