This commit is contained in:
2025-10-29 22:20:21 +08:00
commit 32b3b7b29a
111 changed files with 344425 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,166 @@
import base64
from loguru import logger
from PyQt6.QtCore import Qt, QThread, pyqtSignal
from PyQt6.QtGui import (QColor, QPainter, QPainterPath, QPen, QPixmap)
from ..api import miaoStarsBasicApi
from ...core import cfg, qconfig, userConfig
class CaptchaThread(QThread):
captchaReady = pyqtSignal(QPixmap)
captchaFailed = pyqtSignal(str)
def __init__(self):
super().__init__()
@staticmethod
def _createRoundedPixmap(pixmap, radius=10):
"""创建圆角图片"""
try:
# 获取原始图片尺寸
if pixmap.isNull():
logger.error("原始图片为空,无法创建圆角图片")
return pixmap
size = pixmap.size()
# 创建透明背景的图片
rounded_pixmap = QPixmap(size)
rounded_pixmap.fill(Qt.GlobalColor.transparent)
# 创建对象
painter = QPainter(rounded_pixmap)
painter.setRenderHints(
QPainter.RenderHint.Antialiasing
| QPainter.RenderHint.SmoothPixmapTransform
)
# 创建圆角矩形路径
path = QPainterPath()
path.addRoundedRect(0, 0, size.width(), size.height(), radius, radius)
# 设置裁剪区域
painter.setClipPath(path)
# 绘制原始图片
painter.drawPixmap(0, 0, pixmap)
# 绘制边框
pen = QPen(QColor(200, 200, 200)) # 浅灰色边框
pen.setWidth(1)
painter.setPen(pen)
painter.drawRoundedRect(
0, 0, size.width() - 1, size.height() - 1, radius, radius
)
painter.end()
return rounded_pixmap
except Exception as e:
logger.error(f"创建圆角图片失败:{e}")
return pixmap # 如果出错,返回原始图片
def run(self):
try:
logger.debug("开始获取验证码")
response = miaoStarsBasicApi.getCaptcha()
logger.debug(f"验证码API返回响应: {response}")
if response["code"] == 0:
# 确保data字段存在且为字符串
if "data" in response and isinstance(response["data"], str):
# 分割base64前缀和实际数据
try:
captchaImageData = response["data"].split(",")[1]
logger.debug(f"成功提取base64数据长度: {len(captchaImageData)}")
# 解码base64数据
captchaImage = base64.b64decode(captchaImageData)
logger.debug(f"成功解码base64数据长度: {len(captchaImage)} bytes")
# 加载图片
pixmap = QPixmap()
load_success = pixmap.loadFromData(captchaImage)
if load_success:
logger.debug(f"成功加载图片,尺寸: {pixmap.width()}x{pixmap.height()}")
# 创建圆角图片
pixmap = self._createRoundedPixmap(pixmap, radius=10)
self.captchaReady.emit(pixmap)
else:
logger.error("图片加载失败")
self.captchaFailed.emit("验证码图片加载失败")
self.captchaReady.emit(QPixmap(":app/images/loadFailure.png"))
except (IndexError, ValueError, TypeError) as e:
logger.error(f"验证码数据格式错误: {e}")
self.captchaFailed.emit(f"验证码数据格式错误: {str(e)}")
self.captchaReady.emit(QPixmap(":app/images/loadFailure.png"))
else:
logger.error("验证码响应中缺少有效的data字段")
self.captchaFailed.emit("验证码数据无效")
self.captchaReady.emit(QPixmap(":app/images/loadFailure.png"))
else:
error_msg = response.get("msg", "获取验证码失败")
logger.error(f"获取验证码失败: {error_msg}")
self.captchaFailed.emit(error_msg)
self.captchaReady.emit(QPixmap(":app/images/loadFailure.png"))
except Exception as e:
logger.exception(f"获取验证码过程中发生异常: {e}")
self.captchaFailed.emit(str(e))
self.captchaReady.emit(QPixmap(":app/images/loadFailure.png"))
class LoginThread(QThread):
successLogin = pyqtSignal()
errorLogin = pyqtSignal(str)
def __init__(self, email: str, password: str, captchaCode: str):
super().__init__()
logger.debug(f"初始化许可证服务线程 - 邮箱: {email}")
self.email = email
self.password = password
self.captchaCode = captchaCode
def run(self):
logger.info(f"开始验证用户登录 - 邮箱: {self.email}")
try:
loginResponse = miaoStarsBasicApi.login(
self.email, self.password, self.captchaCode
)
if loginResponse["code"] == 0:
self.successLogin.emit()
qconfig.set(cfg.email, self.email)
qconfig.set(cfg.activationCode, self.password)
userConfig.userData = loginResponse
# 从登录响应中提取token并保存
# 在basicApi的login方法中已经处理了token的设置这里保存到userConfig中以便程序启动时恢复
token = miaoStarsBasicApi.token
if token:
userConfig.setToken(token)
else:
self.errorLogin.emit(loginResponse["msg"])
except Exception as e:
logger.error(f"登录验证过程中发生异常: {e}")
self.errorLogin.emit("系统错误,请稍后重试")
class RegisterThread(QThread):
successRegister = pyqtSignal()
errorRegister = pyqtSignal(str)
def __init__(self, email: str, password: str, captchaCode: str):
super().__init__()
logger.debug(f"初始化许可证服务线程 - 邮箱: {email}")
self.email = email
self.password = password
self.captchaCode = captchaCode
def run(self):
logger.info(f"开始验证用户注册 - 邮箱: {self.email}")
try:
registerRespond = miaoStarsBasicApi.register(
self.email, self.password, self.captchaCode
)
if registerRespond["code"] == 203:
self.successRegister.emit()
else:
logger.error(f"注册失败: {registerRespond['msg']}")
self.errorRegister.emit(registerRespond["msg"])
except Exception as e:
logger.error(f"登录验证过程中发生异常: {e}")
self.errorRegister.emit("系统错误,请稍后重试")

