136 lines
5.2 KiB
Python
136 lines
5.2 KiB
Python
"""
|
|
FreePEP 一键打包分发脚本 (build_exe.py)
|
|
功能:
|
|
1. 检查并自动安装 PyInstaller
|
|
2. 打包 WebUI 为独立可执行文件 FreePEP.exe
|
|
3. 自动抓取并内嵌 Chromium 便携版浏览器内核至 dist/FreePEP/browsers/
|
|
4. 生成开箱即用的完全独立便携版压缩包 (FreePEP-Windows-x64.zip)
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import shutil
|
|
import zipfile
|
|
import subprocess
|
|
|
|
if hasattr(sys.stdout, "reconfigure"):
|
|
sys.stdout.reconfigure(encoding="utf-8")
|
|
|
|
|
|
def check_and_install_pyinstaller():
|
|
"""检查 PyInstaller 是否已安装,未安装则自动安装"""
|
|
try:
|
|
import PyInstaller
|
|
print("[+] 检测到 PyInstaller 已安装。")
|
|
except ImportError:
|
|
print("[*] 未检测到 PyInstaller,正在通过 pip 自动安装...")
|
|
subprocess.check_call([sys.executable, "-m", "pip", "install", "pyinstaller"])
|
|
print("[+] PyInstaller 安装完成!")
|
|
|
|
|
|
def find_playwright_browsers_dir():
|
|
"""定位本机 Playwright 下载的浏览器内核路径"""
|
|
local_app_data = os.environ.get("LOCALAPPDATA", "")
|
|
ms_playwright = os.path.join(local_app_data, "ms-playwright")
|
|
if os.path.exists(ms_playwright):
|
|
return ms_playwright
|
|
return None
|
|
|
|
|
|
def build_package():
|
|
print("=" * 65)
|
|
print(" 🚀 FreePEP 独立 EXE 便携发行包打包脚本")
|
|
print("=" * 65)
|
|
|
|
check_and_install_pyinstaller()
|
|
|
|
dist_dir = os.path.abspath("./dist")
|
|
build_dir = os.path.abspath("./build")
|
|
out_app_dir = os.path.join(dist_dir, "FreePEP")
|
|
|
|
# 清理旧的编译产物
|
|
if os.path.exists(out_app_dir):
|
|
print(f"[*] 清理旧输出目录: {out_app_dir}")
|
|
shutil.rmtree(out_app_dir, ignore_errors=True)
|
|
|
|
# 1. 组装 PyInstaller 命令
|
|
print("\n[1/3] 正在使用 PyInstaller 编译 Python 代码与依赖...")
|
|
cmd = [
|
|
sys.executable, "-m", "PyInstaller",
|
|
"--name=FreePEP",
|
|
"--onedir", # 目录模式(比单文件解压更快、更利于内嵌浏览器)
|
|
"--collect-all=playwright", # 打包 playwright driver 与所有依赖
|
|
"--hidden-import=uvicorn.logging",
|
|
"--hidden-import=uvicorn.loops",
|
|
"--hidden-import=uvicorn.loops.auto",
|
|
"--hidden-import=uvicorn.protocols",
|
|
"--hidden-import=uvicorn.protocols.http",
|
|
"--hidden-import=uvicorn.protocols.http.auto",
|
|
"--hidden-import=uvicorn.protocols.websockets",
|
|
"--hidden-import=uvicorn.protocols.websockets.auto",
|
|
"--hidden-import=uvicorn.lifespans",
|
|
"--hidden-import=uvicorn.lifespans.on",
|
|
"--clean",
|
|
"-y",
|
|
"webui.py"
|
|
]
|
|
|
|
subprocess.check_call(cmd)
|
|
print("[+] 核心程序 FreePEP.exe 编译成功!")
|
|
|
|
# 2. 拷贝 Playwright Chromium 绿色便携浏览器到目标目录
|
|
print("\n[2/3] 正在打包绿色便携版 Chromium 浏览器内核...")
|
|
pw_src = find_playwright_browsers_dir()
|
|
target_browsers_dir = os.path.join(out_app_dir, "_internal", "browsers")
|
|
target_browsers_dir2 = os.path.join(out_app_dir, "browsers")
|
|
|
|
if pw_src:
|
|
print(f"[*] 从本机提取 Chromium 内核: {pw_src}")
|
|
os.makedirs(target_browsers_dir2, exist_ok=True)
|
|
for item in os.listdir(pw_src):
|
|
if "chromium" in item.lower() or "ffmpeg" in item.lower():
|
|
s_path = os.path.join(pw_src, item)
|
|
d_path = os.path.join(target_browsers_dir2, item)
|
|
if not os.path.exists(d_path):
|
|
print(f" -> 拷贝内核组件: {item}")
|
|
if os.path.isdir(s_path):
|
|
shutil.copytree(s_path, d_path)
|
|
else:
|
|
shutil.copy2(s_path, d_path)
|
|
print("[+] 便携浏览器内核内嵌完成!分发给用户无需安装任何浏览器或 Python。")
|
|
else:
|
|
print("[!] 警告: 本机未找到 Playwright 缓存的 Chromium,建议先运行 'playwright install chromium'。")
|
|
|
|
# 拷贝默认说明和依赖
|
|
for f in ["README.md", "pep_catalog.json"]:
|
|
if os.path.exists(f):
|
|
shutil.copy2(f, os.path.join(out_app_dir, f))
|
|
|
|
# 3. 压缩为发布 ZIP 包
|
|
print("\n[3/3] 正在生成发布压缩包...")
|
|
zip_name = "FreePEP-Windows-x64.zip"
|
|
zip_path = os.path.join(dist_dir, zip_name)
|
|
if os.path.exists(zip_path):
|
|
os.remove(zip_path)
|
|
|
|
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zipf:
|
|
for root, dirs, files in os.walk(out_app_dir):
|
|
for file in files:
|
|
abs_f = os.path.join(root, file)
|
|
rel_f = os.path.relpath(abs_f, dist_dir)
|
|
zipf.write(abs_f, rel_f)
|
|
|
|
zip_size_mb = round(os.path.getsize(zip_path) / (1024 * 1024), 2)
|
|
print("\n" + "=" * 65)
|
|
print(f"🎉 打包全部完成!")
|
|
print(f"📁 绿色便携文件夹: {out_app_dir}")
|
|
print(f"📦 最终分发压缩包: {zip_path} ({zip_size_mb} MB)")
|
|
print("=" * 65)
|
|
print("\n👉 分发使用说明:")
|
|
print(" 直接将 FreePEP-Windows-x64.zip 发送给用户即可。")
|
|
print(" 用户解压后双击 FreePEP.exe,无需配置 Python,会自动弹出浏览器打开页面!\n")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
build_package()
|