185 lines
5.7 KiB
Python
185 lines
5.7 KiB
Python
import logging
|
||
import sys
|
||
import traceback
|
||
import os
|
||
import atexit
|
||
import shutil
|
||
import tempfile
|
||
import urllib3
|
||
import ctypes
|
||
import win32event
|
||
import win32api
|
||
import winerror
|
||
from pathlib import Path
|
||
from PyQt5.QtWidgets import QApplication, QMessageBox, QSystemTrayIcon, QMenu
|
||
from PyQt5.QtGui import QIcon
|
||
from PyQt5.QtCore import Qt
|
||
from gui.main_window import MainWindow
|
||
from account_switcher import AccountSwitcher
|
||
|
||
# 禁用所有 SSL 相关警告
|
||
urllib3.disable_warnings()
|
||
logging.getLogger('urllib3').setLevel(logging.ERROR)
|
||
|
||
def prevent_multiple_instances():
|
||
"""防止程序多开
|
||
|
||
Returns:
|
||
bool: 如果是第一个实例返回True,否则返回False
|
||
"""
|
||
try:
|
||
# 创建一个唯一的互斥锁名称
|
||
mutex_name = "Global\\CursorHelper_SingleInstance_Lock"
|
||
|
||
# 尝试创建互斥锁
|
||
handle = win32event.CreateMutex(None, 1, mutex_name)
|
||
if win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS:
|
||
# 互斥锁已存在,说明程序已经在运行
|
||
logging.warning("程序已经在运行")
|
||
QMessageBox.warning(None, "警告", "程序已经在运行!\n请不要重复打开程序。")
|
||
return False
|
||
return True
|
||
except Exception as e:
|
||
logging.error(f"检查程序实例失败: {str(e)}")
|
||
return True # 如果检查失败,允许程序运行
|
||
|
||
def cleanup_temp():
|
||
"""清理临时文件"""
|
||
try:
|
||
temp_dir = Path(tempfile._get_default_tempdir())
|
||
for item in temp_dir.glob('_MEI*'):
|
||
try:
|
||
if item.is_dir():
|
||
shutil.rmtree(str(item), ignore_errors=True)
|
||
elif item.is_file():
|
||
item.unlink()
|
||
except:
|
||
pass
|
||
except:
|
||
pass
|
||
|
||
def setup_logging():
|
||
"""设置日志"""
|
||
try:
|
||
log_dir = Path.home() / ".cursor_switcher" / "logs"
|
||
log_dir.mkdir(parents=True, exist_ok=True)
|
||
|
||
log_file = log_dir / "switcher.log"
|
||
|
||
# 同时输出到文件和控制台
|
||
logging.basicConfig(
|
||
level=logging.INFO,
|
||
format="%(asctime)s - %(levelname)s - %(message)s",
|
||
handlers=[
|
||
logging.FileHandler(log_file, encoding="utf-8"),
|
||
logging.StreamHandler()
|
||
]
|
||
)
|
||
except Exception as e:
|
||
print(f"设置日志失败: {str(e)}")
|
||
|
||
def is_admin():
|
||
"""检查是否具有管理员权限"""
|
||
try:
|
||
return ctypes.windll.shell32.IsUserAnAdmin() != 0
|
||
except:
|
||
return False
|
||
|
||
def run_as_admin():
|
||
"""以管理员权限重新运行程序"""
|
||
try:
|
||
if not is_admin():
|
||
# 获取当前脚本的路径
|
||
script = sys.argv[0]
|
||
params = ' '.join(sys.argv[1:])
|
||
|
||
# 以管理员权限重新运行
|
||
ctypes.windll.shell32.ShellExecuteW(
|
||
None,
|
||
"runas",
|
||
sys.executable,
|
||
f'"{script}" {params}',
|
||
None,
|
||
1
|
||
)
|
||
return True
|
||
except Exception as e:
|
||
print(f"提升权限失败: {str(e)}")
|
||
return False
|
||
|
||
def print_banner():
|
||
"""打印程序横幅"""
|
||
print("""
|
||
====================================
|
||
Cursor 账号管理工具
|
||
====================================
|
||
""")
|
||
|
||
def main():
|
||
"""主函数"""
|
||
try:
|
||
# 0. 检查是否已有实例在运行
|
||
if not prevent_multiple_instances():
|
||
return 1
|
||
|
||
# 1. 首先检查管理员权限
|
||
if not is_admin():
|
||
if run_as_admin():
|
||
return 0
|
||
else:
|
||
QMessageBox.critical(None, "错误", "需要管理员权限运行此程序。\n请右键点击程序,选择'以管理员身份运行'。")
|
||
return 1
|
||
|
||
# 2. 注册退出时的清理函数
|
||
atexit.register(cleanup_temp)
|
||
|
||
# 3. 设置日志
|
||
setup_logging()
|
||
|
||
# 4. 创建QApplication实例
|
||
app = QApplication(sys.argv)
|
||
|
||
# 5. 检查系统托盘
|
||
if not QSystemTrayIcon.isSystemTrayAvailable():
|
||
logging.error("系统托盘不可用")
|
||
QMessageBox.critical(None, "错误", "系统托盘不可用,程序无法正常运行。")
|
||
return 1
|
||
|
||
# 6. 设置应用程序不会在最后一个窗口关闭时退出
|
||
app.setQuitOnLastWindowClosed(False)
|
||
|
||
# 7. 记录系统信息
|
||
logging.info(f"Python版本: {sys.version}")
|
||
logging.info(f"当前工作目录: {Path.cwd()}")
|
||
|
||
# 8. 设置应用程序ID
|
||
if sys.platform == "win32":
|
||
myappid = u'nezha.cursor.helper.v3'
|
||
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
|
||
logging.info(f"设置应用程序ID: {myappid}")
|
||
|
||
# 9. 设置应用程序图标
|
||
icon_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "icon", "two.ico")
|
||
if os.path.exists(icon_path):
|
||
app_icon = QIcon(icon_path)
|
||
if not app_icon.isNull():
|
||
app.setWindowIcon(app_icon)
|
||
logging.info(f"成功设置应用程序图标: {icon_path}")
|
||
|
||
# 10. 创建并显示主窗口
|
||
logging.info("正在初始化主窗口...")
|
||
window = MainWindow()
|
||
window.setWindowIcon(app.windowIcon())
|
||
window.show()
|
||
|
||
# 11. 运行应用程序
|
||
return app.exec_()
|
||
|
||
except Exception as e:
|
||
error_msg = f"程序运行出错: {str(e)}\n{traceback.format_exc()}"
|
||
logging.error(error_msg)
|
||
QMessageBox.critical(None, "错误", error_msg)
|
||
return 1
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main()) |