diff --git a/app/modules/filemanager/transhandler.py b/app/modules/filemanager/transhandler.py index e207445d0..95803d400 100644 --- a/app/modules/filemanager/transhandler.py +++ b/app/modules/filemanager/transhandler.py @@ -536,6 +536,7 @@ class TransHandler: # 整理文件 new_item, err_msg = self.__transfer_file( fileitem=fileitem, + meta=in_meta, mediainfo=mediainfo, target_storage=target_storage, target_file=new_file, @@ -962,6 +963,7 @@ class TransHandler: def __transfer_file( self, fileitem: FileItem, + meta: Optional[MetaBase], mediainfo: MediaInfo, source_oper: StorageBase, target_oper: StorageBase, @@ -974,6 +976,7 @@ class TransHandler: """ 整理一个文件,同时处理其他相关文件 :param fileitem: 原文件 + :param meta: 元数据 :param mediainfo: 媒体信息 :param source_oper: 源存储操作对象 :param target_oper: 目标存储操作对象 @@ -990,6 +993,7 @@ class TransHandler: ) event_data = TransferInterceptEventData( fileitem=fileitem, + meta=meta, mediainfo=mediainfo, target_storage=target_storage, target_path=target_file, diff --git a/app/schemas/event.py b/app/schemas/event.py index 75c9f21e5..15c350908 100644 --- a/app/schemas/event.py +++ b/app/schemas/event.py @@ -388,6 +388,7 @@ class TransferInterceptEventData(ChainEventData): Attributes: # 输入参数 fileitem (FileItem): 源文件 + meta (Any): 元数据 target_storage (str): 目标存储 target_path (Path): 目标路径 transfer_type (str): 整理方式(copy、move、link、softlink等) @@ -401,6 +402,7 @@ class TransferInterceptEventData(ChainEventData): # 输入参数 fileitem: FileItem = Field(..., description="源文件") + meta: Optional[Any] = Field(default=None, description="元数据") mediainfo: Any = Field(..., description="媒体信息") target_storage: str = Field(..., description="目标存储") target_path: Path = Field(..., description="目标路径") diff --git a/tests/test_transfer_job_manager.py b/tests/test_transfer_job_manager.py index d92f85d06..7e02f74b7 100644 --- a/tests/test_transfer_job_manager.py +++ b/tests/test_transfer_job_manager.py @@ -265,6 +265,81 @@ class TransferJobManagerTest(unittest.TestCase): self.assertEqual(target_item, transferinfo.target_item) self.assertEqual(target_folder, transferinfo.target_diritem) + def test_single_file_transfer_intercept_event_carries_file_meta(self): + """ + 单文件整理拦截事件应携带元数据,便于事件处理器按季集匹配。 + """ + handler = TransHandler() + source_item = FileItem( + storage="alist", + path="/downloads/Test.Show.S02E03.mkv", + type="file", + name="Test.Show.S02E03.mkv", + basename="Test.Show.S02E03", + extension="mkv", + size=1024, + modify_time=1715939275.0, + ) + target_path = Path("/library") + target_file = Path("/library/Test.Show.S02E03.mkv") + target_folder = FileItem( + storage="alist", + type="dir", + path="/library/", + name="library", + basename="library", + ) + target_item = FileItem( + storage="alist", + path=target_file.as_posix(), + type="file", + name=target_file.name, + basename=target_file.stem, + extension="mkv", + size=1024, + ) + source_oper = SimpleNamespace( + is_support_transtype=lambda transfer_type: True, + move=lambda fileitem, path, name: True, + ) + target_oper = SimpleNamespace( + get_folder=lambda path: target_folder, + get_item=lambda path: None, + ) + in_meta = MetaVideo("Test.Show.S02E03") + + with patch.object( + TransHandler, "get_rename_path", return_value=target_file + ), patch( + "app.modules.filemanager.transhandler.DirectoryHelper.get_media_root_path", + return_value=Path("/library"), + ), patch.object( + TransHandler, + "_TransHandler__transfer_command", + return_value=(target_item, ""), + ), patch( + "app.modules.filemanager.transhandler.eventmanager.send_event", + return_value=None, + ) as send_event: + transferinfo = handler.transfer_media( + fileitem=source_item, + in_meta=in_meta, + mediainfo=make_media_info(), + target_storage="alist", + target_path=target_path, + transfer_type="move", + source_oper=source_oper, + target_oper=target_oper, + need_scrape=True, + need_notify=True, + ) + + self.assertTrue(transferinfo.success) + event_data = send_event.call_args.args[1] + self.assertIs(in_meta, event_data.meta) + self.assertEqual(2, event_data.meta.begin_season) + self.assertEqual(3, event_data.meta.begin_episode) + def test_success_callback_uses_transfer_result_target_diritem(self): """ 回调发送刮削事件时应直接使用整理结果里的目标目录项。