from fastapi import APIRouter, Depends, status from typing import Dict, Any import logging from backend.models.validation import URLValidationRequest, URLValidationResponse from backend.services.video_service import VideoService from backend.core.exceptions import UserInputError, ValidationError, UnsupportedFormatError logger = logging.getLogger(__name__) router = APIRouter(prefix="/api", tags=["validation"]) def get_video_service() -> VideoService: """Dependency injection for VideoService.""" return VideoService() @router.options("/validate-url") async def validate_url_options(): """Handle CORS preflight for validate-url endpoint.""" return {"message": "OK"} @router.post( "/validate-url", response_model=URLValidationResponse, status_code=status.HTTP_200_OK, summary="Validate YouTube URL", description="Validate a YouTube URL and extract the video ID if valid" ) async def validate_url( request: URLValidationRequest, video_service: VideoService = Depends(get_video_service) ) -> URLValidationResponse: """ Validate a YouTube URL and extract video ID. Args: request: URLValidationRequest containing the URL to validate video_service: VideoService instance for validation logic Returns: URLValidationResponse with validation result and details """ try: # Extract video ID from URL video_id = video_service.extract_video_id(request.url) # Create normalized URL normalized_url = video_service.normalize_url(video_id) logger.info(f"Successfully validated URL: {request.url} -> Video ID: {video_id}") return URLValidationResponse( is_valid=True, video_id=video_id, video_url=normalized_url ) except ValidationError as e: logger.warning(f"Validation error for URL {request.url}: {e.message}") return URLValidationResponse( is_valid=False, error={ "code": e.error_code.value, "message": e.message, "details": e.details, "recoverable": e.recoverable } ) except UnsupportedFormatError as e: logger.warning(f"Unsupported format for URL {request.url}: {e.message}") return URLValidationResponse( is_valid=False, error={ "code": e.error_code.value, "message": e.message, "details": e.details, "recoverable": e.recoverable } ) except UserInputError as e: logger.warning(f"User input error for URL {request.url}: {e.message}") return URLValidationResponse( is_valid=False, error={ "code": e.error_code.value, "message": e.message, "details": e.details, "recoverable": e.recoverable } ) except Exception as e: logger.error(f"Unexpected error validating URL {request.url}: {str(e)}") return URLValidationResponse( is_valid=False, error={ "code": "INTERNAL_ERROR", "message": "An unexpected error occurred while validating the URL", "details": {"url": request.url}, "recoverable": False } ) @router.get( "/supported-formats", response_model=Dict[str, Any], summary="Get supported URL formats", description="Retrieve list of supported YouTube URL formats" ) async def get_supported_formats( video_service: VideoService = Depends(get_video_service) ) -> Dict[str, Any]: """ Get list of supported YouTube URL formats. Args: video_service: VideoService instance Returns: Dictionary containing supported formats and examples """ return { "supported_formats": video_service.get_supported_formats(), "examples": { "standard": "https://youtube.com/watch?v=dQw4w9WgXcQ", "short": "https://youtu.be/dQw4w9WgXcQ", "embed": "https://youtube.com/embed/dQw4w9WgXcQ", "mobile": "https://m.youtube.com/watch?v=dQw4w9WgXcQ" }, "notes": [ "Video IDs must be exactly 11 characters", "Playlist URLs are not currently supported", "URLs with timestamps and other parameters are accepted" ] }