diff --git a/app/controllers/v1/video.py b/app/controllers/v1/video.py index 9154a8cb..689d0aa0 100644 --- a/app/controllers/v1/video.py +++ b/app/controllers/v1/video.py @@ -3,7 +3,7 @@ import shutil from fastapi import Request, Depends, Path, BackgroundTasks, UploadFile -from fastapi.responses import FileResponse +from fastapi.responses import FileResponse, StreamingResponse from fastapi.params import File from loguru import logger @@ -137,7 +137,37 @@ def upload_bgm_file(request: Request, file: UploadFile = File(...)): async def stream_video(request: Request, file_path: str): tasks_dir = utils.task_dir() video_path = os.path.join(tasks_dir, file_path) - if os.path.isfile(video_path): - return FileResponse(video_path, media_type="video/mp4", filename=file_path) - else: - return {"message": "File not found."} + range_header = request.headers.get('Range') + video_size = os.path.getsize(video_path) + start, end = 0, video_size - 1 + + length = video_size + if range_header: + range_ = range_header.split('bytes=')[1] + start, end = [int(part) if part else None for part in range_.split('-')] + if start is None: + start = video_size - end + end = video_size - 1 + if end is None: + end = video_size - 1 + length = end - start + 1 + + def file_iterator(file_path, offset=0, bytes_to_read=None): + with open(file_path, 'rb') as f: + f.seek(offset, os.SEEK_SET) + remaining = bytes_to_read or video_size + while remaining > 0: + bytes_to_read = min(4096, remaining) + data = f.read(bytes_to_read) + if not data: + break + remaining -= len(data) + yield data + + response = StreamingResponse(file_iterator(video_path, start, length), media_type='video/mp4') + response.headers['Content-Range'] = f'bytes {start}-{end}/{video_size}' + response.headers['Accept-Ranges'] = 'bytes' + response.headers['Content-Length'] = str(length) + response.status_code = 206 # Partial Content + + return response