from typing import Any from fastapi import FastAPI, Request from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.middleware.cors import CORSMiddleware from app.api import router as api_router from app.services.video_service import get_video_by_id from jinja2 import pass_context from starlette.datastructures import URL app = FastAPI(title="In-Video Search", docs_url=None, redoc_url=None, openapi_url=None) # Enable CORS app.add_middleware( CORSMiddleware, allow_origins=["*"], # Adjust this in production allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Mount static files app.mount("/static", StaticFiles(directory="app/static"), name="static") # Templates templates = Jinja2Templates(directory="app/templates") @pass_context def https_url_for(context: dict, name: str, **path_params: Any) -> URL: request: Request = context["request"] url: URL = request.url_for(name, **path_params) return url.replace(scheme="https") templates.env.globals["https_url_for"] = https_url_for @app.get("/", response_class=HTMLResponse) async def index(request: Request): return templates.TemplateResponse( "index.html", {"request": request, "title": "In-Video Search"} ) @app.get("/video/{video_id}", response_class=HTMLResponse) async def video_page(request: Request, video_id: str): # Try to get video info from database video = get_video_by_id(video_id) title = "Video Player" # If video exists and has a title, use it if video and video.title: title = video.title # Get the start time from query parameters if available start_time = 0 if "t" in request.query_params: try: # Try to parse the t parameter as seconds t_param = request.query_params.get("t") # First try as a float (seconds) start_time = int(float(t_param)) except (ValueError, TypeError): # If that fails, try parsing as MM:SS or HH:MM:SS format try: if ":" in t_param: parts = t_param.split(":") if len(parts) == 2: # MM:SS start_time = int(parts[0]) * 60 + int(parts[1]) elif len(parts) == 3: # HH:MM:SS start_time = ( int(parts[0]) * 3600 + int(parts[1]) * 60 + int(parts[2]) ) except (ValueError, TypeError, IndexError): # If all parsing fails, default to 0 start_time = 0 return templates.TemplateResponse( "video.html", { "request": request, "title": title, "video_id": video_id, "start_time": start_time, }, ) @app.get("/watch") async def watch_redirect(request: Request, v: str): # Redirect YouTube-style URLs to our video page # If there's a t parameter, include it in the redirect if "t" in request.query_params: return RedirectResponse(url=f"/video/{v}?t={request.query_params.get('t')}") else: return RedirectResponse(url=f"/video/{v}") # Include API routers app.include_router(api_router.router, prefix="/api") if __name__ == "__main__": import uvicorn uvicorn.run("app.main:app", host="0.0.0.0", port=8000, reload=True)