diff --git a/layout/main.ui b/layout/main.ui index 5645152..d5960bc 100644 --- a/layout/main.ui +++ b/layout/main.ui @@ -101,29 +101,52 @@ - - - - 0 - 50 - - - - - 12 - 75 - true - - - - QPushButton { background-color: #0078D4; color: - white; border-radius: 5px; } QPushButton:hover { background-color: - #106EBE; } QPushButton:pressed { background-color: #005A9E; } - - - 🚀 开始换号 - - + + + + + + 0 + 50 + + + + + 12 + 75 + true + + + + QPushButton { background-color: #0078D4; color: + white; border-radius: 5px; } QPushButton:hover { background-color: + #106EBE; } QPushButton:pressed { background-color: #005A9E; } + + + 🚀 开始换号 + + + + + + + + 90 + 50 + + + + + 90 + 50 + + + + 📊 查询额度(暂时无用) + + + + @@ -140,6 +163,16 @@ + + + + 🔧 应急检修,用户勿点 + + + 30 + + + diff --git a/main.py b/main.py index 02eac5f..7f14c5b 100644 --- a/main.py +++ b/main.py @@ -14,7 +14,7 @@ from contextlib import contextmanager from pathlib import Path from typing import Optional -__VERSION__ = "0.0.2" +__VERSION__ = "0.0.3" from PySide6.QtWidgets import ( QApplication, @@ -32,7 +32,7 @@ from PySide6.QtWidgets import ( QScrollArea, QSplashScreen, ) -from PySide6.QtCore import QThread, Signal, Qt, QTimer +from PySide6.QtCore import QThread, Signal, Qt, QTimer, QMetaObject, Q_ARG, Slot from PySide6.QtUiTools import QUiLoader from PySide6.QtGui import QFont, QPixmap, QColor, QPainter, QPalette, QIcon @@ -196,13 +196,13 @@ def update_vsdb_token(config_dir, new_token, new_email, log_callback): "UPDATE ItemTable SET value = ? WHERE key = ?", (value, key) ) - log_callback(f"✓ 更新了 {key}") + # log_callback(f"✓ 更新了 {key}") else: cursor.execute( "INSERT INTO ItemTable (key, value) VALUES (?, ?)", (key, value) ) - log_callback(f"✓ 插入了 {key}") + # log_callback(f"✓ 插入了 {key}") conn.commit() conn.close() @@ -568,6 +568,12 @@ class ChangeTokenThread(QThread): self.finished_signal.emit(False, "未找到 storage.json 文件") return + # 检查并修复只读属性 + if not os.access(storage_file, os.W_OK): + self.log_signal.emit("🔓 检测到文件只读,正在解除只读属性...") + import stat + storage_file.chmod(storage_file.stat().st_mode | stat.S_IWRITE) + # 读取原文件 self.log_signal.emit("📖 读取配置文件...") with open(storage_file, "r", encoding="utf-8") as f: @@ -780,6 +786,8 @@ class MainWindow(QMainWindow): self.btnClearLog = self.findChild(QPushButton, "btnClearLog") self.btnDonate = self.findChild(QPushButton, "btnDonate") self.btnCheckUpdate = self.findChild(QPushButton, "btnCheckUpdate") + self.btnEmergencyRepair = self.findChild(QPushButton, "btnEmergencyRepair") + self.btnQueryUsage = self.findChild(QPushButton, "btnQueryUsage") # 调试信息 print(f"txtToken: {self.txtToken}") @@ -806,6 +814,10 @@ class MainWindow(QMainWindow): self.btnDonate.clicked.connect(self.on_donate_clicked) if self.btnCheckUpdate: self.btnCheckUpdate.clicked.connect(self.on_check_update_clicked) + if self.btnEmergencyRepair: + self.btnEmergencyRepair.clicked.connect(self.on_emergency_repair_clicked) + if self.btnQueryUsage: + self.btnQueryUsage.clicked.connect(self.on_query_usage_clicked) # 设置版本号显示在状态栏右侧 self.statusBar().addPermanentWidget(QLabel(f"Version: {__VERSION__}")) @@ -1056,7 +1068,87 @@ class MainWindow(QMainWindow): dialog = DonateDialog(self) dialog.exec() - def on_change_finished(self, success, message): + def on_emergency_repair_clicked(self): + """应急检修:下载工具到桌面""" + import urllib.request + import threading + + url = "http://7colud.yunzer.cn/software/db%20browser%20for%20sqlite.zip" + desktop = Path.home() / "Desktop" + save_path = desktop / "db browser for sqlite.zip" + + def download(): + try: + self.log("🔧 正在下载检修工具...") + urllib.request.urlretrieve(url, str(save_path)) + self.log(f"✅ 下载完成,已保存到桌面:{save_path.name}") + except Exception as e: + self.log(f"❌ 下载失败: {e}") + + threading.Thread(target=download, daemon=True).start() + + def on_query_usage_clicked(self): + """查询当前token的额度使用情况""" + import threading + + token = self.txtToken.toPlainText().strip() if self.txtToken else "" + if not token: + QMessageBox.warning(self, "提示", "请先在输入框中填入Token") + return + + def query(): + try: + clean_token = token.strip().replace('"', '').replace("SessionToken=", "") + resp = requests.get( + "https://cursor.com/api/usage", + headers={ + "Cookie": f"SessionToken={clean_token}", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0", + "Accept": "application/json", + }, + timeout=10, + ) + if resp.status_code == 401: + msg = "查询失败:Token 已失效 (401 Unauthorized)。请检查账号是否已退出或被封。" + else: + resp.raise_for_status() + data = resp.json() + + lines = [] + premium = data.get("premiumUsage", {}) + if premium: + used = premium.get("numRequestsTotal", 0) + limit = premium.get("maxRequestUsage", "无限制") + lines.append(f"高级模型 (GPT-4/Claude): 已用 {used} / {limit}") + + for model_key, model_data in data.items(): + if isinstance(model_data, dict) and "numRequestsTotal" in model_data: + used = model_data.get("numRequestsTotal", 0) + limit = model_data.get("maxRequestUsage") + limit_str = str(limit) if limit is not None else "无限制" + lines.append(f"{model_key}: 已用 {used} / {limit_str}") + + msg = "\n".join(lines) if lines else "暂无额度数据,请检查账号状态。" + + QMetaObject.invokeMethod( + self, "_show_usage_result", + Qt.ConnectionType.QueuedConnection, + Q_ARG(str, msg) + ) + except Exception as e: + QMetaObject.invokeMethod( + self, "_show_usage_result", + Qt.ConnectionType.QueuedConnection, + Q_ARG(str, f"网络请求错误:{str(e)}") + ) + + threading.Thread(target=query, daemon=True).start() + + @Slot(str) + def _show_usage_result(self, msg): + QMessageBox.information(self, "额度查询结果", msg) + + if self.btnChange: self.btnChange.setEnabled(True) self.btnChange.setText("🚀 开始换号") @@ -1101,4 +1193,4 @@ def main(): if __name__ == "__main__": - main() + main() \ No newline at end of file