import sys import tkinter as tk from tkinter import ttk, messagebox from pathlib import Path import logging import os from PIL import Image, ImageTk import time sys.path.append(str(Path(__file__).parent.parent)) from utils.config import Config from account_switcher import AccountSwitcher def get_version(): try: version_file = Path(__file__).parent.parent / 'version.txt' with open(version_file, 'r', encoding='utf-8') as f: return f.read().strip() except Exception as e: logging.error(f"读取版本号失败: {str(e)}") return "未知版本" class MainWindow: def __init__(self): self.config = Config() self.switcher = AccountSwitcher() self.root = tk.Tk() version = get_version() cursor_version = self.switcher.get_cursor_version() self.root.title(f"听泉Cursor助手 v{version} (本机Cursor版本: {cursor_version})") self.root.geometry("600x500") # 调整窗口大小 self.root.resizable(True, True) # 允许调整窗口大小 # 设置窗口最小尺寸 self.root.minsize(600, 500) try: # 设置图标 - 使用PIL current_dir = os.path.dirname(os.path.abspath(__file__)) icon_path = os.path.join(os.path.dirname(current_dir), "icon", "th.jpg") if os.path.exists(icon_path): # 打开并调整图片大小 img = Image.open(icon_path) img = img.resize((32, 32), Image.Resampling.LANCZOS) # 转换为PhotoImage self.icon = ImageTk.PhotoImage(img) self.root.iconphoto(True, self.icon) logging.info(f"成功加载图标: {icon_path}") else: logging.error(f"图标文件不存在: {icon_path}") except Exception as e: logging.error(f"设置图标失败: {str(e)}") # 设置关闭窗口处理 self.root.protocol("WM_DELETE_WINDOW", self.on_closing) # 初始化状态变量 self.status_var = tk.StringVar(value="") # 设置样式 self.style = ttk.Style() self.style.configure("TButton", padding=5, font=("Microsoft YaHei UI", 9)) self.style.configure("TLabelframe", padding=10, font=("Microsoft YaHei UI", 9)) self.style.configure("TLabel", padding=2, font=("Microsoft YaHei UI", 9)) self.style.configure("Custom.TButton", padding=10, font=("Microsoft YaHei UI", 9)) self.style.configure("Action.TButton", padding=8, font=("Microsoft YaHei UI", 9)) self.setup_ui() # 启动时检查一次状态 self.check_status() def setup_ui(self): """设置UI界面""" # 主框架 main_frame = ttk.Frame(self.root, padding=10) main_frame.pack(fill="both", expand=True) # 功能菜单 menu_frame = ttk.Frame(main_frame) menu_frame.pack(fill="x", pady=(0, 10)) ttk.Label(menu_frame, text="功能(F)").pack(side="left") # 设备ID区域 device_frame = ttk.Frame(main_frame) device_frame.pack(fill="x", pady=(0, 10)) ttk.Label(device_frame, text="设备识别码(勿动):").pack(side="left") self.hardware_id_var = tk.StringVar(value=self.switcher.hardware_id) device_id_entry = ttk.Entry(device_frame, textvariable=self.hardware_id_var, width=35, state="readonly") device_id_entry.pack(side="left", padx=5) copy_btn = ttk.Button(device_frame, text="复制ID", command=self.copy_device_id, width=8) copy_btn.pack(side="left") # 会员状态区域 status_frame = ttk.LabelFrame(main_frame, text="会员状态") status_frame.pack(fill="x", pady=(0, 10)) self.status_text = tk.Text(status_frame, height=5, width=40, font=("Microsoft YaHei UI", 9)) self.status_text.pack(fill="both", padx=5, pady=5) self.status_text.config(state="disabled") # 激活区域 activation_frame = ttk.LabelFrame(main_frame, text="激活(叠加)会员,多个激活码可叠加整体时长") activation_frame.pack(fill="x", pady=(0, 10)) input_frame = ttk.Frame(activation_frame) input_frame.pack(fill="x", padx=5, pady=5) ttk.Label(input_frame, text="激活码:").pack(side="left") self.activation_var = tk.StringVar() activation_entry = ttk.Entry(input_frame, textvariable=self.activation_var, width=35) activation_entry.pack(side="left", padx=5) activate_btn = ttk.Button(input_frame, text="激活", command=self.activate_account, width=8) activate_btn.pack(side="left") # 操作按钮区域 btn_frame = ttk.Frame(main_frame) btn_frame.pack(fill="x", pady=5) self.style.configure("Action.TButton", padding=8) ttk.Button(btn_frame, text="刷新Cursor编辑器授权", command=self.reset_machine_id, style="Action.TButton").pack(fill="x", pady=2) ttk.Button(btn_frame, text="突破Cursor0.45.x限制", command=self.dummy_function, style="Action.TButton").pack(fill="x", pady=2) ttk.Button(btn_frame, text="禁用Cursor版本更新", command=self.dummy_function, style="Action.TButton").pack(fill="x", pady=2) def copy_device_id(self): """复制设备ID到剪贴板""" # 先检查状态 if not self.check_status(): return self.root.clipboard_clear() self.root.clipboard_append(self.hardware_id_var.get()) def activate_account(self): """激活账号""" code = self.activation_var.get().strip() if not code: messagebox.showwarning("提示", "请输入激活码") return self.status_var.set("正在激活...") self.root.update() try: success, message, account_info = self.switcher.check_activation_code(code) if success: # 更新会员信息显示 self.update_status_display(account_info) messagebox.showinfo("激活成功", "激活成功!\n" + message) self.status_var.set("激活成功") # 清空激活码输入框 self.activation_var.set("") else: messagebox.showerror("激活失败", message) self.status_var.set("激活失败") # 激活后检查一次状态 self.check_status() except Exception as e: messagebox.showerror("错误", f"激活失败: {str(e)}") self.status_var.set("发生错误") # 出错后也检查状态 self.check_status() def update_status_display(self, status_info: dict): """更新状态显示""" # 打印API返回的原始数据 logging.info("=== API返回数据 ===") logging.info(f"状态信息: {status_info}") if 'activation_records' in status_info: logging.info("激活记录:") for record in status_info['activation_records']: logging.info(f"- 记录: {record}") # 启用文本框编辑 self.status_text.config(state="normal") # 清空当前内容 self.status_text.delete(1.0, tk.END) # 更新状态文本 status_map = { "active": "正常", "inactive": "未激活", "expired": "已过期" } status_text = status_map.get(status_info.get('status', 'inactive'), "未知") # 构建状态文本 status_lines = [ f"会员状态:{status_text}", f"到期时间:{status_info.get('expire_time', '')}", f"总天数:{status_info.get('total_days', 0)}天", f"剩余天数:{status_info.get('days_left', 0)}天" ] # 如果有激活记录,显示最近一次激活信息 activation_records = status_info.get('activation_records', []) if activation_records: latest_record = activation_records[-1] # 获取最新的激活记录 device_info = latest_record.get('device_info', {}) status_lines.extend([ "", "最近激活信息:", f"激活码:{latest_record.get('code', '')}", f"激活时间:{latest_record.get('activation_time', '')}", f"增加天数:{latest_record.get('days', 0)}天", "", "设备信息:", f"系统:{device_info.get('os', '')}", f"设备名:{device_info.get('device_name', '')}", f"IP地址:{device_info.get('ip', '')}", f"地区:{device_info.get('location', '--')}" ]) # 写入状态信息 self.status_text.insert(tk.END, "\n".join(status_lines)) # 禁用文本框编辑 self.status_text.config(state="disabled") def check_status(self): """检查会员状态 Returns: bool: True 表示激活状态正常,False 表示未激活或已过期 """ try: self.status_var.set("正在检查状态...") self.root.update() status = self.switcher.get_member_status() if status: self.update_status_display(status) if status.get('status') == 'inactive': messagebox.showwarning("警告", "当前设备未激活或激活已失效") self.status_var.set("未激活") return False self.status_var.set("状态检查完成") return True else: # 更新为未激活状态 inactive_status = { "hardware_id": self.switcher.hardware_id, "expire_time": "", "days": 0, "total_days": 0, "status": "inactive", "last_activation": {} } self.update_status_display(inactive_status) self.status_var.set("未激活") messagebox.showwarning("警告", "当前设备未激活") return False except Exception as e: logging.error(f"检查状态失败: {str(e)}") self.status_var.set("状态检查失败") # 显示错误消息 messagebox.showerror("错误", f"检查状态失败: {str(e)}") return False def minimize_window(self): """最小化窗口""" self.root.iconify() def maximize_window(self): """最大化/还原窗口""" if self.root.state() == 'zoomed': self.root.state('normal') else: self.root.state('zoomed') def on_closing(self): """窗口关闭处理""" try: logging.info("正在关闭程序...") # 先退出主循环 self.root.quit() # 等待一小段时间确保资源释放 time.sleep(0.5) except Exception as e: logging.error(f"关闭程序时出错: {str(e)}") finally: try: # 销毁窗口 self.root.destroy() # 再等待一小段时间 time.sleep(0.5) # 强制结束进程 if sys.platform == "win32": import os os._exit(0) except: # 如果还是无法正常关闭,直接强制退出 os._exit(0) def run(self): """运行程序""" self.root.mainloop() def dummy_function(self): """突破版本限制""" # 先检查状态 if not self.check_status(): return try: success, message = self.switcher.bypass_version_limit() if success: messagebox.showinfo("成功", message) else: messagebox.showerror("错误", message) except Exception as e: messagebox.showerror("错误", f"操作失败: {str(e)}") def reset_machine_id(self): """刷新Cursor编辑器授权""" try: # 刷新授权 success, message = self.switcher.refresh_cursor_auth() if success: messagebox.showinfo("成功", "Cursor编辑器授权刷新成功!\n" + message) else: messagebox.showerror("错误", message) except Exception as e: messagebox.showerror("错误", f"刷新失败: {str(e)}")