from datetime import datetime from typing import Dict, List, Any, ClassVar, Optional from uuid import UUID from pydantic import BaseModel, ConfigDict, model_validator, field_validator class MessageHeaderWrapper(BaseModel): Id: int Type: str Timestamp: datetime Source: str @field_validator('Timestamp', mode='before') @classmethod def to_datetime(cls, value: str) -> datetime: return datetime.fromtimestamp(int(value)/1000) class SMSMessage(BaseModel): model_config = ConfigDict(arbitrary_types_allowed=True) path: ClassVar[List[str]] params: ClassVar[Dict[str, Any] | None] = None MessageHeader: MessageHeaderWrapper class DCPInfoWrapper(BaseModel): ID: UUID Title: str Path: str Size: int ImportTime: datetime IsImported: bool VerifyStatus: str ValidateStatus: str IsPlayable: bool IsTransferred: bool class DCPInfoList(SMSMessage): DCPInfo: List[DCPInfoWrapper] | None path = ['content', 'dcp', 'info', 'list'] params = { 'formatDate': 'false' } class PowerStatusWrapper(BaseModel): Device: str State: str class PowerStatus(SMSMessage): PowerStatus: List[PowerStatusWrapper] path = ['status', 'sms', 'powerstatus'] class ShowStatusDetailWrapper(BaseModel): Type: str Id: UUID RemainingTime: int ElapsedTime: int TotalDuration: int CurrentEventId: UUID CurrentEventType: str IsStoppedByMalfunction: bool RewindTimeList: List[int] MalfunctionTime: int @field_validator('RewindTimeList', mode='before') @classmethod def extract(cls, data: str) -> List[int]: return [int(v) for v in data.split(',')] class ShowStatus(SMSMessage): PlayState: str ShowStatusDetail: ShowStatusDetailWrapper PlayBackMode: str AtmosPlayingStatus: str path = ['playback', 'showstatus'] class ImportProgressWrapper(BaseModel): TotalBytesToTransfer: int BytesTransferred: int PercentCompleted: int InProgress: bool ImportPath: str CompletionStatus: str CompletionTime: Optional[datetime] = None DCPTitle: Optional[str] = None class ValidationProgress(BaseModel): TotalBytesToValidate: int BytesValidated: int PercentCompleted: int InProgress: bool Id: UUID CompletionStatus: str CompletionTime: datetime type ValidationProgressElem = ValidationProgress class ValidationProgressWrapper(BaseModel): ValidationProgress: ValidationProgressElem class JobProgress(BaseModel): Id: int ValidateAfterImport: bool AggregatePercentValidated: int State: str ImportProgress: ImportProgressWrapper ValidationProgressList: ValidationProgressWrapper | None IngestedByFolder: bool ContentsTransferType: str type JobProgressElem = JobProgress class JobProgressWrapper(BaseModel): JobProgress: List[JobProgressElem] | JobProgressElem class DCPImportJobList(SMSMessage): IsPaused: bool JobProgressList: JobProgressWrapper | None path = ['content', 'dcp', 'command'] params = {'action': 'ListImportJobs'} class StorageInfo(SMSMessage): FileSystem: str TotalCapacity: int SpaceInUse: int FreeSpace: int path = ['status', 'storage', 'info'] params = {'area': 'DCP'} @model_validator(mode='before') @classmethod def extract(cls, data: Any) -> Any: if isinstance(data, dict): data.update(**data['MBStorageUsage']) del data['MBStorageUsage'] return data