from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse, FileResponse, Response from fastapi.staticfiles import StaticFiles import os import pathlib from contextlib import asynccontextmanager from routes.video_routes import video_router from config import Config # Create the lifespan event handler @asynccontextmanager async def lifespan(app: FastAPI): # Code to run on startup print("Starting up... Creating storage directories.") os.makedirs(Config.TEMP_DIR, exist_ok=True) os.makedirs(Config.VIDEOS_DIR, exist_ok=True) os.makedirs(Config.IMAGES_DIR, exist_ok=True) os.makedirs(Config.AUDIO_DIR, exist_ok=True) # Create static directories if they don't exist static_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), "static") os.makedirs(static_dir, exist_ok=True) static_assets_dir = os.path.join(static_dir, "assets") os.makedirs(static_assets_dir, exist_ok=True) yield # Code to run on shutdown (if any) print("Shutting down...") app = FastAPI(title="Shorts Video API", lifespan=lifespan) # Define the list of allowed origins (frontends) origins = [ "https://shorts-video-six.vercel.app", "https://shorts-video-alpha.vercel.app", "https://huggingface.co/spaces/johnwesley756/shorts-video", "http://localhost:3000", "http://localhost:5173", ] # Configure CORS with the specific origins app.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Register API routes FIRST so they are not shadowed by static mounts app.include_router(video_router, prefix="/api/videos") # Mount static files directory after API routes static_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), "static") if os.path.exists(static_dir): if os.path.exists(os.path.join(static_dir, "assets")): app.mount("/assets", StaticFiles(directory=os.path.join(static_dir, "assets")), name="static_assets") app.mount("/", StaticFiles(directory=static_dir, html=True), name="static") # Add the root endpoint @app.get("/") def read_root(): return {"message": "Welcome to the Shorts Video API"} # Basic error handling @app.exception_handler(404) async def not_found_handler(request, exc): return JSONResponse( status_code=404, content={"error": "Not found"} ) @app.exception_handler(500) async def server_error_handler(request, exc): return JSONResponse( status_code=500, content={"error": "Internal server error"} ) # Fallback for missing video placeholder asset @app.get("/video-placeholder.png") def serve_video_placeholder(): placeholder_path = os.path.join(static_dir, "video-placeholder.png") if os.path.exists(placeholder_path): return FileResponse(placeholder_path, media_type="image/png") # 1x1 transparent PNG import base64 transparent_png_base64 = ( "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO1Jt8EAAAAASUVORK5CYII=" ) return Response(content=base64.b64decode(transparent_png_base64), media_type="image/png") if __name__ == '__main__': import uvicorn # Use environment variables for port if available port = int(os.environ.get('PORT', Config.PORT)) uvicorn.run("app:app", host="0.0.0.0", port=port, reload=Config.DEBUG)