fix lot of thing

This commit is contained in:
2025-11-01 20:14:35 +08:00
parent 39dfb62cbf
commit f006729311
16 changed files with 23303 additions and 3996 deletions

View File

@@ -38,7 +38,7 @@ class AppInfoInterface(QWidget):
mainLayout.setContentsMargins(30, 30, 30, 30)
mainLayout.setAlignment(Qt.AlignmentFlag.AlignTop)
self.titleImageLabel = ImageLabel(":app/images/title.jpg", self)
self.titleImageLabel = ImageLabel(":app/images/title.png", self)
self.titleImageLabel.scaledToHeight(130)
mainLayout.addWidget(self.titleImageLabel, 0, Qt.AlignmentFlag.AlignHCenter)

View File

@@ -95,14 +95,26 @@ class FileCard(CardWidget):
full_path = f"cloudreve://my/{self.fileName}"
else:
# 子目录情况,确保正确拼接路径
# 清理路径,避免重复的斜杠
# 清理路径,避免重复的斜杠和前缀
clean_path = self.filePath.lstrip("/")
# 确保路径中不包含cloudreve://my前缀
clean_path = clean_path.replace("cloudreve://my/", "")
full_path = f"cloudreve://my/{clean_path}/{self.fileName}"
# 确保路径格式正确,没有重复的部分
# 确保路径格式正确,移除重复的前缀
full_path = full_path.replace("cloudreve://my/cloudreve://my", "cloudreve://my")
# 确保没有重复的文件名
if f"/{self.fileName}/{self.fileName}" in full_path:
full_path = full_path.replace(f"/{self.fileName}/{self.fileName}", f"/{self.fileName}")
# 更健壮地处理重复文件名的情况
# 分割路径并去重
path_parts = full_path.split('/')
if len(path_parts) > 1:
# 检查最后一个部分是否是文件名
if path_parts[-1] == self.fileName:
# 检查倒数第二个部分是否也是文件名
if len(path_parts) > 2 and path_parts[-2] == self.fileName:
# 移除重复的文件名部分
path_parts.pop(-2)
full_path = '/'.join(path_parts)
signalBus.addDownloadFileTask.emit(
f"own.{self.suffix}", self.fileName, full_path
@@ -158,7 +170,34 @@ class FileCard(CardWidget):
parent=self.window(),
)
if w.exec():
self.deleteThread = DeleteFileThread(self._id, self.fileType)
# 构建Cloudreve V4 API所需的正确路径格式
if self.filePath == "/":
# 根目录情况
full_path = f"cloudreve://my/{self.fileName}"
else:
# 子目录情况,确保正确拼接路径
# 清理路径,避免重复的斜杠和前缀
clean_path = self.filePath.lstrip("/")
# 确保路径中不包含cloudreve://my前缀
clean_path = clean_path.replace("cloudreve://my/", "")
full_path = f"cloudreve://my/{clean_path}/{self.fileName}"
# 确保路径格式正确,移除重复的前缀
full_path = full_path.replace("cloudreve://my/cloudreve://my", "cloudreve://my")
# 更健壮地处理重复文件名的情况
# 分割路径并去重
path_parts = full_path.split('/')
if len(path_parts) > 1:
# 检查最后一个部分是否是文件名
if path_parts[-1] == self.fileName:
# 检查倒数第二个部分是否也是文件名
if len(path_parts) > 2 and path_parts[-2] == self.fileName:
# 移除重复的文件名部分
path_parts.pop(-2)
full_path = '/'.join(path_parts)
self.deleteThread = DeleteFileThread(full_path, self.fileType)
self.deleteThread.successDelete.connect(self.deleteSuccess)
self.deleteThread.errorDelete.connect(self.deleteError)
self.deleteThread.start()
@@ -200,6 +239,16 @@ class FileCard(CardWidget):
def contextMenuEvent(self, e):
"""重写上下文菜单事件,确保只有右键点击才会触发"""
pass
def mouseDoubleClickEvent(self, event):
"""重写鼠标双击事件,双击文件夹时进入文件夹"""
if self.fileType == "dir":
self.dirClicked()
# 阻止事件继续传播,避免可能的干扰
event.accept()
else:
# 非文件夹时调用父类处理
super().mouseDoubleClickEvent(event)
class ShareFileCard(CardWidget):
@@ -360,3 +409,13 @@ class SharedFolderFileCard(CardWidget):
)
menu.exec(pos, aniType=MenuAnimationType.DROP_DOWN)
def mouseDoubleClickEvent(self, event):
"""重写鼠标双击事件,双击文件夹时进入文件夹"""
if self.fileType == "dir":
self.dirClicked()
# 阻止事件继续传播,避免可能的干扰
event.accept()
else:
# 非文件夹时调用父类处理
super().mouseDoubleClickEvent(event)

View File

