From a0ad8faaf7480f56029e668e342ec5ca622953c6 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Wed, 23 Oct 2024 14:43:47 +0800 Subject: [PATCH] fix #2913 --- .github/workflows/build.yml | 4 +- app/chain/__init__.py | 12 ++--- app/chain/transfer.py | 67 ++++++++++++---------------- app/modules/filemanager/__init__.py | 32 ++++++++----- app/modules/qbittorrent/__init__.py | 17 +------ app/modules/transmission/__init__.py | 17 +------ app/monitor.py | 21 ++++----- app/schemas/system.py | 4 +- app/schemas/transfer.py | 2 + 9 files changed, 71 insertions(+), 105 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9b18c92b..d532003c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -69,8 +69,8 @@ jobs: - name: Generate Release uses: softprops/action-gh-release@v2 with: - tag_name: ${{ env.app_version }} - name: ${{ env.app_version }} + tag_name: v${{ env.app_version }} + name: v${{ env.app_version }} draft: false prerelease: false make_latest: false diff --git a/app/chain/__init__.py b/app/chain/__init__.py index 465a3486..44a4c03e 100644 --- a/app/chain/__init__.py +++ b/app/chain/__init__.py @@ -382,7 +382,7 @@ class ChainBase(metaclass=ABCMeta): return self.run_module("list_torrents", status=status, hashs=hashs, downloader=downloader) def transfer(self, fileitem: FileItem, meta: MetaBase, mediainfo: MediaInfo, - transfer_type: str, target_storage: str = None, target_path: Path = None, + transfer_type: str = None, target_storage: str = None, target_path: Path = None, episodes_info: List[TmdbEpisode] = None, scrape: bool = None) -> Optional[TransferInfo]: """ @@ -401,17 +401,13 @@ class ChainBase(metaclass=ABCMeta): transfer_type=transfer_type, target_storage=target_storage, target_path=target_path, episodes_info=episodes_info, scrape=scrape) - def transfer_completed(self, hashs: str, path: Path = None, - downloader: str = None, transfer_type: str = None) -> None: + def transfer_completed(self, hashs: str, downloader: str = None) -> None: """ - 转移完成后的处理 + 下载器转移完成后的处理 :param hashs: 种子Hash - :param path: 源目录 :param downloader: 下载器 - :param transfer_type: 整理方式 """ - return self.run_module("transfer_completed", hashs=hashs, path=path, - downloader=downloader, transfer_type=transfer_type) + return self.run_module("transfer_completed", hashs=hashs, downloader=downloader) def remove_torrents(self, hashs: Union[str, list], delete_file: bool = True, downloader: str = None) -> bool: diff --git a/app/chain/transfer.py b/app/chain/transfer.py index b716a74b..0b5472fa 100644 --- a/app/chain/transfer.py +++ b/app/chain/transfer.py @@ -92,16 +92,16 @@ class TransferChain(ChainBase): logger.warn(f"文件不存在:{file_path}") continue # 检查是否为下载器监控目录中的文件 - transfer_dirinfo = None + is_downloader_monitor = False for dir_info in download_dirs: if dir_info.monitor_type != "downloader": continue if not dir_info.download_path: continue if file_path.is_relative_to(Path(dir_info.download_path)): - transfer_dirinfo = dir_info + is_downloader_monitor = True break - if not transfer_dirinfo: + if not is_downloader_monitor: logger.debug(f"文件 {file_path} 不在下载器监控目录中,不通过下载器进行整理") continue # 查询下载记录识别情况 @@ -127,7 +127,7 @@ class TransferChain(ChainBase): mediainfo = None # 执行整理 - self.__do_transfer( + state, errmsg = self.__do_transfer( fileitem=FileItem( storage="local", path=str(file_path), @@ -136,15 +136,14 @@ class TransferChain(ChainBase): size=file_path.stat().st_size, extension=file_path.suffix.lstrip('.'), ), - target_storage=transfer_dirinfo.library_storage, mediainfo=mediainfo, - download_hash=torrent.hash, - notify=transfer_dirinfo.notify + download_hash=torrent.hash ) # 设置下载任务状态 - self.transfer_completed(hashs=torrent.hash, path=torrent.path, - transfer_type=transfer_dirinfo.transfer_type) + if state: + self.transfer_completed(hashs=torrent.hash) + # 结束 logger.info("所有下载器中下载完成的文件已整理完成") return True @@ -155,7 +154,7 @@ class TransferChain(ChainBase): target_path: Path = None, transfer_type: str = None, season: int = None, epformat: EpisodeFormat = None, min_filesize: int = 0, scrape: bool = None, - force: bool = False, notify: bool = True) -> Tuple[bool, str]: + force: bool = False) -> Tuple[bool, str]: """ 执行一个复杂目录的整理操作 :param fileitem: 文件项 @@ -193,6 +192,8 @@ class TransferChain(ChainBase): fail_num = 0 # 跳过数量 skip_num = 0 + # 本次整理方式 + current_transfer_type = transfer_type # 获取待整理路径清单 trans_items = self.__get_trans_fileitems(fileitem) @@ -412,6 +413,7 @@ class TransferChain(ChainBase): continue # 汇总信息 + current_transfer_type = transferinfo.transfer_type mkey = (file_mediainfo.tmdb_id, file_meta.begin_season) if mkey not in medias: # 新增信息 @@ -454,7 +456,7 @@ class TransferChain(ChainBase): transfer_meta = metas[mkey] transfer_info = transfers[mkey] # 发送通知 - if notify: + if transfer_info.need_notify: se_str = None if media.type == MediaType.TV: se_str = f"{transfer_meta.season} {StringUtils.format_ep(season_episodes[mkey])}" @@ -473,9 +475,21 @@ class TransferChain(ChainBase): self.eventmanager.send_event(EventType.TransferComplete, { 'meta': transfer_meta, 'mediainfo': media, - 'transferinfo': transfer_info + 'transferinfo': transfer_info, + 'download_hash': download_hash, }) + # 移动模式处理 + if current_transfer_type in ["move"]: + # 下载器hash + if download_hash: + if self.remove_torrents(download_hash): + logger.info(f"移动模式删除种子成功:{download_hash} ") + # 删除残留文件 + if fileitem: + logger.warn(f"删除残留文件夹:【{fileitem.storage}】{fileitem.path}") + self.storagechain.delete_file(fileitem) + # 结束进度 logger.info(f"{fileitem.path} 整理完成,共 {total_num} 个文件," f"失败 {fail_num} 个,跳过 {skip_num} 个") @@ -617,21 +631,10 @@ class TransferChain(ChainBase): # 强制整理 if history.src_fileitem: - # 解析源文件对象 - fileitem = FileItem(**history.src_fileitem) - # 检查目录是否发送通知 - transfer_dirinfo = None - for dir_info in self.directoryhelper.get_download_dirs(): - if not dir_info.download_path: - continue - if fileitem.path.is_relative_to(Path(dir_info.download_path)): - transfer_dirinfo = dir_info - break - state, errmsg = self.__do_transfer(fileitem=fileitem, + state, errmsg = self.__do_transfer(fileitem=FileItem(**history.src_fileitem), mediainfo=mediainfo, download_hash=history.download_hash, - force=True, - notify=transfer_dirinfo.notify if transfer_dirinfo else False) + force=True) if not state: return False, errmsg @@ -666,16 +669,6 @@ class TransferChain(ChainBase): :param force: 是否强制整理 """ logger.info(f"手动整理:{fileitem.path} ...") - - # 检查目录是否发送通知 - transfer_dirinfo = None - for dir_info in self.directoryhelper.get_download_dirs(): - if not dir_info.download_path: - continue - if fileitem.path.is_relative_to(Path(dir_info.download_path)): - transfer_dirinfo = dir_info - break - if tmdbid or doubanid: # 有输入TMDBID时单个识别 # 识别媒体信息 @@ -702,7 +695,6 @@ class TransferChain(ChainBase): min_filesize=min_filesize, scrape=scrape, force=force, - notify=transfer_dirinfo.notify if transfer_dirinfo else False ) if not state: return False, errmsg @@ -720,8 +712,7 @@ class TransferChain(ChainBase): epformat=epformat, min_filesize=min_filesize, scrape=scrape, - force=force, - notify=transfer_dirinfo.notify if transfer_dirinfo else False) + force=force) return state, errmsg def send_transfer_message(self, meta: MetaBase, mediainfo: MediaInfo, diff --git a/app/modules/filemanager/__init__.py b/app/modules/filemanager/__init__.py index eb45890c..dd111445 100644 --- a/app/modules/filemanager/__init__.py +++ b/app/modules/filemanager/__init__.py @@ -281,7 +281,7 @@ class FileManagerModule(_ModuleBase): return storage_oper.usage() def transfer(self, fileitem: FileItem, meta: MetaBase, mediainfo: MediaInfo, - transfer_type: str, target_storage: str = None, target_path: Path = None, + transfer_type: str = None, target_storage: str = None, target_path: Path = None, episodes_info: List[TmdbEpisode] = None, scrape: bool = None) -> TransferInfo: """ @@ -329,12 +329,15 @@ class FileManagerModule(_ModuleBase): need_rename = dir_info.renaming # 覆盖模式 overwrite_mode = dir_info.overwrite_mode + # 是否需要通知 + need_notify = dir_info.notify # 拼装媒体库一、二级子目录 target_path = self.__get_dest_dir(mediainfo=mediainfo, target_dir=dir_info) elif target_path: - # 自定义目标路径 + # 自定义目标路径,仅适用于手动整理的场景 need_scrape = scrape or False need_rename = True + need_notify = False overwrite_mode = "never" else: # 未找到有效的媒体库目录 @@ -355,7 +358,8 @@ class FileManagerModule(_ModuleBase): target_path=target_path, episodes_info=episodes_info, need_scrape=need_scrape, - need_rename=need_rename) + need_rename=need_rename, + need_notify=need_notify) def __get_storage_oper(self, _storage: str, _func: str = None) -> Optional[StorageBase]: """ @@ -811,7 +815,8 @@ class FileManagerModule(_ModuleBase): target_path: Path, episodes_info: List[TmdbEpisode] = None, need_scrape: bool = False, - need_rename: bool = True + need_rename: bool = True, + need_notify: bool = True, ) -> TransferInfo: """ 识别并整理一个文件或者一个目录下的所有文件 @@ -825,6 +830,7 @@ class FileManagerModule(_ModuleBase): :param episodes_info: 当前季的全部集信息 :param need_scrape: 是否需要刮削 :param need_rename: 是否需要重命名 + :param need_notify: 是否需要通知 :return: TransferInfo、错误信息 """ @@ -854,7 +860,8 @@ class FileManagerModule(_ModuleBase): return TransferInfo(success=False, message=errmsg, fileitem=fileitem, - transfer_type=transfer_type) + transfer_type=transfer_type, + need_notify=need_notify) logger.info(f"文件夹 {fileitem.path} 整理成功") # 返回整理后的路径 @@ -875,7 +882,8 @@ class FileManagerModule(_ModuleBase): message=f"未识别到文件集数", fileitem=fileitem, fail_list=[fileitem.path], - transfer_type=transfer_type) + transfer_type=transfer_type, + need_notify=need_notify) # 文件结束季为空 in_meta.end_season = None @@ -938,7 +946,8 @@ class FileManagerModule(_ModuleBase): target_item=target_item, target_diritem=target_diritem, fail_list=[fileitem.path], - transfer_type=transfer_type) + transfer_type=transfer_type, + need_notify=need_notify) case 'never': # 存在不覆盖 return TransferInfo(success=False, @@ -947,7 +956,8 @@ class FileManagerModule(_ModuleBase): target_item=target_item, target_diritem=target_diritem, fail_list=[fileitem.path], - transfer_type=transfer_type) + transfer_type=transfer_type, + need_notify=need_notify) case 'latest': # 仅保留最新版本 logger.info(f"当前整理覆盖模式设置为仅保留最新版本,将覆盖:{new_file}") @@ -969,7 +979,8 @@ class FileManagerModule(_ModuleBase): message=err_msg, fileitem=fileitem, fail_list=[fileitem.path], - transfer_type=transfer_type) + transfer_type=transfer_type, + need_notify=need_notify) logger.info(f"文件 {fileitem.path} 整理成功") return TransferInfo(success=True, @@ -981,7 +992,8 @@ class FileManagerModule(_ModuleBase): file_list=[fileitem.path], file_list_new=[new_item.path], need_scrape=need_scrape, - transfer_type=transfer_type) + transfer_type=transfer_type, + need_notify=need_notify) @staticmethod def __get_naming_dict(meta: MetaBase, mediainfo: MediaInfo, file_ext: str = None, diff --git a/app/modules/qbittorrent/__init__.py b/app/modules/qbittorrent/__init__.py index 303356ff..a2642b51 100644 --- a/app/modules/qbittorrent/__init__.py +++ b/app/modules/qbittorrent/__init__.py @@ -1,4 +1,3 @@ -import shutil from pathlib import Path from typing import Set, Tuple, Optional, Union, List @@ -14,7 +13,6 @@ from app.modules.qbittorrent.qbittorrent import Qbittorrent from app.schemas import TransferTorrent, DownloadingTorrent from app.schemas.types import TorrentStatus, ModuleType from app.utils.string import StringUtils -from app.utils.system import SystemUtils class QbittorrentModule(_ModuleBase, _DownloaderBase[Qbittorrent]): @@ -269,29 +267,16 @@ class QbittorrentModule(_ModuleBase, _DownloaderBase[Qbittorrent]): return None return ret_torrents - def transfer_completed(self, hashs: str, path: Path = None, - downloader: str = None, transfer_type: str = None) -> None: + def transfer_completed(self, hashs: str, downloader: str = None) -> None: """ 转移完成后的处理 :param hashs: 种子Hash - :param path: 源目录 :param downloader: 下载器 - :param transfer_type: 整理方式 """ server: Qbittorrent = self.get_instance(downloader) if not server: return None server.set_torrents_tag(ids=hashs, tags=['已整理']) - # 移动模式删除种子 - if transfer_type and transfer_type in ["move"]: - if self.remove_torrents(hashs): - logger.info(f"移动模式删除种子成功:{hashs} ") - # 删除本地残留文件 - if path and path.exists(): - files = SystemUtils.list_files(path, settings.RMT_MEDIAEXT) - if not files: - logger.warn(f"删除残留文件夹:{path}") - shutil.rmtree(path, ignore_errors=True) def remove_torrents(self, hashs: Union[str, list], delete_file: bool = True, downloader: str = None) -> Optional[bool]: diff --git a/app/modules/transmission/__init__.py b/app/modules/transmission/__init__.py index c4db841a..730b010d 100644 --- a/app/modules/transmission/__init__.py +++ b/app/modules/transmission/__init__.py @@ -1,4 +1,3 @@ -import shutil from pathlib import Path from typing import Set, Tuple, Optional, Union, List @@ -14,7 +13,6 @@ from app.modules.transmission.transmission import Transmission from app.schemas import TransferTorrent, DownloadingTorrent from app.schemas.types import TorrentStatus, ModuleType from app.utils.string import StringUtils -from app.utils.system import SystemUtils class TransmissionModule(_ModuleBase, _DownloaderBase[Transmission]): @@ -256,14 +254,11 @@ class TransmissionModule(_ModuleBase, _DownloaderBase[Transmission]): return None return ret_torrents - def transfer_completed(self, hashs: str, path: Path = None, - downloader: str = None, transfer_type: str = None) -> None: + def transfer_completed(self, hashs: str, downloader: str = None) -> None: """ 转移完成后的处理 :param hashs: 种子Hash - :param path: 源目录 :param downloader: 下载器 - :param transfer_type: 整理方式 """ # 获取下载器 server: Transmission = self.get_instance(downloader) @@ -277,16 +272,6 @@ class TransmissionModule(_ModuleBase, _DownloaderBase[Transmission]): else: tags = ['已整理'] server.set_torrent_tag(ids=hashs, tags=tags) - # 移动模式删除种子 - if transfer_type and transfer_type in ["move"]: - if self.remove_torrents(hashs): - logger.info(f"移动模式删除种子成功:{hashs} ") - # 删除本地残留文件 - if path and path.exists(): - files = SystemUtils.list_files(path, settings.RMT_MEDIAEXT) - if not files: - logger.warn(f"删除残留文件夹:{path}") - shutil.rmtree(path, ignore_errors=True) def remove_torrents(self, hashs: Union[str, list], delete_file: bool = True, downloader: str = None) -> Optional[bool]: diff --git a/app/monitor.py b/app/monitor.py index 9f402f37..1bd6e31e 100644 --- a/app/monitor.py +++ b/app/monitor.py @@ -383,8 +383,7 @@ class Monitor(metaclass=Singleton): return # 查询转移目的目录 - dir_info = self.directoryhelper.get_dir(mediainfo, src_path=Path(mon_path)) - if not dir_info: + if not self.directoryhelper.get_dir(mediainfo, src_path=Path(mon_path)): logger.warn(f"{event_path.name} 未找到对应的目标目录") return @@ -416,11 +415,7 @@ class Monitor(metaclass=Singleton): transferinfo: TransferInfo = self.chain.transfer(fileitem=file_item, meta=file_meta, mediainfo=mediainfo, - transfer_type=dir_info.transfer_type, - target_storage=dir_info.library_storage, - target_path=Path(dir_info.library_path), - episodes_info=episodes_info, - scrape=dir_info.scraping) + episodes_info=episodes_info) if not transferinfo: logger.error("文件转移模块运行失败") @@ -432,7 +427,7 @@ class Monitor(metaclass=Singleton): # 新增转移失败历史记录 self.transferhis.add_fail( fileitem=file_item, - mode=dir_info.transfer_type, + mode=transferinfo.transfer_type if transferinfo else '', download_hash=download_hash, meta=file_meta, mediainfo=mediainfo, @@ -453,15 +448,15 @@ class Monitor(metaclass=Singleton): # 新增转移成功历史记录 self.transferhis.add_success( fileitem=file_item, - mode=dir_info.transfer_type, + mode=transferinfo.transfer_type if transferinfo else '', download_hash=download_hash, meta=file_meta, mediainfo=mediainfo, transferinfo=transferinfo ) - # TODO 汇总刮削 - if dir_info.scraping: + # 汇总刮削 + if transferinfo.need_scrape: self.mediaChain.scrape_metadata(fileitem=transferinfo.target_diritem, meta=file_meta, mediainfo=mediainfo) @@ -475,11 +470,11 @@ class Monitor(metaclass=Singleton): }) # 发送消息汇总 - if dir_info.notify: + if transferinfo.need_notify: self.__collect_msg_medias(mediainfo=mediainfo, file_meta=file_meta, transferinfo=transferinfo) # 移动模式删除空目录 - if dir_info.transfer_type in ["move"]: + if transferinfo.transfer_type in ["move"]: logger.info(f"正在删除: {file_item.storage} {file_item.path}") self.storagechain.delete_file(file_item) diff --git a/app/schemas/system.py b/app/schemas/system.py index e6caea34..5ea109dc 100644 --- a/app/schemas/system.py +++ b/app/schemas/system.py @@ -127,9 +127,9 @@ class TransferDirectoryConf(BaseModel): renaming: Optional[bool] = False # 刮削 scraping: Optional[bool] = False + # 是否发送通知 + notify: Optional[bool] = True # 媒体库类型子目录 library_type_folder: Optional[bool] = False # 媒体库类别子目录 library_category_folder: Optional[bool] = False - # 是否发送通知 - notify: Optional[bool] = True diff --git a/app/schemas/transfer.py b/app/schemas/transfer.py index a5681e6b..67091379 100644 --- a/app/schemas/transfer.py +++ b/app/schemas/transfer.py @@ -66,6 +66,8 @@ class TransferInfo(BaseModel): message: Optional[str] = None # 是否需要刮削 need_scrape: Optional[bool] = False + # 是否需要通知 + need_notify: Optional[bool] = False def to_dict(self): """