View File

@@ -0,0 +1,246 @@
import os
from urllib.parse import urlparse
import requests
from PyQt6.QtCore import QThread, pyqtSignal
from PyQt6.QtGui import QImage, QPixmap
from app.core import miaoStarsBasicApi
class TextLoaderThread(QThread):
"""文本文件加载线程"""
textLoaded = pyqtSignal(str)
errorOccurred = pyqtSignal(str)
progressUpdated = pyqtSignal(int) # 进度更新信号
def __init__(self, url):
super().__init__()
self.url = url
def run(self):
"""线程执行函数"""
try:
# 1. 设置网络请求参数 - 优化连接参数
session = requests.Session()
adapter = requests.adapters.HTTPAdapter(
pool_connections=20,
pool_maxsize=20,
max_retries=5, # 增加重试次数
pool_block=False,
)
session.mount("http://", adapter)
session.mount("https://", adapter)
# 2. 增加超时时间并添加重试机制
response = miaoStarsBasicApi.returnSession().get(
self.url,
stream=True,
timeout=(15, 30), # 增加超时时间连接15秒读取30秒
)
response.raise_for_status()
# 3. 获取文件大小(如果服务器支持)
total_size = int(response.headers.get("content-length", 0))
downloaded_size = 0
# 4. 分块读取并处理 - 使用二进制读取提高速度
content_chunks = []
for chunk in response.iter_content(chunk_size=16384): # 增大块大小
if chunk:
content_chunks.append(chunk)
downloaded_size += len(chunk)
# 更新进度(如果知道总大小)
if total_size > 0:
progress = int((downloaded_size / total_size) * 100)
self.progressUpdated.emit(progress)
# 5. 合并内容并解码
binary_content = b"".join(content_chunks)
if not binary_content:
self.errorOccurred.emit("下载内容为空")
return
# 6. 智能编码检测和解码
text_content = self._decode_content(binary_content)
# 7. 发射加载完成的信号
self.textLoaded.emit(text_content)
except requests.exceptions.Timeout:
self.errorOccurred.emit("请求超时,请检查网络连接或尝试重新加载")
except requests.exceptions.ConnectionError:
self.errorOccurred.emit("网络连接错误,请检查网络设置")
except requests.exceptions.RequestException as e:
self.errorOccurred.emit(f"网络请求错误: {str(e)}")
except Exception as e:
self.errorOccurred.emit(f"文本处理错误: {str(e)}")
def _decode_content(self, binary_content):
"""智能解码二进制内容"""
# 优先尝试UTF-8
encodings = ["utf-8", "gbk", "gb2312", "latin-1", "iso-8859-1", "cp1252"]
for encoding in encodings:
try:
return binary_content.decode(encoding)
except UnicodeDecodeError:
continue
# 如果所有编码都失败,使用替换错误处理
try:
return binary_content.decode("utf-8", errors="replace")
except:
# 最后尝试忽略错误
return binary_content.decode("utf-8", errors="ignore")
def cancel(self):
"""取消下载"""
if self.isRunning():
self.terminate()
self.wait(1000) # 等待线程结束
class ImageLoaderThread(QThread):
"""优化的图片加载线程"""
imageLoaded = pyqtSignal(QPixmap)
errorOccurred = pyqtSignal(str)
progressUpdated = pyqtSignal(int) # 进度更新信号
def __init__(
self, url, cache_dir="image_cache", max_cache_size=50 * 1024 * 1024
): # 50MB缓存
super().__init__()
self.url = url
self.cache_dir = cache_dir
self.max_cache_size = max_cache_size
self._setup_cache()
def _setup_cache(self):
"""设置图片缓存目录"""
if not os.path.exists(self.cache_dir):
os.makedirs(self.cache_dir)
def _get_cache_filename(self):
"""生成缓存文件名"""
parsed_url = urlparse(self.url)
filename = os.path.basename(parsed_url.path) or "image"
# 添加URL哈希避免重名
import hashlib
url_hash = hashlib.md5(self.url.encode()).hexdigest()[:8]
return f"{url_hash}_{filename}"
def _get_cached_image(self):
"""获取缓存图片"""
cache_file = os.path.join(self.cache_dir, self._get_cache_filename())
if os.path.exists(cache_file):
try:
pixmap = QPixmap(cache_file)
if not pixmap.isNull():
return pixmap
except Exception:
pass
return None
def _save_to_cache(self, pixmap):
"""保存图片到缓存"""
try:
cache_file = os.path.join(self.cache_dir, self._get_cache_filename())
pixmap.save(cache_file, "JPG", 80) # 压缩质量80%
self._cleanup_cache() # 清理过期缓存
except Exception:
pass
def _cleanup_cache(self):
"""清理过期的缓存文件"""
# noinspection PyBroadException
try:
files = []
for f in os.listdir(self.cache_dir):
filepath = os.path.join(self.cache_dir, f)
if os.path.isfile(filepath):
files.append((filepath, os.path.getmtime(filepath)))
# 按修改时间排序
files.sort(key=lambda x: x[1])
# 计算总大小
total_size = sum(os.path.getsize(f[0]) for f in files)
# 如果超过最大缓存大小,删除最旧的文件
while total_size > self.max_cache_size and files:
oldest_file = files.pop(0)
total_size -= os.path.getsize(oldest_file[0])
os.remove(oldest_file[0])
except Exception:
pass
def run(self):
"""线程执行函数"""
try:
# 1. 首先检查缓存
cached_pixmap = self._get_cached_image()
if cached_pixmap:
self.imageLoaded.emit(cached_pixmap)
return
# 2. 设置更短的超时时间
session = requests.Session()
adapter = requests.adapters.HTTPAdapter(
pool_connections=10, pool_maxsize=10, max_retries=5 # 重试2次
)
session.mount("http://", adapter)
session.mount("https://", adapter)
# 3. 流式下载,支持进度显示
response = miaoStarsBasicApi.returnSession().get(
self.url, stream=True, timeout=(20, 30) # 连接超时5秒读取超时10秒
)
response.raise_for_status()
# 获取文件大小(如果服务器支持)
total_size = int(response.headers.get("content-length", 0))
downloaded_size = 0
# 4. 分块读取并处理
image_data = b""
for chunk in response.iter_content(chunk_size=8192):
if chunk:
image_data += chunk
downloaded_size += len(chunk)
# 更新进度(如果知道总大小)
if total_size > 0:
progress = int((downloaded_size / total_size) * 100)
self.progressUpdated.emit(progress)
# 5. 从数据创建QImage比QPixmap更快
image = QImage()
image.loadFromData(image_data)
if image.isNull():
raise Exception("无法加载图片数据")
# 6. 转换为QPixmap
pixmap = QPixmap.fromImage(image)
# 7. 保存到缓存
self._save_to_cache(pixmap)
# 发射加载完成的信号
self.imageLoaded.emit(pixmap)
except requests.exceptions.Timeout:
self.errorOccurred.emit("请求超时,请检查网络连接")
except requests.exceptions.ConnectionError:
self.errorOccurred.emit("网络连接错误")
except requests.exceptions.RequestException as e:
self.errorOccurred.emit(f"网络请求错误: {str(e)}")
except Exception as e:
self.errorOccurred.emit(f"图片处理错误: {str(e)}")

