"""Media organizer - Organizes movies and TV shows into proper folder structures.""" import logging from pathlib import Path from domain.movies.entities import Movie from domain.tv_shows.entities import Episode, Season, TVShow from domain.tv_shows.value_objects import SeasonNumber logger = logging.getLogger(__name__) class MediaOrganizer: """ Organizes media files into proper folder structures. This service knows how to organize movies and TV shows according to common media server conventions (Plex, Jellyfin, etc.). """ def __init__(self, movie_folder: Path, tvshow_folder: Path): """ Initialize media organizer. Args: movie_folder: Root folder for movies tvshow_folder: Root folder for TV shows """ self.movie_folder = movie_folder self.tvshow_folder = tvshow_folder def get_movie_destination(self, movie: Movie, filename: str) -> Path: """ Get the destination path for a movie file. Structure: /movies/Movie Title (Year)/Movie.Title.Year.Quality.ext Args: movie: Movie entity filename: Original filename (to extract extension) Returns: Full destination path """ # Create movie folder folder_name = movie.get_folder_name() movie_dir = self.movie_folder / folder_name # Get extension from original filename extension = Path(filename).suffix # Create new filename new_filename = movie.get_filename() + extension return movie_dir / new_filename def get_episode_destination( self, show: TVShow, episode: Episode, filename: str ) -> Path: """ Get the destination path for a TV show episode file. Structure: /tvshows/Show.Name/Season 01/S01E05.Episode.Title.ext Args: show: TVShow entity episode: Episode entity filename: Original filename (to extract extension) Returns: Full destination path """ # Create show folder show_folder_name = show.get_folder_name() show_dir = self.tvshow_folder / show_folder_name # Create season folder season = Season( show_imdb_id=show.imdb_id, season_number=episode.season_number, episode_count=0, # Not needed for folder name ) season_folder_name = season.get_folder_name() season_dir = show_dir / season_folder_name # Get extension from original filename extension = Path(filename).suffix # Create new filename new_filename = episode.get_filename() + extension return season_dir / new_filename def create_movie_directory(self, movie: Movie) -> bool: """ Create the directory structure for a movie. Args: movie: Movie entity Returns: True if successful """ folder_name = movie.get_folder_name() movie_dir = self.movie_folder / folder_name try: movie_dir.mkdir(parents=True, exist_ok=True) logger.info(f"Created movie directory: {movie_dir}") return True except Exception as e: logger.error(f"Failed to create movie directory: {e}") return False def create_episode_directory(self, show: TVShow, season_number: int) -> bool: """ Create the directory structure for a TV show season. Args: show: TVShow entity season_number: Season number Returns: True if successful """ show_folder_name = show.get_folder_name() show_dir = self.tvshow_folder / show_folder_name season = Season( show_imdb_id=show.imdb_id, season_number=SeasonNumber(season_number), episode_count=0, ) season_folder_name = season.get_folder_name() season_dir = show_dir / season_folder_name try: season_dir.mkdir(parents=True, exist_ok=True) logger.info(f"Created season directory: {season_dir}") return True except Exception as e: logger.error(f"Failed to create season directory: {e}") return False