fix storage

This commit is contained in:
jxxghp
2024-07-01 11:57:32 +08:00
parent 302514a469
commit 964e212831
7 changed files with 100 additions and 29 deletions
+9 -7
View File
@@ -14,6 +14,7 @@ from app.helper.message import MessageHelper
from app.helper.module import ModuleHelper from app.helper.module import ModuleHelper
from app.log import logger from app.log import logger
from app.modules import _ModuleBase from app.modules import _ModuleBase
from app.modules.filemanager.storage import StorageBase
from app.schemas import TransferInfo, ExistMediaInfo, TmdbEpisode, MediaDirectory, FileItem from app.schemas import TransferInfo, ExistMediaInfo, TmdbEpisode, MediaDirectory, FileItem
from app.schemas.types import MediaType from app.schemas.types import MediaType
from app.utils.system import SystemUtils from app.utils.system import SystemUtils
@@ -230,12 +231,12 @@ class FileManagerModule(_ModuleBase):
episodes_info=episodes_info, episodes_info=episodes_info,
need_scrape=need_scrape) need_scrape=need_scrape)
def __get_storage_oper(self, storage: str): def __get_storage_oper(self, _storage: str):
""" """
获取存储操作对象 获取存储操作对象
""" """
for storage_schema in self._storage_schemas: for storage_schema in self._storage_schemas:
if storage_schema.schema == storage: if storage_schema.schema == _storage:
return storage_schema() return storage_schema()
return None return None
@@ -259,9 +260,9 @@ class FileManagerModule(_ModuleBase):
logger.error(f"不支持 {fileitem.storage}{target_storage} 的文件整理") logger.error(f"不支持 {fileitem.storage}{target_storage} 的文件整理")
return False return False
# 源操作对象 # 源操作对象
source_oper = self.__get_storage_oper(fileitem.storage) source_oper: StorageBase = self.__get_storage_oper(fileitem.storage)
# 目的操作对象 # 目的操作对象
target_oper = self.__get_storage_oper(target_storage) target_oper: StorageBase = self.__get_storage_oper(target_storage)
with lock: with lock:
if fileitem.storage == "local" and target_storage == "local": if fileitem.storage == "local" and target_storage == "local":
# 本地到本地 # 本地到本地
@@ -281,18 +282,19 @@ class FileManagerModule(_ModuleBase):
if not filepath.exists(): if not filepath.exists():
logger.error(f"文件 {filepath} 不存在") logger.error(f"文件 {filepath} 不存在")
return False return False
# TODO 根据目的路径创建文件夹 # 根据目的路径创建文件夹
target_fileitem = target_oper.get_folder(target_file.parent) target_fileitem = target_oper.get_folder(target_file.parent)
if target_fileitem: if target_fileitem:
# 上传文件 # 上传文件
return target_oper.upload(target_fileitem, filepath) if target_oper.upload(target_fileitem, filepath):
return True
elif transfer_type == "move": elif transfer_type == "move":
# 移动 # 移动
filepath = Path(fileitem.path) filepath = Path(fileitem.path)
if not filepath.exists(): if not filepath.exists():
logger.error(f"文件 {filepath} 不存在") logger.error(f"文件 {filepath} 不存在")
return False return False
# TODO 根据目的路径获取文件夹 # 根据目的路径获取文件夹
target_fileitem = target_oper.get_folder(target_file.parent) target_fileitem = target_oper.get_folder(target_file.parent)
if target_fileitem: if target_fileitem:
# 上传文件 # 上传文件
+2 -2
View File
@@ -1,6 +1,6 @@
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from pathlib import Path from pathlib import Path
from typing import Optional, List, Any from typing import Optional, List
from app import schemas from app import schemas
@@ -109,7 +109,7 @@ class StorageBase(metaclass=ABCMeta):
pass pass
@abstractmethod @abstractmethod
def softlink(self, fileitm: schemas.FileItem, target_file: schemas.FileItem) -> bool: def softlink(self, fileitm: schemas.FileItem, target_file: Path) -> bool:
""" """
软链接文件 软链接文件
""" """
+46 -14
View File
@@ -331,8 +331,7 @@ class AliPan(StorageBase):
self.__handle_error(res, "获取用户信息") self.__handle_error(res, "获取用户信息")
return {} return {}
def list(self, drive_id: str = None, parent_file_id: str = 'root', list_type: str = None, def list(self, fileitem: schemas.FileItem = None) -> List[schemas.FileItem]:
limit: int = 100, order_by: str = 'updated_at', path: str = "/") -> List[schemas.FileItem]:
""" """
浏览文件 浏览文件
limit 返回文件数量,默认 50,最大 100 limit 返回文件数量,默认 50,最大 100
@@ -346,10 +345,11 @@ class AliPan(StorageBase):
# 请求头 # 请求头
headers = self.__get_headers(params) headers = self.__get_headers(params)
# 根目录处理 # 根目录处理
if not drive_id: if not fileitem or not fileitem.drive_id:
return [ return [
schemas.FileItem( schemas.FileItem(
fileid=parent_file_id, storage=self.schema.value,
fileid=fileitem.fileid,
drive_id=params.get("resourceDriveId"), drive_id=params.get("resourceDriveId"),
parent_fileid="root", parent_fileid="root",
type="dir", type="dir",
@@ -357,7 +357,8 @@ class AliPan(StorageBase):
name="资源库" name="资源库"
), ),
schemas.FileItem( schemas.FileItem(
fileid=parent_file_id, storage=self.schema.value,
fileid=fileitem.fileid,
drive_id=params.get("backDriveId"), drive_id=params.get("backDriveId"),
parent_fileid="root", parent_fileid="root",
type="dir", type="dir",
@@ -370,13 +371,12 @@ class AliPan(StorageBase):
# 分页获取 # 分页获取
next_marker = None next_marker = None
while True: while True:
if not parent_file_id or parent_file_id == "/": if not fileitem.parent_fileid or fileitem.parent_fileid == "/":
parent_file_id = "root" parent_file_id = "root"
else:
parent_file_id = fileitem.fileid
res = RequestUtils(headers=headers, timeout=10).post_res(self.list_file_url, json={ res = RequestUtils(headers=headers, timeout=10).post_res(self.list_file_url, json={
"drive_id": drive_id, "drive_id": fileitem.drive_id,
"type": list_type,
"limit": limit,
"order_by": order_by,
"parent_file_id": parent_file_id, "parent_file_id": parent_file_id,
"marker": next_marker "marker": next_marker
}, params={ }, params={
@@ -400,10 +400,11 @@ class AliPan(StorageBase):
self.__handle_error(res, "浏览文件") self.__handle_error(res, "浏览文件")
break break
return [schemas.FileItem( return [schemas.FileItem(
storage=self.schema.value,
fileid=fileinfo.get("file_id"), fileid=fileinfo.get("file_id"),
parent_fileid=fileinfo.get("parent_file_id"), parent_fileid=fileinfo.get("parent_file_id"),
type="dir" if fileinfo.get("type") == "folder" else "file", type="dir" if fileinfo.get("type") == "folder" else "file",
path=f"{path}{fileinfo.get('name')}" + ("/" if fileinfo.get("type") == "folder" else ""), path=f"{fileitem.path}{fileinfo.get('name')}" + ("/" if fileinfo.get("type") == "folder" else ""),
name=fileinfo.get("name"), name=fileinfo.get("name"),
size=fileinfo.get("size"), size=fileinfo.get("size"),
extension=fileinfo.get("file_extension"), extension=fileinfo.get("file_extension"),
@@ -441,6 +442,7 @@ class AliPan(StorageBase):
""" """
result = res.json() result = res.json()
return schemas.FileItem( return schemas.FileItem(
storage=self.schema.value,
fileid=result.get("file_id"), fileid=result.get("file_id"),
drive_id=result.get("drive_id"), drive_id=result.get("drive_id"),
parent_fileid=result.get("parent_file_id"), parent_fileid=result.get("parent_file_id"),
@@ -454,9 +456,36 @@ class AliPan(StorageBase):
def get_folder(self, path: Path) -> Optional[schemas.FileItem]: def get_folder(self, path: Path) -> Optional[schemas.FileItem]:
""" """
TODO 获取目录,不存在则创建 根据文件路程获取目录,不存在则创建
""" """
pass
def __find_dir_name(_fileitem: schemas.FileItem, _name: str) -> Optional[schemas.FileItem]:
"""
查找下级目录中匹配名称的目录
"""
sub_files = self.list(_fileitem)
for sub_file in sub_files:
if sub_file.type != "dir":
continue
if sub_file.name == _name:
return sub_file
return None
# 逐级查找和创建目录
fileitem = schemas.FileItem(fileid="root")
for part in path.parts:
if part == "/":
continue
dir_file = __find_dir_name(fileitem, part)
if dir_file:
return dir_file
else:
dir_file = self.create_folder(dir_file, part)
if not dir_file:
logger.warn(f"创建 aplipan 目录 {fileitem.path}{part} 失败!")
return None
fileitem = dir_file
return None
def delete(self, fileitem: schemas.FileItem) -> bool: def delete(self, fileitem: schemas.FileItem) -> bool:
""" """
@@ -491,6 +520,7 @@ class AliPan(StorageBase):
if res: if res:
result = res.json() result = res.json()
return schemas.FileItem( return schemas.FileItem(
storage=self.schema.value,
fileid=result.get("file_id"), fileid=result.get("file_id"),
drive_id=result.get("drive_id"), drive_id=result.get("drive_id"),
parent_fileid=result.get("parent_file_id"), parent_fileid=result.get("parent_file_id"),
@@ -582,6 +612,7 @@ class AliPan(StorageBase):
if result.get("exist"): if result.get("exist"):
logger.info(f"文件{result.get('file_name')}已存在,无需上传") logger.info(f"文件{result.get('file_name')}已存在,无需上传")
return schemas.FileItem( return schemas.FileItem(
storage=self.schema.value,
drive_id=result.get("drive_id"), drive_id=result.get("drive_id"),
fileid=result.get("file_id"), fileid=result.get("file_id"),
parent_fileid=result.get("parent_file_id"), parent_fileid=result.get("parent_file_id"),
@@ -616,6 +647,7 @@ class AliPan(StorageBase):
return None return None
result = res.json() result = res.json()
return schemas.FileItem( return schemas.FileItem(
storage=self.schema.value,
fileid=result.get("file_id"), fileid=result.get("file_id"),
drive_id=result.get("drive_id"), drive_id=result.get("drive_id"),
parent_fileid=result.get("parent_file_id"), parent_fileid=result.get("parent_file_id"),
@@ -659,7 +691,7 @@ class AliPan(StorageBase):
""" """
pass pass
def softlink(self, fileitm: schemas.FileItem, target_file: schemas.FileItem) -> bool: def softlink(self, fileitm: schemas.FileItem, target_file: Path) -> bool:
""" """
软链接文件 软链接文件
""" """
+7
View File
@@ -42,6 +42,7 @@ class LocalStorage(StorageBase):
partitions = SystemUtils.get_windows_drives() or ["C:/"] partitions = SystemUtils.get_windows_drives() or ["C:/"]
for partition in partitions: for partition in partitions:
ret_items.append(schemas.FileItem( ret_items.append(schemas.FileItem(
storage=self.schema.value,
type="dir", type="dir",
path=partition + "/", path=partition + "/",
name=partition, name=partition,
@@ -65,6 +66,7 @@ class LocalStorage(StorageBase):
# 如果是文件 # 如果是文件
if path_obj.is_file(): if path_obj.is_file():
ret_items.append(schemas.FileItem( ret_items.append(schemas.FileItem(
storage=self.schema.value,
type="file", type="file",
path=str(path_obj).replace("\\", "/"), path=str(path_obj).replace("\\", "/"),
name=path_obj.name, name=path_obj.name,
@@ -78,6 +80,7 @@ class LocalStorage(StorageBase):
# 扁历所有目录 # 扁历所有目录
for item in SystemUtils.list_sub_directory(path_obj): for item in SystemUtils.list_sub_directory(path_obj):
ret_items.append(schemas.FileItem( ret_items.append(schemas.FileItem(
storage=self.schema.value,
type="dir", type="dir",
path=str(item).replace("\\", "/") + "/", path=str(item).replace("\\", "/") + "/",
name=item.name, name=item.name,
@@ -88,6 +91,7 @@ class LocalStorage(StorageBase):
# 遍历所有文件,不含子目录 # 遍历所有文件,不含子目录
for item in SystemUtils.list_sub_all(path_obj): for item in SystemUtils.list_sub_all(path_obj):
ret_items.append(schemas.FileItem( ret_items.append(schemas.FileItem(
storage=self.schema.value,
type="file", type="file",
path=str(item).replace("\\", "/"), path=str(item).replace("\\", "/"),
name=item.name, name=item.name,
@@ -108,6 +112,7 @@ class LocalStorage(StorageBase):
if not path_obj.exists(): if not path_obj.exists():
path_obj.mkdir(parents=True, exist_ok=True) path_obj.mkdir(parents=True, exist_ok=True)
return schemas.FileItem( return schemas.FileItem(
storage=self.schema.value,
type="dir", type="dir",
path=str(path_obj).replace("\\", "/") + "/", path=str(path_obj).replace("\\", "/") + "/",
name=name, name=name,
@@ -127,6 +132,7 @@ class LocalStorage(StorageBase):
""" """
path_obj = Path(fileitm.path) path_obj = Path(fileitm.path)
return schemas.FileItem( return schemas.FileItem(
storage=self.schema.value,
type="file", type="file",
path=str(path_obj).replace("\\", "/"), path=str(path_obj).replace("\\", "/"),
name=path_obj.name, name=path_obj.name,
@@ -178,6 +184,7 @@ class LocalStorage(StorageBase):
filepath.rename(path) filepath.rename(path)
if path.exists(): if path.exists():
return schemas.FileItem( return schemas.FileItem(
storage=self.schema.value,
type="file", type="file",
path=str(path).replace("\\", "/"), path=str(path).replace("\\", "/"),
name=path.name, name=path.name,
+1 -1
View File
@@ -103,5 +103,5 @@ class Rclone(StorageBase):
def link(self, fileitm: schemas.FileItem, target_file: Path) -> bool: def link(self, fileitm: schemas.FileItem, target_file: Path) -> bool:
pass pass
def softlink(self, fileitm: schemas.FileItem, target_file: schemas.FileItem) -> bool: def softlink(self, fileitm: schemas.FileItem, target_file: Path) -> bool:
pass pass
+34 -4
View File
@@ -162,8 +162,9 @@ class U115Pan(StorageBase, metaclass=Singleton):
if not self.__init_cloud(): if not self.__init_cloud():
return None return None
try: try:
items = self.cloud.storage().list(dir_id=fileitem.parent_fileid) items = self.cloud.storage().list(dir_id=fileitem.fileid)
return [schemas.FileItem( return [schemas.FileItem(
storage=self.schema.value,
fileid=item.file_id, fileid=item.file_id,
parent_fileid=item.parent_id, parent_fileid=item.parent_id,
type="dir" if item.is_dir else "file", type="dir" if item.is_dir else "file",
@@ -187,6 +188,7 @@ class U115Pan(StorageBase, metaclass=Singleton):
try: try:
result = self.cloud.storage().make_dir(fileitem.parent_fileid, name) result = self.cloud.storage().make_dir(fileitem.parent_fileid, name)
return schemas.FileItem( return schemas.FileItem(
storage=self.schema.value,
fileid=result.file_id, fileid=result.file_id,
parent_fileid=result.parent_id, parent_fileid=result.parent_id,
type="dir", type="dir",
@@ -201,9 +203,36 @@ class U115Pan(StorageBase, metaclass=Singleton):
def get_folder(self, path: Path) -> Optional[schemas.FileItem]: def get_folder(self, path: Path) -> Optional[schemas.FileItem]:
""" """
TODO 获取目录,不存在则创建 根据文件路程获取目录,不存在则创建
""" """
pass
def __find_dir_name(_fileitem: schemas.FileItem, _name: str) -> Optional[schemas.FileItem]:
"""
查找下级目录中匹配名称的目录
"""
sub_files = self.list(_fileitem)
for sub_file in sub_files:
if sub_file.type != "dir":
continue
if sub_file.name == _name:
return sub_file
return None
# 逐级查找和创建目录
fileitem = schemas.FileItem(fileid="0")
for part in path.parts:
if part == "/":
continue
dir_file = __find_dir_name(fileitem, part)
if dir_file:
return dir_file
else:
dir_file = self.create_folder(dir_file, part)
if not dir_file:
logger.warn(f"创建 115 目录 {fileitem.path}{part} 失败!")
return None
fileitem = dir_file
return None
def detail(self, fileitm: schemas.FileItem) -> Optional[schemas.FileItem]: def detail(self, fileitm: schemas.FileItem) -> Optional[schemas.FileItem]:
""" """
@@ -286,6 +315,7 @@ class U115Pan(StorageBase, metaclass=Singleton):
fileitem = result.get('data') fileitem = result.get('data')
logger.info(f"115上传文件成功:{fileitem}") logger.info(f"115上传文件成功:{fileitem}")
return schemas.FileItem( return schemas.FileItem(
storage=self.schema.value,
fileid=fileitem.get('file_id'), fileid=fileitem.get('file_id'),
parent_fileid=fileitem.fileid, parent_fileid=fileitem.fileid,
type="file", type="file",
@@ -321,5 +351,5 @@ class U115Pan(StorageBase, metaclass=Singleton):
def link(self, fileitm: schemas.FileItem, target_file: Path) -> bool: def link(self, fileitm: schemas.FileItem, target_file: Path) -> bool:
pass pass
def softlink(self, fileitm: schemas.FileItem, target_file: schemas.FileItem) -> bool: def softlink(self, fileitm: schemas.FileItem, target_file: Path) -> bool:
pass pass
+1 -1
View File
@@ -9,7 +9,7 @@ class FileItem(BaseModel):
# 类型 dir/file # 类型 dir/file
type: Optional[str] = None type: Optional[str] = None
# 文件路径 # 文件路径
path: Optional[str] = None path: Optional[str] = "/"
# 文件名 # 文件名
name: Optional[str] = None name: Optional[str] = None
# 文件名 # 文件名