View File

@@ -0,0 +1,287 @@
# coding: utf-8
import os
import subprocess
import tempfile
from loguru import logger
from PyQt6.QtCore import QEventLoop, QObject, QThread, pyqtSignal
from PyQt6.QtCore import QUrl
from PyQt6.QtMultimedia import QAudioOutput, QMediaPlayer
class LocalTextToSpeechThread(QThread):
"""本地文本转语音播放线程 - Windows优化版"""
# 信号定义
playback_started = pyqtSignal() # 播放开始
playback_finished = pyqtSignal() # 播放完成
playback_error = pyqtSignal(str) # 播放错误
progress_updated = pyqtSignal(int) # 播放进度更新
synthesis_completed = pyqtSignal(str) # 语音合成完成(返回文件路径)
def __init__(self, text, parent=None):
super().__init__(parent)
self.text = text
self.audio_file_path = None
self.media_player = None
self.audio_output = None
self._stop_requested = False
def run(self):
"""线程执行函数"""
try:
# 1. 将文本转换为语音文件
self.audio_file_path = self._text_to_speech(self.text)
if not self.audio_file_path or self._stop_requested:
return
# 发射合成完成信号
self.synthesis_completed.emit(self.audio_file_path)
# 2. 播放语音
self._play_audio(self.audio_file_path)
except Exception as e:
self.playback_error.emit(f"语音播放错误: {str(e)}")
def _text_to_speech(self, text):
"""使用本地TTS引擎将文本转换为语音文件"""
try:
# 检查文本长度
if not text or len(text.strip()) == 0:
self.playback_error.emit("文本内容为空")
return None
# 限制文本长度,避免合成时间过长
max_length = 1000
if len(text) > max_length:
text = text[:max_length] + "。文本过长,已截断。"
self.playback_error.emit(f"文本过长,已截断前{max_length}个字符")
# 优先使用pyttsx3效率最高
try:
import pyttsx3
return self._pyttsx3_tts(text)
except ImportError:
# 备用方案使用Windows内置TTS
return self._windows_tts(text)
except Exception as e:
self.playback_error.emit(f"语音合成失败: {str(e)}")
return None
def _pyttsx3_tts(self, text):
"""使用pyttsx3合成语音 - 优化版"""
try:
import pyttsx3
# 初始化TTS引擎
engine = pyttsx3.init()
# 设置语音属性 - 提高效率
engine.setProperty('rate', 200) # 提高语速
engine.setProperty('volume', 0.9) # 提高音量
# 创建临时文件保存音频
with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as temp_file:
temp_path = temp_file.name
# 保存语音到文件
engine.save_to_file(text, temp_path)
engine.runAndWait()
# 检查文件是否成功创建
if os.path.exists(temp_path) and os.path.getsize(temp_path) > 0:
return temp_path
else:
logger.error("语音文件生成失败")
except Exception as e:
# 如果pyttsx3失败尝试Windows TTS
return self._windows_tts(text)
def _windows_tts(self, text):
"""Windows系统TTS - 优化版"""
try:
# 方法1: 使用PowerShell命令 - 最可靠
return self._powershell_tts(text)
except Exception as e:
logger.error(f"Windows TTS失败: {str(e)}")
def _powershell_tts(self, text):
"""使用PowerShell合成语音 - 优化版"""
try:
# 创建临时文件
with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as temp_file:
temp_path = temp_file.name
# 转义文本中的特殊字符
escaped_text = text.replace('"', '`"').replace("'", "`'")
# 使用PowerShell的SpeechSynthesizer - 简化命令
ps_script = f"""
Add-Type -AssemblyName System.Speech
$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer
$speak.SetOutputToWaveFile("{temp_path}")
$speak.Speak("{escaped_text}")
$speak.Dispose()
"""
# 使用更高效的方式执行PowerShell
process = subprocess.Popen(
["powershell", "-Command", ps_script],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True
)
# 等待进程完成,设置超时
try:
stdout, stderr = process.communicate(timeout=30)
if process.returncode != 0:
logger.error(f"PowerShell执行失败: {stderr.decode('gbk', errors='ignore')}")
except subprocess.TimeoutExpired:
process.kill()
logger.error(f"PowerShell超时")
if os.path.exists(temp_path) and os.path.getsize(temp_path) > 0:
return temp_path
else:
logger.error("语音文件生成失败")
except Exception as e:
# raise Exception(f"PowerShell TTS失败: {str(e)}")
logger.error(f"PowerShell TTS失败{e}")
def _play_audio(self, file_path):
"""播放音频文件 - 优化版"""
if self._stop_requested:
return
try:
# 创建媒体播放器和音频输出
self.media_player = QMediaPlayer()
self.audio_output = QAudioOutput()
self.media_player.setAudioOutput(self.audio_output)
# 设置音量
self.audio_output.setVolume(1.0)
# 连接信号
self.media_player.playbackStateChanged.connect(self._on_playback_state_changed)
self.media_player.positionChanged.connect(self._on_position_changed)
self.media_player.durationChanged.connect(self._on_duration_changed)
self.media_player.errorOccurred.connect(self._on_player_error)
# 设置媒体源并开始播放
self.media_player.setSource(QUrl.fromLocalFile(file_path))
self.media_player.play()
# 使用事件循环等待播放完成
loop = QEventLoop()
self.media_player.playbackStateChanged.connect(
lambda state: loop.quit() if state == QMediaPlayer.PlaybackState.StoppedState else None
)
loop.exec()
except Exception as e:
raise Exception(f"音频播放失败: {str(e)}")
finally:
# 清理临时文件
if file_path and os.path.exists(file_path):
try:
os.unlink(file_path)
except:
pass
def _on_playback_state_changed(self, state):
"""处理播放状态变化"""
from PyQt6.QtMultimedia import QMediaPlayer
if state == QMediaPlayer.PlaybackState.StoppedState:
self.playback_finished.emit()
def _on_position_changed(self, position):
"""处理播放位置变化"""
if (self.media_player and
self.media_player.duration() > 0):
progress = int((position / self.media_player.duration()) * 100)
self.progress_updated.emit(progress)
def _on_duration_changed(self, duration):
"""处理时长变化"""
if duration > 0:
self.playback_started.emit()
def _on_player_error(self, error, error_string):
"""处理播放器错误"""
self.playback_error.emit(f"播放器错误: {error_string}")
def stop_playback(self):
"""停止播放"""
self._stop_requested = True
if self.media_player and self.media_player.playbackState() != QMediaPlayer.PlaybackState.StoppedState:
self.media_player.stop()
# 清理临时文件
if self.audio_file_path and os.path.exists(self.audio_file_path):
try:
os.unlink(self.audio_file_path)
except:
pass
class LocalSpeechController(QObject):
"""本地语音播放控制器"""
def __init__(self, parent=None):
super().__init__(parent)
self.speech_thread = None
def play_text(self, text):
"""播放文本语音"""
# 停止当前播放
self.stop_playback()
# 创建新的语音线程
self.speech_thread = LocalTextToSpeechThread(text)
# 连接信号
self.speech_thread.playback_started.connect(self._on_playback_started)
self.speech_thread.playback_finished.connect(self._on_playback_finished)
self.speech_thread.playback_error.connect(self._on_playback_error)
self.speech_thread.progress_updated.connect(self._on_progress_updated)
self.speech_thread.synthesis_completed.connect(self._on_synthesis_completed)
# 开始播放
self.speech_thread.start()
def stop_playback(self):
"""停止播放"""
if self.speech_thread and self.speech_thread.isRunning():
self.speech_thread.stop_playback()
self.speech_thread.wait(1000) # 等待线程结束最多1秒
def is_playing(self):
"""检查是否正在播放"""
return self.speech_thread and self.speech_thread.isRunning()
def _on_playback_started(self):
"""处理播放开始"""
logger.info("语音播放开始")
def _on_playback_finished(self):
"""处理播放完成"""
logger.success("语音播放完成")
def _on_playback_error(self, error_msg):
"""处理播放错误"""
logger.warning(f"语音播放错误: {error_msg}")
def _on_progress_updated(self, progress):
...
def _on_synthesis_completed(self, file_path):
"""处理语音合成完成"""
logger.info(f"语音合成完成,文件路径: {file_path}")

