add upload api
This commit is contained in:
parent
ae0e171dd2
commit
0133c6e60c
@ -47,10 +47,8 @@ def userinfo(_: schemas.TokenPayload = Depends(verify_token)) -> Any:
|
||||
查询用户信息
|
||||
"""
|
||||
aliyunhelper = AliyunHelper()
|
||||
# 浏览一次文件确定token正确性
|
||||
aliyunhelper.list_files()
|
||||
# 查询用户信息返回
|
||||
info = aliyunhelper.get_user_info()
|
||||
info = aliyunhelper.user_info()
|
||||
if info:
|
||||
return schemas.Response(success=True, data=info)
|
||||
return schemas.Response(success=False)
|
||||
@ -76,7 +74,7 @@ def list_aliyun(fileitem: schemas.FileItem,
|
||||
if sort == "time":
|
||||
sort = "updated_at"
|
||||
if fileitem.type == "file":
|
||||
fileinfo = AliyunHelper().get_file_detail(fileitem.fileid)
|
||||
fileinfo = AliyunHelper().detail(fileitem.fileid)
|
||||
if fileinfo:
|
||||
return [schemas.FileItem(
|
||||
fileid=fileinfo.get("file_id"),
|
||||
@ -91,7 +89,7 @@ def list_aliyun(fileitem: schemas.FileItem,
|
||||
drive_id=fileinfo.get("drive_id"),
|
||||
)]
|
||||
return []
|
||||
items = AliyunHelper().list_files(drive_id=fileitem.drive_id, parent_file_id=fileitem.fileid, order_by=sort)
|
||||
items = AliyunHelper().list(drive_id=fileitem.drive_id, parent_file_id=fileitem.fileid, order_by=sort)
|
||||
if not items:
|
||||
return []
|
||||
return [schemas.FileItem(
|
||||
@ -131,7 +129,7 @@ def delete_aliyun(fileitem: schemas.FileItem,
|
||||
"""
|
||||
if not fileitem.fileid:
|
||||
return schemas.Response(success=False)
|
||||
result = AliyunHelper().delete_file(fileitem.fileid)
|
||||
result = AliyunHelper().delete(fileitem.fileid)
|
||||
if result:
|
||||
return schemas.Response(success=True)
|
||||
return schemas.Response(success=False)
|
||||
@ -145,7 +143,7 @@ def download_aliyun(fileid: str,
|
||||
"""
|
||||
if not fileid:
|
||||
return schemas.Response(success=False)
|
||||
url = AliyunHelper().get_download_url(fileid)
|
||||
url = AliyunHelper().download(fileid)
|
||||
if url:
|
||||
# 重定向
|
||||
return Response(status_code=302, headers={"Location": url})
|
||||
@ -162,7 +160,7 @@ def rename_aliyun(fileitem: schemas.FileItem,
|
||||
"""
|
||||
if not fileitem.fileid or not new_name:
|
||||
return schemas.Response(success=False)
|
||||
result = AliyunHelper().rename_file(fileitem.fileid, new_name)
|
||||
result = AliyunHelper().rename(fileitem.fileid, new_name)
|
||||
if result:
|
||||
if recursive:
|
||||
transferchain = TransferChain()
|
||||
@ -214,7 +212,7 @@ def image_aliyun(fileid: str, _: schemas.TokenPayload = Depends(verify_uri_token
|
||||
"""
|
||||
if not fileid:
|
||||
return schemas.Response(success=False)
|
||||
url = AliyunHelper().get_download_url(fileid)
|
||||
url = AliyunHelper().download_url(fileid)
|
||||
if url:
|
||||
# 重定向
|
||||
return Response(status_code=302, headers={"Location": url})
|
||||
|
@ -46,7 +46,7 @@ def storage(_: schemas.TokenPayload = Depends(verify_token)) -> Any:
|
||||
"""
|
||||
查询存储空间信息
|
||||
"""
|
||||
storage_info = U115Helper().get_storage()
|
||||
storage_info = U115Helper().storage()
|
||||
if storage_info:
|
||||
return schemas.Response(success=True, data={
|
||||
"total": storage_info[0],
|
||||
@ -87,7 +87,7 @@ def list_115(fileitem: schemas.FileItem,
|
||||
extension=suffix,
|
||||
pickcode=fileitem.pickcode
|
||||
)]
|
||||
items = U115Helper().list_files(parent_file_id=fileid)
|
||||
items = U115Helper().list(parent_file_id=fileid)
|
||||
if not items:
|
||||
return []
|
||||
file_list = [schemas.FileItem(
|
||||
@ -131,7 +131,7 @@ def delete_115(fileitem: schemas.FileItem,
|
||||
"""
|
||||
if not fileitem.fileid:
|
||||
return schemas.Response(success=False)
|
||||
result = U115Helper().delete_file(fileitem.fileid)
|
||||
result = U115Helper().delete(fileitem.fileid)
|
||||
if result:
|
||||
return schemas.Response(success=True)
|
||||
return schemas.Response(success=False)
|
||||
@ -164,7 +164,7 @@ def rename_115(fileitem: schemas.FileItem,
|
||||
"""
|
||||
if not fileitem.fileid or not new_name:
|
||||
return schemas.Response(success=False)
|
||||
result = U115Helper().rename_file(fileitem.fileid, new_name)
|
||||
result = U115Helper().rename(fileitem.fileid, new_name)
|
||||
if result:
|
||||
if recursive:
|
||||
transferchain = TransferChain()
|
||||
|
@ -2,6 +2,7 @@ import base64
|
||||
import json
|
||||
import time
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from typing import Optional, Tuple, List
|
||||
|
||||
from requests import Response
|
||||
@ -50,7 +51,11 @@ class AliyunHelper:
|
||||
# 获取下载链接
|
||||
download_url = "https://api.aliyundrive.com/v2/file/get_download_url"
|
||||
# 移动文件
|
||||
move_file_url = "https://api.aliyundrive.com/v3/file/move"
|
||||
move_file_url = "https://api.aliyundrive.com/v2/file/move"
|
||||
# 创建文件
|
||||
create_file_url = "https://api.aliyundrive.com/adrive/v2/file/create"
|
||||
# 上传文件完成
|
||||
upload_file_complete_url = "https://api.aliyundrive.com/v2/file/complete"
|
||||
|
||||
def __init__(self):
|
||||
self.systemconfig = SystemConfigOper()
|
||||
@ -71,32 +76,32 @@ class AliyunHelper:
|
||||
if action:
|
||||
if code == "DeviceSessionSignatureInvalid":
|
||||
logger.warn("设备已失效,正在重新建立会话...")
|
||||
self.create_session(self.get_headers(self.auth_params))
|
||||
self.__create_session(self.get_headers(self.__auth_params))
|
||||
if code == "UserDeviceOffline":
|
||||
logger.warn("设备已离线,尝试重新登录,如仍报错请检查阿里云盘绑定设备数量是否超限!")
|
||||
self.create_session(self.get_headers(self.auth_params))
|
||||
self.__create_session(self.get_headers(self.__auth_params))
|
||||
if code == "AccessTokenInvalid":
|
||||
logger.warn("访问令牌已失效,正在刷新令牌...")
|
||||
self.__update_accesstoken(self.auth_params, self.auth_params.get("refreshToken"))
|
||||
self.__update_accesstoken(self.__auth_params, self.__auth_params.get("refreshToken"))
|
||||
else:
|
||||
logger.info(f"Aliyun {apiname}成功")
|
||||
|
||||
@property
|
||||
def auth_params(self):
|
||||
def __auth_params(self):
|
||||
"""
|
||||
获取阿里云盘认证参数并初始化参数格式
|
||||
"""
|
||||
return self.systemconfig.get(SystemConfigKey.UserAliyunParams) or {}
|
||||
|
||||
def update_params(self, params: dict):
|
||||
def __update_params(self, params: dict):
|
||||
"""
|
||||
设置阿里云盘认证参数
|
||||
"""
|
||||
current_params = self.auth_params
|
||||
current_params = self.__auth_params
|
||||
current_params.update(params)
|
||||
self.systemconfig.set(SystemConfigKey.UserAliyunParams, current_params)
|
||||
|
||||
def clear_params(self):
|
||||
def __clear_params(self):
|
||||
"""
|
||||
清除阿里云盘认证参数
|
||||
"""
|
||||
@ -173,8 +178,8 @@ class AliyunHelper:
|
||||
"defaultDriveId": pds_login_result.get('defaultDriveId'),
|
||||
"updateTime": time.time(),
|
||||
})
|
||||
self.update_params(data)
|
||||
self.get_user_info()
|
||||
self.__update_params(data)
|
||||
self.user_info()
|
||||
except Exception as e:
|
||||
return {}, f"bizExt 解码失败:{str(e)}"
|
||||
return data, ""
|
||||
@ -198,9 +203,9 @@ class AliyunHelper:
|
||||
code = data.get("code")
|
||||
if code in ["RefreshTokenExpired", "InvalidParameter.RefreshToken"]:
|
||||
logger.warn("刷新令牌已过期,请重新登录!")
|
||||
self.clear_params()
|
||||
self.__clear_params()
|
||||
return False
|
||||
self.update_params({
|
||||
self.__update_params({
|
||||
"accessToken": data.get('access_token'),
|
||||
"expiresIn": data.get('expires_in'),
|
||||
"updateTime": time.time()
|
||||
@ -211,10 +216,11 @@ class AliyunHelper:
|
||||
self.__handle_error(res, "更新令牌", action=False)
|
||||
return False
|
||||
|
||||
def create_session(self, headers: dict):
|
||||
def __create_session(self, headers: dict):
|
||||
"""
|
||||
创建会话
|
||||
"""
|
||||
|
||||
def __os_name():
|
||||
"""
|
||||
获取操作系统名称
|
||||
@ -233,11 +239,12 @@ class AliyunHelper:
|
||||
})
|
||||
self.__handle_error(res, "创建会话", action=False)
|
||||
|
||||
def get_access_params(self) -> Optional[dict]:
|
||||
@property
|
||||
def __access_params(self) -> Optional[dict]:
|
||||
"""
|
||||
获取阿里云盘访问参数,如果超时则更新后返回
|
||||
"""
|
||||
params = self.auth_params
|
||||
params = self.__auth_params
|
||||
if not params:
|
||||
logger.warn("阿里云盘访问令牌不存在,请先扫码登录!")
|
||||
return None
|
||||
@ -246,7 +253,7 @@ class AliyunHelper:
|
||||
refresh_token = params.get("refreshToken")
|
||||
if not expires_in or not update_time or not refresh_token:
|
||||
logger.warn("阿里云盘访问令牌参数错误,请重新扫码登录!")
|
||||
self.clear_params()
|
||||
self.__clear_params()
|
||||
return None
|
||||
# 是否需要更新设备信息
|
||||
update_device = False
|
||||
@ -262,11 +269,11 @@ class AliyunHelper:
|
||||
if not x_device_id:
|
||||
x_device_id = uuid.uuid4().hex
|
||||
params['x_device_id'] = x_device_id
|
||||
self.update_params({"x_device_id": x_device_id})
|
||||
self.__update_params({"x_device_id": x_device_id})
|
||||
update_device = True
|
||||
# 更新设备信息重新创建会话
|
||||
if update_device:
|
||||
self.create_session(self.get_headers(params))
|
||||
self.__create_session(self.get_headers(params))
|
||||
return params
|
||||
|
||||
def get_headers(self, params: dict):
|
||||
@ -286,18 +293,18 @@ class AliyunHelper:
|
||||
"x-signature": self._X_SIGNATURE
|
||||
}
|
||||
|
||||
def get_user_info(self) -> dict:
|
||||
def user_info(self) -> dict:
|
||||
"""
|
||||
获取用户信息(drive_id等)
|
||||
"""
|
||||
params = self.get_access_params()
|
||||
params = self.__access_params
|
||||
if not params:
|
||||
return {}
|
||||
headers = self.get_headers(params)
|
||||
res = RequestUtils(headers=headers, timeout=10).post_res(self.user_info_url)
|
||||
if res:
|
||||
result = res.json()
|
||||
self.update_params({
|
||||
self.__update_params({
|
||||
"resourceDriveId": result.get("resource_drive_id"),
|
||||
"backDriveId": result.get("backup_drive_id")
|
||||
})
|
||||
@ -306,7 +313,7 @@ class AliyunHelper:
|
||||
self.__handle_error(res, "获取用户信息")
|
||||
return {}
|
||||
|
||||
def list_files(self, drive_id: str = None, parent_file_id: str = 'root', list_type: str = None,
|
||||
def list(self, drive_id: str = None, parent_file_id: str = 'root', list_type: str = None,
|
||||
limit: int = 100, order_by: str = 'updated_at') -> List[dict]:
|
||||
"""
|
||||
浏览文件
|
||||
@ -315,7 +322,7 @@ class AliyunHelper:
|
||||
parent_file_id 根目录为root
|
||||
type all | file | folder
|
||||
"""
|
||||
params = self.get_access_params()
|
||||
params = self.__access_params
|
||||
if not params:
|
||||
return []
|
||||
# 请求头
|
||||
@ -379,7 +386,7 @@ class AliyunHelper:
|
||||
"""
|
||||
创建目录
|
||||
"""
|
||||
params = self.get_access_params()
|
||||
params = self.__access_params
|
||||
if not params:
|
||||
return None
|
||||
headers = self.get_headers(params)
|
||||
@ -414,11 +421,11 @@ class AliyunHelper:
|
||||
self.__handle_error(res, "创建目录")
|
||||
return None
|
||||
|
||||
def delete_file(self, file_id: str) -> bool:
|
||||
def delete(self, file_id: str) -> bool:
|
||||
"""
|
||||
删除文件
|
||||
"""
|
||||
params = self.get_access_params()
|
||||
params = self.__access_params
|
||||
if not params:
|
||||
return False
|
||||
headers = self.get_headers(params)
|
||||
@ -432,11 +439,11 @@ class AliyunHelper:
|
||||
self.__handle_error(res, "删除文件")
|
||||
return False
|
||||
|
||||
def get_file_detail(self, file_id: str) -> Optional[dict]:
|
||||
def detail(self, file_id: str) -> Optional[dict]:
|
||||
"""
|
||||
获取文件详情
|
||||
"""
|
||||
params = self.get_access_params()
|
||||
params = self.__access_params
|
||||
if not params:
|
||||
return None
|
||||
headers = self.get_headers(params)
|
||||
@ -450,11 +457,11 @@ class AliyunHelper:
|
||||
self.__handle_error(res, "获取文件详情")
|
||||
return None
|
||||
|
||||
def rename_file(self, file_id: str, name: str) -> bool:
|
||||
def rename(self, file_id: str, name: str) -> bool:
|
||||
"""
|
||||
重命名文件
|
||||
"""
|
||||
params = self.get_access_params()
|
||||
params = self.__access_params
|
||||
if not params:
|
||||
return False
|
||||
headers = self.get_headers(params)
|
||||
@ -470,11 +477,11 @@ class AliyunHelper:
|
||||
self.__handle_error(res, "重命名文件")
|
||||
return False
|
||||
|
||||
def get_download_url(self, file_id: str) -> Optional[str]:
|
||||
def download(self, file_id: str) -> Optional[str]:
|
||||
"""
|
||||
获取下载链接
|
||||
"""
|
||||
params = self.get_access_params()
|
||||
params = self.__access_params
|
||||
if not params:
|
||||
return None
|
||||
headers = self.get_headers(params)
|
||||
@ -492,7 +499,7 @@ class AliyunHelper:
|
||||
"""
|
||||
移动文件
|
||||
"""
|
||||
params = self.get_access_params()
|
||||
params = self.__access_params
|
||||
if not params:
|
||||
return False
|
||||
headers = self.get_headers(params)
|
||||
@ -507,3 +514,52 @@ class AliyunHelper:
|
||||
else:
|
||||
self.__handle_error(res, "移动文件")
|
||||
return False
|
||||
|
||||
def upload(self, parent_file_id: str, name: str, filepath: Path) -> Optional[dict]:
|
||||
"""
|
||||
上传文件,并标记完成
|
||||
"""
|
||||
params = self.__access_params
|
||||
if not params:
|
||||
return None
|
||||
headers = self.get_headers(params)
|
||||
res = RequestUtils(headers=headers, timeout=10).post_res(self.create_file_url, json={
|
||||
"drive_id": params.get("resourceDriveId"),
|
||||
"parent_file_id": parent_file_id,
|
||||
"name": name,
|
||||
"type": "file",
|
||||
"check_name_mode": "refuse"
|
||||
})
|
||||
if not res:
|
||||
self.__handle_error(res, "创建文件")
|
||||
return None
|
||||
# 获取上传参数
|
||||
result = res.json()
|
||||
drive_id = result.get("drive_id")
|
||||
file_id = result.get("file_id")
|
||||
upload_id = result.get("upload_id")
|
||||
part_info_list = result.get("part_info_list")
|
||||
if part_info_list:
|
||||
# 上传地址
|
||||
upload_url = part_info_list[0].get("upload_url")
|
||||
# 上传文件
|
||||
res = RequestUtils(headers=headers).put_res(upload_url, data=filepath.read_bytes())
|
||||
if not res:
|
||||
self.__handle_error(res, "上传文件")
|
||||
return None
|
||||
# 标记文件上传完毕
|
||||
res = RequestUtils(headers=headers, timeout=10).post_res(self.upload_file_complete_url, json={
|
||||
"drive_id": drive_id,
|
||||
"file_id": file_id,
|
||||
"upload_id": upload_id
|
||||
})
|
||||
if not res:
|
||||
self.__handle_error(res, "标记上传状态")
|
||||
return None
|
||||
return {
|
||||
"drive_id": drive_id,
|
||||
"file_id": file_id
|
||||
}
|
||||
else:
|
||||
logger.warn("上传文件失败:无法获取上传地址!")
|
||||
return None
|
||||
|
@ -1,6 +1,7 @@
|
||||
import base64
|
||||
from typing import Optional, Tuple, Generator
|
||||
|
||||
import oss2
|
||||
import py115
|
||||
from py115 import Cloud
|
||||
from py115.types import LoginTarget, QrcodeSession, QrcodeStatus, Credential, File, DownloadTicket
|
||||
@ -26,7 +27,7 @@ class U115Helper(metaclass=Singleton):
|
||||
"""
|
||||
初始化Cloud
|
||||
"""
|
||||
credential = self.credential
|
||||
credential = self.__credential
|
||||
if not credential:
|
||||
logger.warn("115未登录,请先登录!")
|
||||
return False
|
||||
@ -35,12 +36,12 @@ class U115Helper(metaclass=Singleton):
|
||||
self.cloud = py115.connect(credential)
|
||||
except Exception as err:
|
||||
logger.error(f"115连接失败,请重新扫码登录:{str(err)}")
|
||||
self.clear_credential()
|
||||
self.__clear_credential()
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def credential(self) -> Optional[Credential]:
|
||||
def __credential(self) -> Optional[Credential]:
|
||||
"""
|
||||
获取已保存的115认证参数
|
||||
"""
|
||||
@ -49,13 +50,13 @@ class U115Helper(metaclass=Singleton):
|
||||
return None
|
||||
return Credential.from_dict(cookie_dict)
|
||||
|
||||
def save_credentail(self, credential: Credential):
|
||||
def __save_credentail(self, credential: Credential):
|
||||
"""
|
||||
设置115认证参数
|
||||
"""
|
||||
self.systemconfig.set(SystemConfigKey.User115Params, credential.to_dict())
|
||||
|
||||
def clear_credential(self):
|
||||
def __clear_credential(self):
|
||||
"""
|
||||
清除115认证参数
|
||||
"""
|
||||
@ -91,7 +92,7 @@ class U115Helper(metaclass=Singleton):
|
||||
status = self.cloud.qrcode_poll(self._session)
|
||||
if status == QrcodeStatus.Done:
|
||||
# 确认完成,保存认证信息
|
||||
self.save_credentail(self.cloud.export_credentail())
|
||||
self.__save_credentail(self.cloud.export_credentail())
|
||||
result = {
|
||||
"status": 1,
|
||||
"tip": "登录成功!"
|
||||
@ -123,7 +124,19 @@ class U115Helper(metaclass=Singleton):
|
||||
except Exception as e:
|
||||
return {}, f"115登录确认失败:{str(e)}"
|
||||
|
||||
def list_files(self, parent_file_id: str = '0') -> Optional[Generator[File, None, None]]:
|
||||
def storage(self) -> Optional[Tuple[int, int]]:
|
||||
"""
|
||||
获取存储空间
|
||||
"""
|
||||
if not self.__init_cloud():
|
||||
return None
|
||||
try:
|
||||
return self.cloud.storage().space()
|
||||
except Exception as e:
|
||||
logger.error(f"获取115存储空间失败:{str(e)}")
|
||||
return None
|
||||
|
||||
def list(self, parent_file_id: str = '0') -> Optional[Generator[File, None, None]]:
|
||||
"""
|
||||
浏览文件
|
||||
"""
|
||||
@ -147,7 +160,7 @@ class U115Helper(metaclass=Singleton):
|
||||
logger.error(f"创建115目录失败:{str(e)}")
|
||||
return None
|
||||
|
||||
def delete_file(self, file_id: str) -> bool:
|
||||
def delete(self, file_id: str) -> bool:
|
||||
"""
|
||||
删除文件
|
||||
"""
|
||||
@ -160,7 +173,7 @@ class U115Helper(metaclass=Singleton):
|
||||
logger.error(f"删除115文件失败:{str(e)}")
|
||||
return False
|
||||
|
||||
def rename_file(self, file_id: str, name: str) -> bool:
|
||||
def rename(self, file_id: str, name: str) -> bool:
|
||||
"""
|
||||
重命名文件
|
||||
"""
|
||||
@ -185,18 +198,6 @@ class U115Helper(metaclass=Singleton):
|
||||
logger.error(f"115下载失败:{str(e)}")
|
||||
return None
|
||||
|
||||
def get_storage(self) -> Optional[Tuple[int, int]]:
|
||||
"""
|
||||
获取存储空间
|
||||
"""
|
||||
if not self.__init_cloud():
|
||||
return None
|
||||
try:
|
||||
return self.cloud.storage().space()
|
||||
except Exception as e:
|
||||
logger.error(f"获取115存储空间失败:{str(e)}")
|
||||
return None
|
||||
|
||||
def move(self, file_id: str, target_id: str) -> bool:
|
||||
"""
|
||||
移动文件
|
||||
@ -209,3 +210,40 @@ class U115Helper(metaclass=Singleton):
|
||||
except Exception as e:
|
||||
logger.error(f"移动115文件失败:{str(e)}")
|
||||
return False
|
||||
|
||||
def upload(self, file_path: str, parent_file_id: str) -> Optional[dict]:
|
||||
"""
|
||||
上传文件
|
||||
"""
|
||||
if not self.__init_cloud():
|
||||
return None
|
||||
try:
|
||||
ticket = self.cloud.storage().request_upload(dir_id=parent_file_id, file_path=file_path)
|
||||
if ticket is None:
|
||||
logger.warn(f"115请求上传出错")
|
||||
return None
|
||||
elif ticket.is_done:
|
||||
logger.warn(f"115请求上传失败:文件已存在")
|
||||
return {}
|
||||
else:
|
||||
auth = oss2.StsAuth(**ticket.oss_token)
|
||||
bucket = oss2.Bucket(
|
||||
auth=auth,
|
||||
endpoint=ticket.oss_endpoint,
|
||||
bucket_name=ticket.bucket_name,
|
||||
)
|
||||
por = bucket.put_object_from_file(
|
||||
key=ticket.object_key,
|
||||
filename=file_path,
|
||||
headers=ticket.headers,
|
||||
)
|
||||
result = por.resp.response.json()
|
||||
if result:
|
||||
logger.info(f"115上传文件成功:{result}")
|
||||
return result
|
||||
else:
|
||||
logger.warn(f"115上传文件失败:{por.resp.response.text}")
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error(f"上传115文件失败:{str(e)}")
|
||||
return None
|
||||
|
@ -58,4 +58,5 @@ pystray~=0.19.5
|
||||
pyotp~=2.9.0
|
||||
Pinyin2Hanzi~=0.1.1
|
||||
pywebpush~=2.0.0
|
||||
py115~=0.0.4
|
||||
py115~=0.0.4
|
||||
oss2~=2.18.6
|
Loading…
x
Reference in New Issue
Block a user