@@ -68,8 +68,37 @@ class LinkageSwitchingBase(ScrollArea):
fileDate = data.get("created_at", data.get("date", ""))
fileSize = data.get("size", 0)
# 构建符合Cloudreve V4 API要求的正确URI格式
if filePath == "/" or filePath == "":
# 根目录情况
full_uri = f"cloudreve://my/{fileName}"
else:
# 子目录情况,确保正确拼接路径
# 清理路径,避免重复的斜杠和前缀
clean_path = filePath.lstrip("/")
# 确保路径中不包含cloudreve://my前缀
clean_path = clean_path.replace("cloudreve://my/", "")
full_uri = f"cloudreve://my/{clean_path}/{fileName}"
# 确保路径格式正确,移除重复的前缀
full_uri = full_uri.replace("cloudreve://my/cloudreve://my", "cloudreve://my")
# 更健壮地处理重复文件名的情况
# 分割路径并去重
path_parts = full_uri.split('/')
if len(path_parts) > 1:
# 检查最后一个部分是否是文件名
if path_parts[-1] == fileName:
# 检查倒数第二个部分是否也是文件名
if len(path_parts) > 2 and path_parts[-2] == fileName:
# 移除重复的文件名部分
path_parts.pop(-2)
full_uri = '/'.join(path_parts)
logger.debug(f"构建文件URI: {full_uri}")
fileCard = FileCard(
fileId,
full_uri, # 传递完整的URI而不是文件ID
fileName,
fileType,
filePath,

View File

@@ -181,16 +181,15 @@ class MainWindow(CustomFluentWindow):
# 窗口大小改变时更新背景
def imagePreview(self, _id):
# 使用V4 API进行预览
url = f"/file/preview/{_id}"
self.previewBox = OptimizedPreviewBox(self, url)
# 直接传递文件ID给OptimizedPreviewBox让它内部使用getFileUrl获取临时URL
self.previewBox = OptimizedPreviewBox(self, fileId=_id)
if self.previewBox.exec():
pass
def txtPreview(self, _id):
# 使用V4 API获取内容
url = f"/file/content/{_id}"
self.previewBox = PreviewTextBox(self, url, _id)
# 直接使用fileUri不再构建URL
# _id 应该是 cloudreve:// 格式的URI
self.previewBox = PreviewTextBox(self, "", _id)
if self.previewBox.exec():
pass

View File

@@ -37,11 +37,11 @@ def createThumbnail(pixmap, max_size=200):
class OptimizedPreviewBox(MessageBoxBase):
def __init__(self, parent=None, url=None):
def __init__(self, parent=None, url=None, fileId=None):
super().__init__(parent=parent)
# 处理URL确保它是完整的URL
self.url = self._ensure_full_url(url)
logger.info(f"初始化图片预览框URL: {self.url}")
self.fileId = fileId # 保存文件ID
self.url = url # 暂存原始URL可能需要作为fallback
logger.info(f"初始化图片预览框,文件ID: {self.fileId}, 原始URL: {self.url}")
self.widget.setMinimumSize(500, 500)
self.original_pixmap = None
@@ -58,16 +58,9 @@ class OptimizedPreviewBox(MessageBoxBase):
self.previewLabel.setScaledContents(False) # 重要:禁用自动缩放
self.viewLayout.addWidget(self.previewLabel, 0, Qt.AlignmentFlag.AlignCenter)
# 使用优化的图片加载线程
self.imageLoaderThread = ImageLoaderThread(self.url)
self.imageLoaderThread.imageLoaded.connect(self.setPreviewImg)
self.imageLoaderThread.errorOccurred.connect(self.handleError)
self.imageLoaderThread.progressUpdated.connect(self.updateProgress)
# 延迟启动加载避免阻塞UI初始化
from PyQt6.QtCore import QTimer
QTimer.singleShot(100, self.startLoading)
QTimer.singleShot(100, self._initImageLoading)
def _ensure_full_url(self, url):
"""确保URL是完整的添加scheme和base URL如果缺失"""
@@ -87,10 +80,94 @@ class OptimizedPreviewBox(MessageBoxBase):
logger.debug(f"将相对路径转换为完整URL: {url} -> {full_url}")
return full_url
def startLoading(self):
"""开始加载图片"""
logger.info(f"开始加载图片: {self.url}")
def _initImageLoading(self):
"""初始化图片加载优先使用getFileUrl方法获取临时URL"""
if self.fileId:
logger.info(f"使用文件URI {self.fileId} 获取临时预览URL")
try:
# 使用getFileUrl方法获取临时URL
from app.core.api import miaoStarsBasicApi
response = miaoStarsBasicApi.getFileUrl(self.fileId, redirect=False)
# 详细记录响应内容
logger.debug(f"getFileUrl响应: {response}")
# 处理getFileUrl的返回值支持多种格式
if isinstance(response, str):
# 直接返回URL字符串的情况
preview_url = response.strip('` ')
logger.info(f"成功获取临时预览URL: {preview_url}")
self.url = preview_url
elif isinstance(response, dict):
# 检查是否有code字段表示错误
if response.get('code') == -1:
error_msg = response.get('msg', '获取临时URL失败')
logger.warning(f"获取临时URL失败: {error_msg}将使用原始URL作为fallback")
# 检查是否有urls字段Cloudreve API返回格式
elif 'urls' in response and isinstance(response['urls'], list) and len(response['urls']) > 0:
preview_url = response['urls'][0].get('url', '').strip('` ')
logger.info(f"成功获取临时预览URL: {preview_url}")
self.url = preview_url
# 检查是否有data字段Cloudreve V4 API标准格式
elif 'data' in response:
data = response['data']
if isinstance(data, dict):
# 如果data是字典检查是否包含urls数组
if 'urls' in data and isinstance(data['urls'], list) and len(data['urls']) > 0:
preview_url = data['urls'][0].get('url', '').strip('` ')
logger.info(f"成功从data中获取临时预览URL: {preview_url}")
self.url = preview_url
else:
# 尝试将data直接转为字符串作为fallback
preview_url = str(data).strip('` ')
logger.warning(f"data字段不包含urls数组使用原始data字符串: {preview_url}")
self.url = preview_url
else:
# data不是字典直接转为字符串
preview_url = str(data).strip('` ')
logger.info(f"成功获取临时预览URL: {preview_url}")
self.url = preview_url
else:
error_msg = response.get('msg', '获取临时URL失败')
logger.warning(f"获取临时URL失败: {error_msg}将使用原始URL作为fallback")
if self.url:
self.url = self._ensure_full_url(self.url)
logger.info(f"使用处理后的fallback URL: {self.url}")
else:
logger.error("没有可用的URL无法加载图片")
self.handleError("没有可用的图片URL")
return
except Exception as e:
logger.error(f"获取预览URL时发生异常: {str(e)}")
# 尝试使用备用方式处理
if self.url:
self.url = self._ensure_full_url(self.url)
logger.info(f"异常后使用处理后的fallback URL: {self.url}")
else:
logger.error("异常后没有可用的URL无法加载图片")
self.handleError(f"获取URL异常: {str(e)}")
return
else:
# 如果没有fileId尝试处理原始URL
if self.url:
self.url = self._ensure_full_url(self.url)
logger.info(f"使用处理后的原始URL: {self.url}")
else:
logger.error("没有提供文件ID或URL无法加载图片")
self.handleError("没有提供图片URL")
return
# 创建图片加载线程
self.imageLoaderThread = ImageLoaderThread(self.url)
self.imageLoaderThread.imageLoaded.connect(self.setPreviewImg)
self.imageLoaderThread.errorOccurred.connect(self.handleError)
self.imageLoaderThread.progressUpdated.connect(self.updateProgress)
# 开始加载
self.imageLoaderThread.start()
logger.info(f"开始加载图片: {self.url}")
# startLoading方法已被_initImageLoading替代
def updateProgress(self, progress):
"""更新加载进度"""
@@ -204,8 +281,8 @@ class PreviewTextBox(MessageBoxBase):
self.loadingCard.load()
self.viewLayout.addWidget(self.loadingCard, 0, Qt.AlignmentFlag.AlignCenter)
# 使用文本加载线程
self.textLoaderThread = TextLoaderThread(url)
# 确保在创建线程前使用处理后的URL
self.textLoaderThread = TextLoaderThread(self.url, fileId=_id)
self.textLoaderThread.textLoaded.connect(self.setTextContent)
self.textLoaderThread.errorOccurred.connect(self.handleError)
self.textLoaderThread.progressUpdated.connect(self.updateProgress)
@@ -311,6 +388,41 @@ class PreviewTextBox(MessageBoxBase):
def startLoading(self):
"""开始加载文本"""
# 如果有fileId尝试获取临时URL
if self._id:
logger.info(f"使用文件URI {self._id} 获取临时文本URL")
response = miaoStarsBasicApi.getFileUrl(self._id, redirect=False)
# 处理getFileUrl的返回值支持多种格式
preview_url = None
if isinstance(response, dict):
# 检查是否是Cloudreve V4 API格式 (data.urls)
if response.get('code') == 0 and 'data' in response:
data = response['data']
# 格式1: data.urls数组
if isinstance(data, dict) and 'urls' in data and isinstance(data['urls'], list) and len(data['urls']) > 0:
preview_url = data['urls'][0].get('url', '').strip('` ')
# 格式2: data直接包含URL
elif isinstance(data, str):
preview_url = data.strip('` ')
# 检查是否直接包含urls字段
elif 'urls' in response and isinstance(response['urls'], list) and len(response['urls']) > 0:
preview_url = response['urls'][0].get('url', '').strip('` ')
# 如果成功获取到URL
if preview_url:
self.url = preview_url
logger.info(f"成功获取临时文本URL: {self.url}")
else:
error_msg = response.get('msg', '获取临时URL失败')
logger.warning(f"获取临时URL失败: {error_msg}将使用处理后的原始URL")
# 更新线程的URL和fileId
self.textLoaderThread = TextLoaderThread(self.url, fileId=self._id)
self.textLoaderThread.textLoaded.connect(self.setTextContent)
self.textLoaderThread.errorOccurred.connect(self.handleError)
self.textLoaderThread.progressUpdated.connect(self.updateProgress)
logger.info(f"开始加载文本文件: {self.url}")
self.textLoaderThread.start()