mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-28 03:27:31 +08:00
fix #3180
This commit is contained in:
@@ -393,10 +393,14 @@ class TransferChain(ChainBase):
|
|||||||
if src_match:
|
if src_match:
|
||||||
# 按源目录匹配,以便找到更合适的目录配置
|
# 按源目录匹配,以便找到更合适的目录配置
|
||||||
target_directory = self.directoryhelper.get_dir(file_mediainfo,
|
target_directory = self.directoryhelper.get_dir(file_mediainfo,
|
||||||
storage=file_item.storage, src_path=file_path)
|
storage=file_item.storage,
|
||||||
|
src_path=file_path,
|
||||||
|
target_storage=target_storage)
|
||||||
else:
|
else:
|
||||||
# 未指定目标路径,根据媒体信息获取目标目录
|
# 未指定目标路径,根据媒体信息获取目标目录
|
||||||
target_directory = self.directoryhelper.get_dir(file_mediainfo)
|
target_directory = self.directoryhelper.get_dir(file_mediainfo,
|
||||||
|
storage=target_storage,
|
||||||
|
target_storage=target_storage)
|
||||||
|
|
||||||
# 执行整理
|
# 执行整理
|
||||||
transferinfo: TransferInfo = self.transfer(fileitem=file_item,
|
transferinfo: TransferInfo = self.transfer(fileitem=file_item,
|
||||||
|
|||||||
+17
-13
@@ -48,16 +48,18 @@ class DirectoryHelper:
|
|||||||
"""
|
"""
|
||||||
return [d for d in self.get_library_dirs() if d.library_storage == "local"]
|
return [d for d in self.get_library_dirs() if d.library_storage == "local"]
|
||||||
|
|
||||||
def get_dir(self, media: MediaInfo, storage: str = "local",
|
def get_dir(self, media: MediaInfo,
|
||||||
src_path: Path = None, dest_path: Path = None, fileitem: schemas.FileItem = None
|
storage: str = "local", fileitem: schemas.FileItem = None, src_path: Path = None,
|
||||||
|
target_storage: str = "local", dest_path: Path = None
|
||||||
) -> Optional[schemas.TransferDirectoryConf]:
|
) -> Optional[schemas.TransferDirectoryConf]:
|
||||||
"""
|
"""
|
||||||
根据媒体信息获取下载目录、媒体库目录配置
|
根据媒体信息获取下载目录、媒体库目录配置
|
||||||
:param media: 媒体信息
|
:param media: 媒体信息
|
||||||
:param storage: 存储类型
|
:param storage: 源存储类型
|
||||||
|
:param target_storage: 目标存储类型
|
||||||
|
:param fileitem: 文件项,使用文件路径匹配
|
||||||
:param src_path: 源目录,有值时直接匹配
|
:param src_path: 源目录,有值时直接匹配
|
||||||
:param dest_path: 目标目录,有值时直接匹配
|
:param dest_path: 目标目录,有值时直接匹配
|
||||||
:param fileitem: 文件项,使用文件路径匹配
|
|
||||||
"""
|
"""
|
||||||
# 处理类型
|
# 处理类型
|
||||||
if not media:
|
if not media:
|
||||||
@@ -70,21 +72,23 @@ class DirectoryHelper:
|
|||||||
# 没有启用整理的目录
|
# 没有启用整理的目录
|
||||||
if not d.monitor_type:
|
if not d.monitor_type:
|
||||||
continue
|
continue
|
||||||
# 存储类型不匹配
|
# 源存储类型不匹配
|
||||||
if storage and d.storage != storage:
|
if storage and d.storage != storage:
|
||||||
continue
|
continue
|
||||||
# 下载目录
|
# 目标存储类型不匹配
|
||||||
download_path = Path(d.download_path)
|
if target_storage and d.library_storage != target_storage:
|
||||||
# 媒体库目录
|
continue
|
||||||
library_path = Path(d.library_path)
|
# 有文件项时,源存储不匹配
|
||||||
# 有源目录时,源目录不匹配下载目录
|
if fileitem and fileitem.storage != d.storage:
|
||||||
if src_path and not src_path.is_relative_to(download_path):
|
|
||||||
continue
|
continue
|
||||||
# 有文件项时,文件项不匹配下载目录
|
# 有文件项时,文件项不匹配下载目录
|
||||||
if fileitem and not Path(fileitem.path).is_relative_to(download_path):
|
if fileitem and not Path(fileitem.path).is_relative_to(d.download_path):
|
||||||
|
continue
|
||||||
|
# 有源目录时,源目录不匹配下载目录
|
||||||
|
if src_path and not src_path.is_relative_to(d.download_path):
|
||||||
continue
|
continue
|
||||||
# 有目标目录时,目标目录不匹配媒体库目录
|
# 有目标目录时,目标目录不匹配媒体库目录
|
||||||
if dest_path and not dest_path.is_relative_to(library_path):
|
if dest_path and not dest_path.is_relative_to(d.library_path):
|
||||||
continue
|
continue
|
||||||
# 目录类型为全部的,符合条件
|
# 目录类型为全部的,符合条件
|
||||||
if not d.media_type:
|
if not d.media_type:
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import copy
|
|
||||||
import re
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
@@ -463,9 +462,9 @@ class FileManagerModule(_ModuleBase):
|
|||||||
target_file.parent.mkdir(parents=True)
|
target_file.parent.mkdir(parents=True)
|
||||||
# 本地到本地
|
# 本地到本地
|
||||||
if transfer_type == "copy":
|
if transfer_type == "copy":
|
||||||
state = source_oper.copy(fileitem, target_file)
|
state = source_oper.copy(fileitem, target_file.parent, target_file.name)
|
||||||
elif transfer_type == "move":
|
elif transfer_type == "move":
|
||||||
state = source_oper.move(fileitem, target_file)
|
state = source_oper.move(fileitem, target_file.parent, target_file.name)
|
||||||
elif transfer_type == "link":
|
elif transfer_type == "link":
|
||||||
state = source_oper.link(fileitem, target_file)
|
state = source_oper.link(fileitem, target_file)
|
||||||
elif transfer_type == "softlink":
|
elif transfer_type == "softlink":
|
||||||
@@ -493,7 +492,7 @@ class FileManagerModule(_ModuleBase):
|
|||||||
else:
|
else:
|
||||||
return None, f"{fileitem.path} 上传 {target_storage} 失败"
|
return None, f"{fileitem.path} 上传 {target_storage} 失败"
|
||||||
else:
|
else:
|
||||||
return None, f"{target_file.parent} {target_storage} 目录获取失败"
|
return None, f"【{target_storage}】{target_file.parent} 目录获取失败"
|
||||||
elif transfer_type == "move":
|
elif transfer_type == "move":
|
||||||
# 移动
|
# 移动
|
||||||
# 根据目的路径获取文件夹
|
# 根据目的路径获取文件夹
|
||||||
@@ -508,7 +507,7 @@ class FileManagerModule(_ModuleBase):
|
|||||||
else:
|
else:
|
||||||
return None, f"{fileitem.path} 上传 {target_storage} 失败"
|
return None, f"{fileitem.path} 上传 {target_storage} 失败"
|
||||||
else:
|
else:
|
||||||
return None, f"{target_file.parent} {target_storage} 目录获取失败"
|
return None, f"【{target_storage}】{target_file.parent} 目录获取失败"
|
||||||
elif fileitem.storage != "local" and target_storage == "local":
|
elif fileitem.storage != "local" and target_storage == "local":
|
||||||
# 网盘到本地
|
# 网盘到本地
|
||||||
if target_file.exists():
|
if target_file.exists():
|
||||||
@@ -532,25 +531,20 @@ class FileManagerModule(_ModuleBase):
|
|||||||
return None, f"{fileitem.path} {fileitem.storage} 下载失败"
|
return None, f"{fileitem.path} {fileitem.storage} 下载失败"
|
||||||
elif fileitem.storage == target_storage:
|
elif fileitem.storage == target_storage:
|
||||||
# 同一网盘
|
# 同一网盘
|
||||||
# 根据目的路径获取文件夹
|
if transfer_type == "copy":
|
||||||
target_diritem = target_oper.get_folder(target_file.parent)
|
# 移动文件到新目录
|
||||||
if target_diritem:
|
if source_oper.move(fileitem, target_file.parent, target_file.name):
|
||||||
# 重命名文件
|
return target_oper.get_item(target_file), ""
|
||||||
if target_oper.rename(fileitem, target_file.name):
|
|
||||||
# 移动文件到新目录
|
|
||||||
if source_oper.move(fileitem, target_diritem):
|
|
||||||
ret_fileitem = copy.deepcopy(fileitem)
|
|
||||||
ret_fileitem.path = target_diritem.path + "/" + target_file.name
|
|
||||||
ret_fileitem.name = target_file.name
|
|
||||||
ret_fileitem.basename = target_file.stem
|
|
||||||
ret_fileitem.parent_fileid = target_diritem.fileid
|
|
||||||
return ret_fileitem, ""
|
|
||||||
else:
|
|
||||||
return None, f"{fileitem.path} {target_storage} 移动文件失败"
|
|
||||||
else:
|
else:
|
||||||
return None, f"{fileitem.path} {target_storage} 重命名文件失败"
|
return None, f"【{target_storage}】{fileitem.path} 移动文件失败"
|
||||||
|
elif transfer_type == "move":
|
||||||
|
# 移动文件到新目录
|
||||||
|
if source_oper.move(fileitem, target_file.parent, target_file.name):
|
||||||
|
return target_oper.get_item(target_file), ""
|
||||||
|
else:
|
||||||
|
return None, f"【{target_storage}】{fileitem.path} 移动文件失败"
|
||||||
else:
|
else:
|
||||||
return None, f"{target_file.parent} {target_storage} 目录获取失败"
|
return None, f"不支持的整理方式:{transfer_type}"
|
||||||
|
|
||||||
return None, "未知错误"
|
return None, "未知错误"
|
||||||
|
|
||||||
@@ -815,7 +809,8 @@ class FileManagerModule(_ModuleBase):
|
|||||||
else:
|
else:
|
||||||
logger.info(f"正在删除已存在的文件:{target_file}")
|
logger.info(f"正在删除已存在的文件:{target_file}")
|
||||||
target_file.unlink()
|
target_file.unlink()
|
||||||
logger.info(f"正在整理文件:【{fileitem.storage}】{fileitem.path} 到 【{target_storage}】{target_file}")
|
logger.info(f"正在整理文件:【{fileitem.storage}】{fileitem.path} 到 【{target_storage}】{target_file},"
|
||||||
|
f"操作类型:{transfer_type}")
|
||||||
new_item, errmsg = self.__transfer_command(fileitem=fileitem,
|
new_item, errmsg = self.__transfer_command(fileitem=fileitem,
|
||||||
target_storage=target_storage,
|
target_storage=target_storage,
|
||||||
target_file=target_file,
|
target_file=target_file,
|
||||||
|
|||||||
@@ -122,7 +122,6 @@ class StorageBase(metaclass=ABCMeta):
|
|||||||
下载文件,保存到本地,返回本地临时文件地址
|
下载文件,保存到本地,返回本地临时文件地址
|
||||||
:param fileitem: 文件项
|
:param fileitem: 文件项
|
||||||
:param path: 文件保存路径
|
:param path: 文件保存路径
|
||||||
|
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -144,16 +143,22 @@ class StorageBase(metaclass=ABCMeta):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def copy(self, fileitem: schemas.FileItem, target: Union[schemas.FileItem, Path]) -> bool:
|
def copy(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
|
||||||
"""
|
"""
|
||||||
复制文件
|
复制文件
|
||||||
|
:param fileitem: 文件项
|
||||||
|
:param path: 目标目录
|
||||||
|
:param new_name: 新文件名
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def move(self, fileitem: schemas.FileItem, target: Union[schemas.FileItem, Path]) -> bool:
|
def move(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
|
||||||
"""
|
"""
|
||||||
移动文件
|
移动文件
|
||||||
|
:param fileitem: 文件项
|
||||||
|
:param path: 目标目录
|
||||||
|
:param new_name: 新文件名
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ class AliPan(StorageBase, metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
初始化 aligo
|
初始化 aligo
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def show_qrcode(qr_link: str):
|
def show_qrcode(qr_link: str):
|
||||||
"""
|
"""
|
||||||
显示二维码
|
显示二维码
|
||||||
@@ -370,6 +371,9 @@ class AliPan(StorageBase, metaclass=Singleton):
|
|||||||
def upload(self, fileitem: schemas.FileItem, path: Path, new_name: str = None) -> Optional[schemas.FileItem]:
|
def upload(self, fileitem: schemas.FileItem, path: Path, new_name: str = None) -> Optional[schemas.FileItem]:
|
||||||
"""
|
"""
|
||||||
上传文件,并标记完成
|
上传文件,并标记完成
|
||||||
|
:param fileitem: 上传目录项
|
||||||
|
:param path: 目标目录
|
||||||
|
:param new_name: 新文件名
|
||||||
"""
|
"""
|
||||||
if not self.aligo:
|
if not self.aligo:
|
||||||
return None
|
return None
|
||||||
@@ -383,19 +387,41 @@ class AliPan(StorageBase, metaclass=Singleton):
|
|||||||
return self.__get_fileitem(item)
|
return self.__get_fileitem(item)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def move(self, fileitem: schemas.FileItem, target: schemas.FileItem) -> bool:
|
def move(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
|
||||||
"""
|
"""
|
||||||
移动文件
|
移动文件
|
||||||
|
:param fileitem: 文件项
|
||||||
|
:param path: 目标目录
|
||||||
|
:param new_name: 新文件名
|
||||||
"""
|
"""
|
||||||
if not self.aligo:
|
if not self.aligo:
|
||||||
return False
|
return False
|
||||||
|
target = self.get_folder(path)
|
||||||
|
if not target:
|
||||||
|
return False
|
||||||
if self.aligo.move_file(file_id=fileitem.fileid, drive_id=fileitem.drive_id,
|
if self.aligo.move_file(file_id=fileitem.fileid, drive_id=fileitem.drive_id,
|
||||||
to_parent_file_id=target.fileid, to_drive_id=target.drive_id):
|
to_parent_file_id=target.fileid, to_drive_id=target.drive_id,
|
||||||
|
new_name=new_name):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def copy(self, fileitem: schemas.FileItem, target: schemas.FileItem) -> bool:
|
def copy(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
|
||||||
pass
|
"""
|
||||||
|
复制文件
|
||||||
|
:param fileitem: 文件项
|
||||||
|
:param path: 目标目录
|
||||||
|
:param new_name: 新文件名
|
||||||
|
"""
|
||||||
|
if not self.aligo:
|
||||||
|
return False
|
||||||
|
target = self.get_folder(path)
|
||||||
|
if not target:
|
||||||
|
return False
|
||||||
|
if self.aligo.copy_file(file_id=fileitem.fileid, drive_id=fileitem.drive_id,
|
||||||
|
to_parent_file_id=target.fileid, to_drive_id=target.drive_id,
|
||||||
|
new_name=new_name):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
|
def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Tuple, List, Dict, Union
|
from typing import Optional, List, Dict
|
||||||
|
|
||||||
from requests import Response
|
|
||||||
from cachetools import cached, TTLCache
|
from cachetools import cached, TTLCache
|
||||||
|
from requests import Response
|
||||||
|
|
||||||
from app import schemas
|
from app import schemas
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
@@ -13,10 +13,11 @@ from app.log import logger
|
|||||||
from app.modules.filemanager.storages import StorageBase
|
from app.modules.filemanager.storages import StorageBase
|
||||||
from app.schemas.types import StorageSchema
|
from app.schemas.types import StorageSchema
|
||||||
from app.utils.http import RequestUtils
|
from app.utils.http import RequestUtils
|
||||||
|
from app.utils.singleton import Singleton
|
||||||
from app.utils.url import UrlUtils
|
from app.utils.url import UrlUtils
|
||||||
|
|
||||||
|
|
||||||
class Alist(StorageBase):
|
class Alist(StorageBase, metaclass=Singleton):
|
||||||
"""
|
"""
|
||||||
Alist相关操作
|
Alist相关操作
|
||||||
api文档:https://alist.nn.ci/zh/guide/api
|
api文档:https://alist.nn.ci/zh/guide/api
|
||||||
@@ -348,7 +349,7 @@ class Alist(StorageBase):
|
|||||||
|
|
||||||
result = resp.json()
|
result = resp.json()
|
||||||
if result["code"] != 200:
|
if result["code"] != 200:
|
||||||
logging.warning(f'获取文件 {path} 失败,错误信息:{result["message"]}')
|
logging.debug(f'获取文件 {path} 失败,错误信息:{result["message"]}')
|
||||||
return
|
return
|
||||||
|
|
||||||
return schemas.FileItem(
|
return schemas.FileItem(
|
||||||
@@ -576,51 +577,21 @@ class Alist(StorageBase):
|
|||||||
"""
|
"""
|
||||||
return self.get_item(Path(fileitem.path))
|
return self.get_item(Path(fileitem.path))
|
||||||
|
|
||||||
@staticmethod
|
def copy(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
|
||||||
def __get_copy_and_move_data(
|
|
||||||
fileitem: schemas.FileItem, target: Union[schemas.FileItem, Path]
|
|
||||||
) -> Tuple[str, str, List[str], bool]:
|
|
||||||
"""
|
|
||||||
获取复制或移动文件需要的数据
|
|
||||||
|
|
||||||
:param fileitem: 文件项
|
|
||||||
:param target: 目标文件项或目标路径
|
|
||||||
:return: 源目录,目标目录,文件名列表,是否有效
|
|
||||||
"""
|
|
||||||
name = Path(target).name
|
|
||||||
if fileitem.name != name:
|
|
||||||
return "", "", [], False
|
|
||||||
|
|
||||||
src_dir = Path(fileitem.path).parent.as_posix()
|
|
||||||
if isinstance(target, schemas.FileItem):
|
|
||||||
traget_dir = Path(target.path).parent.as_posix()
|
|
||||||
else:
|
|
||||||
traget_dir = target.parent.as_posix()
|
|
||||||
|
|
||||||
return src_dir, traget_dir, [name], True
|
|
||||||
|
|
||||||
def copy(
|
|
||||||
self, fileitem: schemas.FileItem, target: Union[schemas.FileItem, Path]
|
|
||||||
) -> bool:
|
|
||||||
"""
|
"""
|
||||||
复制文件
|
复制文件
|
||||||
|
:param fileitem: 文件项
|
||||||
源文件名和目标文件名必须相同
|
:param path: 目标目录
|
||||||
|
:param new_name: 新文件名
|
||||||
"""
|
"""
|
||||||
src_dir, dst_dir, names, is_valid = self.__get_copy_and_move_data(
|
|
||||||
fileitem, target
|
|
||||||
)
|
|
||||||
if not is_valid:
|
|
||||||
return False
|
|
||||||
|
|
||||||
resp: Response = RequestUtils(
|
resp: Response = RequestUtils(
|
||||||
headers=self.__get_header_with_token()
|
headers=self.__get_header_with_token()
|
||||||
).post_res(
|
).post_res(
|
||||||
self.__get_api_url("/api/fs/copy"),
|
self.__get_api_url("/api/fs/copy"),
|
||||||
json={
|
json={
|
||||||
"src_dir": src_dir,
|
"src_dir": Path(fileitem.path).parent.as_posix(),
|
||||||
"dst_dir": dst_dir,
|
"dst_dir": path.as_posix(),
|
||||||
"names": names,
|
"names": [fileitem.name],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
@@ -655,28 +626,31 @@ class Alist(StorageBase):
|
|||||||
f'复制文件 {fileitem.path} 失败,错误信息:{result["message"]}'
|
f'复制文件 {fileitem.path} 失败,错误信息:{result["message"]}'
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
# 重命名
|
||||||
|
if fileitem.name != new_name:
|
||||||
|
self.rename(
|
||||||
|
self.get_item(path / fileitem.name), new_name
|
||||||
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def move(
|
def move(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
|
||||||
self, fileitem: schemas.FileItem, target: Union[schemas.FileItem, Path]
|
|
||||||
) -> bool:
|
|
||||||
"""
|
"""
|
||||||
移动文件
|
移动文件
|
||||||
|
:param fileitem: 文件项
|
||||||
|
:param path: 目标目录
|
||||||
|
:param new_name: 新文件名
|
||||||
"""
|
"""
|
||||||
src_dir, dst_dir, names, is_valid = self.__get_copy_and_move_data(
|
# 先重命名
|
||||||
fileitem, target
|
if fileitem.name != new_name:
|
||||||
)
|
self.rename(fileitem, new_name)
|
||||||
if not is_valid:
|
|
||||||
return False
|
|
||||||
|
|
||||||
resp: Response = RequestUtils(
|
resp: Response = RequestUtils(
|
||||||
headers=self.__get_header_with_token()
|
headers=self.__get_header_with_token()
|
||||||
).post_res(
|
).post_res(
|
||||||
self.__get_api_url("/api/fs/move"),
|
self.__get_api_url("/api/fs/move"),
|
||||||
json={
|
json={
|
||||||
"src_dir": src_dir,
|
"src_dir": Path(fileitem.path).parent.as_posix(),
|
||||||
"dst_dir": dst_dir,
|
"dst_dir": path.as_posix(),
|
||||||
"names": names,
|
"names": [new_name],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
@@ -757,15 +731,7 @@ class Alist(StorageBase):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __parse_timestamp(time_str: str) -> float:
|
def __parse_timestamp(time_str: str) -> float:
|
||||||
# try:
|
"""
|
||||||
# # 尝试解析带微秒的时间格式
|
直接使用 ISO 8601 格式解析时间
|
||||||
# dt = datetime.strptime(time_str[:26], '%Y-%m-%dT%H:%M:%S.%f')
|
"""
|
||||||
# except ValueError:
|
return datetime.fromisoformat(time_str).timestamp()
|
||||||
# # 如果失败,尝试解析不带微秒的时间格式
|
|
||||||
# dt = datetime.strptime(time_str, '%Y-%m-%dT%H:%M:%SZ')
|
|
||||||
|
|
||||||
# 直接使用 ISO 8601 格式解析时间
|
|
||||||
dt = datetime.fromisoformat(time_str)
|
|
||||||
|
|
||||||
# 返回时间戳
|
|
||||||
return dt.timestamp()
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class LocalStorage(StorageBase):
|
|||||||
"""
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def __get_fileitem(self, path: Path):
|
def __get_fileitem(self, path: Path) -> schemas.FileItem:
|
||||||
"""
|
"""
|
||||||
获取文件项
|
获取文件项
|
||||||
"""
|
"""
|
||||||
@@ -52,7 +52,7 @@ class LocalStorage(StorageBase):
|
|||||||
modify_time=path.stat().st_mtime,
|
modify_time=path.stat().st_mtime,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __get_diritem(self, path: Path):
|
def __get_diritem(self, path: Path) -> schemas.FileItem:
|
||||||
"""
|
"""
|
||||||
获取目录项
|
获取目录项
|
||||||
"""
|
"""
|
||||||
@@ -201,17 +201,6 @@ class LocalStorage(StorageBase):
|
|||||||
return None
|
return None
|
||||||
return self.get_item(target_path)
|
return self.get_item(target_path)
|
||||||
|
|
||||||
def copy(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
|
|
||||||
"""
|
|
||||||
复制文件
|
|
||||||
"""
|
|
||||||
file_path = Path(fileitem.path)
|
|
||||||
code, message = SystemUtils.copy(file_path, target_file)
|
|
||||||
if code != 0:
|
|
||||||
logger.error(f"复制文件失败:{message}")
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
|
def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
|
||||||
"""
|
"""
|
||||||
硬链接文件
|
硬链接文件
|
||||||
@@ -234,12 +223,29 @@ class LocalStorage(StorageBase):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def move(self, fileitem: schemas.FileItem, target: Path) -> bool:
|
def copy(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
|
||||||
"""
|
"""
|
||||||
移动文件
|
复制文件
|
||||||
|
:param fileitem: 文件项
|
||||||
|
:param path: 目标目录
|
||||||
|
:param new_name: 新文件名
|
||||||
"""
|
"""
|
||||||
file_path = Path(fileitem.path)
|
file_path = Path(fileitem.path)
|
||||||
code, message = SystemUtils.move(file_path, target)
|
code, message = SystemUtils.copy(file_path, path / new_name)
|
||||||
|
if code != 0:
|
||||||
|
logger.error(f"复制文件失败:{message}")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def move(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
|
||||||
|
"""
|
||||||
|
移动文件
|
||||||
|
:param fileitem: 文件项
|
||||||
|
:param path: 目标目录
|
||||||
|
:param new_name: 新文件名
|
||||||
|
"""
|
||||||
|
file_path = Path(fileitem.path)
|
||||||
|
code, message = SystemUtils.move(file_path, path / new_name)
|
||||||
if code != 0:
|
if code != 0:
|
||||||
logger.error(f"移动文件失败:{message}")
|
logger.error(f"移动文件失败:{message}")
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -306,16 +306,19 @@ class Rclone(StorageBase):
|
|||||||
logger.error(f"rclone获取文件详情失败:{err}")
|
logger.error(f"rclone获取文件详情失败:{err}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def move(self, fileitem: schemas.FileItem, target: Path) -> bool:
|
def move(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
|
||||||
"""
|
"""
|
||||||
移动文件,target_file格式:rclone:path
|
移动文件
|
||||||
|
:param fileitem: 文件项
|
||||||
|
:param path: 目标目录
|
||||||
|
:param new_name: 新文件名
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
retcode = subprocess.run(
|
retcode = subprocess.run(
|
||||||
[
|
[
|
||||||
'rclone', 'moveto',
|
'rclone', 'moveto',
|
||||||
f'MP:{fileitem.path}',
|
f'MP:{fileitem.path}',
|
||||||
f'MP:{target}'
|
f'MP:{path / new_name}'
|
||||||
],
|
],
|
||||||
startupinfo=self.__get_hidden_shell()
|
startupinfo=self.__get_hidden_shell()
|
||||||
).returncode
|
).returncode
|
||||||
@@ -325,8 +328,27 @@ class Rclone(StorageBase):
|
|||||||
logger.error(f"rclone移动文件失败:{err}")
|
logger.error(f"rclone移动文件失败:{err}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def copy(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
|
def copy(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
|
||||||
pass
|
"""
|
||||||
|
复制文件
|
||||||
|
:param fileitem: 文件项
|
||||||
|
:param path: 目标目录
|
||||||
|
:param new_name: 新文件名
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
retcode = subprocess.run(
|
||||||
|
[
|
||||||
|
'rclone', 'copyto',
|
||||||
|
f'MP:{fileitem.path}',
|
||||||
|
f'MP:{path / new_name}'
|
||||||
|
],
|
||||||
|
startupinfo=self.__get_hidden_shell()
|
||||||
|
).returncode
|
||||||
|
if retcode == 0:
|
||||||
|
return True
|
||||||
|
except Exception as err:
|
||||||
|
logger.error(f"rclone复制文件失败:{err}")
|
||||||
|
return False
|
||||||
|
|
||||||
def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
|
def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -358,32 +358,38 @@ class U115Pan(StorageBase, metaclass=Singleton):
|
|||||||
logger.error(f"115上传文件失败:{str(e)}")
|
logger.error(f"115上传文件失败:{str(e)}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def move(self, fileitem: schemas.FileItem, target: schemas.FileItem) -> bool:
|
def copy(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
|
||||||
"""
|
|
||||||
移动文件
|
|
||||||
"""
|
|
||||||
if not self.client:
|
|
||||||
return False
|
|
||||||
try:
|
|
||||||
self.client.fs.move(fileitem.path, target.path)
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"115移动文件失败:{str(e)}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def copy(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
|
|
||||||
"""
|
"""
|
||||||
复制文件
|
复制文件
|
||||||
|
:param fileitem: 文件项
|
||||||
|
:param path: 目标目录
|
||||||
|
:param new_name: 新文件名
|
||||||
"""
|
"""
|
||||||
if not self.client:
|
if not self.client:
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
self.client.fs.copy(fileitem.path, target_file)
|
self.client.fs.copy(fileitem.path, path / new_name)
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"115复制文件失败:{str(e)}")
|
logger.error(f"115复制文件失败:{str(e)}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def move(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
|
||||||
|
"""
|
||||||
|
移动文件
|
||||||
|
:param fileitem: 文件项
|
||||||
|
:param path: 目标目录
|
||||||
|
:param new_name: 新文件名
|
||||||
|
"""
|
||||||
|
if not self.client:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
self.client.fs.move(fileitem.path, path / new_name)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"115移动文件失败:{str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
|
def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user