PyInstallerEx 0.1.9__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {pyinstallerex-0.1.9/src/PyInstallerEx.egg-info → pyinstallerex-0.2.2}/PKG-INFO +49 -7
  2. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/README.md +47 -6
  3. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/pyproject.toml +3 -2
  4. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/setup.py +2 -1
  5. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx/__main__.py +6 -5
  6. pyinstallerex-0.2.2/src/PyInstallerEx/server.py +291 -0
  7. pyinstallerex-0.2.2/src/PyInstallerEx/web/favicon.ico +0 -0
  8. pyinstallerex-0.2.2/src/PyInstallerEx/web/index.html +664 -0
  9. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2/src/PyInstallerEx.egg-info}/PKG-INFO +49 -7
  10. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx.egg-info/SOURCES.txt +3 -1
  11. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx.egg-info/requires.txt +1 -0
  12. pyinstallerex-0.1.9/src/PyInstallerEx/PyInstallerEx.py +0 -0
  13. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/LICENSE +0 -0
  14. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/bin/launcher_windows.exe +0 -0
  15. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/setup.cfg +0 -0
  16. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx/__init__.py +0 -0
  17. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx/core/__init__.py +0 -0
  18. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx/core/config.py +0 -0
  19. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx/core/packager.py +0 -0
  20. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx/utils/__init__.py +0 -0
  21. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx/utils/compression.py +0 -0
  22. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx/utils/file_utils.py +0 -0
  23. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx/utils/icon_helper.py +0 -0
  24. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx/utils/logging.py +0 -0
  25. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx/utils/system_utils.py +0 -0
  26. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx.egg-info/dependency_links.txt +0 -0
  27. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx.egg-info/entry_points.txt +0 -0
  28. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx.egg-info/not-zip-safe +0 -0
  29. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/src/PyInstallerEx.egg-info/top_level.txt +0 -0
  30. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/test/test_python27_compatibility.py +0 -0
  31. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/test/test_python3x_compatibility.py +0 -0
  32. {pyinstallerex-0.1.9 → pyinstallerex-0.2.2}/test/test_rust_launcher.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyInstallerEx
3
- Version: 0.1.9
3
+ Version: 0.2.2
4
4
  Summary: 扩展PyInstaller 使其拥有单文件安装功能不用每次都解压执行
5
5
  Home-page: https://gitee.com/iiixxxiii/py-installer-ex
6
6
  Author: lixin
@@ -27,6 +27,7 @@ Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
27
27
  Description-Content-Type: text/markdown
28
28
  License-File: LICENSE
29
29
  Requires-Dist: PyInstaller>=3.2.1
30
+ Requires-Dist: pyquickwebgui
30
31
  Dynamic: author
31
32
  Dynamic: home-page
32
33
  Dynamic: license-file
@@ -52,6 +53,9 @@ PyInstallerEx 是一个基于 PyInstaller 的增强版打包工具,能够将 P
52
53
  4. **灵活解压模式**:支持解压到系统临时目录或 exe 所在目录(通过 `--extract-mode` 参数控制)
53
54
  5. **跨平台支持**:Windows、Linux x86/ARM全平台覆盖
54
55
  6. **配置灵活**:支持嵌入式配置读取,命令行参数覆盖配置文件
56
+ 7. **Web GUI 界面**:无参数启动时自动打开图形化界面,可视化配置打包参数
57
+ - **多语言支持**:支持中文/英文界面切换,设置持久化保存
58
+ - **文件选择对话框**:原生 tkinter 文件/文件夹选择器,支持初始路径记忆
55
59
 
56
60
  ## 🔧 环境要求
57
61
 
@@ -130,6 +134,26 @@ pip install pyinstallerex
130
134
 
131
135
  ### 基本用法
132
136
 
