fix(video-player): fix the video player to permit the nagivation through the video (it was because de fast api server refused range request)
Some checks failed
Deploy to Development / build-and-deploy (push) Failing after 2m15s
Some checks failed
Deploy to Development / build-and-deploy (push) Failing after 2m15s
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
from fastapi import FastAPI
|
||||
from fastapi import FastAPI, Request, Response, HTTPException
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from contextlib import asynccontextmanager
|
||||
import os
|
||||
from pathlib import Path
|
||||
import mimetypes
|
||||
|
||||
from config.settings import settings
|
||||
from config.database import engine, Base
|
||||
@@ -198,10 +199,89 @@ app.add_middleware(
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
expose_headers=["Content-Range", "Accept-Ranges"],
|
||||
)
|
||||
|
||||
# Mount static files for uploads
|
||||
app.mount("/uploads", StaticFiles(directory=settings.UPLOAD_PATH), name="uploads")
|
||||
# Endpoint personnalisé pour servir les vidéos avec support Range
|
||||
@app.get("/uploads/{file_path:path}")
|
||||
async def serve_media_with_range(request: Request, file_path: str):
|
||||
"""
|
||||
Serve media files with proper Range request support for video scrubbing.
|
||||
"""
|
||||
file_full_path = Path(settings.UPLOAD_PATH) / file_path
|
||||
|
||||
# Vérifier que le fichier existe
|
||||
if not file_full_path.exists() or not file_full_path.is_file():
|
||||
raise HTTPException(status_code=404, detail="File not found")
|
||||
|
||||
# Vérifier que le fichier est dans le répertoire uploads (sécurité)
|
||||
try:
|
||||
file_full_path.resolve().relative_to(Path(settings.UPLOAD_PATH).resolve())
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=403, detail="Access denied")
|
||||
|
||||
# Obtenir la taille du fichier
|
||||
file_size = file_full_path.stat().st_size
|
||||
|
||||
# Déterminer le content type
|
||||
content_type, _ = mimetypes.guess_type(str(file_full_path))
|
||||
if not content_type:
|
||||
content_type = "application/octet-stream"
|
||||
|
||||
# Gérer les requêtes Range
|
||||
range_header = request.headers.get("Range")
|
||||
|
||||
if range_header:
|
||||
# Parser le header Range (format: bytes=start-end)
|
||||
range_match = range_header.replace("bytes=", "").split("-")
|
||||
start = int(range_match[0]) if range_match[0] else 0
|
||||
end = int(range_match[1]) if range_match[1] and range_match[1] else file_size - 1
|
||||
|
||||
# Valider la plage
|
||||
if start >= file_size or end >= file_size or start > end:
|
||||
return Response(
|
||||
status_code=416,
|
||||
headers={
|
||||
"Content-Range": f"bytes */{file_size}",
|
||||
"Accept-Ranges": "bytes"
|
||||
}
|
||||
)
|
||||
|
||||
# Lire la plage demandée
|
||||
chunk_size = end - start + 1
|
||||
with open(file_full_path, "rb") as f:
|
||||
f.seek(start)
|
||||
chunk = f.read(chunk_size)
|
||||
|
||||
# Retourner la réponse 206 Partial Content
|
||||
return Response(
|
||||
content=chunk,
|
||||
status_code=206,
|
||||
headers={
|
||||
"Content-Range": f"bytes {start}-{end}/{file_size}",
|
||||
"Accept-Ranges": "bytes",
|
||||
"Content-Length": str(chunk_size),
|
||||
"Content-Type": content_type,
|
||||
},
|
||||
media_type=content_type
|
||||
)
|
||||
else:
|
||||
# Pas de Range header, retourner le fichier complet
|
||||
with open(file_full_path, "rb") as f:
|
||||
content = f.read()
|
||||
|
||||
return Response(
|
||||
content=content,
|
||||
headers={
|
||||
"Accept-Ranges": "bytes",
|
||||
"Content-Length": str(file_size),
|
||||
"Content-Type": content_type,
|
||||
},
|
||||
media_type=content_type
|
||||
)
|
||||
|
||||
# Note: StaticFiles mount retiré car notre endpoint personnalisé gère tous les fichiers
|
||||
# avec support Range pour permettre le scrubbing vidéo
|
||||
|
||||
# Include routers
|
||||
app.include_router(auth.router, prefix="/api/auth", tags=["Authentication"])
|
||||
|
||||
Reference in New Issue
Block a user