mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-07 00:16:57 +08:00
fix storage api
This commit is contained in:
@@ -1,15 +1,16 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, List
|
from typing import Any, List
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
from starlette.responses import FileResponse
|
from starlette.responses import FileResponse, Response
|
||||||
|
|
||||||
from app import schemas
|
from app import schemas
|
||||||
from app.chain.storage import StorageChain
|
from app.chain.storage import StorageChain
|
||||||
from app.chain.transfer import TransferChain
|
from app.chain.transfer import TransferChain
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
from app.core.metainfo import MetaInfoPath
|
from app.core.metainfo import MetaInfoPath
|
||||||
from app.core.security import verify_token, verify_uri_token
|
from app.core.security import verify_token
|
||||||
|
from app.db.models import User
|
||||||
from app.db.user_oper import get_current_active_superuser
|
from app.db.user_oper import get_current_active_superuser
|
||||||
from app.helper.progress import ProgressHelper
|
from app.helper.progress import ProgressHelper
|
||||||
from app.schemas.types import ProgressKey
|
from app.schemas.types import ProgressKey
|
||||||
@@ -45,7 +46,7 @@ def check(name: str, ck: str = None, t: str = None, _: schemas.TokenPayload = De
|
|||||||
@router.post("/save/{name}", summary="保存存储配置", response_model=schemas.Response)
|
@router.post("/save/{name}", summary="保存存储配置", response_model=schemas.Response)
|
||||||
def save(name: str,
|
def save(name: str,
|
||||||
conf: dict,
|
conf: dict,
|
||||||
_: schemas.TokenPayload = Depends(get_current_active_superuser)) -> Any:
|
_: User = Depends(get_current_active_superuser)) -> Any:
|
||||||
"""
|
"""
|
||||||
保存存储配置
|
保存存储配置
|
||||||
"""
|
"""
|
||||||
@@ -56,7 +57,7 @@ def save(name: str,
|
|||||||
@router.post("/list", summary="所有目录和文件", response_model=List[schemas.FileItem])
|
@router.post("/list", summary="所有目录和文件", response_model=List[schemas.FileItem])
|
||||||
def list(fileitem: schemas.FileItem,
|
def list(fileitem: schemas.FileItem,
|
||||||
sort: str = 'updated_at',
|
sort: str = 'updated_at',
|
||||||
_: schemas.TokenPayload = Depends(get_current_active_superuser)) -> Any:
|
_: User = Depends(get_current_active_superuser)) -> Any:
|
||||||
"""
|
"""
|
||||||
查询当前目录下所有目录和文件
|
查询当前目录下所有目录和文件
|
||||||
:param fileitem: 文件项
|
:param fileitem: 文件项
|
||||||
@@ -76,7 +77,7 @@ def list(fileitem: schemas.FileItem,
|
|||||||
@router.post("/mkdir", summary="创建目录", response_model=schemas.Response)
|
@router.post("/mkdir", summary="创建目录", response_model=schemas.Response)
|
||||||
def mkdir(fileitem: schemas.FileItem,
|
def mkdir(fileitem: schemas.FileItem,
|
||||||
name: str,
|
name: str,
|
||||||
_: schemas.TokenPayload = Depends(get_current_active_superuser)) -> Any:
|
_: User = Depends(get_current_active_superuser)) -> Any:
|
||||||
"""
|
"""
|
||||||
创建目录
|
创建目录
|
||||||
:param fileitem: 文件项
|
:param fileitem: 文件项
|
||||||
@@ -93,7 +94,7 @@ def mkdir(fileitem: schemas.FileItem,
|
|||||||
|
|
||||||
@router.post("/delete", summary="删除文件或目录", response_model=schemas.Response)
|
@router.post("/delete", summary="删除文件或目录", response_model=schemas.Response)
|
||||||
def delete(fileitem: schemas.FileItem,
|
def delete(fileitem: schemas.FileItem,
|
||||||
_: schemas.TokenPayload = Depends(get_current_active_superuser)) -> Any:
|
_: User = Depends(get_current_active_superuser)) -> Any:
|
||||||
"""
|
"""
|
||||||
删除文件或目录
|
删除文件或目录
|
||||||
:param fileitem: 文件项
|
:param fileitem: 文件项
|
||||||
@@ -107,25 +108,39 @@ def delete(fileitem: schemas.FileItem,
|
|||||||
|
|
||||||
@router.post("/download", summary="下载文件")
|
@router.post("/download", summary="下载文件")
|
||||||
def download(fileitem: schemas.FileItem,
|
def download(fileitem: schemas.FileItem,
|
||||||
_: schemas.TokenPayload = Depends(verify_uri_token)) -> Any:
|
_: User = Depends(get_current_active_superuser)) -> Any:
|
||||||
"""
|
"""
|
||||||
下载文件或目录
|
下载文件或目录
|
||||||
:param fileitem: 文件项
|
:param fileitem: 文件项
|
||||||
:param _: token
|
:param _: token
|
||||||
"""
|
"""
|
||||||
# 临时目录
|
# 临时目录
|
||||||
tmp_file = settings.TEMP_PATH / fileitem.name
|
tmp_file = StorageChain().download_file(fileitem)
|
||||||
status = StorageChain().download_file(fileitem, tmp_file)
|
if tmp_file:
|
||||||
if status:
|
|
||||||
return FileResponse(path=tmp_file)
|
return FileResponse(path=tmp_file)
|
||||||
return schemas.Response(success=False)
|
return schemas.Response(success=False)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/image", summary="预览图片")
|
||||||
|
def image(fileitem: schemas.FileItem,
|
||||||
|
_: User = Depends(get_current_active_superuser)) -> Any:
|
||||||
|
"""
|
||||||
|
下载文件或目录
|
||||||
|
:param fileitem: 文件项
|
||||||
|
:param _: token
|
||||||
|
"""
|
||||||
|
# 临时目录
|
||||||
|
tmp_file = StorageChain().download_file(fileitem)
|
||||||
|
if not tmp_file:
|
||||||
|
raise HTTPException(status_code=500, detail="图片读取出错")
|
||||||
|
return Response(content=tmp_file.read_bytes(), media_type="image/jpeg")
|
||||||
|
|
||||||
|
|
||||||
@router.post("/rename", summary="重命名文件或目录", response_model=schemas.Response)
|
@router.post("/rename", summary="重命名文件或目录", response_model=schemas.Response)
|
||||||
def rename(fileitem: schemas.FileItem,
|
def rename(fileitem: schemas.FileItem,
|
||||||
new_name: str,
|
new_name: str,
|
||||||
recursive: bool = False,
|
recursive: bool = False,
|
||||||
_: schemas.TokenPayload = Depends(get_current_active_superuser)) -> Any:
|
_: User = Depends(get_current_active_superuser)) -> Any:
|
||||||
"""
|
"""
|
||||||
重命名文件或目录
|
重命名文件或目录
|
||||||
:param fileitem: 文件项
|
:param fileitem: 文件项
|
||||||
@@ -181,7 +196,7 @@ def rename(fileitem: schemas.FileItem,
|
|||||||
|
|
||||||
|
|
||||||
@router.get("/usage/{name}", summary="存储空间信息", response_model=schemas.StorageUsage)
|
@router.get("/usage/{name}", summary="存储空间信息", response_model=schemas.StorageUsage)
|
||||||
def usage(name: str, _: schemas.TokenPayload = Depends(get_current_active_superuser)) -> Any:
|
def usage(name: str, _: User = Depends(get_current_active_superuser)) -> Any:
|
||||||
"""
|
"""
|
||||||
查询存储空间
|
查询存储空间
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -40,11 +40,11 @@ class StorageChain(ChainBase):
|
|||||||
"""
|
"""
|
||||||
return self.run_module("create_folder", fileitem=fileitem, name=name)
|
return self.run_module("create_folder", fileitem=fileitem, name=name)
|
||||||
|
|
||||||
def download_file(self, fileitem: schemas.FileItem, path: str) -> Optional[bool]:
|
def download_file(self, fileitem: schemas.FileItem) -> Optional[Path]:
|
||||||
"""
|
"""
|
||||||
下载文件
|
下载文件
|
||||||
"""
|
"""
|
||||||
return self.run_module("download_file", fileitem=fileitem, path=path)
|
return self.run_module("download_file", fileitem=fileitem)
|
||||||
|
|
||||||
def upload_file(self, fileitem: schemas.FileItem, path: Path) -> Optional[bool]:
|
def upload_file(self, fileitem: schemas.FileItem, path: Path) -> Optional[bool]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -185,15 +185,15 @@ class FileManagerModule(_ModuleBase):
|
|||||||
return False
|
return False
|
||||||
return storage_oper.rename(fileitem, name)
|
return storage_oper.rename(fileitem, name)
|
||||||
|
|
||||||
def download_file(self, fileitem: FileItem, path: Path) -> bool:
|
def download_file(self, fileitem: FileItem) -> Optional[Path]:
|
||||||
"""
|
"""
|
||||||
下载文件
|
下载文件
|
||||||
"""
|
"""
|
||||||
storage_oper = self.__get_storage_oper(fileitem.storage)
|
storage_oper = self.__get_storage_oper(fileitem.storage)
|
||||||
if not storage_oper:
|
if not storage_oper:
|
||||||
logger.error(f"不支持 {fileitem.storage} 的下载处理")
|
logger.error(f"不支持 {fileitem.storage} 的下载处理")
|
||||||
return False
|
return None
|
||||||
return storage_oper.download(fileitem, path)
|
return storage_oper.download(fileitem)
|
||||||
|
|
||||||
def upload_file(self, fileitem: FileItem, path: Path) -> Optional[FileItem]:
|
def upload_file(self, fileitem: FileItem, path: Path) -> Optional[FileItem]:
|
||||||
"""
|
"""
|
||||||
@@ -414,13 +414,19 @@ class FileManagerModule(_ModuleBase):
|
|||||||
# 网盘到本地
|
# 网盘到本地
|
||||||
if transfer_type == "copy":
|
if transfer_type == "copy":
|
||||||
# 下载
|
# 下载
|
||||||
if source_oper.download(fileitem, target_file):
|
tmp_file = source_oper.download(fileitem)
|
||||||
|
if tmp_file:
|
||||||
|
# 将tmp_file移动后target_file
|
||||||
|
tmp_file.rename(target_file)
|
||||||
return __get_targetitem(target_file), ""
|
return __get_targetitem(target_file), ""
|
||||||
else:
|
else:
|
||||||
return None, f"{fileitem.path} {fileitem.storage} 下载失败"
|
return None, f"{fileitem.path} {fileitem.storage} 下载失败"
|
||||||
elif transfer_type == "move":
|
elif transfer_type == "move":
|
||||||
# 下载
|
# 下载
|
||||||
if source_oper.download(fileitem, target_file):
|
tmp_file = source_oper.download(fileitem)
|
||||||
|
if tmp_file:
|
||||||
|
# 将tmp_file移动后target_file
|
||||||
|
tmp_file.rename(target_file)
|
||||||
# 删除源文件
|
# 删除源文件
|
||||||
source_oper.delete(fileitem)
|
source_oper.delete(fileitem)
|
||||||
return __get_targetitem(target_file), ""
|
return __get_targetitem(target_file), ""
|
||||||
|
|||||||
@@ -96,9 +96,9 @@ class StorageBase(metaclass=ABCMeta):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def download(self, fileitm: schemas.FileItem, path: Path) -> bool:
|
def download(self, fileitm: schemas.FileItem) -> Path:
|
||||||
"""
|
"""
|
||||||
下载文件,保存到本地
|
下载文件,保存到本地,返回本地临时文件地址
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -587,13 +587,13 @@ class AliPan(StorageBase):
|
|||||||
self.__handle_error(res, "重命名文件")
|
self.__handle_error(res, "重命名文件")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def download(self, fileitem: schemas.FileItem, path: Path) -> bool:
|
def download(self, fileitem: schemas.FileItem) -> Optional[Path]:
|
||||||
"""
|
"""
|
||||||
下载文件,保存到本地
|
下载文件,保存到本地
|
||||||
"""
|
"""
|
||||||
params = self.__access_params
|
params = self.__access_params
|
||||||
if not params:
|
if not params:
|
||||||
return False
|
return None
|
||||||
headers = self.__get_headers(params)
|
headers = self.__get_headers(params)
|
||||||
res = RequestUtils(headers=headers, timeout=10).post_res(self.download_url, json={
|
res = RequestUtils(headers=headers, timeout=10).post_res(self.download_url, json={
|
||||||
"drive_id": fileitem.drive_id,
|
"drive_id": fileitem.drive_id,
|
||||||
@@ -602,15 +602,16 @@ class AliPan(StorageBase):
|
|||||||
if res:
|
if res:
|
||||||
download_url = res.json().get("url")
|
download_url = res.json().get("url")
|
||||||
if not download_url:
|
if not download_url:
|
||||||
return False
|
return None
|
||||||
res = RequestUtils().get_res(download_url)
|
res = RequestUtils().get_res(download_url)
|
||||||
if res:
|
if res:
|
||||||
|
path = settings.TEMP_PATH / fileitem.name
|
||||||
with path.open("wb") as f:
|
with path.open("wb") as f:
|
||||||
f.write(res.content)
|
f.write(res.content)
|
||||||
return True
|
return path
|
||||||
else:
|
else:
|
||||||
self.__handle_error(res, "获取下载链接")
|
self.__handle_error(res, "获取下载链接")
|
||||||
return False
|
return None
|
||||||
|
|
||||||
def upload(self, fileitem: schemas.FileItem, path: Path) -> Optional[schemas.FileItem]:
|
def upload(self, fileitem: schemas.FileItem, path: Path) -> Optional[schemas.FileItem]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -177,11 +177,11 @@ class LocalStorage(StorageBase):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def download(self, fileitem: schemas.FileItem, path: Path) -> bool:
|
def download(self, fileitem: schemas.FileItem) -> Optional[Path]:
|
||||||
"""
|
"""
|
||||||
下载文件
|
下载文件
|
||||||
"""
|
"""
|
||||||
pass
|
return Path(fileitem.path)
|
||||||
|
|
||||||
def upload(self, fileitem: schemas.FileItem, path: Path) -> Optional[schemas.FileItem]:
|
def upload(self, fileitem: schemas.FileItem, path: Path) -> Optional[schemas.FileItem]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from pathlib import Path
|
|||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
|
|
||||||
from app import schemas
|
from app import schemas
|
||||||
|
from app.core.config import settings
|
||||||
from app.log import logger
|
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
|
||||||
@@ -225,24 +226,25 @@ class Rclone(StorageBase):
|
|||||||
logger.error(f"rclone重命名文件失败:{err}")
|
logger.error(f"rclone重命名文件失败:{err}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def download(self, fileitm: schemas.FileItem, path: Path) -> bool:
|
def download(self, fileitem: schemas.FileItem) -> Optional[Path]:
|
||||||
"""
|
"""
|
||||||
下载文件
|
下载文件
|
||||||
"""
|
"""
|
||||||
|
path = settings.TEMP_PATH / fileitem.name
|
||||||
try:
|
try:
|
||||||
retcode = subprocess.run(
|
retcode = subprocess.run(
|
||||||
[
|
[
|
||||||
'rclone', 'copyto',
|
'rclone', 'copyto',
|
||||||
f'MP:{fileitm.path}',
|
f'MP:{fileitem.path}',
|
||||||
f'{path}'
|
f'{path}'
|
||||||
],
|
],
|
||||||
startupinfo=self.__get_hidden_shell()
|
startupinfo=self.__get_hidden_shell()
|
||||||
).returncode
|
).returncode
|
||||||
if retcode == 0:
|
if retcode == 0:
|
||||||
return True
|
return path
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"rclone复制文件失败:{err}")
|
logger.error(f"rclone复制文件失败:{err}")
|
||||||
return False
|
return None
|
||||||
|
|
||||||
def upload(self, fileitm: schemas.FileItem, path: Path) -> Optional[schemas.FileItem]:
|
def upload(self, fileitm: schemas.FileItem, path: Path) -> Optional[schemas.FileItem]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from py115 import Cloud
|
|||||||
from py115.types import LoginTarget, QrcodeSession, QrcodeStatus, Credential
|
from py115.types import LoginTarget, QrcodeSession, QrcodeStatus, Credential
|
||||||
|
|
||||||
from app import schemas
|
from app import schemas
|
||||||
|
from app.core.config import settings
|
||||||
from app.log import logger
|
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
|
||||||
@@ -289,23 +290,24 @@ class U115Pan(StorageBase, metaclass=Singleton):
|
|||||||
logger.error(f"115重命名文件失败:{str(e)}")
|
logger.error(f"115重命名文件失败:{str(e)}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def download(self, fileitem: schemas.FileItem, path: Path) -> bool:
|
def download(self, fileitem: schemas.FileItem) -> Optional[Path]:
|
||||||
"""
|
"""
|
||||||
获取下载链接
|
获取下载链接
|
||||||
"""
|
"""
|
||||||
if not self.__init_cloud():
|
if not self.__init_cloud():
|
||||||
return False
|
return None
|
||||||
try:
|
try:
|
||||||
ticket = self.cloud.storage().request_download(fileitem.pickcode)
|
ticket = self.cloud.storage().request_download(fileitem.pickcode)
|
||||||
if ticket:
|
if ticket:
|
||||||
|
path = settings.TEMP_PATH / fileitem.name
|
||||||
res = RequestUtils(headers=ticket.headers).get_res(ticket.url)
|
res = RequestUtils(headers=ticket.headers).get_res(ticket.url)
|
||||||
if res:
|
if res:
|
||||||
with open(path, "wb") as f:
|
with open(path, "wb") as f:
|
||||||
f.write(res.content)
|
f.write(res.content)
|
||||||
return True
|
return path
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"115下载失败:{str(e)}")
|
logger.error(f"115下载失败:{str(e)}")
|
||||||
return False
|
return None
|
||||||
|
|
||||||
def upload(self, fileitem: schemas.FileItem, path: Path) -> Optional[schemas.FileItem]:
|
def upload(self, fileitem: schemas.FileItem, path: Path) -> Optional[schemas.FileItem]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user