View File

@@ -0,0 +1,199 @@
from loguru import logger
from PyQt6.QtCore import QThread, pyqtSignal
from PyQt6.QtGui import QPixmap
from ..api import miaoStarsBasicApi
class UserNickNameUpdateThread(QThread):
successUpdate = pyqtSignal()
errorUpdate = pyqtSignal(str)
def __init__(self, nickName: str):
super().__init__()
logger.debug(f"初始化用户昵称服务线程 - 昵称: {nickName}")
self.nickName = nickName
def run(self):
logger.info(f"开始更新用户昵称 - 昵称: {self.nickName}")
try:
response = miaoStarsBasicApi.updateUserNickname(self.nickName)
print(response)
if response["code"] == 0:
self.successUpdate.emit()
else:
logger.error("更新失败:", response["msg"])
self.errorUpdate.emit(response["msg"])
except Exception as e:
logger.error(f"更新用户昵称过程中发生异常: {e}")
self.errorUpdate.emit("系统错误,请稍后重试")
class UserAvatarUpdateThread(QThread):
successUpdate = pyqtSignal()
errorUpdate = pyqtSignal(str)
def __init__(self, avatarPath: str):
super().__init__()
logger.debug(f"初始化用户头像服务线程 - 头像路径: {avatarPath}")
self.avatarPath = avatarPath
def run(self):
logger.info(f"开始更新用户头像 - 头像路径: {self.avatarPath}")
try:
response = miaoStarsBasicApi.updateUserAvatar(self.avatarPath)
if response["code"] == 0:
logger.info("头像更新成功")
self.successUpdate.emit()
else:
logger.error(f"更新失败,错误信息: {response['msg']}")
self.errorUpdate.emit(f"更新失败: {response['msg']}")
except Exception as e:
logger.error(f"更新用户头像过程中发生异常: {e}")
self.errorUpdate.emit("系统错误,请稍后重试")
class GetUserAvatarThread(QThread):
avatarPixmap = pyqtSignal(QPixmap)
def __init__(self, size: str):
super().__init__()
logger.debug(f"初始化获取用户头像服务线程 - 头像尺寸: {size}")
self.size = size
def run(self):
logger.info(f"开始获取用户头像 - 头像尺寸: {self.size}")
try:
response = miaoStarsBasicApi.getUserAvatar(self.size)
self.avatarPixmap.emit(response)
except Exception as e:
logger.error(f"获取用户头像过程中发生异常: {e}")
self.avatarPixmap.emit(QPixmap(":app/images/logo.png"))
class GetPackThread(QThread):
storageDictSignal = pyqtSignal(dict)
def __init__(self):
super().__init__()
def run(self):
logger.info("开始请求用户配额包")
try:
response = miaoStarsBasicApi.getUserPack()
self.storageDictSignal.emit(response)
except Exception as e:
logger.error(f"获取用户配额包过程中发生异常: {e}")
self.storageDictSignal.emit(
{
"code": 0,
"data": {
"base": 0,
"pack": 0,
"used": 0,
"total": 0,
"packs": [],
},
"msg": "",
}
)
class GetPoliciesThread(QThread):
"""获取策略列表线程"""
successGetSignal = pyqtSignal(list)
errorSignal = pyqtSignal(str)
def __init__(self):
super().__init__()
def run(self):
try:
response = miaoStarsBasicApi.getPolicy()
if response["code"] == 0:
self.successGetSignal.emit(response["data"])
else:
self.errorSignal.emit(f"API返回错误: {response.get('msg')}")
except Exception as e:
self.errorSignal.emit(f"获取策略列表失败: {str(e)}")
class ChangePolicyThread(QThread):
"""更改策略线程"""
successChangedSignal = pyqtSignal()
errorSignal = pyqtSignal(str)
def __init__(self, path, policy_id):
super().__init__()
self.path = path
self.policy_id = policy_id
def run(self):
try:
response = miaoStarsBasicApi.changePolicy(self.path, self.policy_id)
if response["code"] == 0:
self.successChangedSignal.emit()
else:
self.errorSignal.emit(
f"更改策略失败: {response.get('msg', '未知错误')}"
)
except Exception as e:
self.errorSignal.emit(f"更改策略请求失败: {str(e)}")
class DeleteTagThread(QThread):
"""删除标签线程"""
successDeleteSignal = pyqtSignal()
errorSignal = pyqtSignal(str)
def __init__(self, tagId):
super().__init__()
self.tagId = tagId
def run(self):
try:
response = miaoStarsBasicApi.deleteTag(self.tagId)
if response["code"] == 0:
self.successDeleteSignal.emit()
logger.info(f"删除标签成功: {self.tagId}")
else:
logger.error(f"删除标签失败: {response.get('msg')}")
self.errorSignal.emit(f"删除标签失败: {response.get('msg')}")
except Exception as e:
self.errorSignal.emit(f"{str(e)}")
logger.error(f"删除标签请求失败: {str(e)}")
class AddTagThread(QThread):
"""添加标签的线程类"""
successSignal = pyqtSignal(str, dict) # 标签名称, 响应数据
errorSignal = pyqtSignal(str, str) # 标签名称, 错误信息
def __init__(self, name, expression, parent=None):
super().__init__(parent)
self.name = name
self.expression = expression
def run(self):
"""线程执行的主方法"""
try:
response = miaoStarsBasicApi.addTag(self.name, self.expression)
if response["code"] == 0:
logger.info(f"添加标签成功: {self.name}")
self.successSignal.emit(self.name, response)
else:
logger.error(f"添加标签失败: {self.name} - {response.get('msg')}")
self.errorSignal.emit(self.name, response.get("msg"))
except Exception as e:
logger.error(f"添加标签异常: {self.name} - {str(e)}")
self.errorSignal.emit(self.name, str(e))