import os import uvicorn from pathlib import Path from fastapi import FastAPI, UploadFile, File, Header from fastapi.responses import StreamingResponse from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from config import ServerConfig app = FastAPI() app.mount('/home', StaticFiles(directory='static', html=True), name='static') app.add_middleware( CORSMiddleware, allow_origins=['*'], allow_credentials=True, allow_methods=['*'], allow_headers=['*'], ) @app.post('/upload') async def upload_file(file: UploadFile = File(...)): video_path = os.path.join(ServerConfig.video_upload_path, file.filename + '.mp4') with open(video_path, 'wb') as video: video.write(await file.read()) return {'status': 200, 'id': os.path.splitext(file.filename)[0]} @app.get("/fetch/{id}") async def fetch_file(id: str, range: str = Header(None)) -> StreamingResponse: video_path = Path(os.path.join(ServerConfig.video_play_path, id + '.mp4')) video_size = video_path.stat().st_size start = 0 end = video_size - 1 chunk_size = min(video_size, ServerConfig.video_chunk_size) headers = { 'Content-Type': 'video/mp4', 'Content-Disposition': f'attachment; filename="{id}.mp4"', } if range: start, end = range.replace('bytes=', '').split('-') start = int(start) end = int(end) if end else video_size - 1 chunk_size = min(end - start + 1, ServerConfig.video_chunk_size) headers['Content-Range'] = f'bytes {start}-{end}/{video_size}' headers['Accept-Ranges'] = 'bytes' headers['Content-Disposition'] = 'inline' def file_reader(): with open(video_path, 'rb') as video: video.seek(start) while True: data = video.read(chunk_size) if not data: break yield data return StreamingResponse(file_reader(), status_code=206, headers=headers, media_type='video/mp4') if __name__ == "__main__": uvicorn.run(app=app)