"""Subtitle domain entities.""" from dataclasses import dataclass from ..shared.value_objects import FilePath, ImdbId from .value_objects import Language, SubtitleFormat, TimingOffset @dataclass class Subtitle: """ Subtitle entity representing a subtitle file. Can be associated with either a movie or a TV show episode. """ media_imdb_id: ImdbId language: Language format: SubtitleFormat file_path: FilePath # Optional: for TV shows season_number: int | None = None episode_number: int | None = None # Subtitle metadata timing_offset: TimingOffset = TimingOffset(0) hearing_impaired: bool = False forced: bool = False # Forced subtitles (for foreign language parts) # Source information source: str | None = None # e.g., "OpenSubtitles", "Subscene" uploader: str | None = None download_count: int | None = None rating: float | None = None def __post_init__(self): """Validate subtitle entity.""" # Ensure ImdbId is actually an ImdbId instance if not isinstance(self.media_imdb_id, ImdbId): if isinstance(self.media_imdb_id, str): object.__setattr__(self, "media_imdb_id", ImdbId(self.media_imdb_id)) # Ensure Language is actually a Language instance if not isinstance(self.language, Language): if isinstance(self.language, str): object.__setattr__(self, "language", Language.from_code(self.language)) # Ensure SubtitleFormat is actually a SubtitleFormat instance if not isinstance(self.format, SubtitleFormat): if isinstance(self.format, str): object.__setattr__( self, "format", SubtitleFormat.from_extension(self.format) ) # Ensure FilePath is actually a FilePath instance if not isinstance(self.file_path, FilePath): object.__setattr__(self, "file_path", FilePath(self.file_path)) def is_for_movie(self) -> bool: """Check if this subtitle is for a movie.""" return self.season_number is None and self.episode_number is None def is_for_episode(self) -> bool: """Check if this subtitle is for a TV show episode.""" return self.season_number is not None and self.episode_number is not None def get_filename(self) -> str: """ Get the suggested filename for this subtitle. Format for movies: "Movie.Title.{lang}.{format}" Format for episodes: "S01E05.{lang}.{format}" """ if self.is_for_episode(): base = f"S{self.season_number:02d}E{self.episode_number:02d}" else: # For movies, use the file path stem base = self.file_path.value.stem parts = [base, self.language.value] if self.hearing_impaired: parts.append("hi") if self.forced: parts.append("forced") return f"{'.'.join(parts)}.{self.format.value}" def __str__(self) -> str: if self.is_for_episode(): return f"Subtitle S{self.season_number:02d}E{self.episode_number:02d} ({self.language.value})" return f"Subtitle ({self.language.value})" def __repr__(self) -> str: return f"Subtitle(media={self.media_imdb_id}, lang={self.language.value})"