137
+ #### 启动 Web GUI(图形界面)
138
+
139
+ 直接运行命令,不带任何参数,即可启动 Web GUI 界面:
140
+
141
+ ```bash
142
+ # 以下三种方式均可
143
+ PyInstallerEx
144
+ pyinstallerex
145
+ python -m PyInstallerEx
146
+ ```
147
+
148
+ 启动后会自动打开浏览器窗口,支持:
149
+ - 选择脚本或文件夹打包模式
150
+ - 可视化配置输出名称、版本、引擎、图标等参数
151
+ - 实时查看构建日志和结果
152
+
153
+ #### 命令行模式
154
+
155
+ 带参数时使用命令行模式:
156
+
133
157
  ```bash
134
158
  # 使用 pyinstallerex 命令
135
159
  pyinstallerex your_script.py
@@ -327,7 +351,11 @@ py-installer-ex/
327
351
  │ ├── PyInstallerEx/ # Python 主程序
328
352
  │ │ ├── __init__.py
329
353
  │ │ ├── __main__.py # CLI入口点
354
+ │ │ ├── server.py # Web GUI 后端服务
330
355
  │ │ ├── PyInstallerEx.py # 主模块
356
+ │ │ ├── web/
357
+ │ │ │ ├── index.html # Web GUI 前端页面
358
+ │ │ │ └── favicon.ico # 页面图标
331
359
  │ │ ├── core/
332
360
  │ │ │ ├── config.py # 配置管理
333
361
  │ │ │ └── packager.py # 打包逻辑
@@ -449,20 +477,34 @@ script\install.bat
449
477
 
450
478
  - **Python 2.7+ / 3.x**: 主要开发语言
451
479
  - **PyInstaller >= 3.2.1**: 应用程序打包基础
480
+ - **pyquickwebgui**: Web GUI 图形界面框架
452
481
  - **Rust (edition 2021)**: 启动器开发语言(serde/serde_json、md5、flate2)
453
482
  - **JSON**: 配置文件格式
454
483
  - **ZIP**: 应用程序压缩格式
455
484
 
456
- ## 🔮 未来扩展方向
485
+ ## 未来扩展方向
457
486
 
458
- 1. **GUI界面**:添加图形化配置界面
459
- 2. **数字签名**:支持代码签名和安全验证
460
- 3. **增量更新**:实现应用程序的增量更新功能
461
- 4. **更多平台**:支持macOS等其他操作系统
462
- 5. **插件系统**:允许扩展自定义打包逻辑
487
+ 1. ~~**GUI界面**~~:✅ 已实现 Web GUI 图形化界面(基于 pyquickwebgui)
488
+ 2. ~~**多语言支持**~~:✅ 已实现中英文双语界面,localStorage + 配置文件双持久化
489
+ 3. **数字签名**:支持代码签名和安全验证
490
+ 4. **增量更新**:实现应用程序的增量更新功能
491
+ 5. **更多平台**:支持macOS等其他操作系统
492
+ 6. **插件系统**:允许扩展自定义打包逻辑
463
493
 
464
494
  ## 更新日志
465
495
 
496
+ - 2026-07-07 V 0.2.2
497
+ - 新增 **Web GUI 多语言支持**:支持中文/英文界面实时切换
498
+ - 新增 **语言设置持久化**:使用用户主目录下 `.pyinstallerex/ui_config.json` 配置文件保存语言偏好
499
+
500
+
501
+ - 2026-07-07 V 0.2.1
502
+ - 新增 **Web GUI 图形界面**:不带参数直接运行 `PyInstallerEx` 即可启动
503
+ - 基于 `pyquickwebgui` 实现,支持脚本模式/文件夹模式切换
504
+ - 可视化配置打包参数(引擎、图标、解压模式、输出目录等)
505
+ - 实时日志输出与构建状态轮询
506
+ - 新增 `server.py` 后端服务及 `web/` 前端页面
507
+
466
508
  - 2026-07-03 V 0.1.10
467
509
  - 新增 `--folder` 参数,支持文件夹直接打包模式:跳过引擎构建,直接将指定文件夹压缩并附加到启动器
468
510
  - 新增 `--run` 参数,支持自定义解压后运行的主程序入口(配置 `main` 字段)
@@ -18,6 +18,9 @@ PyInstallerEx 是一个基于 PyInstaller 的增强版打包工具,能够将 P
18
18
  4. **灵活解压模式**:支持解压到系统临时目录或 exe 所在目录(通过 `--extract-mode` 参数控制)
19
19
  5. **跨平台支持**:Windows、Linux x86/ARM全平台覆盖
20
20
  6. **配置灵活**:支持嵌入式配置读取,命令行参数覆盖配置文件
21
+ 7. **Web GUI 界面**:无参数启动时自动打开图形化界面,可视化配置打包参数
22
+ - **多语言支持**:支持中文/英文界面切换,设置持久化保存
23
+ - **文件选择对话框**:原生 tkinter 文件/文件夹选择器,支持初始路径记忆
21
24
 
22
25
  ## 🔧 环境要求
23
26
 
@@ -96,6 +99,26 @@ pip install pyinstallerex
96
99
 
97
100
  ### 基本用法
98
101
 
102
+ #### 启动 Web GUI(图形界面)
103
+
104
+ 直接运行命令,不带任何参数,即可启动 Web GUI 界面:
105
+
106
+ ```bash
107
+ # 以下三种方式均可
108
+ PyInstallerEx
109
+ pyinstallerex
110
+ python -m PyInstallerEx
111
+ ```
112
+
113
+ 启动后会自动打开浏览器窗口,支持:
114
+ - 选择脚本或文件夹打包模式
115
+ - 可视化配置输出名称、版本、引擎、图标等参数
116
+ - 实时查看构建日志和结果
117
+
118
+ #### 命令行模式
119
+
120
+ 带参数时使用命令行模式:
121
+
99
122
  ```bash
