mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-04 23:17:20 +08:00
fix: respect OpenList directory path contract
This commit is contained in:
@@ -66,11 +66,16 @@ class Alist(StorageBase, metaclass=WeakSingleton):
|
|||||||
) -> schemas.FileItem:
|
) -> schemas.FileItem:
|
||||||
"""
|
"""
|
||||||
根据目标路径构造文件项,用于 OpenList 操作成功但元数据短时间不可见的场景。
|
根据目标路径构造文件项,用于 OpenList 操作成功但元数据短时间不可见的场景。
|
||||||
|
目录项路径需要遵循 FileItem 以斜杠结尾的约定。
|
||||||
"""
|
"""
|
||||||
|
target_path_str = target_path.as_posix()
|
||||||
|
if source_item.type == "dir" and not target_path_str.endswith("/"):
|
||||||
|
target_path_str = f"{target_path_str}/"
|
||||||
|
|
||||||
return schemas.FileItem(
|
return schemas.FileItem(
|
||||||
storage=self.schema.value,
|
storage=self.schema.value,
|
||||||
type=source_item.type,
|
type=source_item.type,
|
||||||
path=target_path.as_posix(),
|
path=target_path_str,
|
||||||
name=target_path.name,
|
name=target_path.name,
|
||||||
basename=target_path.stem,
|
basename=target_path.stem,
|
||||||
extension=target_path.suffix[1:] if source_item.type != "dir" else None,
|
extension=target_path.suffix[1:] if source_item.type != "dir" else None,
|
||||||
|
|||||||
@@ -127,41 +127,6 @@ class TransHandler:
|
|||||||
size=size if item_type == "file" else None,
|
size=size if item_type == "file" else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def __build_transfer_target_diritem(
|
|
||||||
target_storage: str, target_path: Path
|
|
||||||
) -> FileItem:
|
|
||||||
"""
|
|
||||||
按已确认的目标目录路径构造整理结果目录项。
|
|
||||||
"""
|
|
||||||
return FileItem(
|
|
||||||
storage=target_storage,
|
|
||||||
path=TransHandler.__format_dir_path(target_path),
|
|
||||||
name=target_path.name,
|
|
||||||
basename=target_path.stem,
|
|
||||||
type="dir",
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def __format_dir_path(path: Path) -> str:
|
|
||||||
"""
|
|
||||||
按 FileItem 目录路径约定返回以斜杠结尾的路径。
|
|
||||||
"""
|
|
||||||
path_str = path.as_posix()
|
|
||||||
if path_str != "/" and not path_str.endswith("/"):
|
|
||||||
return f"{path_str}/"
|
|
||||||
return path_str
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def __normalize_dir_path(path: Optional[str]) -> str:
|
|
||||||
"""
|
|
||||||
比较目录路径时忽略尾部斜杠,兼容不同存储返回的目录项格式。
|
|
||||||
"""
|
|
||||||
if not path:
|
|
||||||
return ""
|
|
||||||
path_str = Path(str(path)).as_posix().rstrip("/")
|
|
||||||
return path_str or "/"
|
|
||||||
|
|
||||||
def transfer_media(
|
def transfer_media(
|
||||||
self,
|
self,
|
||||||
fileitem: FileItem,
|
fileitem: FileItem,
|
||||||
@@ -316,10 +281,6 @@ class TransHandler:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
logger.info(f"文件夹 {fileitem.path} 整理成功")
|
logger.info(f"文件夹 {fileitem.path} 整理成功")
|
||||||
if self.__normalize_dir_path(new_diritem.path) != self.__normalize_dir_path(new_path.as_posix()):
|
|
||||||
new_diritem = self.__build_transfer_target_diritem(
|
|
||||||
target_storage=target_storage, target_path=new_path
|
|
||||||
)
|
|
||||||
# 返回整理后的路径
|
# 返回整理后的路径
|
||||||
self.__update_result(
|
self.__update_result(
|
||||||
result=result,
|
result=result,
|
||||||
@@ -440,11 +401,6 @@ class TransHandler:
|
|||||||
need_notify=need_notify,
|
need_notify=need_notify,
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
# 目标目录已创建成功但元数据可能短暂缺字段,整理结果直接按目标路径补全。
|
|
||||||
if self.__normalize_dir_path(target_diritem.path) != self.__normalize_dir_path(folder_path.as_posix()):
|
|
||||||
target_diritem = self.__build_transfer_target_diritem(
|
|
||||||
target_storage=target_storage, target_path=folder_path
|
|
||||||
)
|
|
||||||
|
|
||||||
# 判断是否要覆盖,附加文件强制覆盖
|
# 判断是否要覆盖,附加文件强制覆盖
|
||||||
overflag = False
|
overflag = False
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ class AlistStorageTest(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertIsNotNone(folder)
|
self.assertIsNotNone(folder)
|
||||||
self.assertEqual("/library/Test Show (2026)/Season 1", folder.path)
|
self.assertEqual("/library/Test Show (2026)/Season 1/", folder.path)
|
||||||
self.assertEqual("alist", folder.storage)
|
self.assertEqual("alist", folder.storage)
|
||||||
self.assertEqual("dir", folder.type)
|
self.assertEqual("dir", folder.type)
|
||||||
|
|
||||||
|
|||||||
@@ -163,9 +163,10 @@ class TransferJobManagerTest(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
target_folder = FileItem(
|
target_folder = FileItem(
|
||||||
storage="alist",
|
storage="alist",
|
||||||
path=target_path.parent.as_posix(),
|
path=f"{target_path.parent.as_posix()}/",
|
||||||
type="dir",
|
type="dir",
|
||||||
name=target_path.parent.name,
|
name=target_path.parent.name,
|
||||||
|
basename=target_path.parent.stem,
|
||||||
)
|
)
|
||||||
source_oper = SimpleNamespace(
|
source_oper = SimpleNamespace(
|
||||||
is_support_transtype=lambda transfer_type: True,
|
is_support_transtype=lambda transfer_type: True,
|
||||||
@@ -192,9 +193,9 @@ class TransferJobManagerTest(unittest.TestCase):
|
|||||||
self.assertEqual("file", new_item.type)
|
self.assertEqual("file", new_item.type)
|
||||||
self.assertEqual(1024, new_item.size)
|
self.assertEqual(1024, new_item.size)
|
||||||
|
|
||||||
def test_transfer_media_passes_complete_result_when_target_metadata_is_delayed(self):
|
def test_transfer_media_uses_target_folder_returned_by_storage(self):
|
||||||
"""
|
"""
|
||||||
整理成功时应在结果源头带上完整目标项,回调和事件不再二次拼装。
|
整理成功时直接使用存储层返回的目标目录项,回调和事件不再二次拼装。
|
||||||
"""
|
"""
|
||||||
handler = TransHandler()
|
handler = TransHandler()
|
||||||
source_item = FileItem(
|
source_item = FileItem(
|
||||||
@@ -214,6 +215,9 @@ class TransferJobManagerTest(unittest.TestCase):
|
|||||||
target_folder = FileItem(
|
target_folder = FileItem(
|
||||||
storage="alist",
|
storage="alist",
|
||||||
type="dir",
|
type="dir",
|
||||||
|
path="/library/",
|
||||||
|
name="library",
|
||||||
|
basename="library",
|
||||||
)
|
)
|
||||||
target_item = FileItem(
|
target_item = FileItem(
|
||||||
storage="alist",
|
storage="alist",
|
||||||
@@ -259,10 +263,7 @@ class TransferJobManagerTest(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertTrue(transferinfo.success)
|
self.assertTrue(transferinfo.success)
|
||||||
self.assertEqual(target_item, transferinfo.target_item)
|
self.assertEqual(target_item, transferinfo.target_item)
|
||||||
self.assertIsNotNone(transferinfo.target_diritem)
|
self.assertEqual(target_folder, transferinfo.target_diritem)
|
||||||
self.assertEqual("/library/", transferinfo.target_diritem.path)
|
|
||||||
self.assertEqual("alist", transferinfo.target_diritem.storage)
|
|
||||||
self.assertEqual("dir", transferinfo.target_diritem.type)
|
|
||||||
|
|
||||||
def test_success_callback_uses_transfer_result_target_diritem(self):
|
def test_success_callback_uses_transfer_result_target_diritem(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user