diff --git a/backend/src/torrent/service.py b/backend/src/torrent/service.py index d8ad92a..696bfc1 100644 --- a/backend/src/torrent/service.py +++ b/backend/src/torrent/service.py @@ -19,7 +19,7 @@ from config import BasicConfig from indexer import IndexerQueryResult from torrent.repository import get_seasons_files_of_torrent, get_show_of_torrent, save_torrent from torrent.schemas import Torrent, TorrentStatus, TorrentId -from torrent.utils import list_files_recursively, get_torrent_filepath, import_file +from torrent.utils import list_files_recursively, get_torrent_filepath, import_file, extract_archives from tv.schemas import SeasonFile, Show log = logging.getLogger(__name__) @@ -139,30 +139,38 @@ class TorrentService: self.api_client.torrents_resume(torrent_hashes=torrent.hash) return self.get_torrent_status(torrent=torrent) - # TODO: add ability to automatically extract archives def import_torrent(self, torrent: Torrent) -> Torrent: log.info(f"importing torrent {torrent}") + + # get all files, extract archives if necessary and get all files (extracted) files again all_files = list_files_recursively(path=get_torrent_filepath(torrent=torrent)) log.debug(f"Found {len(all_files)} files downloaded by the torrent") - files = [] + extract_archives(all_files) + all_files = list_files_recursively(path=get_torrent_filepath(torrent=torrent)) + + # Filter videos and subtitles from all files + video_files = [] subtitle_files = [] for file in all_files: file_type = mimetypes.guess_file_type(file) if file_type[0] is not None: if file_type[0].startswith("video"): - files.append(file) + video_files.append(file) log.debug(f"File is a video, it will be imported: {file}") elif file_type[0].startswith("text") and file.suffix == ".srt": subtitle_files.append(file) log.debug(f"File is a subtitle, it will be imported: {file}") else: - log.debug(f"File is not a video, will not be imported: {file}") - log.info(f"Importing these {len(files)} files:\n" + pprint.pformat(files)) + log.debug(f"File is neither a video nor a subtitle, will not be imported: {file}") + log.info(f"Importing these {len(video_files)} files:\n" + pprint.pformat(video_files)) + # Fetch show and season information show: Show = get_show_of_torrent(db=self.db, torrent_id=torrent.id) show_file_path = BasicConfig().tv_directory / f"{show.name} ({show.year}) [{show.metadata_provider}id-{show.external_id}]" - season_files: list[SeasonFile] = get_seasons_files_of_torrent(db=self.db, torrent_id=torrent.id) + log.info(f"Found {len(season_files)} season files associated with torrent {torrent.title}") + + # creating directories and hard linking files for season_file in season_files: season = tv.service.get_season(db=self.db, season_id=season_file.season_id) season_path = show_file_path / Path(f"Season {season.number}") @@ -196,7 +204,7 @@ class TorrentService: log.debug(f"Didn't find any pattern {subtitle_pattern} in subtitle file: {subtitle_file.name}") # import episode videos - for file in files: + for file in video_files: log.debug(f"Searching for pattern {pattern} in video file: {file.name}") if re.search(pattern, file.name): log.debug(f"Found matching pattern: {pattern} in file {file.name}") diff --git a/backend/src/torrent/utils.py b/backend/src/torrent/utils.py index 76d303d..f69e3e9 100644 --- a/backend/src/torrent/utils.py +++ b/backend/src/torrent/utils.py @@ -1,25 +1,37 @@ import logging +import mimetypes from pathlib import Path +import patoolib + from config import BasicConfig from torrent.schemas import Torrent +log = logging.getLogger(__name__) def list_files_recursively(path: Path = Path(".")) -> list[Path]: files = list(path.glob("**/*")) - logging.debug(f"Found {len(files)} entries via glob") + log.debug(f"Found {len(files)} entries via glob") valid_files = [] for x in files: if x.is_dir(): - logging.debug(f"'{x}' is a directory") + log.debug(f"'{x}' is a directory") elif x.is_symlink(): - logging.debug(f"'{x}' is a symlink") + log.debug(f"'{x}' is a symlink") else: valid_files.append(x) - logging.debug(f"Returning {len(valid_files)} files after filtering") + log.debug(f"Returning {len(valid_files)} files after filtering") return valid_files +def extract_archives(files): + for file in files: + file_type = mimetypes.guess_type(file) + log.debug(f"File: {file}, Size: {file.stat().st_size} bytes, Type: {file_type}") + if file_type[0] == 'application/x-compressed': + log.debug(f"File {file} is a compressed file, extracting it into directory {file.parent}") + patoolib.extract_archive(str(file), outdir=str(file.parent)) + def get_torrent_filepath(torrent: Torrent): return BasicConfig().torrent_directory / torrent.title