"""Picture source schemas.""" from datetime import datetime from typing import List, Literal, Optional from pydantic import BaseModel, Field class PictureSourceCreate(BaseModel): """Request to create a picture source.""" name: str = Field(description="Stream name", min_length=1, max_length=100) stream_type: Literal["raw", "processed", "static_image", "video"] = Field(description="Stream type") display_index: Optional[int] = Field(None, description="Display index (raw streams)", ge=0) capture_template_id: Optional[str] = Field(None, description="Capture template ID (raw streams)") target_fps: Optional[int] = Field(None, description="Target FPS", ge=1, le=90) source_stream_id: Optional[str] = Field(None, description="Source stream ID (processed streams)") postprocessing_template_id: Optional[str] = Field(None, description="Postprocessing template ID (processed streams)") image_source: Optional[str] = Field(None, description="Image URL or file path (static_image streams)") description: Optional[str] = Field(None, description="Stream description", max_length=500) tags: List[str] = Field(default_factory=list, description="User-defined tags") # Video fields url: Optional[str] = Field(None, description="Video URL, file path, or YouTube URL") loop: bool = Field(True, description="Loop video playback") playback_speed: float = Field(1.0, description="Playback speed multiplier", ge=0.1, le=10.0) start_time: Optional[float] = Field(None, description="Trim start time in seconds", ge=0) end_time: Optional[float] = Field(None, description="Trim end time in seconds", ge=0) resolution_limit: Optional[int] = Field(None, description="Max width in pixels for decode downscale", ge=64, le=7680) clock_id: Optional[str] = Field(None, description="Sync clock ID for frame-accurate timing") class PictureSourceUpdate(BaseModel): """Request to update a picture source.""" name: Optional[str] = Field(None, description="Stream name", min_length=1, max_length=100) display_index: Optional[int] = Field(None, description="Display index (raw streams)", ge=0) capture_template_id: Optional[str] = Field(None, description="Capture template ID (raw streams)") target_fps: Optional[int] = Field(None, description="Target FPS", ge=1, le=90) source_stream_id: Optional[str] = Field(None, description="Source stream ID (processed streams)") postprocessing_template_id: Optional[str] = Field(None, description="Postprocessing template ID (processed streams)") image_source: Optional[str] = Field(None, description="Image URL or file path (static_image streams)") description: Optional[str] = Field(None, description="Stream description", max_length=500) tags: Optional[List[str]] = None # Video fields url: Optional[str] = Field(None, description="Video URL, file path, or YouTube URL") loop: Optional[bool] = Field(None, description="Loop video playback") playback_speed: Optional[float] = Field(None, description="Playback speed multiplier", ge=0.1, le=10.0) start_time: Optional[float] = Field(None, description="Trim start time in seconds", ge=0) end_time: Optional[float] = Field(None, description="Trim end time in seconds", ge=0) resolution_limit: Optional[int] = Field(None, description="Max width in pixels for decode downscale", ge=64, le=7680) clock_id: Optional[str] = Field(None, description="Sync clock ID for frame-accurate timing") class PictureSourceResponse(BaseModel): """Picture source information response.""" id: str = Field(description="Stream ID") name: str = Field(description="Stream name") stream_type: str = Field(description="Stream type (raw, processed, static_image, or video)") display_index: Optional[int] = Field(None, description="Display index") capture_template_id: Optional[str] = Field(None, description="Capture template ID") target_fps: Optional[int] = Field(None, description="Target FPS") source_stream_id: Optional[str] = Field(None, description="Source stream ID") postprocessing_template_id: Optional[str] = Field(None, description="Postprocessing template ID") image_source: Optional[str] = Field(None, description="Image URL or file path") tags: List[str] = Field(default_factory=list, description="User-defined tags") created_at: datetime = Field(description="Creation timestamp") updated_at: datetime = Field(description="Last update timestamp") description: Optional[str] = Field(None, description="Stream description") # Video fields url: Optional[str] = Field(None, description="Video URL") loop: Optional[bool] = Field(None, description="Loop video playback") playback_speed: Optional[float] = Field(None, description="Playback speed multiplier") start_time: Optional[float] = Field(None, description="Trim start time in seconds") end_time: Optional[float] = Field(None, description="Trim end time in seconds") resolution_limit: Optional[int] = Field(None, description="Max width for decode") clock_id: Optional[str] = Field(None, description="Sync clock ID") class PictureSourceListResponse(BaseModel): """List of picture sources response.""" streams: List[PictureSourceResponse] = Field(description="List of picture sources") count: int = Field(description="Number of streams") class PictureSourceTestRequest(BaseModel): """Request to test a picture source.""" capture_duration: float = Field(default=5.0, ge=0.0, le=30.0, description="Duration to capture in seconds (0 = single frame)") border_width: int = Field(default=10, ge=1, le=100, description="Border width in pixels for preview") class ImageValidateRequest(BaseModel): """Request to validate an image source (URL or file path).""" image_source: str = Field(description="Image URL or local file path") class ImageValidateResponse(BaseModel): """Response from image validation.""" valid: bool = Field(description="Whether the image source is accessible and valid") width: Optional[int] = Field(None, description="Image width in pixels") height: Optional[int] = Field(None, description="Image height in pixels") preview: Optional[str] = Field(None, description="Base64-encoded JPEG thumbnail") error: Optional[str] = Field(None, description="Error message if invalid")