youtube-summarizer/backend/api/validation.py

135 lines
4.3 KiB
Python

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.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"
]
}