"""Movie domain entities.""" from dataclasses import dataclass, field from typing import Optional from datetime import datetime from ..shared.value_objects import ImdbId, FilePath, FileSize from .value_objects import MovieTitle, ReleaseYear, Quality @dataclass class Movie: """ Movie entity representing a movie in the media library. This is the main aggregate root for the movies domain. """ imdb_id: ImdbId title: MovieTitle release_year: Optional[ReleaseYear] = None quality: Quality = Quality.UNKNOWN file_path: Optional[FilePath] = None file_size: Optional[FileSize] = None tmdb_id: Optional[int] = None overview: Optional[str] = None poster_path: Optional[str] = None vote_average: Optional[float] = None added_at: datetime = field(default_factory=datetime.now) def __post_init__(self): """Validate movie entity.""" # Ensure ImdbId is actually an ImdbId instance if not isinstance(self.imdb_id, ImdbId): if isinstance(self.imdb_id, str): object.__setattr__(self, 'imdb_id', ImdbId(self.imdb_id)) else: raise ValueError(f"imdb_id must be ImdbId or str, got {type(self.imdb_id)}") # Ensure MovieTitle is actually a MovieTitle instance if not isinstance(self.title, MovieTitle): if isinstance(self.title, str): object.__setattr__(self, 'title', MovieTitle(self.title)) else: raise ValueError(f"title must be MovieTitle or str, got {type(self.title)}") def has_file(self) -> bool: """Check if the movie has an associated file.""" return self.file_path is not None and self.file_path.exists() def is_downloaded(self) -> bool: """Check if the movie is downloaded (has a file).""" return self.has_file() def get_folder_name(self) -> str: """ Get the folder name for this movie. Format: "Title (Year)" Example: "Inception (2010)" """ if self.release_year: return f"{self.title.value} ({self.release_year.value})" return self.title.value def get_filename(self) -> str: """ Get the suggested filename for this movie. Format: "Title.Year.Quality.ext" Example: "Inception.2010.1080p.mkv" """ parts = [self.title.normalized()] if self.release_year: parts.append(str(self.release_year.value)) if self.quality != Quality.UNKNOWN: parts.append(self.quality.value) # Extension will be added based on actual file return ".".join(parts) def __str__(self) -> str: return f"{self.title.value} ({self.release_year.value if self.release_year else 'Unknown'})" def __repr__(self) -> str: return f"Movie(imdb_id={self.imdb_id}, title='{self.title.value}')"