""" 更高级的打包脚本,使用 spec 文件进行更精细的控制 这个脚本会生成一个 .spec 文件并基于它进行打包 """ import os import sys import shutil import subprocess import platform import datetime import argparse from pathlib import Path def install_requirements(): """安装必要的依赖""" requirements = ["pyinstaller", "colorama", "requests"] for req in requirements: print(f"正在检查 {req}...") try: __import__(req) print(f"✅ {req} 已安装") except ImportError: print(f"❌ {req} 未安装,正在安装...") try: subprocess.run([sys.executable, "-m", "pip", "install", req], check=True) print(f"✅ {req} 安装成功") except subprocess.SubprocessError as e: print(f"❌ {req} 安装失败: {e}") return False return True def create_spec_file(app_name): """创建 .spec 文件""" print("正在创建 .spec 文件...") # 获取当前工作目录 current_dir = os.path.abspath(os.path.dirname(__file__)) # 自动检测项目中的所有 Python 文件 python_files = [] for file in os.listdir(current_dir): if file.endswith('.py') and file != 'package.py' and file != 'package_spec.py': python_files.append(file) main_script = 'cursor_pro_register.py' if main_script not in python_files: print(f"❌ 找不到主脚本文件 {main_script}!") return False # 确保 turnstilePatch 目录存在 turnstile_path = os.path.join(current_dir, 'turnstilePatch') if not os.path.exists(turnstile_path): print("⚠️ 警告: 找不到 turnstilePatch 目录,功能可能受限") # 获取资源文件 datas = [] if os.path.exists(turnstile_path): datas.append((turnstile_path, 'turnstilePatch')) # 检查其他可能的资源文件夹 for folder in ['assets', 'config', 'data']: folder_path = os.path.join(current_dir, folder) if os.path.exists(folder_path) and os.path.isdir(folder_path): datas.append((folder_path, folder)) # 确定输出文件名 output_name = app_name if app_name else "cursor动态账号注册机" print(f"输出文件名设置为: {output_name}") # 生成 spec 文件内容 spec_content = f"""# -*- mode: python ; coding: utf-8 -*- import sys from pathlib import Path block_cipher = None # 收集项目文件 a = Analysis( ['{main_script}'], pathex=['{current_dir}'], binaries=[], datas={datas}, hiddenimports=[ 'colorama', 'requests', 'json', 'random', 'datetime', 'enum', 'dotenv', 'tkinter', 'tkinter.messagebox', 'tkinter.ttk', 'threading', 'queue', 'urllib', 'urllib.request', 'urllib.parse', 'time', 'sys', 'os', 'traceback', 'logging', 'typing', 're', 'base64', 'platform', 'collections' ], hookspath=[], hooksconfig={{}}, runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False, ) # 创建可执行文件 pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE( pyz, a.scripts, a.binaries, a.zipfiles, a.datas, [], name='{output_name}', debug=False, bootloader_ignore_signals=False, strip=False, upx=False, upx_exclude=[], runtime_tmpdir=None, console=True, disable_windowed_traceback=False, argv_emulation=False, target_arch=None, codesign_identity=None, entitlements_file=None, icon=None, ) """ spec_file = 'cursor_pro_register.spec' with open(spec_file, 'w', encoding='utf-8') as f: f.write(spec_content) print(f"✅ 已创建 {spec_file}") return True def build_from_spec(keep_previous, app_name): """从 spec 文件构建可执行文件""" print("开始从 spec 文件构建可执行文件...") dist_folder = "dist" build_folder = "build" # 如果不保留旧版本,则清除dist和build目录 if not keep_previous: for folder in [dist_folder, build_folder]: if os.path.exists(folder): shutil.rmtree(folder) print(f"已清理 {folder} 文件夹") else: # 确保目录存在 os.makedirs(dist_folder, exist_ok=True) os.makedirs(build_folder, exist_ok=True) print("将保留先前版本") # 生成版本标识(用于区分构建文件夹) timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") build_dir = os.path.join(build_folder, f"build_{timestamp}") # 确定输出文件名 output_name = app_name if app_name else "cursor动态账号注册机" # 构建命令 cmd = ["pyinstaller", "--workpath", build_dir, "cursor_pro_register.spec", "--clean", "--noupx"] print(f"执行命令: {' '.join(cmd)}") try: # 运行 PyInstaller 使用 spec 文件 subprocess.run(cmd, check=True) # 检查构建结果 executable_name = f"{output_name}.exe" if platform.system() == "Windows" else output_name executable_path = os.path.join("dist", executable_name) if os.path.exists(executable_path): print(f"\n✅ 打包成功! 可执行文件位于: {executable_path}") # 获取文件大小 size_bytes = os.path.getsize(executable_path) size_mb = size_bytes / (1024 * 1024) print(f"可执行文件大小: {size_mb:.2f} MB") return True else: print(f"❌ 打包过程可能出错,找不到可执行文件: {executable_path}") return False except subprocess.SubprocessError as e: print(f"❌ 打包失败: {e}") return False if __name__ == "__main__": print("=" * 50) print("Cursor Pro Register 高级打包工具") print("=" * 50) # 解析命令行参数 parser = argparse.ArgumentParser(description="Cursor Pro Register 高级打包工具") parser.add_argument("app_name", nargs="?", default="cursor动态账号注册机", help="应用名称") parser.add_argument("keep_previous", nargs="?", type=int, default=0, help="是否保留先前版本 (1=是, 0=否)") args = parser.parse_args() print(f"接收到的参数: 应用名称=\"{args.app_name}\", 保留旧版本={bool(args.keep_previous)}") # 安装必要的依赖 if not install_requirements(): print("❌ 安装依赖失败,打包终止") sys.exit(1) # 创建 spec 文件 if not create_spec_file(args.app_name): print("❌ 创建 spec 文件失败,打包终止") sys.exit(1) # 从 spec 文件构建 if build_from_spec(bool(args.keep_previous), args.app_name): print("\n打包过程完成!") else: print("\n打包过程出现错误,请检查上面的日志信息") input("按任意键退出...")