mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-06-28 03:02:34 +08:00
fix storage
This commit is contained in:
@@ -14,6 +14,7 @@ from app.helper.message import MessageHelper
|
||||
from app.helper.module import ModuleHelper
|
||||
from app.log import logger
|
||||
from app.modules import _ModuleBase
|
||||
from app.modules.filemanager.storage import StorageBase
|
||||
from app.schemas import TransferInfo, ExistMediaInfo, TmdbEpisode, MediaDirectory, FileItem
|
||||
from app.schemas.types import MediaType
|
||||
from app.utils.system import SystemUtils
|
||||
@@ -230,12 +231,12 @@ class FileManagerModule(_ModuleBase):
|
||||
episodes_info=episodes_info,
|
||||
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:
|
||||
if storage_schema.schema == storage:
|
||||
if storage_schema.schema == _storage:
|
||||
return storage_schema()
|
||||
return None
|
||||
|
||||
@@ -259,9 +260,9 @@ class FileManagerModule(_ModuleBase):
|
||||
logger.error(f"不支持 {fileitem.storage} 到 {target_storage} 的文件整理")
|
||||
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:
|
||||
if fileitem.storage == "local" and target_storage == "local":
|
||||
# 本地到本地
|
||||
@@ -281,18 +282,19 @@ class FileManagerModule(_ModuleBase):
|
||||
if not filepath.exists():
|
||||
logger.error(f"文件 {filepath} 不存在")
|
||||
return False
|
||||
# TODO 根据目的路径创建文件夹
|
||||
# 根据目的路径创建文件夹
|
||||
target_fileitem = target_oper.get_folder(target_file.parent)
|
||||
if target_fileitem:
|
||||
# 上传文件
|
||||
return target_oper.upload(target_fileitem, filepath)
|
||||
if target_oper.upload(target_fileitem, filepath):
|
||||
return True
|
||||
elif transfer_type == "move":
|
||||
# 移动
|
||||
filepath = Path(fileitem.path)
|
||||
if not filepath.exists():
|
||||
logger.error(f"文件 {filepath} 不存在")
|
||||
return False
|
||||
# TODO 根据目的路径获取文件夹
|
||||
# 根据目的路径获取文件夹
|
||||
target_fileitem = target_oper.get_folder(target_file.parent)
|
||||
if target_fileitem:
|
||||
# 上传文件
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from pathlib import Path
|
||||
from typing import Optional, List, Any
|
||||
from typing import Optional, List
|
||||
|
||||
from app import schemas
|
||||
|
||||
@@ -109,7 +109,7 @@ class StorageBase(metaclass=ABCMeta):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def softlink(self, fileitm: schemas.FileItem, target_file: schemas.FileItem) -> bool:
|
||||
def softlink(self, fileitm: schemas.FileItem, target_file: Path) -> bool:
|
||||
"""
|
||||
软链接文件
|
||||
"""
|
||||
|
||||
@@ -331,8 +331,7 @@ class AliPan(StorageBase):
|
||||
self.__handle_error(res, "获取用户信息")
|
||||
return {}
|
||||
|
||||
def list(self, drive_id: str = None, parent_file_id: str = 'root', list_type: str = None,
|
||||
limit: int = 100, order_by: str = 'updated_at', path: str = "/") -> List[schemas.FileItem]:
|
||||
def list(self, fileitem: schemas.FileItem = None) -> List[schemas.FileItem]:
|
||||
"""
|
||||
浏览文件
|
||||
limit 返回文件数量,默认 50,最大 100
|
||||
@@ -346,10 +345,11 @@ class AliPan(StorageBase):
|
||||
# 请求头
|
||||
headers = self.__get_headers(params)
|
||||
# 根目录处理
|
||||
if not drive_id:
|
||||
if not fileitem or not fileitem.drive_id:
|
||||
return [
|
||||
schemas.FileItem(
|
||||
fileid=parent_file_id,
|
||||
storage=self.schema.value,
|
||||
fileid=fileitem.fileid,
|
||||
drive_id=params.get("resourceDriveId"),
|
||||
parent_fileid="root",
|
||||
type="dir",
|
||||
@@ -357,7 +357,8 @@ class AliPan(StorageBase):
|
||||
name="资源库"
|
||||
),
|
||||
schemas.FileItem(
|
||||
fileid=parent_file_id,
|
||||
storage=self.schema.value,
|
||||
fileid=fileitem.fileid,
|
||||
drive_id=params.get("backDriveId"),
|
||||
parent_fileid="root",
|
||||
type="dir",
|
||||
@@ -370,13 +371,12 @@ class AliPan(StorageBase):
|
||||
# 分页获取
|
||||
next_marker = None
|
||||
while True:
|
||||
if not parent_file_id or parent_file_id == "/":
|
||||
if not fileitem.parent_fileid or fileitem.parent_fileid == "/":
|
||||
parent_file_id = "root"
|
||||
else:
|
||||
parent_file_id = fileitem.fileid
|
||||
res = RequestUtils(headers=headers, timeout=10).post_res(self.list_file_url, json={
|
||||
"drive_id": drive_id,
|
||||
"type": list_type,
|
||||
"limit": limit,
|
||||
"order_by": order_by,
|
||||
"drive_id": fileitem.drive_id,
|
||||
"parent_file_id": parent_file_id,
|
||||
"marker": next_marker
|
||||
}, params={
|
||||
@@ -400,10 +400,11 @@ class AliPan(StorageBase):
|
||||
self.__handle_error(res, "浏览文件")
|
||||
break
|
||||
return [schemas.FileItem(
|
||||
storage=self.schema.value,
|
||||
fileid=fileinfo.get("file_id"),
|
||||
parent_fileid=fileinfo.get("parent_file_id"),
|
||||
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"),
|
||||
size=fileinfo.get("size"),
|
||||
extension=fileinfo.get("file_extension"),
|
||||
@@ -441,6 +442,7 @@ class AliPan(StorageBase):
|
||||
"""
|
||||
result = res.json()
|
||||
return schemas.FileItem(
|
||||
storage=self.schema.value,
|
||||
fileid=result.get("file_id"),
|
||||
drive_id=result.get("drive_id"),
|
||||
parent_fileid=result.get("parent_file_id"),
|
||||
@@ -454,9 +456,36 @@ class AliPan(StorageBase):
|
||||
|
||||
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:
|
||||
"""
|
||||
@@ -491,6 +520,7 @@ class AliPan(StorageBase):
|
||||
if res:
|
||||
result = res.json()
|
||||
return schemas.FileItem(
|
||||
storage=self.schema.value,
|
||||
fileid=result.get("file_id"),
|
||||
drive_id=result.get("drive_id"),
|
||||
parent_fileid=result.get("parent_file_id"),
|
||||
@@ -582,6 +612,7 @@ class AliPan(StorageBase):
|
||||
if result.get("exist"):
|
||||
logger.info(f"文件{result.get('file_name')}已存在,无需上传")
|
||||
return schemas.FileItem(
|
||||
storage=self.schema.value,
|
||||
drive_id=result.get("drive_id"),
|
||||
fileid=result.get("file_id"),
|
||||
parent_fileid=result.get("parent_file_id"),
|
||||
@@ -616,6 +647,7 @@ class AliPan(StorageBase):
|
||||
return None
|
||||
result = res.json()
|
||||
return schemas.FileItem(
|
||||
storage=self.schema.value,
|
||||
fileid=result.get("file_id"),
|
||||
drive_id=result.get("drive_id"),
|
||||
parent_fileid=result.get("parent_file_id"),
|
||||
@@ -659,7 +691,7 @@ class AliPan(StorageBase):
|
||||
"""
|
||||
pass
|
||||
|
||||
def softlink(self, fileitm: schemas.FileItem, target_file: schemas.FileItem) -> bool:
|
||||
def softlink(self, fileitm: schemas.FileItem, target_file: Path) -> bool:
|
||||
"""
|
||||
软链接文件
|
||||
"""
|
||||
|
||||
@@ -42,6 +42,7 @@ class LocalStorage(StorageBase):
|
||||
partitions = SystemUtils.get_windows_drives() or ["C:/"]
|
||||
for partition in partitions:
|
||||
ret_items.append(schemas.FileItem(
|
||||
storage=self.schema.value,
|
||||
type="dir",
|
||||
path=partition + "/",
|
||||
name=partition,
|
||||
@@ -65,6 +66,7 @@ class LocalStorage(StorageBase):
|
||||
# 如果是文件
|
||||
if path_obj.is_file():
|
||||
ret_items.append(schemas.FileItem(
|
||||
storage=self.schema.value,
|
||||
type="file",
|
||||
path=str(path_obj).replace("\\", "/"),
|
||||
name=path_obj.name,
|
||||
@@ -78,6 +80,7 @@ class LocalStorage(StorageBase):
|
||||
# 扁历所有目录
|
||||
for item in SystemUtils.list_sub_directory(path_obj):
|
||||
ret_items.append(schemas.FileItem(
|
||||
storage=self.schema.value,
|
||||
type="dir",
|
||||
path=str(item).replace("\\", "/") + "/",
|
||||
name=item.name,
|
||||
@@ -88,6 +91,7 @@ class LocalStorage(StorageBase):
|
||||
# 遍历所有文件,不含子目录
|
||||
for item in SystemUtils.list_sub_all(path_obj):
|
||||
ret_items.append(schemas.FileItem(
|
||||
storage=self.schema.value,
|
||||
type="file",
|
||||
path=str(item).replace("\\", "/"),
|
||||
name=item.name,
|
||||
@@ -108,6 +112,7 @@ class LocalStorage(StorageBase):
|
||||
if not path_obj.exists():
|
||||
path_obj.mkdir(parents=True, exist_ok=True)
|
||||
return schemas.FileItem(
|
||||
storage=self.schema.value,
|
||||
type="dir",
|
||||
path=str(path_obj).replace("\\", "/") + "/",
|
||||
name=name,
|
||||
@@ -127,6 +132,7 @@ class LocalStorage(StorageBase):
|
||||
"""
|
||||
path_obj = Path(fileitm.path)
|
||||
return schemas.FileItem(
|
||||
storage=self.schema.value,
|
||||
type="file",
|
||||
path=str(path_obj).replace("\\", "/"),
|
||||
name=path_obj.name,
|
||||
@@ -178,6 +184,7 @@ class LocalStorage(StorageBase):
|
||||
filepath.rename(path)
|
||||
if path.exists():
|
||||
return schemas.FileItem(
|
||||
storage=self.schema.value,
|
||||
type="file",
|
||||
path=str(path).replace("\\", "/"),
|
||||
name=path.name,
|
||||
|
||||
@@ -103,5 +103,5 @@ class Rclone(StorageBase):
|
||||
def link(self, fileitm: schemas.FileItem, target_file: Path) -> bool:
|
||||
pass
|
||||
|
||||
def softlink(self, fileitm: schemas.FileItem, target_file: schemas.FileItem) -> bool:
|
||||
def softlink(self, fileitm: schemas.FileItem, target_file: Path) -> bool:
|
||||
pass
|
||||
|
||||
@@ -162,8 +162,9 @@ class U115Pan(StorageBase, metaclass=Singleton):
|
||||
if not self.__init_cloud():
|
||||
return None
|
||||
try:
|
||||
items = self.cloud.storage().list(dir_id=fileitem.parent_fileid)
|
||||
items = self.cloud.storage().list(dir_id=fileitem.fileid)
|
||||
return [schemas.FileItem(
|
||||
storage=self.schema.value,
|
||||
fileid=item.file_id,
|
||||
parent_fileid=item.parent_id,
|
||||
type="dir" if item.is_dir else "file",
|
||||
@@ -187,6 +188,7 @@ class U115Pan(StorageBase, metaclass=Singleton):
|
||||
try:
|
||||
result = self.cloud.storage().make_dir(fileitem.parent_fileid, name)
|
||||
return schemas.FileItem(
|
||||
storage=self.schema.value,
|
||||
fileid=result.file_id,
|
||||
parent_fileid=result.parent_id,
|
||||
type="dir",
|
||||
@@ -201,9 +203,36 @@ class U115Pan(StorageBase, metaclass=Singleton):
|
||||
|
||||
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]:
|
||||
"""
|
||||
@@ -286,6 +315,7 @@ class U115Pan(StorageBase, metaclass=Singleton):
|
||||
fileitem = result.get('data')
|
||||
logger.info(f"115上传文件成功:{fileitem}")
|
||||
return schemas.FileItem(
|
||||
storage=self.schema.value,
|
||||
fileid=fileitem.get('file_id'),
|
||||
parent_fileid=fileitem.fileid,
|
||||
type="file",
|
||||
@@ -321,5 +351,5 @@ class U115Pan(StorageBase, metaclass=Singleton):
|
||||
def link(self, fileitm: schemas.FileItem, target_file: Path) -> bool:
|
||||
pass
|
||||
|
||||
def softlink(self, fileitm: schemas.FileItem, target_file: schemas.FileItem) -> bool:
|
||||
def softlink(self, fileitm: schemas.FileItem, target_file: Path) -> bool:
|
||||
pass
|
||||
|
||||
@@ -9,7 +9,7 @@ class FileItem(BaseModel):
|
||||
# 类型 dir/file
|
||||
type: Optional[str] = None
|
||||
# 文件路径
|
||||
path: Optional[str] = None
|
||||
path: Optional[str] = "/"
|
||||
# 文件名
|
||||
name: Optional[str] = None
|
||||
# 文件名
|
||||
|
||||
Reference in New Issue
Block a user