2nzi's picture
update app
16c970a verified
raw
history blame
9.3 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
from ...services.clip_assignment import ClipAssignmentService
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())
active_assignement = True
# 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, user_info['uid'], sport_id)
if user_info['role'] in ["admin", "user_intern"] and active_assignement:
clip_service = ClipAssignmentService()
await clip_service.assign_clips_to_user(user_info["uid"], user_info["role"])
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))
@router.post("/clips/assign")
async def assign_clips(user_info=Depends(require_role(["admin", "user_intern"]))):
try:
clip_service = ClipAssignmentService()
await clip_service.assign_clips_to_user(user_info["uid"], user_info["role"])
return {"message": "Clips assignés avec succès"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.delete("/clips/{clip_id}/user")
async def remove_clip(clip_id: str, user_info=Depends(require_role(["admin"]))):
try:
clip_service = ClipAssignmentService()
await clip_service.remove_clip_from_user(user_info["uid"], clip_id)
return {"message": "Clip retiré avec succès"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.post("/clips/sync")
async def sync_user_clips(user_info=Depends(require_role(["admin", "user_intern"]))):
"""Synchronise les clips disponibles pour l'utilisateur lors de sa connexion"""
try:
clip_service = ClipAssignmentService()
await clip_service.assign_clips_to_user(user_info["uid"], user_info["role"])
return {"message": "Clips synchronisés avec succès"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/clips/debug/{user_id}")
async def debug_user_clips(user_id: str, user_info=Depends(require_role(["admin"]))):
"""Endpoint de débogage pour vérifier les clips d'un utilisateur"""
try:
user_ref = db.collection('users').document(user_id)
user_doc = user_ref.get()
if not user_doc.exists:
raise HTTPException(status_code=404, detail="Utilisateur non trouvé")
user_data = user_doc.to_dict()
return {
"clips_count": len(user_data.get("clips", [])),
"clips": user_data.get("clips", [])
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))