100
123
  # 使用 pyinstallerex 命令
101
124
  pyinstallerex your_script.py
@@ -293,7 +316,11 @@ py-installer-ex/
293
316
  │ ├── PyInstallerEx/ # Python 主程序
294
317
  │ │ ├── __init__.py
295
318
  │ │ ├── __main__.py # CLI入口点
319
+ │ │ ├── server.py # Web GUI 后端服务
296
320
  │ │ ├── PyInstallerEx.py # 主模块
321
+ │ │ ├── web/
322
+ │ │ │ ├── index.html # Web GUI 前端页面
323
+ │ │ │ └── favicon.ico # 页面图标
297
324
  │ │ ├── core/
298
325
  │ │ │ ├── config.py # 配置管理
299
326
  │ │ │ └── packager.py # 打包逻辑
@@ -415,20 +442,34 @@ script\install.bat
415
442
 
416
443
  - **Python 2.7+ / 3.x**: 主要开发语言
417
444
  - **PyInstaller >= 3.2.1**: 应用程序打包基础
445
+ - **pyquickwebgui**: Web GUI 图形界面框架
418
446
  - **Rust (edition 2021)**: 启动器开发语言(serde/serde_json、md5、flate2)
419
447
  - **JSON**: 配置文件格式
420
448
  - **ZIP**: 应用程序压缩格式
421
449
 
422
- ## 🔮 未来扩展方向
450
+ ## 未来扩展方向
423
451
 
424
- 1. **GUI界面**:添加图形化配置界面
425
- 2. **数字签名**:支持代码签名和安全验证
426
- 3. **增量更新**:实现应用程序的增量更新功能
427
- 4. **更多平台**:支持macOS等其他操作系统
428
- 5. **插件系统**:允许扩展自定义打包逻辑
452
+ 1. ~~**GUI界面**~~:✅ 已实现 Web GUI 图形化界面(基于 pyquickwebgui)
453
+ 2. ~~**多语言支持**~~:✅ 已实现中英文双语界面,localStorage + 配置文件双持久化
454
+ 3. **数字签名**:支持代码签名和安全验证
455
+ 4. **增量更新**:实现应用程序的增量更新功能
456
+ 5. **更多平台**:支持macOS等其他操作系统
457
+ 6. **插件系统**:允许扩展自定义打包逻辑
429
458
 
430
459
  ## 更新日志
431
460
 
461
+ - 2026-07-07 V 0.2.2
462
+ - 新增 **Web GUI 多语言支持**:支持中文/英文界面实时切换
463
+ - 新增 **语言设置持久化**:使用用户主目录下 `.pyinstallerex/ui_config.json` 配置文件保存语言偏好
464
+
465
+
466
+ - 2026-07-07 V 0.2.1
467
+ - 新增 **Web GUI 图形界面**:不带参数直接运行 `PyInstallerEx` 即可启动
468
+ - 基于 `pyquickwebgui` 实现,支持脚本模式/文件夹模式切换
469
+ - 可视化配置打包参数(引擎、图标、解压模式、输出目录等)
470
+ - 实时日志输出与构建状态轮询
471
+ - 新增 `server.py` 后端服务及 `web/` 前端页面
472
+
432
473
  - 2026-07-03 V 0.1.10
433
474
  - 新增 `--folder` 参数,支持文件夹直接打包模式:跳过引擎构建,直接将指定文件夹压缩并附加到启动器
434
475
  - 新增 `--run` 参数,支持自定义解压后运行的主程序入口(配置 `main` 字段)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "PyInstallerEx"
7
- version = "0.1.9"
7
+ version = "0.2.2"
8
8
  description = "扩展PyInstaller 使其拥有单文件安装功能不用每次都解压执行"
