"""Audio Upload Data Transfer Object""" from dataclasses import dataclass from typing import Optional import mimetypes import os @dataclass class AudioUploadDto: """DTO for file upload data Handles audio file upload information including filename, content, and content type validation. """ filename: str content: bytes content_type: str size: Optional[int] = None def __post_init__(self): """Validate the DTO after initialization""" self._validate() if self.size is None: self.size = len(self.content) def _validate(self): """Validate audio upload data""" if not self.filename: raise ValueError("Filename cannot be empty") if not self.content: raise ValueError("Audio content cannot be empty") if not self.content_type: raise ValueError("Content type cannot be empty") # Validate file extension _, ext = os.path.splitext(self.filename.lower()) supported_extensions = ['.wav', '.mp3', '.m4a', '.flac', '.ogg'] if ext not in supported_extensions: raise ValueError(f"Unsupported file extension: {ext}. Supported: {supported_extensions}") # Validate content type expected_content_type = mimetypes.guess_type(self.filename)[0] if expected_content_type and not self.content_type.startswith('audio/'): raise ValueError(f"Invalid content type: {self.content_type}. Expected audio/* type") # Validate file size (max 100MB) max_size = 100 * 1024 * 1024 # 100MB if len(self.content) > max_size: raise ValueError(f"File too large: {len(self.content)} bytes. Maximum: {max_size} bytes") # Validate minimum file size (at least 1KB) min_size = 1024 # 1KB if len(self.content) < min_size: raise ValueError(f"File too small: {len(self.content)} bytes. Minimum: {min_size} bytes") @property def file_extension(self) -> str: """Get the file extension""" return os.path.splitext(self.filename.lower())[1] @property def base_filename(self) -> str: """Get filename without extension""" return os.path.splitext(self.filename)[0] def to_dict(self) -> dict: """Convert to dictionary representation""" return { 'filename': self.filename, 'content_type': self.content_type, 'size': self.size, 'file_extension': self.file_extension }