fix lot of thing
This commit is contained in:
@@ -371,14 +371,16 @@ class MiaoStarsBasicApi:
|
||||
if path == "/" or path == "":
|
||||
uri = "cloudreve://my/"
|
||||
else:
|
||||
# 清理路径,确保不包含cloudreve://my前缀
|
||||
normalized_path = path.strip("/").replace("\\", "/").replace("cloudreve://my/", "")
|
||||
# 使用quote_plus正确编码路径,确保特殊字符被正确处理
|
||||
# 首先规范化路径分隔符
|
||||
normalized_path = path.strip("/").replace("\\", "/")
|
||||
# 对路径部分进行URL编码
|
||||
encoded_path = quote_plus(normalized_path)
|
||||
# 由于quote_plus会将斜杠也编码,我们需要恢复它们
|
||||
encoded_path = encoded_path.replace("%2F", "/")
|
||||
uri = f"cloudreve://my/{encoded_path}"
|
||||
|
||||
# 确保路径格式正确,移除重复的前缀
|
||||
uri = uri.replace("cloudreve://my/cloudreve://my", "cloudreve://my")
|
||||
|
||||
# 添加必需的分页参数
|
||||
params = {
|
||||
@@ -403,12 +405,12 @@ class MiaoStarsBasicApi:
|
||||
|
||||
def getPolicy(self):
|
||||
"""获取用户存储策略"""
|
||||
url = "/user/policies"
|
||||
url = "/user/setting/policies"
|
||||
r = self.request("GET", url)
|
||||
|
||||
# 转换响应格式
|
||||
if isinstance(r, list):
|
||||
return {"code": 0, "data": r}
|
||||
return r
|
||||
else:
|
||||
return {"code": 0, "data": []}
|
||||
|
||||
@@ -427,11 +429,28 @@ class MiaoStarsBasicApi:
|
||||
"""创建文件夹"""
|
||||
url = "/file/create"
|
||||
currentPath = policyConfig.returnCurrentPath()
|
||||
# 根据Cloudreve V4 API规范构建uri参数,确保不会有重复斜杠
|
||||
if currentPath == "/":
|
||||
# 根据Cloudreve V4 API规范构建uri参数,确保不会有重复斜杠和前缀
|
||||
# 清理currentPath,确保不包含cloudreve://my前缀
|
||||
clean_current_path = currentPath.replace("cloudreve://my", "")
|
||||
|
||||
if clean_current_path == "/":
|
||||
uri = f"cloudreve://my/{name}"
|
||||
else:
|
||||
uri = f"cloudreve://my{currentPath}/{name}"
|
||||
uri = f"cloudreve://my{clean_current_path}/{name}"
|
||||
|
||||
# 确保路径格式正确,移除重复的前缀
|
||||
uri = uri.replace("cloudreve://my/cloudreve://my", "cloudreve://my")
|
||||
|
||||
# 更健壮地处理重复文件名的情况
|
||||
path_parts = uri.split('/')
|
||||
if len(path_parts) > 1:
|
||||
# 检查最后一个部分是否是名称
|
||||
if path_parts[-1] == name:
|
||||
# 检查倒数第二个部分是否也是名称
|
||||
if len(path_parts) > 2 and path_parts[-2] == name:
|
||||
# 移除重复的名称部分
|
||||
path_parts.pop(-2)
|
||||
uri = '/'.join(path_parts)
|
||||
r = self.request("POST", url, json={"uri": uri, "type": "folder", "err_on_conflict": True})
|
||||
|
||||
# 转换响应格式
|
||||
@@ -440,20 +459,26 @@ class MiaoStarsBasicApi:
|
||||
else:
|
||||
return {"code": -1, "msg": r.get("msg", "文件夹创建失败")}
|
||||
|
||||
def deleteFile(self, fileId, fileType: Literal["file", "dir"]):
|
||||
"""删除文件"""
|
||||
url = "/file/delete"
|
||||
def deleteFile(self, fileUri, fileType: Literal["file", "dir"]):
|
||||
"""删除文件 (Cloudreve V4 API)"""
|
||||
url = "/file"
|
||||
|
||||
# 现在调用方已经传入了正确格式的URI
|
||||
logger.debug(f"删除文件,URI: {fileUri}")
|
||||
|
||||
# 根据Cloudreve V4 API规范,使用uris参数列表
|
||||
deleteData = {
|
||||
"items": [fileId] if fileType == "file" else [],
|
||||
"dirs": [fileId] if fileType == "dir" else []
|
||||
"uris": [fileUri]
|
||||
}
|
||||
r = self.request("POST", url, json=deleteData)
|
||||
r = self.request("DELETE", url, json=deleteData)
|
||||
|
||||
# 转换响应格式
|
||||
if r.get("count") > 0:
|
||||
# Cloudreve V4 响应格式:{code: 0} 表示成功
|
||||
if isinstance(r, dict) and r.get("code") == 0:
|
||||
return {"code": 0, "msg": "删除成功"}
|
||||
else:
|
||||
return {"code": -1, "msg": r.get("error", "删除失败")}
|
||||
error_msg = r.get("msg", r.get("error", "删除失败"))
|
||||
return {"code": -1, "msg": error_msg}
|
||||
|
||||
def wareSearch(
|
||||
self,
|
||||
@@ -564,6 +589,213 @@ class MiaoStarsBasicApi:
|
||||
else:
|
||||
return {"code": -1, "msg": r.get("error", "文件内容更新失败")}
|
||||
|
||||
def getFileUrl(self, fileUri, redirect=False):
|
||||
"""获取文件临时下载URL (Cloudreve V4 API)"""
|
||||
url = "/file/url"
|
||||
|
||||
# 确保传入的是正确格式的URI
|
||||
if not fileUri.startswith("cloudreve://"):
|
||||
logger.error(f"无效的URI格式: {fileUri},必须以cloudreve://开头")
|
||||
return {"code": -1, "msg": "无效的URI格式"}
|
||||
|
||||
# 修复文件名重复问题 - 保留URI编码文件名,删除后面的原始文件名
|
||||
if fileUri and '/' in fileUri:
|
||||
import urllib.parse
|
||||
parts = fileUri.split('/')
|
||||
|
||||
# 检查是否存在潜在的文件名重复情况
|
||||
if len(parts) >= 2:
|
||||
# 解码最后一个部分,检查是否与倒数第二个部分解码后相同
|
||||
try:
|
||||
decoded_last = urllib.parse.unquote(parts[-1])
|
||||
decoded_prev = urllib.parse.unquote(parts[-2])
|
||||
|
||||
# 如果解码后相同,或者最后一个部分是原始文件名(没有编码)
|
||||
if decoded_last == decoded_prev or parts[-1] == decoded_prev:
|
||||
# 保留编码的文件名部分,移除后面的重复部分
|
||||
fileUri = '/'.join(parts[:-1])
|
||||
logger.debug(f"修复了重复文件名的URI: {fileUri}")
|
||||
except Exception as e:
|
||||
logger.debug(f"解码URI部分时出错: {str(e)}")
|
||||
|
||||
data = {
|
||||
"uris": [fileUri],
|
||||
"redirect": redirect,
|
||||
"download": False # 设置为False以获取预览URL
|
||||
}
|
||||
logger.debug(f"获取文件URL,URI: {fileUri}")
|
||||
r = self.request("POST", url, json=data)
|
||||
|
||||
# 转换响应格式
|
||||
# 直接返回API响应,让调用者处理不同的返回格式
|
||||
logger.debug(f"getFileUrl API响应: {r}")
|
||||
|
||||
# 如果是成功的响应格式,确保返回完整的响应对象
|
||||
if isinstance(r, dict):
|
||||
# 兼容不同的成功响应格式
|
||||
if "urls" in r and isinstance(r["urls"], list):
|
||||
# 清理URL中的反引号和多余空格
|
||||
for url_item in r["urls"]:
|
||||
if isinstance(url_item, dict) and "url" in url_item:
|
||||
url_item["url"] = url_item["url"].strip('` ')
|
||||
return r
|
||||
elif r.get("code") == 0 and "data" in r:
|
||||
# Cloudreve标准格式
|
||||
return r
|
||||
elif r.get("code") != 0:
|
||||
# 错误响应
|
||||
return r
|
||||
|
||||
# 如果响应不符合预期格式,返回错误
|
||||
logger.error(f"getFileUrl响应格式不符合预期: {r}")
|
||||
return {"code": -1, "msg": "获取文件URL失败,响应格式错误"}
|
||||
|
||||
def getFileContent(self, fileUri):
|
||||
"""获取文件内容 (Cloudreve V4 API - PUT /file/content)"""
|
||||
url = "/file/content"
|
||||
|
||||
# 确保传入的是正确格式的URI
|
||||
if not fileUri.startswith("cloudreve://"):
|
||||
logger.error(f"无效的URI格式: {fileUri},必须以cloudreve://开头")
|
||||
return {"code": -1, "msg": "无效的URI格式"}
|
||||
|
||||
# 修复文件名重复问题 - 保留URI编码文件名,删除后面的原始文件名
|
||||
if fileUri and '/' in fileUri:
|
||||
import urllib.parse
|
||||
parts = fileUri.split('/')
|
||||
|
||||
# 检查是否存在潜在的文件名重复情况
|
||||
if len(parts) >= 2:
|
||||
# 解码最后一个部分,检查是否与倒数第二个部分解码后相同
|
||||
try:
|
||||
decoded_last = urllib.parse.unquote(parts[-1])
|
||||
decoded_prev = urllib.parse.unquote(parts[-2])
|
||||
|
||||
# 如果解码后相同,或者最后一个部分是原始文件名(没有编码)
|
||||
if decoded_last == decoded_prev or parts[-1] == decoded_prev:
|
||||
# 保留编码的文件名部分,移除后面的重复部分
|
||||
fileUri = '/'.join(parts[:-1])
|
||||
logger.debug(f"getFileContent - 修复了重复文件名的URI: {fileUri}")
|
||||
except Exception as e:
|
||||
logger.debug(f"解码URI部分时出错: {str(e)}")
|
||||
|
||||
# 构建查询参数
|
||||
params = {"uri": fileUri}
|
||||
|
||||
logger.debug(f"获取文件内容,URI: {fileUri}")
|
||||
|
||||
try:
|
||||
# 使用PUT请求获取文件内容
|
||||
r = self.request("PUT", url, params=params)
|
||||
|
||||
# 转换响应格式
|
||||
if isinstance(r, bytes):
|
||||
# 直接返回二进制内容
|
||||
return {"code": 0, "data": r}
|
||||
elif isinstance(r, dict):
|
||||
if r.get("code") == 0:
|
||||
# 确保返回的数据是二进制格式
|
||||
data = r.get("data")
|
||||
if isinstance(data, bytes):
|
||||
return {"code": 0, "data": data}
|
||||
elif isinstance(data, dict) or isinstance(data, list):
|
||||
# 如果data是字典或列表,说明可能是API响应错误,使用URL方式获取
|
||||
logger.warning(f"获取到的数据是{type(data).__name__}类型,不是二进制数据,将尝试使用URL方式")
|
||||
|
||||
# 尝试使用getFileUrl获取临时URL,然后下载内容
|
||||
url_response = self.getFileUrl(fileUri)
|
||||
if url_response.get("code") == 0 and "data" in url_response and "urls" in url_response["data"]:
|
||||
urls = url_response["data"]["urls"]
|
||||
if urls and isinstance(urls[0], dict) and "url" in urls[0]:
|
||||
temp_url = urls[0]["url"]
|
||||
# 使用session获取文件内容
|
||||
session_response = self.returnSession().get(temp_url, stream=True, timeout=(15, 30))
|
||||
session_response.raise_for_status()
|
||||
binary_content = session_response.content
|
||||
logger.info(f"成功从临时URL获取文件内容,大小: {len(binary_content)} 字节")
|
||||
return {"code": 0, "data": binary_content}
|
||||
else:
|
||||
# 尝试将其他类型转换为二进制
|
||||
try:
|
||||
if isinstance(data, str):
|
||||
return {"code": 0, "data": data.encode('utf-8')}
|
||||
else:
|
||||
return {"code": 0, "data": str(data).encode('utf-8')}
|
||||
except Exception:
|
||||
pass
|
||||
# 错误响应
|
||||
return {"code": r.get("code", -1), "msg": r.get("msg", "获取文件内容失败")}
|
||||
else:
|
||||
# 未知响应类型,尝试转换为二进制
|
||||
try:
|
||||
return {"code": 0, "data": str(r).encode('utf-8')}
|
||||
except Exception:
|
||||
return {"code": -1, "msg": f"未知的响应类型: {type(r).__name__}"}
|
||||
except Exception as e:
|
||||
logger.error(f"获取文件内容时发生异常: {str(e)}")
|
||||
return {"code": -1, "msg": f"获取文件内容失败: {str(e)}"}
|
||||
|
||||
def updateFileContent(self, fileUri, content, previous_version=None):
|
||||
"""更新文件内容 (Cloudreve V4 API - PUT /file/content)"""
|
||||
url = "/file/content"
|
||||
|
||||
# 确保传入的是正确格式的URI
|
||||
if not fileUri.startswith("cloudreve://"):
|
||||
logger.error(f"无效的URI格式: {fileUri},必须以cloudreve://开头")
|
||||
return {"code": -1, "msg": "无效的URI格式"}
|
||||
|
||||
# 构建查询参数
|
||||
params = {"uri": fileUri}
|
||||
if previous_version:
|
||||
params["previous"] = previous_version
|
||||
|
||||
# 设置请求头
|
||||
headers = {
|
||||
"Content-Length": str(len(content))
|
||||
}
|
||||
|
||||
logger.debug(f"更新文件内容,URI: {fileUri}")
|
||||
r = self.request("PUT", url, params=params, data=content, headers=headers)
|
||||
|
||||
# 转换响应格式
|
||||
if isinstance(r, dict) and r.get("code") == 0:
|
||||
return {"code": 0, "data": r.get("data", {})}
|
||||
else:
|
||||
error_msg = r.get("msg", r.get("error", "更新文件内容失败"))
|
||||
return {"code": -1, "msg": error_msg}
|
||||
|
||||
def createViewerSession(self, fileUri, viewer_id, preferred_action="view", version=None, parent_uri=None):
|
||||
"""创建查看器会话 (Cloudreve V4 API - PUT /file/viewerSession)"""
|
||||
url = "/file/viewerSession"
|
||||
|
||||
# 确保传入的是正确格式的URI
|
||||
if not fileUri.startswith("cloudreve://"):
|
||||
logger.error(f"无效的URI格式: {fileUri},必须以cloudreve://开头")
|
||||
return {"code": -1, "msg": "无效的URI格式"}
|
||||
|
||||
# 构建请求体
|
||||
data = {
|
||||
"uri": fileUri,
|
||||
"viewer_id": viewer_id,
|
||||
"preferred_action": preferred_action
|
||||
}
|
||||
|
||||
# 添加可选参数
|
||||
if version:
|
||||
data["version"] = version
|
||||
if parent_uri:
|
||||
data["parent_uri"] = parent_uri
|
||||
|
||||
logger.debug(f"创建查看器会话,URI: {fileUri}, viewer_id: {viewer_id}")
|
||||
r = self.request("PUT", url, json=data)
|
||||
|
||||
# 转换响应格式
|
||||
if isinstance(r, dict) and r.get("code") == 0:
|
||||
return {"code": 0, "data": r.get("data", {})}
|
||||
else:
|
||||
error_msg = r.get("msg", r.get("error", "创建查看器会话失败"))
|
||||
return {"code": -1, "msg": error_msg}
|
||||
|
||||
def updateUserNickname(self, nickName):
|
||||
"""更新用户昵称 (Cloudreve V4 API)"""
|
||||
url = "/user/profile"
|
||||
@@ -577,3 +809,7 @@ class MiaoStarsBasicApi:
|
||||
return {"code": 0, "msg": "昵称更新成功"}
|
||||
else:
|
||||
return {"code": -1, "msg": r.get("error", "昵称更新失败")}
|
||||
|
||||
|
||||
# 创建全局实例,方便其他模块直接使用
|
||||
basicApi = MiaoStarsBasicApi()
|
||||
|
||||
Reference in New Issue
Block a user