9
9
  readme = "README.md"
10
10
  requires-python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
@@ -32,6 +32,7 @@ classifiers = [
32
32
  ]
33
33
  dependencies = [
34
34
  "PyInstaller>=3.2.1",
35
+ "pyquickwebgui",
35
36
  ]
36
37
 
37
38
  [project.urls]
@@ -45,4 +46,4 @@ PyInstallerEx = "PyInstallerEx.__main__:main"
45
46
  where = ["src"]
46
47
 
47
48
  [tool.setuptools.package-data]
48
- PyInstallerEx = ["../bin/*"]
49
+ PyInstallerEx = ["../bin/*", "web/*"]
@@ -25,7 +25,7 @@ setup(
25
25
  packages=find_packages(where="src"), # 自动发现src目录下的子包
26
26
  include_package_data=True, # 包含包数据文件
27
27
  package_data={
28
- "PyInstallerEx": ["../bin/*"], # 包含bin目录中的所有文件
28
+ "PyInstallerEx": ["../bin/*", "web/*"], # 包含bin目录中的所有文件及web前端文件
29
29
  },
30
30
  data_files=[
31
31
  ('bin', [
@@ -35,6 +35,7 @@ setup(
35
35
  python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", # 兼容 2.7 和 3.4+
36
36
  install_requires=[ # 依赖列表
37
37
  "PyInstaller>=3.2.1",
38
+ "pyquickwebgui",
38
39
  # Windows平台可选依赖,用于设置exe图标(需要手动安装)
39
40
  # pip install pywin32 或 pip install pefile
40
41
  ],
@@ -46,6 +46,12 @@ def main():
46
46
 
47
47
  args = parser.parse_args()
48
48
 
49
+ # 无任何参数时启动 Web GUI 模式
50
+ if not args.script and not args.folder:
51
+ from .server import start_web_gui
52
+ start_web_gui()
53
+ return
54
+
49
55
  # 设置日志
50
56
  setup_logging(args.verbose)
51
57
 
@@ -55,11 +61,6 @@ def main():
55
61
  print("[FAIL] Error: 'script' and '--folder' are mutually exclusive. Please specify only one.", file=sys.stderr)
56
62
  sys.exit(1)
57
63
 
58
- # 必须提供 script 或 --folder 之一
59
- if not args.script and not args.folder:
60
- print("[FAIL] Error: either 'script' or '--folder' must be specified.", file=sys.stderr)
61
- sys.exit(1)
62
-
63
64
  # --folder 模式校验:目录必须存在
64
65
  if args.folder:
65
66
  if not os.path.isdir(args.folder):
@@ -0,0 +1,291 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ PyInstallerEx Web GUI 服务器
4
+ 基于 pyquickwebgui 提供图形化打包界面
5
+ """
6
+
7
+ from __future__ import print_function
8
+ import os
9
+ import sys
10
+ import json
11
+ import threading
12
+
13
+ from pyquickwebgui import QuikeUI
14
+
15
+ from .core.packager import PackageBuilder
16
+ from .core.config import PackageConfig
17
+ from .utils.logging import setup_logging
18
+
19
+
20
+ # 全局构建状态
21
+ _build_status = {
22
+ "running": False,
23
+ "progress": "",
24
+ "output": "",
25
+ "success": None,
26
+ "log": [],
27
+ }
28
+
29
+ # UI 配置文件路径(存储语言等设置)- 放在用户主目录下
30
+ _user_home = os.path.expanduser('~')
31
+ _ui_config_dir = os.path.join(_user_home, '.pyinstallerex')
32
+ if not os.path.exists(_ui_config_dir):
33
+ try:
34
+ os.makedirs(_ui_config_dir)
35
+ except Exception:
36
+ pass
37
+ _ui_config_file = os.path.join(_ui_config_dir, 'ui_config.json')
38
+
39
+
40
+ def _load_ui_config():
41
+ """加载 UI 配置(语言等)"""
42
+ try:
43
+ if os.path.exists(_ui_config_file):
44
+ with open(_ui_config_file, 'r', encoding='utf-8') as f:
45
+ return json.load(f)
46
+ except Exception:
47
+ pass
48
+ return {"language": "en"}
49
+
50
+
51
+ def _save_ui_config(config):
52
+ """保存 UI 配置"""
53
+ try:
54
+ with open(_ui_config_file, 'w', encoding='utf-8') as f:
55
+ json.dump(config, f, ensure_ascii=False, indent=2)
56
+ except Exception as e:
57
+ print("[PyInstallerEx] Failed to save UI config: {0}".format(e))
58
+
59
+ # 全局 QuikeUI 实例
60
+ _web_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "web")
61
+ qui = QuikeUI(
62
+ web_path=_web_dir,
63
+ index_html="index.html",
64
+ title="PyInstallerEx",
65
+ icon="favicon.ico",
66
+ width=900,
67
+ height=680,
68
+ debug=False,
69
+ )
70
+
71
+
72
+ def _reset_status():
73
+ """重置构建状态"""
74
+ _build_status["running"] = False
75
+ _build_status["progress"] = ""
76
+ _build_status["output"] = ""
77
+ _build_status["success"] = None
78
+ _build_status["log"] = []
79
+
80
+
81
+ def _append_log(msg):
82
+ """追加日志"""
83
+ _build_status["log"].append(msg)
84
+ print(msg)
85
+
86
+
87
+ @qui.expose
88
+ def get_status():
89
+ """获取当前构建状态"""
90
+ return dict(_build_status)
91
+
92
+
93
+ @qui.expose
94
+ def pick_file(initial_dir, file_types):
95
+ """打开文件选择对话框
96
+
97
+ Args:
98
+ initial_dir: 初始目录
99
+ file_types: 文件类型过滤,如 '.py' 或 '.ico'
100
+ """
101
+ try:
102
+ import tkinter as tk
103
+ from tkinter import filedialog
104
+ if initial_dir and os.path.isdir(initial_dir):
105
+ print("[PyInstallerEx] pick_file folder: {0}".format(initial_dir))
106
+ root = tk.Tk()
107
+ root.attributes("-topmost", True)
108
+ root.withdraw()
109
+ ft = [("{0} files".format(file_types), "*{0}".format(file_types)), ("All files", "*.*")]
110
+ result = filedialog.askopenfilename(initialdir=initial_dir, filetypes=ft)
111
+ print("[PyInstallerEx] pick_file result: {0}".format(repr(result)))
112
+ return result if result else ""
113
+ else:
114
+ return 'Not valid folder'
115
+ except Exception as e:
116
+ print("[PyInstallerEx] pick_file error: {0}".format(e))
117
+ return "Error: {0}".format(e)
118
+
119
+
120
+ @qui.expose
121
+ def pick_folder(initial_dir):
122
+ """打开文件夹选择对话框
123
+
124
+ Args:
125
+ initial_dir: 初始目录
126
+ """
127
+ try:
128
+ import tkinter as tk
129
+ from tkinter import filedialog
130
+ if initial_dir and os.path.isdir(initial_dir):
131
+ print("[PyInstallerEx] pick_folder folder: {0}".format(initial_dir))
132
+ root = tk.Tk()
133
+ root.attributes("-topmost", True)
134
+ root.withdraw()
135
+ result = filedialog.askdirectory(initialdir=initial_dir)
136
+ print("[PyInstallerEx] pick_folder result: {0}".format(repr(result)))
137
+ return result if result else ""
138
+ else:
139
+ return 'Not valid folder'
140
+ except Exception as e:
141
+ print("[PyInstallerEx] pick_folder error: {0}".format(e))
142
+ return "Error: {0}".format(e)
143
+
144
+
145
+ @qui.expose
146
+ def start_build(config_json):
147
+ """
148
+ 启动打包构建任务
149
+
150
+ Args:
151
+ config_json: JSON 字符串,包含打包配置
152
+ """
153
+ if _build_status["running"]:
154
+ return {"success": False, "message": "A build task is already running"}
155
+
156
+ _reset_status()
157
+ _build_status["running"] = True
158
+
159
+ try:
160
+ cfg = json.loads(config_json)
161
+ except Exception as e:
162
+ _build_status["running"] = False
163
+ return {"success": False, "message": "Invalid config JSON: {0}".format(e)}
164
+
165
+ def _run_build():
166
+ try:
167
+ _append_log("[INFO] Starting build...")
168
+ _build_status["progress"] = "Initializing..."
169
+
170
+ # 构建 PackageConfig
171
+ config = PackageConfig()
172
+ config.filename = cfg.get("filename", "{filename}")
173
+ config.version = cfg.get("version", "1.0.0")
174
+ config.description = cfg.get("description", "")
175
+ config.author = cfg.get("author", "Unknown")
176
+ config.extract_mode = cfg.get("extract_mode", "temp")
177
+ config.engine_mode = cfg.get("engine_mode", "pyinstaller")
178
+ config.main = cfg.get("main", None)
179
+
180
+ # 图标处理
181
+ icon_path = cfg.get("icon", None)
182
+ if icon_path and os.path.exists(icon_path):
183
+ config.icon = icon_path
184
+ else:
185
+ default_icon = os.path.join(os.path.dirname(os.path.abspath(__file__)), "logo.ico")
186
+ if os.path.exists(default_icon):
187
+ config.icon = default_icon
188
+ else:
189
+ config.icon = None
190
+
191
+ # 设置日志级别
192
+ verbose = cfg.get("verbose", False)
193
+ setup_logging(verbose)
194
+
195
+ builder = PackageBuilder(config, verbose=verbose)
196
+ output_dir = cfg.get("output_dir", None) or None
197
+
198
+ # 文件夹模式 or 脚本模式
199
+ folder_path = cfg.get("folder", None)
200
+ script_path = cfg.get("script", None)
201
+
202
+ if folder_path:
203
+ _build_status["progress"] = "Packaging folder..."
204
+ if not os.path.isdir(folder_path):
205
+ raise ValueError("Folder not found: {0}".format(folder_path))
206
+
207
+ if cfg.get("name"):
208
+ config.filename = cfg["name"]
209
+ elif config.filename == "{filename}":
210
+ config.filename = os.path.basename(folder_path)
211
+
212
+ result_path = builder.build_folder(folder_path, output_dir)
213
+ elif script_path:
214
+ _build_status["progress"] = "Packaging script..."
215
+ if not os.path.isfile(script_path):
216
+ raise ValueError("Script not found: {0}".format(script_path))
217
+
218
+ if cfg.get("name"):
219
+ config.filename = cfg["name"]
220
+ elif config.filename == "{filename}":
221
+ config.filename = os.path.splitext(os.path.basename(script_path))[0]
222
+
223
+ result_path = builder.build(script_path, output_dir)
224
+ else:
225
+ raise ValueError("Either 'script' or 'folder' must be specified")
226
+
227
+ _build_status["progress"] = "Done"
228
+ _build_status["output"] = result_path
229
+ _build_status["success"] = True
230
+ _append_log("[OK] Build completed: {0}".format(result_path))
231
+
232
+ except Exception as e:
233
+ _build_status["progress"] = "Failed"
234
+ _build_status["success"] = False
235
+ _build_status["output"] = str(e)
236
+ _append_log("[FAIL] Build failed: {0}".format(e))
237
+ finally:
238
+ _build_status["running"] = False
239
+
240
+ # 在后台线程执行构建
241
+ t = threading.Thread(target=_run_build)
242
+ t.daemon = True
243
+ t.start()
244
+
245
+ return {"success": True, "message": "Build started"}
246
+
247
+
248
+ @qui.expose
249
+ def get_default_config():
250
+ """获取默认配置模板"""
251
+ default_icon = os.path.join(os.path.dirname(os.path.abspath(__file__)), "logo.ico")
252
+ ui_config = _load_ui_config()
253
+ return {
254
+ "filename": "{filename}",
255
+ "version": "1.0.0",
256
+ "description": "Application packaged with PyInstallerEx",
257
+ "author": "Unknown",
258
+ "extract_mode": "temp",
259
+ "engine_mode": "pyinstaller",
260
+ "icon": default_icon if os.path.exists(default_icon) else "",
261
+ "output_dir": "",
262
+ "verbose": False,
263
+ "language": ui_config.get("language", "en"),
264
+ }
265
+
266
+
267
+ @qui.expose
268
+ def set_language(lang):
269
+ """设置界面语言并保存到配置文件
270
+
271
+ Args:
272
+ lang: 'en' or 'cn'
273
+ """
274
+ if lang not in ('en', 'cn'):
275
+ return {"success": False, "message": "Invalid language: {0}".format(lang)}
276
+
277
+ ui_config = _load_ui_config()
278
+ ui_config["language"] = lang
279
+ _save_ui_config(ui_config)
280
+ print("[PyInstallerEx] Language saved: {0}".format(lang))
281
+ return {"success": True, "language": lang}
282
+
283
+
284
+ def start_web_gui():
285
+ """启动 Web GUI"""
286
+ print("[PyInstallerEx] Starting Web GUI...")
287
+ qui.run()
288
+
289
+
290
+ if __name__ == "__main__":
291
+ start_web_gui()