fix(transfer): create local target before remote download (#6493)

This commit is contained in:
jxxghp
2026-08-29 10:34:14 +08:00
parent 754038566c
commit 27f357b1d2
2 changed files with 46 additions and 4 deletions

View File

@@ -1410,7 +1410,7 @@ class TransHandler:
transfer_type: str,
) -> Tuple[Optional[FileItem], str]:
"""
处理单个文件
处理单个文件,确保跨存储下载的本地目标目录已准备就绪
:param fileitem: 源文件
:param target_storage: 目标存储
:param source_oper: 源存储操作对象
@@ -1538,14 +1538,13 @@ class TransHandler:
return __get_targetitem(target_file), ""
# 网盘到本地
if transfer_type in ["copy", "move"]:
# 远程存储适配器会直接在传入目录创建文件,下载前必须先建好目录。
target_file.parent.mkdir(parents=True, exist_ok=True)
# 下载
tmp_file = source_oper.download(
fileitem=fileitem, path=target_file.parent
)
if tmp_file:
# 创建目录
if not target_file.parent.exists():
target_file.parent.mkdir(parents=True, exist_ok=True)
# 将tmp_file移动后target_file
SystemUtils.move(tmp_file, target_file)
if transfer_type == "move":

View File

@@ -401,3 +401,46 @@ def test_cross_storage_move_materializes_before_independent_source_delete(tmp_pa
assert runner.steps[0][2]["transfer_type"] == "copy"
target_oper.upload.assert_called_once()
source_oper.delete.assert_called_once_with(source_item)
def test_remote_to_local_transfer_creates_target_directory_before_download(tmp_path):
"""网盘到本地的下载开始前必须先创建缺失的目标目录。"""
target_file = tmp_path / "library" / "Season 1" / "episode.mkv"
source_item = FileItem(
storage="alist",
path="/downloads/episode.mkv",
name="episode.mkv",
type="file",
size=5,
extension="mkv",
)
def download(*, fileitem, path):
"""模拟只接受已存在本地目录的网盘下载适配器。"""
assert fileitem is source_item
assert path == target_file.parent
assert path.is_dir()
temporary_file = path / fileitem.name
temporary_file.write_bytes(b"movie")
return temporary_file
source_oper = Mock()
source_oper.download.side_effect = download
result, error = TransHandler._TransHandler__transfer_command(
fileitem=source_item,
target_storage="local",
source_oper=source_oper,
target_oper=Mock(),
target_file=target_file,
transfer_type="move",
)
assert error == ""
assert result is not None
assert target_file.read_bytes() == b"movie"
source_oper.download.assert_called_once_with(
fileitem=source_item,
path=target_file.parent,
)
source_oper.delete.assert_called_once_with(source_item)