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