From 7c7561029a4462f4defb7bf5a2948dd84bf392b0 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sat, 23 Nov 2024 11:19:25 +0800 Subject: [PATCH] =?UTF-8?q?fix=20#3178=20=E6=89=8B=E5=8A=A8=E6=95=B4?= =?UTF-8?q?=E7=90=86=E6=97=B6=E6=94=AF=E6=8C=81=E9=80=89=E6=8B=A9=E4=B8=80?= =?UTF-8?q?=E4=BA=8C=E7=BA=A7=E5=88=86=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/endpoints/transfer.py | 4 ++ app/chain/__init__.py | 5 +++ app/chain/transfer.py | 13 +++++- app/modules/filemanager/__init__.py | 67 ++++++++++++++++++++--------- 4 files changed, 68 insertions(+), 21 deletions(-) diff --git a/app/api/endpoints/transfer.py b/app/api/endpoints/transfer.py index ac732766..5cc16a41 100644 --- a/app/api/endpoints/transfer.py +++ b/app/api/endpoints/transfer.py @@ -35,6 +35,8 @@ class ManualTransferItem(BaseModel): episode_offset: Optional[str] = None, min_filesize: Optional[int] = 0, scrape: bool = False, + library_type_folder: bool = False, + library_category_folder: bool = False, from_history: bool = False @@ -148,6 +150,8 @@ def manual_transfer(transer_item: ManualTransferItem, epformat=epformat, min_filesize=transer_item.min_filesize, scrape=transer_item.scrape, + library_type_folder=transer_item.library_type_folder, + library_category_folder=transer_item.library_category_folder, force=force ) # 失败 diff --git a/app/chain/__init__.py b/app/chain/__init__.py index 1e4ac296..33aa065e 100644 --- a/app/chain/__init__.py +++ b/app/chain/__init__.py @@ -385,6 +385,7 @@ class ChainBase(metaclass=ABCMeta): target_directory: TransferDirectoryConf = None, target_storage: str = None, target_path: Path = None, transfer_type: str = None, scrape: bool = None, + library_type_folder: bool = False, library_category_folder: bool = False, episodes_info: List[TmdbEpisode] = None) -> Optional[TransferInfo]: """ 文件转移 @@ -396,6 +397,8 @@ class ChainBase(metaclass=ABCMeta): :param target_path: 目标路径 :param transfer_type: 转移模式 :param scrape: 是否刮削元数据 + :param library_type_folder: 是否按类型创建目录 + :param library_category_folder: 是否按类别创建目录 :param episodes_info: 当前季的全部集信息 :return: {path, target_path, message} """ @@ -404,6 +407,8 @@ class ChainBase(metaclass=ABCMeta): target_directory=target_directory, target_path=target_path, target_storage=target_storage, transfer_type=transfer_type, scrape=scrape, + library_type_folder=library_type_folder, + library_category_folder=library_category_folder, episodes_info=episodes_info) def transfer_completed(self, hashs: str, downloader: str = None) -> None: diff --git a/app/chain/transfer.py b/app/chain/transfer.py index 8e179856..2274f56c 100644 --- a/app/chain/transfer.py +++ b/app/chain/transfer.py @@ -148,6 +148,7 @@ class TransferChain(ChainBase): target_directory: TransferDirectoryConf = None, target_storage: str = None, target_path: Path = None, transfer_type: str = None, scrape: bool = None, + library_type_folder: bool = False, library_category_folder: bool = False, season: int = None, epformat: EpisodeFormat = None, min_filesize: int = 0, download_hash: str = None, force: bool = False, src_match: bool = False) -> Tuple[bool, str]: @@ -161,6 +162,8 @@ class TransferChain(ChainBase): :param target_path: 目标路径 :param transfer_type: 整理类型 :param scrape: 是否刮削元数据 + :param library_type_folder: 媒体库类型子目录 + :param library_category_folder: 媒体库类别子目录 :param season: 季 :param epformat: 剧集格式 :param min_filesize: 最小文件大小(MB) @@ -409,7 +412,9 @@ class TransferChain(ChainBase): target_path=target_path, transfer_type=transfer_type, episodes_info=episodes_info, - scrape=scrape) + scrape=scrape, + library_type_folder=library_type_folder, + library_category_folder=library_category_folder) if not transferinfo: logger.error("文件整理模块运行失败") return False, "文件整理模块运行失败" @@ -680,6 +685,8 @@ class TransferChain(ChainBase): epformat: EpisodeFormat = None, min_filesize: int = 0, scrape: bool = None, + library_type_folder: bool = False, + library_category_folder: bool = False, force: bool = False) -> Tuple[bool, Union[str, list]]: """ 手动整理,支持复杂条件,带进度显示 @@ -694,6 +701,8 @@ class TransferChain(ChainBase): :param epformat: 剧集格式 :param min_filesize: 最小文件大小(MB) :param scrape: 是否刮削元数据 + :param library_type_folder: 是否按类型建立目录 + :param library_category_folder: 是否按类别建立目录 :param force: 是否强制整理 """ logger.info(f"手动整理:{fileitem.path} ...") @@ -722,6 +731,8 @@ class TransferChain(ChainBase): epformat=epformat, min_filesize=min_filesize, scrape=scrape, + library_type_folder=library_type_folder, + library_category_folder=library_category_folder, force=force, ) if not state: diff --git a/app/modules/filemanager/__init__.py b/app/modules/filemanager/__init__.py index 063a65bb..ea90394b 100644 --- a/app/modules/filemanager/__init__.py +++ b/app/modules/filemanager/__init__.py @@ -322,6 +322,7 @@ class FileManagerModule(_ModuleBase): target_directory: TransferDirectoryConf = None, target_storage: str = None, target_path: Path = None, transfer_type: str = None, scrape: bool = None, + library_type_folder: bool = False, library_category_folder: bool = False, episodes_info: List[TmdbEpisode] = None) -> TransferInfo: """ 文件整理 @@ -333,6 +334,8 @@ class FileManagerModule(_ModuleBase): :param target_path: 目标路径 :param transfer_type: 转移模式 :param scrape: 是否刮削元数据 + :param library_type_folder: 是否按媒体类型创建目录 + :param library_category_folder: 是否按媒体类别创建目录 :param episodes_info: 当前季的全部集信息 :return: {path, target_path, message} """ @@ -350,7 +353,9 @@ class FileManagerModule(_ModuleBase): # 获取目标路径 if target_directory: # 拼装媒体库一、二级子目录 - target_path = self.__get_dest_dir(mediainfo=mediainfo, target_dir=target_directory) + target_path = self.__get_dest_dir(mediainfo=mediainfo, target_dir=target_directory, + need_type_folder=library_type_folder, + need_category_folder=library_category_folder) # 目标存储类型 if not target_storage: target_storage = target_directory.library_storage @@ -362,24 +367,27 @@ class FileManagerModule(_ModuleBase): return TransferInfo(success=False, fileitem=fileitem, message=f"{target_directory.name} 未设置整理方式") - # 是否需要刮削 - if scrape is None: - need_scrape = target_directory.scraping - else: - need_scrape = scrape # 是否需要重命名 need_rename = target_directory.renaming # 是否需要通知 need_notify = target_directory.notify # 覆盖模式 overwrite_mode = target_directory.overwrite_mode + # 是否需要刮削 + if scrape is None: + need_scrape = target_directory.scraping + else: + need_scrape = scrape elif target_path: # 手动整理的场景,有自定义目标路径 + target_path = self.__get_dest_path(mediainfo=mediainfo, target_path=target_path, + need_type_folder=library_type_folder, + need_category_folder=library_category_folder) need_scrape = scrape or False need_rename = True need_notify = False overwrite_mode = "never" - logger.warn(f"{target_path} 为自定义路径, 通知将不会发送") + logger.info(f"{target_path} 为自定义路径, 通知将不会发送") else: # 未找到有效的媒体库目录 logger.error( @@ -827,26 +835,43 @@ class FileManagerModule(_ModuleBase): return None, errmsg @staticmethod - def __get_dest_dir(mediainfo: MediaInfo, target_dir: TransferDirectoryConf) -> Path: + def __get_dest_path(mediainfo: MediaInfo, target_path: Path, + need_type_folder: bool = False, need_category_folder: bool = False): + """ + 获取目标路径 + """ + if need_type_folder: + target_path = target_path / mediainfo.type.value + if need_category_folder and mediainfo.category: + target_path = target_path / mediainfo.category + return target_path + + @staticmethod + def __get_dest_dir(mediainfo: MediaInfo, target_dir: TransferDirectoryConf, + need_type_folder: bool = None, need_category_folder: bool = None) -> Path: """ 根据设置并装媒体库目录 :param mediainfo: 媒体信息 :target_dir: 媒体库根目录 - :typename_dir: 是否加上类型目录 + :need_type_folder: 是否需要按媒体类型创建目录 + :need_category_folder: 是否需要按媒体类别创建目录 """ - if not target_dir.media_type and target_dir.library_type_folder: + if need_type_folder is None: + need_type_folder = target_dir.library_type_folder + if need_category_folder is None: + need_category_folder = target_dir.library_category_folder + if not target_dir.media_type and need_type_folder: # 一级自动分类 library_dir = Path(target_dir.library_path) / mediainfo.type.value - elif target_dir.media_type and target_dir.library_type_folder: + elif target_dir.media_type and need_type_folder: # 一级手动分类 library_dir = Path(target_dir.library_path) / target_dir.media_type else: library_dir = Path(target_dir.library_path) - - if not target_dir.media_category and target_dir.library_category_folder and mediainfo.category: + if not target_dir.media_category and need_category_folder and mediainfo.category: # 二级自动分类 library_dir = library_dir / mediainfo.category - elif target_dir.media_category and target_dir.library_category_folder: + elif target_dir.media_category and need_category_folder: # 二级手动分类 library_dir = library_dir / target_dir.media_category @@ -1212,17 +1237,19 @@ class FileManagerModule(_ModuleBase): # 重命名格式 rename_format = settings.TV_RENAME_FORMAT \ if mediainfo.type == MediaType.TV else settings.MOVIE_RENAME_FORMAT - # 获取相对路径(重命名路径) - rel_path = self.get_rename_path( + # 计算重命名中的文件夹层数 + rename_format_level = len(rename_format.split("/")) - 1 + if rename_format_level < 1: + continue + # 获取路径(重命名路径) + target_path = self.get_rename_path( + path=dir_path, template_string=rename_format, rename_dict=self.__get_naming_dict(meta=MetaInfo(mediainfo.title), mediainfo=mediainfo) ) # 取相对路径的第1层目录 - if rel_path.parts: - media_path = dir_path / rel_path.parts[0] - else: - continue + media_path = target_path.parents[rename_format_level - 1] # 检索媒体文件 fileitem = storage_oper.get_item(media_path) if not fileitem: