import os import shutil import subprocess import tempfile from fastapi import FastAPI, File, UploadFile, Form, HTTPException, BackgroundTasks from fastapi.responses import FileResponse, RedirectResponse from fastapi.middleware.cors import CORSMiddleware app = FastAPI() # Add CORS middleware (adjust allow_origins for production) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Ensure the base temporary directory exists. TEMP_DIR = "temp_files" os.makedirs(TEMP_DIR, exist_ok=True) @app.get("/") def read_root(): return {"message": "Video Subtitle Server is running"} @app.post("/burn-subtitles") async def burn_subtitles( background_tasks: BackgroundTasks, video: UploadFile = File(...), subtitle: UploadFile = File(...), font_size: str = Form("20"), font_color: str = Form("white"), output_format: str = Form("mp4") ): # Create a unique temporary directory for this job. job_dir = tempfile.mkdtemp(prefix='job_', dir=TEMP_DIR) try: # Build file paths. video_path = os.path.join(job_dir, f"input{os.path.splitext(video.filename)[1]}") subtitle_path = os.path.join(job_dir, "subtitles.srt") output_path = os.path.join(job_dir, f"output.{output_format}") # Save uploaded video file. with open(video_path, "wb") as video_file: shutil.copyfileobj(video.file, video_file) # Save uploaded subtitle file. with open(subtitle_path, "wb") as subtitle_file: shutil.copyfileobj(subtitle.file, subtitle_file) # Format the font color for FFmpeg if provided as hex. if font_color.startswith('#'): font_color = font_color.lstrip('#') if len(font_color) == 6: r, g, b = font_color[0:2], font_color[2:4], font_color[4:6] font_color = f"&H{b}{g}{r}&" # Build the subtitle style string. subtitle_style = f"FontSize={font_size},PrimaryColour={font_color}" command = [ "ffmpeg", "-i", video_path, "-vf", f"subtitles={subtitle_path}:force_style='{subtitle_style}'", "-c:a", "copy", output_path ] # Run the FFmpeg command. process = subprocess.run(command, capture_output=True, text=True) if process.returncode != 0: raise HTTPException(status_code=500, detail=f"FFmpeg Error: {process.stderr}") # Schedule cleanup of the job directory after the response is sent. background_tasks.add_task(shutil.rmtree, job_dir) return FileResponse( output_path, media_type=f"video/{output_format}", filename=f"processed_video.{output_format}" ) except Exception as e: # Clean up immediately on error. shutil.rmtree(job_dir, ignore_errors=True) raise HTTPException(status_code=500, detail=str(e)) @app.post("/convert-srt") async def convert_srt( background_tasks: BackgroundTasks, subtitle: UploadFile = File(...), ): job_dir = tempfile.mkdtemp(prefix='job_', dir=TEMP_DIR) try: subtitle_path = os.path.join(job_dir, "subtitles.srt") with open(subtitle_path, "wb") as subtitle_file: shutil.copyfileobj(subtitle.file, subtitle_file) background_tasks.add_task(shutil.rmtree, job_dir) return FileResponse( subtitle_path, media_type="text/plain", filename="subtitles.srt" ) except Exception as e: shutil.rmtree(job_dir, ignore_errors=True) raise HTTPException(status_code=500, detail=str(e)) @app.get("/health") def health_check(): return {"status": "healthy"} @app.get("/doc") def redirect_to_docs(): return RedirectResponse(url="/docs")