feat(预览): 支持更多文本文件类型预览并增强URL处理
添加对js和html文件类型的文本预览支持,并改进预览组件的URL处理逻辑。现在能自动补全相对路径为完整URL,同时增加详细的日志记录以便调试。
This commit is contained in:
@@ -83,7 +83,7 @@ class FileCard(CardWidget):
|
|||||||
"gif",
|
"gif",
|
||||||
]:
|
]:
|
||||||
signalBus.imagePreviewSignal.emit(self._id)
|
signalBus.imagePreviewSignal.emit(self._id)
|
||||||
if self.fileType == "file" and self.suffix in ["txt", "py", "md"]:
|
if self.fileType == "file" and self.suffix in ["txt", "py", "md", "js", "html"]:
|
||||||
signalBus.txtPreviewSignal.emit(self._id)
|
signalBus.txtPreviewSignal.emit(self._id)
|
||||||
|
|
||||||
def downloadFile(self):
|
def downloadFile(self):
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ from qfluentwidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from app.core import (ImageLoaderThread, TextLoaderThread, UpdateFileContentThread)
|
from app.core import (ImageLoaderThread, TextLoaderThread, UpdateFileContentThread)
|
||||||
|
from app.core.api import miaoStarsBasicApi
|
||||||
from app.core.services.text_speech import LocalSpeechController
|
from app.core.services.text_speech import LocalSpeechController
|
||||||
from app.view.components.empty_card import EmptyCard
|
from app.view.components.empty_card import EmptyCard
|
||||||
|
|
||||||
@@ -38,6 +39,9 @@ def createThumbnail(pixmap, max_size=200):
|
|||||||
class OptimizedPreviewBox(MessageBoxBase):
|
class OptimizedPreviewBox(MessageBoxBase):
|
||||||
def __init__(self, parent=None, url=None):
|
def __init__(self, parent=None, url=None):
|
||||||
super().__init__(parent=parent)
|
super().__init__(parent=parent)
|
||||||
|
# 处理URL,确保它是完整的URL
|
||||||
|
self.url = self._ensure_full_url(url)
|
||||||
|
logger.info(f"初始化图片预览框,URL: {self.url}")
|
||||||
self.widget.setMinimumSize(500, 500)
|
self.widget.setMinimumSize(500, 500)
|
||||||
|
|
||||||
self.original_pixmap = None
|
self.original_pixmap = None
|
||||||
@@ -55,7 +59,7 @@ class OptimizedPreviewBox(MessageBoxBase):
|
|||||||
self.viewLayout.addWidget(self.previewLabel, 0, Qt.AlignmentFlag.AlignCenter)
|
self.viewLayout.addWidget(self.previewLabel, 0, Qt.AlignmentFlag.AlignCenter)
|
||||||
|
|
||||||
# 使用优化的图片加载线程
|
# 使用优化的图片加载线程
|
||||||
self.imageLoaderThread = ImageLoaderThread(url)
|
self.imageLoaderThread = ImageLoaderThread(self.url)
|
||||||
self.imageLoaderThread.imageLoaded.connect(self.setPreviewImg)
|
self.imageLoaderThread.imageLoaded.connect(self.setPreviewImg)
|
||||||
self.imageLoaderThread.errorOccurred.connect(self.handleError)
|
self.imageLoaderThread.errorOccurred.connect(self.handleError)
|
||||||
self.imageLoaderThread.progressUpdated.connect(self.updateProgress)
|
self.imageLoaderThread.progressUpdated.connect(self.updateProgress)
|
||||||
@@ -65,16 +69,37 @@ class OptimizedPreviewBox(MessageBoxBase):
|
|||||||
|
|
||||||
QTimer.singleShot(100, self.startLoading)
|
QTimer.singleShot(100, self.startLoading)
|
||||||
|
|
||||||
|
def _ensure_full_url(self, url):
|
||||||
|
"""确保URL是完整的,添加scheme和base URL(如果缺失)"""
|
||||||
|
if not url:
|
||||||
|
return url
|
||||||
|
|
||||||
|
# 检查URL是否已经包含scheme
|
||||||
|
if url.startswith(('http://', 'https://')):
|
||||||
|
return url
|
||||||
|
|
||||||
|
# 对于相对路径,使用API的base URL构建完整URL
|
||||||
|
# 移除可能的前导斜杠,避免重复
|
||||||
|
path = url.lstrip('/')
|
||||||
|
# 从MiaoStarsBasicApi获取base URL,但只使用到域名部分
|
||||||
|
base_url = miaoStarsBasicApi.basicApi.split('/api/v4')[0]
|
||||||
|
full_url = f"{base_url}/{path}"
|
||||||
|
logger.debug(f"将相对路径转换为完整URL: {url} -> {full_url}")
|
||||||
|
return full_url
|
||||||
|
|
||||||
def startLoading(self):
|
def startLoading(self):
|
||||||
"""开始加载图片"""
|
"""开始加载图片"""
|
||||||
|
logger.info(f"开始加载图片: {self.url}")
|
||||||
self.imageLoaderThread.start()
|
self.imageLoaderThread.start()
|
||||||
|
|
||||||
def updateProgress(self, progress):
|
def updateProgress(self, progress):
|
||||||
"""更新加载进度"""
|
"""更新加载进度"""
|
||||||
|
logger.debug(f"图片加载进度: {progress}%")
|
||||||
self.loadingCard.setText(f"正在加载图片... {progress}%")
|
self.loadingCard.setText(f"正在加载图片... {progress}%")
|
||||||
|
|
||||||
def setPreviewImg(self, img: QPixmap):
|
def setPreviewImg(self, img: QPixmap):
|
||||||
"""设置预览图片"""
|
"""设置预览图片"""
|
||||||
|
logger.info(f"图片加载成功,尺寸: {img.width()}x{img.height()}px")
|
||||||
self.loadingCard.hide()
|
self.loadingCard.hide()
|
||||||
self.original_pixmap = img
|
self.original_pixmap = img
|
||||||
|
|
||||||
@@ -131,6 +156,7 @@ class OptimizedPreviewBox(MessageBoxBase):
|
|||||||
|
|
||||||
def handleError(self, msg):
|
def handleError(self, msg):
|
||||||
"""处理加载错误"""
|
"""处理加载错误"""
|
||||||
|
logger.error(f"图片预览失败: {msg}")
|
||||||
self.loadingCard.error()
|
self.loadingCard.error()
|
||||||
self.previewLabel.hide()
|
self.previewLabel.hide()
|
||||||
|
|
||||||
@@ -141,6 +167,9 @@ class PreviewTextBox(MessageBoxBase):
|
|||||||
|
|
||||||
def __init__(self, parent=None, url=None, _id=None):
|
def __init__(self, parent=None, url=None, _id=None):
|
||||||
super().__init__(parent=parent)
|
super().__init__(parent=parent)
|
||||||
|
# 处理URL,确保它是完整的URL
|
||||||
|
self.url = self._ensure_full_url(url)
|
||||||
|
logger.info(f"初始化文本预览框,URL: {self.url}, 文件ID: {_id}")
|
||||||
self.updateTxtThread = None
|
self.updateTxtThread = None
|
||||||
self.widget.setMinimumSize(600, 400)
|
self.widget.setMinimumSize(600, 400)
|
||||||
self._id = _id
|
self._id = _id
|
||||||
@@ -205,7 +234,7 @@ class PreviewTextBox(MessageBoxBase):
|
|||||||
QTimer.singleShot(100, self.startLoading)
|
QTimer.singleShot(100, self.startLoading)
|
||||||
|
|
||||||
def saveText(self):
|
def saveText(self):
|
||||||
logger.info("保存用户修改")
|
logger.info(f"保存文本文件修改,文件ID: {self._id}")
|
||||||
# 显示进度条并禁用按钮
|
# 显示进度条并禁用按钮
|
||||||
self.saveProgressBar.show()
|
self.saveProgressBar.show()
|
||||||
self.saveButton.setEnabled(False)
|
self.saveButton.setEnabled(False)
|
||||||
@@ -218,6 +247,7 @@ class PreviewTextBox(MessageBoxBase):
|
|||||||
self.saveTextThread.start()
|
self.saveTextThread.start()
|
||||||
|
|
||||||
def _successSave(self):
|
def _successSave(self):
|
||||||
|
logger.info(f"文本文件保存成功,文件ID: {self._id}")
|
||||||
InfoBar.success(
|
InfoBar.success(
|
||||||
"成功",
|
"成功",
|
||||||
"修改保存成功",
|
"修改保存成功",
|
||||||
@@ -232,6 +262,7 @@ class PreviewTextBox(MessageBoxBase):
|
|||||||
QTimer.singleShot(700, self.accept)
|
QTimer.singleShot(700, self.accept)
|
||||||
|
|
||||||
def _errorSave(self, msg):
|
def _errorSave(self, msg):
|
||||||
|
logger.error(f"文本文件保存失败,文件ID: {self._id}, 错误: {msg}")
|
||||||
InfoBar.error(
|
InfoBar.error(
|
||||||
"失败",
|
"失败",
|
||||||
msg,
|
msg,
|
||||||
@@ -250,24 +281,47 @@ class PreviewTextBox(MessageBoxBase):
|
|||||||
if not self.isSpeaking:
|
if not self.isSpeaking:
|
||||||
text = self.textEdit.toPlainText()
|
text = self.textEdit.toPlainText()
|
||||||
if text and len(text.strip()) > 0:
|
if text and len(text.strip()) > 0:
|
||||||
|
logger.info(f"开始文本朗读,文件ID: {self._id}")
|
||||||
self.speech_controller.play_text(text)
|
self.speech_controller.play_text(text)
|
||||||
self.isSpeaking = True
|
self.isSpeaking = True
|
||||||
self.textSpeakButton.setText("暂停朗读")
|
self.textSpeakButton.setText("暂停朗读")
|
||||||
else:
|
else:
|
||||||
|
logger.info(f"暂停文本朗读,文件ID: {self._id}")
|
||||||
self.speech_controller.stop_playback()
|
self.speech_controller.stop_playback()
|
||||||
self.isSpeaking = False
|
self.isSpeaking = False
|
||||||
self.textSpeakButton.setText("朗读文本")
|
self.textSpeakButton.setText("朗读文本")
|
||||||
|
|
||||||
|
def _ensure_full_url(self, url):
|
||||||
|
"""确保URL是完整的,添加scheme和base URL(如果缺失)"""
|
||||||
|
if not url:
|
||||||
|
return url
|
||||||
|
|
||||||
|
# 检查URL是否已经包含scheme
|
||||||
|
if url.startswith(('http://', 'https://')):
|
||||||
|
return url
|
||||||
|
|
||||||
|
# 对于相对路径,使用API的base URL构建完整URL
|
||||||
|
# 移除可能的前导斜杠,避免重复
|
||||||
|
path = url.lstrip('/')
|
||||||
|
# 从MiaoStarsBasicApi获取base URL,但只使用到域名部分
|
||||||
|
base_url = miaoStarsBasicApi.basicApi.split('/api/v4')[0]
|
||||||
|
full_url = f"{base_url}/{path}"
|
||||||
|
logger.debug(f"将相对路径转换为完整URL: {url} -> {full_url}")
|
||||||
|
return full_url
|
||||||
|
|
||||||
def startLoading(self):
|
def startLoading(self):
|
||||||
"""开始加载文本"""
|
"""开始加载文本"""
|
||||||
|
logger.info(f"开始加载文本文件: {self.url}")
|
||||||
self.textLoaderThread.start()
|
self.textLoaderThread.start()
|
||||||
|
|
||||||
def updateProgress(self, progress):
|
def updateProgress(self, progress):
|
||||||
"""更新加载进度"""
|
"""更新加载进度"""
|
||||||
|
logger.debug(f"文本加载进度: {progress}%")
|
||||||
self.loadingCard.setText(f"正在加载文本... {progress}%")
|
self.loadingCard.setText(f"正在加载文本... {progress}%")
|
||||||
|
|
||||||
def setTextContent(self, content):
|
def setTextContent(self, content):
|
||||||
"""设置文本内容"""
|
"""设置文本内容"""
|
||||||
|
logger.info(f"文本文件加载成功,原始内容长度: {len(content)}字符")
|
||||||
self.loadingCard.hide()
|
self.loadingCard.hide()
|
||||||
self.textEdit.show()
|
self.textEdit.show()
|
||||||
self.textSpeakButton.show()
|
self.textSpeakButton.show()
|
||||||
@@ -275,6 +329,7 @@ class PreviewTextBox(MessageBoxBase):
|
|||||||
# 限制显示的内容长度,避免性能问题
|
# 限制显示的内容长度,避免性能问题
|
||||||
max_display_length = 100000 # 最多显示10万个字符
|
max_display_length = 100000 # 最多显示10万个字符
|
||||||
if len(content) > max_display_length:
|
if len(content) > max_display_length:
|
||||||
|
logger.warning(f"文本内容过长,已截断显示,原始长度: {len(content)}字符")
|
||||||
content = (
|
content = (
|
||||||
content[:max_display_length]
|
content[:max_display_length]
|
||||||
+ f"\n\n... (内容过长,已截断前{max_display_length}个字符,完整内容请下载文件查看)"
|
+ f"\n\n... (内容过长,已截断前{max_display_length}个字符,完整内容请下载文件查看)"
|
||||||
@@ -284,6 +339,7 @@ class PreviewTextBox(MessageBoxBase):
|
|||||||
|
|
||||||
def handleError(self, error_msg):
|
def handleError(self, error_msg):
|
||||||
"""处理加载错误"""
|
"""处理加载错误"""
|
||||||
|
logger.error(f"文本预览失败,URL: {self.url}, 错误: {error_msg}")
|
||||||
self.loadingCard.error()
|
self.loadingCard.error()
|
||||||
|
|
||||||
def resizeEvent(self, event):
|
def resizeEvent(self, event):
|
||||||
|
|||||||
Reference in New Issue
Block a user