'update'
This commit is contained in:
parent
1b54447ccb
commit
0011b1b558
Binary file not shown.
@ -850,19 +850,47 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblSilentToken">
|
||||
<property name="text">
|
||||
<string>请输入新 Token (兼容纯 token / Cookie 串):</string>
|
||||
<widget class="QLineEdit" name="txtSilentToken">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>在此输入 ID,例如:11</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="txtSilentToken">
|
||||
<property name="placeholderText">
|
||||
<string>在此粘贴 Token,格式支持 Workos... 或原始 token</string>
|
||||
<widget class="QLabel" name="lblCurrentDetectId">
|
||||
<property name="text">
|
||||
<string>当前检测 ID:-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="lblCurrentDetectToken">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="html">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">当前 Token:-</p></body></html></string>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_silentButtons">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnSilentChange">
|
||||
<property name="minimumSize">
|
||||
@ -876,6 +904,34 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnSilentUnavailable">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>42</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>不可用</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnSilentCopyToken">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>42</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>复制 Token</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
248
main.py
248
main.py
@ -892,6 +892,118 @@ class OneClickRenewalThread(QThread):
|
||||
self.finished_signal.emit(False, str(e), "")
|
||||
|
||||
|
||||
class SilentDetectThread(QThread):
|
||||
log_signal = Signal(str)
|
||||
finished_signal = Signal(bool, str, int) # (success, message/token, next_id)
|
||||
|
||||
def __init__(self, target_id):
|
||||
super().__init__()
|
||||
self.target_id = target_id
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
self.log_signal.emit(f"🔄 正在从服务端获取 ID={self.target_id} 的 Token...")
|
||||
url = f"https://api.yunzer.cn/api/cursor/token/peek?id={self.target_id}&data_type=tk"
|
||||
|
||||
response_data = None
|
||||
try:
|
||||
response = requests.get(url, timeout=15)
|
||||
response.raise_for_status()
|
||||
response_data = response.json()
|
||||
except Exception:
|
||||
# 备用连接(直连,不走系统代理)
|
||||
with requests.Session() as session:
|
||||
session.trust_env = False
|
||||
response = session.get(url, timeout=15)
|
||||
response.raise_for_status()
|
||||
response_data = response.json()
|
||||
|
||||
if not response_data or response_data.get("code") != 200:
|
||||
msg = response_data.get("msg") or "获取失败"
|
||||
self.finished_signal.emit(False, f"获取 Token 失败: {msg}", 0)
|
||||
return
|
||||
|
||||
data_obj = response_data.get("data") or {}
|
||||
new_token = data_obj.get("token")
|
||||
self.new_token = new_token
|
||||
next_id = data_obj.get("next_id") or (int(self.target_id) + 1)
|
||||
|
||||
if not new_token:
|
||||
self.finished_signal.emit(False, "服务端返回的 Token 为空!", 0)
|
||||
return
|
||||
|
||||
self.log_signal.emit("✅ 成功提取 Token!正在执行本地更换...")
|
||||
new_email = generate_random_email()
|
||||
|
||||
config_dir = get_cursor_config_path()
|
||||
if not config_dir.exists():
|
||||
self.finished_signal.emit(False, "未找到Cursor配置目录", 0)
|
||||
return
|
||||
|
||||
# 读取原 storage.json 并更新
|
||||
storage_file = config_dir / "storage.json"
|
||||
if not storage_file.exists():
|
||||
self.finished_signal.emit(False, "未找到 storage.json 文件", 0)
|
||||
return
|
||||
|
||||
if not os.access(storage_file, os.W_OK):
|
||||
import stat
|
||||
storage_file.chmod(storage_file.stat().st_mode | stat.S_IWRITE)
|
||||
|
||||
with open(storage_file, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
data = json.loads(content) if content.strip() else {}
|
||||
|
||||
old_email = (
|
||||
data.get("cursorAuth", {}).get("cachedEmail")
|
||||
or data.get("cursorAccount", {}).get("email")
|
||||
or ""
|
||||
)
|
||||
if old_email:
|
||||
new_email = str(old_email).strip()
|
||||
|
||||
# 修改 storage.json 的数据
|
||||
if "cursorAuth" not in data:
|
||||
data["cursorAuth"] = {}
|
||||
data["cursorAuth"]["accessToken"] = new_token
|
||||
data["cursorAuth"]["refreshToken"] = new_token
|
||||
data["cursorAuth"]["cachedEmail"] = new_email
|
||||
data["cursorAuth"]["cachedSignUpType"] = data["cursorAuth"].get("cachedSignUpType", "Auth_0")
|
||||
data["cursorAuth"]["onboardingDate"] = datetime.utcnow().isoformat(timespec="milliseconds") + "Z"
|
||||
data["cursorAuth"]["plan"] = "pro"
|
||||
data["cursorAuth"]["stripeMembershipType"] = "pro"
|
||||
data["cursorAuth"]["membershipType"] = "pro"
|
||||
|
||||
if "cursorAccount" not in data:
|
||||
data["cursorAccount"] = {}
|
||||
data["cursorAccount"]["token"] = new_token
|
||||
data["cursorAccount"]["email"] = new_email
|
||||
data["cursorAccount"]["plan"] = "pro"
|
||||
|
||||
# 刷新机器 ID
|
||||
new_machine_id = generate_machine_id()
|
||||
data["telemetryMacMachineId"] = new_machine_id
|
||||
data["telemetryDevDeviceId"] = new_machine_id
|
||||
data["workspaceIdentifier"] = new_machine_id
|
||||
data["membershipType"] = "pro"
|
||||
|
||||
with open(storage_file, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||
|
||||
# 更新 Cursor 数据库 state.vscdb
|
||||
self.log_signal.emit("📦 更新 Cursor 数据库...")
|
||||
db_ok = update_vsdb_token(config_dir, new_token, new_email, self.log_signal.emit)
|
||||
if not db_ok:
|
||||
self.finished_signal.emit(False, "更新 Cursor 数据库失败,可能是 Cursor 进程未完全关闭,请在任务管理器中结束所有 Cursor 进程,或尝试以管理员身份运行本软件。", 0)
|
||||
return
|
||||
|
||||
self.log_signal.emit(f"✅ 无感换号完成!下一条 ID 推荐为: {next_id}")
|
||||
self.finished_signal.emit(True, "检测换号成功!", next_id)
|
||||
|
||||
except Exception as e:
|
||||
self.finished_signal.emit(False, f"发生异常: {str(e)}", 0)
|
||||
|
||||
|
||||
def get_device_info() -> str:
|
||||
"""获取 CPU/RAM/磁盘等设备信息"""
|
||||
try:
|
||||
@ -1270,6 +1382,43 @@ class MainWindow(QMainWindow):
|
||||
self.actionUsageGuide = self.findChild(QAction, "actionUsageGuide")
|
||||
self.actionDonate = self.findChild(QAction, "actionDonate")
|
||||
self.actionAbout = self.findChild(QAction, "actionAbout")
|
||||
|
||||
# 无感检测相关组件
|
||||
self.txtSilentToken = self.findChild(QLineEdit, "txtSilentToken")
|
||||
self.btnSilentChange = self.findChild(QPushButton, "btnSilentChange")
|
||||
self.btnSilentUnavailable = self.findChild(QPushButton, "btnSilentUnavailable")
|
||||
self.btnSilentCopyToken = self.findChild(QPushButton, "btnSilentCopyToken")
|
||||
self.lblSilentToken = self.findChild(QLabel, "lblSilentToken")
|
||||
self.lblCurrentDetectId = self.findChild(QLabel, "lblCurrentDetectId")
|
||||
self.lblCurrentDetectToken = self.findChild(QTextEdit, "lblCurrentDetectToken")
|
||||
self.groupHelpSilentDetect = self.findChild(QGroupBox, "groupHelpSilentDetect")
|
||||
self.lblHelpSilentDetectDesc = self.findChild(QLabel, "lblHelpSilentDetectDesc")
|
||||
|
||||
# 调整无感检测界面的提示词,使其适配以 ID 检测换号的新功能
|
||||
if self.lblSilentToken:
|
||||
self.lblSilentToken.setText("请输入要检测的号池 ID(如 11):")
|
||||
if self.txtSilentToken:
|
||||
self.txtSilentToken.setPlaceholderText("在此输入数字 ID,例如:11")
|
||||
self.txtSilentToken.setMaximumWidth(150)
|
||||
if self.btnSilentChange:
|
||||
self.btnSilentChange.setText("无感换号")
|
||||
if self.btnSilentUnavailable:
|
||||
self.btnSilentUnavailable.setText("不可用")
|
||||
if self.btnSilentCopyToken:
|
||||
self.btnSilentCopyToken.setText("复制 Token")
|
||||
if self.lblCurrentDetectId:
|
||||
self.lblCurrentDetectId.setText("当前检测 ID:-")
|
||||
if self.lblCurrentDetectToken:
|
||||
self.lblCurrentDetectToken.setText("当前 Token:-")
|
||||
if self.groupHelpSilentDetect:
|
||||
self.groupHelpSilentDetect.setTitle("帮助-无感检测(ID 换号版)")
|
||||
if self.lblHelpSilentDetectDesc:
|
||||
self.lblHelpSilentDetectDesc.setText("无感检测:输入服务器号池的记录 ID,点击检测将自动从服务器拉取对应 Token,为您执行本地换号,并自动打开 Cursor,方便快速测试。")
|
||||
|
||||
# 初始化当前检测状态变量
|
||||
self.current_detect_id = ""
|
||||
self.current_detect_token = ""
|
||||
|
||||
self._load_cached_logs_to_ui()
|
||||
|
||||
# 调试信息
|
||||
@ -1337,6 +1486,12 @@ class MainWindow(QMainWindow):
|
||||
self.btnRefreshMemberStatus.clicked.connect(lambda: self.on_refresh_member_status_clicked(show_popup=True))
|
||||
if self.btnOneClickRenewal:
|
||||
self.btnOneClickRenewal.clicked.connect(self.on_one_click_renewal_clicked)
|
||||
if self.btnSilentChange:
|
||||
self.btnSilentChange.clicked.connect(self.on_silent_detect_clicked)
|
||||
if self.btnSilentUnavailable:
|
||||
self.btnSilentUnavailable.clicked.connect(self.on_silent_unavailable_clicked)
|
||||
if self.btnSilentCopyToken:
|
||||
self.btnSilentCopyToken.clicked.connect(self.on_silent_copy_token_clicked)
|
||||
if self.actionExit:
|
||||
self.actionExit.triggered.connect(self.close)
|
||||
if self.actionEmergencyRepair:
|
||||
@ -2468,6 +2623,99 @@ class MainWindow(QMainWindow):
|
||||
else:
|
||||
QMessageBox.critical(self, "失败", message)
|
||||
|
||||
@Slot(bool, str, int)
|
||||
def on_silent_detect_finished(self, success, message, next_id):
|
||||
if self.btnSilentChange:
|
||||
self.btnSilentChange.setEnabled(True)
|
||||
self.btnSilentChange.setText("无感换号")
|
||||
|
||||
if success:
|
||||
# 记录当前成功检测到的 ID 和 Token,并更新上方显示
|
||||
self.current_detect_id = getattr(self.detect_thread, "target_id", "")
|
||||
self.current_detect_token = getattr(self.detect_thread, "new_token", "")
|
||||
if self.lblCurrentDetectId:
|
||||
self.lblCurrentDetectId.setText(f"当前检测 ID:{self.current_detect_id}")
|
||||
if self.lblCurrentDetectToken:
|
||||
self.lblCurrentDetectToken.setText(f"当前 Token:{self.current_detect_token}")
|
||||
|
||||
self.log(f"🚀 换号成功 (ID={self.current_detect_id})")
|
||||
self.log(f"🔑 提取的 Token: {self.current_detect_token}")
|
||||
self.log("🚀 正在为您启动 Cursor...")
|
||||
self.on_open_cursor_clicked()
|
||||
QMessageBox.information(self, "成功", "无感检测换号成功!\n已自动为您启动 Cursor。")
|
||||
else:
|
||||
QMessageBox.critical(self, "错误", message)
|
||||
|
||||
def on_silent_detect_clicked(self):
|
||||
"""执行无感检测换号。"""
|
||||
id_str = self.txtSilentToken.text().strip() if self.txtSilentToken else ""
|
||||
if not id_str:
|
||||
QMessageBox.warning(self, "警告", "请先输入要检测的 ID!")
|
||||
return
|
||||
if not id_str.isdigit():
|
||||
QMessageBox.warning(self, "警告", "ID 必须为纯数字!")
|
||||
return
|
||||
|
||||
if is_cursor_running():
|
||||
msg_box = QMessageBox(self)
|
||||
msg_box.setWindowTitle("Cursor正在运行")
|
||||
msg_box.setText("检测到 Cursor 正在运行!\n由于更新数据库需要独占锁,请先关闭 Cursor。")
|
||||
msg_box.setIcon(QMessageBox.Warning)
|
||||
btn_close = msg_box.addButton("💀 强制关闭并继续", QMessageBox.ActionRole)
|
||||
btn_cancel = msg_box.addButton("取消", QMessageBox.RejectRole)
|
||||
msg_box.setDefaultButton(btn_cancel)
|
||||
msg_box.exec_()
|
||||
|
||||
if msg_box.clickedButton() == btn_close:
|
||||
self.log("💀 正在强制关闭Cursor...")
|
||||
if kill_cursor():
|
||||
self.log("✅ Cursor已关闭")
|
||||
else:
|
||||
self.log("⚠️ 未找到运行中的Cursor进程")
|
||||
QMessageBox.warning(self, "警告", "未找到运行中的Cursor进程")
|
||||
return
|
||||
else:
|
||||
return
|
||||
|
||||
if self.btnSilentChange:
|
||||
self.btnSilentChange.setEnabled(False)
|
||||
self.btnSilentChange.setText("🔍 检测换号中...")
|
||||
|
||||
self.detect_thread = SilentDetectThread(id_str)
|
||||
self.detect_thread.log_signal.connect(self.log)
|
||||
self.detect_thread.finished_signal.connect(self.on_silent_detect_finished)
|
||||
self.detect_thread.start()
|
||||
|
||||
@Slot()
|
||||
def on_silent_unavailable_clicked(self):
|
||||
"""用户反馈当前 Token 不可用占位逻辑。"""
|
||||
if not getattr(self, "current_detect_id", None):
|
||||
QMessageBox.warning(self, "警告", "请先成功换号/检测一个 ID!")
|
||||
return
|
||||
|
||||
reply = QMessageBox.question(
|
||||
self,
|
||||
"反馈 Token 不可用",
|
||||
f"确定要反馈当前 ID: {self.current_detect_id} 对应的 Token 为不可用吗?",
|
||||
QMessageBox.Yes | QMessageBox.No,
|
||||
QMessageBox.No
|
||||
)
|
||||
if reply == QMessageBox.Yes:
|
||||
self.log(f"⚠️ 用户已点击不可用按钮反馈 ID: {self.current_detect_id}。")
|
||||
QMessageBox.information(self, "提示", "已收到反馈,不可用接口待后端实现。")
|
||||
|
||||
@Slot()
|
||||
def on_silent_copy_token_clicked(self):
|
||||
"""复制当前检测到的 Token 到剪贴板。"""
|
||||
if not getattr(self, "current_detect_token", None):
|
||||
QMessageBox.warning(self, "警告", "当前没有可复制的 Token,请先成功换号/检测一个 ID!")
|
||||
return
|
||||
|
||||
clipboard = QApplication.clipboard()
|
||||
clipboard.setText(self.current_detect_token)
|
||||
self.log("📋 已复制当前检测到的 Token 到剪贴板。")
|
||||
QMessageBox.information(self, "成功", "Token 已成功复制到剪贴板!")
|
||||
|
||||
|
||||
def main():
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user