From 0011b1b558adfabf35610d20bc75ec469365fa4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=BF=97=E5=BC=BA?= <357099073@qq.com> Date: Tue, 16 Jun 2026 18:14:51 +0800 Subject: [PATCH] 'update' --- __pycache__/main.cpython-313.pyc | Bin 138996 -> 153899 bytes layout/main1.ui | 96 +++++++++--- main.py | 248 +++++++++++++++++++++++++++++++ 3 files changed, 324 insertions(+), 20 deletions(-) diff --git a/__pycache__/main.cpython-313.pyc b/__pycache__/main.cpython-313.pyc index 342e5d5ef33b25bbbbe6a15d91cd72bdaf209c4a..91f8fe1f09294be1365093e0caca718686f77860 100644 GIT binary patch delta 17813 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 diff --git a/layout/main1.ui b/layout/main1.ui index 2e6cc8c..511326b 100644 --- a/layout/main1.ui +++ b/layout/main1.ui @@ -850,32 +850,88 @@ - - - 请输入新 Token (兼容纯 token / Cookie 串): - - - - - - - 在此粘贴 Token,格式支持 Workos... 或原始 token - - - - - - + + - 0 - 42 + 150 + 16777215 - - 无感换号 + + 在此输入 ID,例如:11 + + + + 当前检测 ID:- + + + + + + + true + + + <!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> + + + + 16777215 + 80 + + + + + + + + + + + 0 + 42 + + + + 无感换号 + + + + + + + + 0 + 42 + + + + 不可用 + + + + + + + + 0 + 42 + + + + 复制 Token + + + + + diff --git a/main.py b/main.py index d78e4a1..37dd397 100644 --- a/main.py +++ b/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)