From 8530d54fccd2a1217ba3e8dc6e1a1a8ecbd40204 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Tue, 2 Jul 2024 18:16:52 +0800 Subject: [PATCH] fix filemanager --- app/helper/directory.py | 22 +++++---- app/helper/storage.py | 23 +++++++++ app/modules/filemanager/__init__.py | 60 +++++++++++++---------- app/modules/filemanager/storage/alipan.py | 8 ++- app/modules/filemanager/storage/rclone.py | 4 +- app/modules/filemanager/storage/u115.py | 4 +- app/schemas/system.py | 12 +++++ app/schemas/types.py | 2 + 8 files changed, 95 insertions(+), 40 deletions(-) create mode 100644 app/helper/storage.py diff --git a/app/helper/directory.py b/app/helper/directory.py index d1ab40ab..b67ea044 100644 --- a/app/helper/directory.py +++ b/app/helper/directory.py @@ -15,15 +15,20 @@ class DirectoryHelper: def __init__(self): self.systemconfig = SystemConfigOper() - def get_download_dirs(self) -> List[schemas.TransferDirectoryConf]: + def get_dirs(self) -> List[schemas.TransferDirectoryConf]: """ 获取所有下载目录 """ dir_confs: List[dict] = self.systemconfig.get(SystemConfigKey.Directories) if not dir_confs: return [] - dirs = [schemas.TransferDirectoryConf(**d) for d in dir_confs] - return sorted([d for d in dirs if d.download_path], key=lambda x: x.priority) + return [schemas.TransferDirectoryConf(**d) for d in dir_confs] + + def get_download_dirs(self) -> List[schemas.TransferDirectoryConf]: + """ + 获取所有下载目录 + """ + return sorted([d for d in self.get_dirs() if d.download_path], key=lambda x: x.priority) def get_local_download_dirs(self) -> List[schemas.TransferDirectoryConf]: """ @@ -35,11 +40,7 @@ class DirectoryHelper: """ 获取所有媒体库目录 """ - dir_confs: List[dict] = self.systemconfig.get(SystemConfigKey.Directories) - if not dir_confs: - return [] - dirs = [schemas.TransferDirectoryConf(**d) for d in dir_confs] - return sorted([d for d in dirs if d.library_path], key=lambda x: x.priority) + return sorted([d for d in self.get_dirs() if d.library_path], key=lambda x: x.priority) def get_local_library_dirs(self) -> List[schemas.TransferDirectoryConf]: """ @@ -61,9 +62,12 @@ class DirectoryHelper: media_type = media.type.value else: media_type = MediaType.UNKNOWN.value - dirs = self.get_download_dirs() + dirs = self.get_dirs() # 按照配置顺序查找 for d in dirs: + if not d.download_path or not d.library_path: + continue + # 下载目录 download_path = Path(d.download_path) # 有目录时直接匹配 if src_path and download_path != src_path: diff --git a/app/helper/storage.py b/app/helper/storage.py new file mode 100644 index 00000000..2216b88f --- /dev/null +++ b/app/helper/storage.py @@ -0,0 +1,23 @@ +from typing import List + +from app import schemas +from app.db.systemconfig_oper import SystemConfigOper +from app.schemas.types import SystemConfigKey + + +class StorageHelper: + """ + 存储帮助类 + """ + + def __init__(self): + self.systemconfig = SystemConfigOper() + + def get_storagies(self) -> List[schemas.StorageConf]: + """ + 获取所有存储设置 + """ + storage_confs: List[dict] = self.systemconfig.get(SystemConfigKey.Storages) + if not storage_confs: + return [] + return [schemas.StorageConf(**s) for s in storage_confs] diff --git a/app/modules/filemanager/__init__.py b/app/modules/filemanager/__init__.py index 4a1cc2b9..e957f280 100644 --- a/app/modules/filemanager/__init__.py +++ b/app/modules/filemanager/__init__.py @@ -51,31 +51,37 @@ class FileManagerModule(_ModuleBase): 测试模块连接性 """ directoryhelper = DirectoryHelper() - # 检查本地下载目录是否存在 - download_paths = directoryhelper.get_local_download_dirs() - if not download_paths: - return False, "下载目录未设置" - for d_path in download_paths: - path = d_path.download_path - if not path: - return False, f"下载目录 {d_path.name} 对应路径未设置" - download_path = Path(path) - if not download_path.exists(): - return False, f"下载目录 {d_path.name} 对应路径 {path} 不存在" - # 检查本地媒体库目录是否存在 - libaray_paths = directoryhelper.get_local_library_dirs() - if not libaray_paths: - return False, "媒体库目录未设置" - for l_path in libaray_paths: - path = l_path.library_path - if not path: - return False, f"媒体库目录 {l_path.name} 对应路径未设置" - library_path = Path(path) - if not library_path.exists(): - return False, f"媒体库目录{l_path.name} 对应的路径 {path} 不存在" - # TODO 检查硬链接条件 + # 检查目录 + dirs = directoryhelper.get_dirs() + if not dirs: + return False, "未设置任何目录" + for d in dirs: + download_path = d.download_path + if not download_path: + return False, f"{d.name} 的下载目录未设置" + if d.storage == "local" and not Path(download_path).exists(): + return False, f"{d.name} 的下载目录 {download_path} 不存在" + library_path = d.library_path + if not library_path: + return False, f"{d.name} 的媒体库目录未设置" + if d.library_storage == "local" and not Path(library_path).exists(): + return False, f"{d.name} 的媒体库目录 {library_path} 不存在" + # 检查软硬链接 + if d.transfer_type in ["link", "softlink"] \ + and (d.storage != "local" or d.library_storage != "local"): + return False, f"{d.name} 不是本地存储,不支持软硬链接" + # 检查硬链接 + if d.transfer_type == "link" \ + and not SystemUtils.is_same_disk(Path(download_path), Path(library_path)): + return False, f"{d.name} 的下载目录 {download_path} 与媒体库目录 {library_path} 不在同一磁盘,无法硬链接" + # 检查网盘 + if d.storage != "local": + storage_oper = self.__get_storage_oper(d.storage) + if not storage_oper: + return False, f"{d.name} 的存储类型 {d.storage} 不支持" + if not storage_oper.check(): + return False, f"{d.name} 的存储测试不通过" - # TODO 检查网盘目录 return True, "" def init_setting(self) -> Tuple[str, Union[str, bool]]: @@ -155,14 +161,14 @@ class FileManagerModule(_ModuleBase): return False return storage_oper.download(fileitem, path) - def upload_file(self, fileitem: FileItem, path: Path) -> bool: + def upload_file(self, fileitem: FileItem, path: Path) -> Optional[FileItem]: """ 上传文件 """ storage_oper = self.__get_storage_oper(fileitem.storage) if not storage_oper: logger.error(f"不支持 {fileitem.storage} 的上传处理") - return False + return None return storage_oper.upload(fileitem, path) def transfer(self, fileitem: FileItem, meta: MetaBase, mediainfo: MediaInfo, @@ -227,7 +233,7 @@ class FileManagerModule(_ModuleBase): need_scrape=need_scrape, need_rename=need_rename) - def __get_storage_oper(self, _storage: str): + def __get_storage_oper(self, _storage: str) -> Optional[StorageBase]: """ 获取存储操作对象 """ diff --git a/app/modules/filemanager/storage/alipan.py b/app/modules/filemanager/storage/alipan.py index 7d188f1c..b78928d3 100644 --- a/app/modules/filemanager/storage/alipan.py +++ b/app/modules/filemanager/storage/alipan.py @@ -309,7 +309,13 @@ class AliPan(StorageBase): """ 检查存储是否可用 """ - pass + params = self.__access_params + if not params: + return False + return True if self.list(schemas.FileItem( + fileid="root", + drive_id=params.get("resourceDriveId") + )) else False def user_info(self) -> dict: """ diff --git a/app/modules/filemanager/storage/rclone.py b/app/modules/filemanager/storage/rclone.py index c9ad871f..29b56919 100644 --- a/app/modules/filemanager/storage/rclone.py +++ b/app/modules/filemanager/storage/rclone.py @@ -11,7 +11,7 @@ from app.utils.system import SystemUtils class Rclone(StorageBase): """ - rclone相关操作 + TODO rclone相关操作 """ # 存储类型 @@ -53,7 +53,7 @@ class Rclone(StorageBase): def rename(self, fileitm: schemas.FileItem, name: str) -> bool: pass - def download(self, fileitm: schemas.FileItem, path: Path) -> bool: + def download(self, fileitm: schemas.FileItem, path: Path): pass def upload(self, fileitm: schemas.FileItem, path: Path) -> Optional[schemas.FileItem]: diff --git a/app/modules/filemanager/storage/u115.py b/app/modules/filemanager/storage/u115.py index 7ba0e708..7f47fb91 100644 --- a/app/modules/filemanager/storage/u115.py +++ b/app/modules/filemanager/storage/u115.py @@ -153,7 +153,9 @@ class U115Pan(StorageBase, metaclass=Singleton): """ 检查存储是否可用 """ - pass + return True if self.list(schemas.FileItem( + fileid="0" + )) else False def list(self, fileitem: schemas.FileItem) -> Optional[List[schemas.FileItem]]: """ diff --git a/app/schemas/system.py b/app/schemas/system.py index c8678188..7ceab74c 100644 --- a/app/schemas/system.py +++ b/app/schemas/system.py @@ -49,6 +49,18 @@ class NotificationConf(BaseModel): enabled: Optional[bool] = False +class StorageConf(BaseModel): + """ + 存储配置 + """ + # 名称 + name: Optional[str] = None + # 类型 local/alipan/u115/rclone + type: Optional[str] = None + # 配置 + config: Optional[dict] = {} + + class TransferDirectoryConf(BaseModel): """ 文件整理目录配置 diff --git a/app/schemas/types.py b/app/schemas/types.py index 0d727cfb..314a14a8 100644 --- a/app/schemas/types.py +++ b/app/schemas/types.py @@ -66,6 +66,8 @@ class SystemConfigKey(Enum): Notifications = "Notifications" # 目录配置 Directories = "Directories" + # 存储配置 + Storages = "Storages" # 阿里云盘认证参数 UserAliyunParams = "UserAliyunParams" # 115网盘认证参数