2nzi's picture
update backend with video upload on HF
923cd30 verified
raw
history blame
6.94 kB
from fastapi import APIRouter, File, UploadFile, Depends, HTTPException, Form
from firebase_admin import firestore
import hashlib
import uuid
from ...core.auth import require_role, get_user
from typing import List, Optional, Dict
from app.services.youtube_downloader import download_youtube_video, parse_urls
from ...services.processor import process_video
from typing import Dict
from ...core.firebase import db # Modifier cette ligne
router = APIRouter()
@router.get("/videos")
async def get_videos(user_info=Depends(get_user)):
try:
# Récupération des vidéos globales
videos_ref = db.collection('videos')
videos = []
# Récupération du statut utilisateur
user_status_ref = db.collection('user_video_status').document(user_info['uid'])
user_status_doc = user_status_ref.get()
user_statuses = user_status_doc.to_dict() if user_status_doc.exists else {"video_status": []}
# Fusion des données
for doc in videos_ref.stream():
video_data = doc.to_dict()
video_data['id'] = doc.id
# Ajout du statut spécifique à l'utilisateur
user_status = next(
(status for status in user_status_doc.get('video_status', [])
if status['uuid'] == doc.id),
None
)
video_data['user_status'] = user_status['status'] if user_status else 'ready'
videos.append(video_data)
return {"videos": videos}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.post("/videos/upload")
async def upload_video(
sport_id: str = Form(...),
file: Optional[UploadFile] = File(None),
youtube_url: Optional[str] = Form(None),
user_info=Depends(require_role(["admin", "user_intern"]))
):
try:
responses = []
urls_to_process = []
# Collecter toutes les URLs à traiter
if youtube_url:
# Cas URL YouTube directe - peut contenir plusieurs URLs séparées par des points-virgules
urls_to_process.extend(parse_urls(youtube_url))
elif file and file.content_type in ['text/plain', 'text/csv']:
# Cas fichier texte avec URLs
text_content = (await file.read()).decode('utf-8')
urls_to_process.extend(parse_urls(text_content))
elif file:
# Cas upload direct de vidéo
content = await file.read()
return await process_single_video(content, sport_id, user_info, file.filename)
if not urls_to_process and not file:
raise HTTPException(status_code=400, detail="Aucune URL YouTube valide trouvée")
# Traiter chaque URL
for url in urls_to_process:
try:
print(f"[DEBUG] Processing YouTube URL: {url}")
content = await download_youtube_video(url)
result = await process_single_video(content, sport_id, user_info, f"YouTube: {url}")
responses.append({
"url": url,
"status": "success",
"video_id": result["video_id"]
})
except Exception as e:
print(f"[ERROR] Failed to process URL {url}: {str(e)}")
responses.append({
"url": url,
"status": "error",
"error": str(e)
})
return {
"message": f"Traitement terminé pour {len(responses)} vidéos",
"results": responses
}
except Exception as e:
print(f"[ERROR] Upload failed: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
async def process_single_video(content: bytes, sport_id: str, user_info: dict, title: str):
"""Traite une seule vidéo et retourne son ID"""
video_uuid = str(uuid.uuid4())
# Calcul du hash MD5
md5_hash = hashlib.md5()
md5_hash.update(content)
file_hash = md5_hash.hexdigest()
# Vérification des doublons
existing_videos = db.collection('videos').where('md5_hash', '==', file_hash).get()
if len(existing_videos) > 0:
return {"message": "Cette vidéo existe déjà", "video_id": existing_videos[0].id}
# Création de l'entrée Firestore
video_data = {
"uuid": video_uuid,
"sport_id": sport_id,
"upload_date": firestore.SERVER_TIMESTAMP,
"uploaded_by": user_info['uid'],
"title": title,
"status": "downloading",
"md5_hash": file_hash,
"paths": {
"raw": f"{sport_id}/raw/{video_uuid}_raw.mp4",
"compressed": f"{sport_id}/compressed/{video_uuid}_compressed.mp4",
"reduced_videos": []
},
"scenes": [],
"reduced_scenes": []
}
db.collection('videos').document(video_uuid).set(video_data)
await process_video(video_uuid, content)
return {"message": "Upload initié", "video_id": video_uuid}
@router.put("/videos/{video_id}/status")
async def update_video_status(
video_id: str,
status: str,
user_info=Depends(get_user)
):
try:
# Vérifier si la vidéo existe
video_ref = db.collection('videos').document(video_id)
video_doc = video_ref.get()
if not video_doc.exists:
raise HTTPException(status_code=404, detail="Vidéo non trouvée")
# Mettre à jour ou créer le statut utilisateur
user_status_ref = db.collection('user_video_status').document(user_info['uid'])
user_status_doc = user_status_ref.get()
if user_status_doc.exists:
statuses = user_status_doc.get('video_status', [])
# Mettre à jour le statut existant ou ajouter un nouveau
status_updated = False
for s in statuses:
if s['uuid'] == video_id:
s['status'] = status
status_updated = True
break
if not status_updated:
statuses.append({
'uuid': video_id,
'status': status
})
user_status_ref.update({'video_status': statuses})
else:
# Créer un nouveau document avec le statut
user_status_ref.set({
'video_status': [{
'uuid': video_id,
'status': status
}]
})
return {"message": "Statut mis à jour avec succès"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))