mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-05-13 07:26:45 +00:00
fix: prevent storage operations in preview mode and add tests for transfer preview logic
This commit is contained in:
@@ -1974,7 +1974,10 @@ class TransferChain(ChainBase, ConfigReloadMixin, metaclass=Singleton):
|
||||
return False, f"{fileitem.name} 没有找到可整理的媒体文件"
|
||||
|
||||
planned_file_count = len(file_items)
|
||||
logger.info(f"正在计划整理 {planned_file_count} 个文件...")
|
||||
if preview:
|
||||
logger.info(f"正在预览 {planned_file_count} 个文件的整理路径...")
|
||||
else:
|
||||
logger.info(f"正在计划整理 {planned_file_count} 个文件...")
|
||||
|
||||
# 整理所有文件
|
||||
transfer_tasks: List[TransferTask] = []
|
||||
|
||||
@@ -860,6 +860,17 @@ class PluginHelper(metaclass=WeakSingleton):
|
||||
strategies.append(("直连", base_cmd))
|
||||
return strategies
|
||||
|
||||
@staticmethod
|
||||
def __build_runtime_pip_command(*args: str) -> List[str]:
|
||||
"""
|
||||
优先使用当前解释器同目录的 pip 入口,以便 uv-pip-compat 能接管兼容命令。
|
||||
"""
|
||||
pip_name = "pip.exe" if sys.platform == "win32" else "pip"
|
||||
pip_bin = Path(sys.executable).with_name(pip_name)
|
||||
if pip_bin.exists():
|
||||
return [str(pip_bin), *args]
|
||||
return [sys.executable, "-m", "pip", *args]
|
||||
|
||||
@staticmethod
|
||||
def __format_pkg_name_for_pip(name: str) -> str:
|
||||
"""
|
||||
@@ -1217,7 +1228,7 @@ class PluginHelper(metaclass=WeakSingleton):
|
||||
安装完成后立即执行运行环境自检,尽量在插件加载前发现依赖图已被污染。
|
||||
"""
|
||||
checks = [
|
||||
("pip check", [sys.executable, "-m", "pip", "check"]),
|
||||
("pip check", cls.__build_runtime_pip_command("check")),
|
||||
("核心依赖导入检查", [sys.executable, "-c", cls._runtime_import_probe]),
|
||||
]
|
||||
for check_name, command in checks:
|
||||
|
||||
@@ -63,6 +63,26 @@ class TransHandler:
|
||||
current_value = value
|
||||
setattr(result, key, current_value)
|
||||
|
||||
@staticmethod
|
||||
def __build_preview_item(
|
||||
storage: str,
|
||||
path: Path,
|
||||
item_type: str,
|
||||
size: Optional[int] = None,
|
||||
) -> FileItem:
|
||||
"""
|
||||
构造预览结果中的文件项,不访问真实存储。
|
||||
"""
|
||||
return FileItem(
|
||||
storage=storage,
|
||||
path=path.as_posix(),
|
||||
name=path.name,
|
||||
basename=path.stem,
|
||||
type=item_type,
|
||||
extension=path.suffix.lstrip(".") if item_type == "file" else None,
|
||||
size=size if item_type == "file" else None,
|
||||
)
|
||||
|
||||
def transfer_media(
|
||||
self,
|
||||
fileitem: FileItem,
|
||||
@@ -161,12 +181,10 @@ class TransHandler:
|
||||
else:
|
||||
new_path = target_path / fileitem.name
|
||||
if preview:
|
||||
preview_diritem = FileItem(
|
||||
preview_diritem = self.__build_preview_item(
|
||||
storage=target_storage,
|
||||
path=new_path.as_posix(),
|
||||
name=new_path.name,
|
||||
basename=new_path.stem,
|
||||
type="dir",
|
||||
path=new_path,
|
||||
item_type="dir",
|
||||
)
|
||||
self.__update_result(
|
||||
result=result,
|
||||
@@ -291,27 +309,47 @@ class TransHandler:
|
||||
|
||||
# 目标目录
|
||||
if preview:
|
||||
target_diritem = FileItem(
|
||||
# 预览只做路径推算,不检查目录或同名文件冲突,避免目标存储探测触发真实整理。
|
||||
target_diritem = self.__build_preview_item(
|
||||
storage=target_storage,
|
||||
path=folder_path.as_posix(),
|
||||
name=folder_path.name,
|
||||
basename=folder_path.stem,
|
||||
type="dir",
|
||||
path=folder_path,
|
||||
item_type="dir",
|
||||
)
|
||||
else:
|
||||
target_diritem = target_oper.get_folder(folder_path)
|
||||
if not target_diritem:
|
||||
logger.error(f"目标目录 {folder_path} 获取失败")
|
||||
self.__update_result(
|
||||
result=result,
|
||||
success=False,
|
||||
message=f"目标目录 {folder_path} 获取失败",
|
||||
fileitem=fileitem,
|
||||
fail_list=[fileitem.path],
|
||||
transfer_type=transfer_type,
|
||||
need_notify=need_notify,
|
||||
)
|
||||
return result
|
||||
target_item = self.__build_preview_item(
|
||||
storage=target_storage,
|
||||
path=new_file,
|
||||
item_type="file",
|
||||
size=fileitem.size,
|
||||
)
|
||||
self.__update_result(
|
||||
result=result,
|
||||
success=True,
|
||||
fileitem=fileitem,
|
||||
target_item=target_item,
|
||||
target_diritem=target_diritem,
|
||||
file_list=[fileitem.path],
|
||||
file_list_new=[new_file.as_posix()],
|
||||
file_count=1,
|
||||
total_size=fileitem.size or 0,
|
||||
need_scrape=need_scrape,
|
||||
transfer_type=transfer_type,
|
||||
need_notify=False,
|
||||
)
|
||||
return result
|
||||
|
||||
target_diritem = target_oper.get_folder(folder_path)
|
||||
if not target_diritem:
|
||||
logger.error(f"目标目录 {folder_path} 获取失败")
|
||||
self.__update_result(
|
||||
result=result,
|
||||
success=False,
|
||||
message=f"目标目录 {folder_path} 获取失败",
|
||||
fileitem=fileitem,
|
||||
fail_list=[fileitem.path],
|
||||
transfer_type=transfer_type,
|
||||
need_notify=need_notify,
|
||||
)
|
||||
return result
|
||||
|
||||
# 判断是否要覆盖,附加文件强制覆盖
|
||||
overflag = False
|
||||
@@ -439,40 +477,11 @@ class TransHandler:
|
||||
logger.info(
|
||||
f"当前整理覆盖模式设置为 {overwrite_mode},仅保留最新版本,正在删除已有版本文件 ..."
|
||||
)
|
||||
if not preview:
|
||||
self.__delete_version_files(target_oper, new_file)
|
||||
self.__delete_version_files(target_oper, new_file)
|
||||
else:
|
||||
# 附加文件 总是需要覆盖
|
||||
overflag = True
|
||||
|
||||
if preview:
|
||||
target_item = target_oper.get_item(new_file)
|
||||
if not target_item:
|
||||
target_item = FileItem(
|
||||
storage=target_storage,
|
||||
path=new_file.as_posix(),
|
||||
name=new_file.name,
|
||||
basename=new_file.stem,
|
||||
type="file",
|
||||
extension=new_file.suffix.lstrip("."),
|
||||
size=fileitem.size,
|
||||
)
|
||||
self.__update_result(
|
||||
result=result,
|
||||
success=True,
|
||||
fileitem=fileitem,
|
||||
target_item=target_item,
|
||||
target_diritem=target_diritem,
|
||||
file_list=[fileitem.path],
|
||||
file_list_new=[new_file.as_posix()],
|
||||
file_count=1,
|
||||
total_size=fileitem.size or 0,
|
||||
need_scrape=need_scrape,
|
||||
transfer_type=transfer_type,
|
||||
need_notify=False,
|
||||
)
|
||||
return result
|
||||
|
||||
# 整理文件
|
||||
new_item, err_msg = self.__transfer_file(
|
||||
fileitem=fileitem,
|
||||
|
||||
Reference in New Issue
Block a user