# -*- coding: utf-8 -*- import sys import os import traceback from datetime import datetime def get_app_path(): """获取应用程序路径""" if getattr(sys, 'frozen', False): # 如果是打包后的应用 return os.path.dirname(sys.executable) else: # 如果是开发环境 return os.path.dirname(os.path.abspath(__file__)) def setup_logging(): """设置日志""" app_path = get_app_path() log_dir = os.path.join(app_path, 'logs') os.makedirs(log_dir, exist_ok=True) log_file = os.path.join(log_dir, 'app.log') error_log = os.path.join(app_path, 'error.log') # 配置日志 logging.basicConfig( filename=log_file, level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) # 设置错误日志处理 def handle_exception(exc_type, exc_value, exc_traceback): if issubclass(exc_type, KeyboardInterrupt): sys.__excepthook__(exc_type, exc_value, exc_traceback) return error_msg = ''.join(traceback.format_exception(exc_type, exc_value, exc_traceback)) try: with open(error_log, 'a') as f: f.write(f"\n{'-'*60}\n") f.write(f"Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n") f.write(error_msg) logging.error(f"Uncaught exception:\n{error_msg}") except Exception as e: print(f"Error writing to log file: {str(e)}") print(error_msg) sys.excepthook = handle_exception # 添加父目录到系统路径 current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.append(parent_dir) try: from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton, QLabel, QLineEdit, QTextEdit, QMessageBox, QHBoxLayout, QFrame, QStackedWidget) from PyQt5.QtCore import Qt, QThread, pyqtSignal from PyQt5.QtGui import QFont, QIcon, QPalette, QColor from update_cursor_token import CursorTokenUpdater from logger import logging except Exception as e: error_path = os.path.join(get_app_path(), 'error.log') with open(error_path, 'w') as f: f.write(f"Import Error: {str(e)}\n") f.write(traceback.format_exc()) sys.exit(1) # macOS 风格的颜色 MACOS_COLORS = { 'background': '#F5F5F7', # 浅灰色背景 'button': '#0066CC', # 蓝色按钮 'button_hover': '#0052A3', # 深蓝色悬停 'button_pressed': '#003D7A', # 更深的蓝色按下 'text': '#1D1D1F', # 深色文字 'frame': '#FFFFFF', # 白色框架 'input': '#FFFFFF', # 白色输入框 'input_text': '#1D1D1F', # 深色输入文字 'border': '#E5E5E5' # 边框颜色 } class UpdateWorker(QThread): """后台更新线程""" finished = pyqtSignal(bool, str) progress = pyqtSignal(str) def __init__(self, updater): super().__init__() self.updater = updater def run(self): try: success = self.updater.full_update_process() if success: self.finished.emit(True, "更新成功!") else: self.finished.emit(False, "更新失败,请查看日志") except Exception as e: self.finished.emit(False, f"发生错误: {str(e)}") class MainWindow(QMainWindow): def __init__(self): super().__init__() try: logging.info("正在初始化主窗口...") self.updater = CursorTokenUpdater() self.init_ui() # 检查会员状态 self.check_member_status() logging.info("主窗口初始化完成") except Exception as e: logging.error(f"初始化主窗口时发生错误: {str(e)}") QMessageBox.critical(self, "错误", f"初始化失败: {str(e)}") def init_ui(self): # 设置窗口基本属性 self.setWindowTitle('听泉助手') self.setMinimumSize(600, 500) # 设置macOS风格的样式 self.setStyleSheet(f""" QMainWindow {{ background-color: {MACOS_COLORS['background']}; }} QPushButton {{ background-color: {MACOS_COLORS['button']}; color: white; border: none; border-radius: 6px; padding: 8px 16px; font-size: 13px; min-width: 100px; }} QPushButton:hover {{ background-color: {MACOS_COLORS['button_hover']}; }} QPushButton:pressed {{ background-color: {MACOS_COLORS['button_pressed']}; }} QLabel {{ color: {MACOS_COLORS['text']}; font-size: 13px; }} QLabel[title="true"] {{ font-size: 24px; font-weight: bold; }} QTextEdit {{ background-color: {MACOS_COLORS['input']}; color: {MACOS_COLORS['input_text']}; border: 1px solid {MACOS_COLORS['border']}; border-radius: 6px; padding: 8px; font-size: 13px; }} QLineEdit {{ background-color: {MACOS_COLORS['input']}; color: {MACOS_COLORS['input_text']}; border: 1px solid {MACOS_COLORS['border']}; border-radius: 6px; padding: 8px; font-size: 13px; }} QFrame {{ background-color: {MACOS_COLORS['frame']}; border: 1px solid {MACOS_COLORS['border']}; border-radius: 8px; }} QMessageBox {{ background-color: {MACOS_COLORS['background']}; }} QMessageBox QPushButton {{ min-width: 80px; padding: 6px 12px; }} """) # 创建主窗口部件 central_widget = QWidget() self.setCentralWidget(central_widget) layout = QVBoxLayout(central_widget) layout.setSpacing(16) layout.setContentsMargins(20, 20, 20, 20) # 标题 title_label = QLabel("听泉助手") title_label.setProperty("title", "true") title_label.setAlignment(Qt.AlignCenter) layout.addWidget(title_label) # 设备ID显示区域 device_frame = QFrame() device_layout = QHBoxLayout(device_frame) device_layout.setContentsMargins(16, 16, 16, 16) device_id_label = QLabel("设备标识:") self.device_id_text = QLineEdit() self.device_id_text.setReadOnly(True) try: hardware_id = self.updater.hardware_id logging.info(f"获取到硬件ID: {hardware_id}") self.device_id_text.setText(hardware_id) except Exception as e: logging.error(f"获取硬件ID失败: {str(e)}") self.device_id_text.setText("获取失败") copy_button = QPushButton("复制ID") copy_button.setMaximumWidth(100) copy_button.clicked.connect(self.copy_device_id) device_layout.addWidget(device_id_label) device_layout.addWidget(self.device_id_text) device_layout.addWidget(copy_button) layout.addWidget(device_frame) # 会员状态区域 member_frame = QFrame() member_layout = QVBoxLayout(member_frame) member_layout.setContentsMargins(16, 16, 16, 16) member_title = QLabel("会员状态") member_title.setAlignment(Qt.AlignCenter) member_layout.addWidget(member_title) self.member_info = QTextEdit() self.member_info.setReadOnly(True) self.member_info.setFixedHeight(80) self.member_info.setText("会员状态: 正常\n到期时间: 2025-02-22 20:44:23") member_layout.addWidget(self.member_info) layout.addWidget(member_frame) # 激活区域 activate_frame = QFrame() activate_layout = QVBoxLayout(activate_frame) activate_layout.setContentsMargins(16, 16, 16, 16) activate_title = QLabel("激活会员") activate_title.setAlignment(Qt.AlignCenter) input_layout = QHBoxLayout() self.activate_input = QLineEdit() self.activate_input.setPlaceholderText("请输入激活码") activate_button = QPushButton("激活") activate_button.setMaximumWidth(100) activate_button.clicked.connect(self.activate_license) input_layout.addWidget(self.activate_input) input_layout.addWidget(activate_button) activate_layout.addWidget(activate_title) activate_layout.addLayout(input_layout) layout.addWidget(activate_frame) # 功能按钮区域 button_frame = QFrame() button_layout = QVBoxLayout(button_frame) button_layout.setSpacing(12) button_layout.setContentsMargins(16, 16, 16, 16) self.update_button = QPushButton("刷新授权") self.update_button.clicked.connect(self.start_update) self.reset_button = QPushButton("重置机器码") self.reset_button.clicked.connect(self.reset_machine) self.disable_update_button = QPushButton("禁用更新") self.disable_update_button.clicked.connect(self.disable_cursor_update) button_layout.addWidget(self.update_button) button_layout.addWidget(self.reset_button) button_layout.addWidget(self.disable_update_button) layout.addWidget(button_frame) def copy_device_id(self): clipboard = QApplication.clipboard() clipboard.setText(self.device_id_text.text()) QMessageBox.information(self, "成功", "设备ID已复制到剪贴板") def append_log(self, text): self.member_info.append(text) def start_update(self): self.update_button.setEnabled(False) self.worker = UpdateWorker(self.updater) self.worker.finished.connect(self.update_finished) self.worker.start() def update_finished(self, success, message): self.update_button.setEnabled(True) if success: QMessageBox.information(self, "成功", message) else: QMessageBox.warning(self, "失败", message) def reset_machine(self): try: self.updater.reset_machine_id() QMessageBox.information(self, "成功", "机器ID已重置") except Exception as e: QMessageBox.critical(self, "错误", f"重置失败: {str(e)}") def activate_license(self): """激活许可证""" try: license_key = self.activate_input.text().strip() if not license_key: QMessageBox.warning(self, "提示", "请输入激活码") return # 禁用激活按钮,防止重复点击 self.activate_input.setEnabled(False) self.update_button.setEnabled(False) # 显示处理中的提示 QApplication.processEvents() # 调用激活接口 success, message, account_info = self.updater.check_activation_code(license_key) if success: # 更新界面显示 self.member_info.clear() self.member_info.append(f"会员状态: 已激活") self.member_info.append(f"到期时间: {account_info['expire_time']}") self.member_info.append(f"剩余天数: {account_info['days_left']}天") # 显示成功消息 QMessageBox.information(self, "激活成功", f"设备已成功激活!\n" f"到期时间: {account_info['expire_time']}\n" f"剩余天数: {account_info['days_left']}天") # 清空激活码输入框 self.activate_input.clear() logging.info(f"设备激活成功,到期时间: {account_info['expire_time']}") else: QMessageBox.warning(self, "激活失败", message) logging.error(f"激活失败: {message}") except Exception as e: logging.error(f"激活过程中发生错误: {str(e)}") QMessageBox.critical(self, "错误", f"激活过程发生错误: {str(e)}") finally: # 恢复按钮状态 self.activate_input.setEnabled(True) self.update_button.setEnabled(True) def disable_cursor_update(self): try: # 这里添加禁用更新逻辑 QMessageBox.information(self, "成功", "已禁用Cursor更新") except Exception as e: QMessageBox.critical(self, "错误", f"操作失败: {str(e)}") def check_member_status(self): """检查会员状态""" try: logging.info("正在检查会员状态...") self.member_info.clear() self.member_info.append("正在检查会员状态...") QApplication.processEvents() # 调用API检查状态 success, message, account_info = self.updater.check_member_status() if success and account_info: # 更新会员信息显示 self.member_info.clear() self.member_info.append(f"会员状态: 已激活") self.member_info.append(f"到期时间: {account_info['expire_time']}") self.member_info.append(f"剩余天数: {account_info['days_left']}天") logging.info(f"会员状态检查完成 - 到期时间: {account_info['expire_time']}") else: # 显示未激活状态 self.member_info.clear() self.member_info.append("会员状态: 未激活") self.member_info.append("请输入激活码进行激活") logging.warning("会员状态检查结果:未激活") except Exception as e: self.member_info.clear() self.member_info.append("会员状态: 检查失败") self.member_info.append("请稍后重试") logging.error(f"检查会员状态时发生错误: {str(e)}") def main(): try: # 设置日志 setup_logging() logging.info("应用程序启动") app = QApplication(sys.argv) app.setApplicationName("听泉助手") app.setOrganizationName("听泉") app.setOrganizationDomain("cursor.pro") try: window = MainWindow() window.show() logging.info("主窗口已显示") return app.exec_() except Exception as e: logging.error(f"主窗口创建失败: {str(e)}") logging.error(traceback.format_exc()) QMessageBox.critical(None, "错误", f"程序启动失败: {str(e)}") return 1 except Exception as e: error_path = os.path.join(get_app_path(), 'error.log') with open(error_path, 'a') as f: f.write(f"\nApplication Error: {str(e)}\n") f.write(traceback.format_exc()) return 1 if __name__ == '__main__': sys.exit(main())