mirror of
https://github.com/hyb-oyqq/FRAISEMOE-Addons-Installer-NEXT.git
synced 2026-04-05 17:26:31 +00:00
Compare commits
10 Commits
1.4.0
...
803f32b567
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
803f32b567 | ||
|
|
ca6ef6443b | ||
|
|
ef7763dea0 | ||
|
|
4b170b14f4 | ||
|
|
7f8e94fc25 | ||
|
|
ba653b3470 | ||
|
|
b1807abff7 | ||
|
|
75ac82cb41 | ||
|
|
e75f52ab9c | ||
|
|
adcd6da5b4 |
65
.github/workflows/build-release.yml
vendored
Normal file
65
.github/workflows/build-release.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
name: Build and Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*' # 任意 tag 都会触发构建
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: windows-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
cache: 'pip'
|
||||||
|
cache-dependency-path: 'source/requirements.txt'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install -r source/requirements.txt
|
||||||
|
|
||||||
|
- name: Get version from tag
|
||||||
|
id: get_version
|
||||||
|
run: |
|
||||||
|
$version = "${{ github.ref_name }}"
|
||||||
|
echo "VERSION=$version" >> $env:GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Verify icon file
|
||||||
|
run: |
|
||||||
|
cd source
|
||||||
|
if (Test-Path "assets/images/ICO/icon.ico") {
|
||||||
|
Write-Host "Icon file found"
|
||||||
|
Get-Item "assets/images/ICO/icon.ico"
|
||||||
|
} else {
|
||||||
|
Write-Host "Icon file NOT found!"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Build with PyInstaller
|
||||||
|
run: |
|
||||||
|
cd source
|
||||||
|
pyinstaller --noconfirm build.spec
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: release-${{ steps.get_version.outputs.VERSION }}
|
||||||
|
path: source/dist/FRAISEMOE_Addons_Installer_NEXT.exe
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
name: release-${{ steps.get_version.outputs.VERSION }}
|
||||||
|
files: source/dist/FRAISEMOE_Addons_Installer_NEXT.exe
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
generate_release_notes: true
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -31,6 +31,7 @@ MANIFEST
|
|||||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
*.manifest
|
*.manifest
|
||||||
*.spec
|
*.spec
|
||||||
|
!source/build.spec
|
||||||
|
|
||||||
# Installer logs
|
# Installer logs
|
||||||
pip-log.txt
|
pip-log.txt
|
||||||
|
|||||||
73
source/build.spec
Normal file
73
source/build.spec
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# -*- mode: python ; coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from PyInstaller.utils.hooks import collect_submodules, collect_data_files
|
||||||
|
|
||||||
|
block_cipher = None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 收集所有子模块
|
||||||
|
hiddenimports = []
|
||||||
|
hiddenimports += collect_submodules('workers')
|
||||||
|
hiddenimports += collect_submodules('core')
|
||||||
|
hiddenimports += collect_submodules('core.managers')
|
||||||
|
hiddenimports += collect_submodules('core.handlers')
|
||||||
|
hiddenimports += collect_submodules('ui')
|
||||||
|
hiddenimports += collect_submodules('ui.components')
|
||||||
|
hiddenimports += collect_submodules('utils')
|
||||||
|
hiddenimports += collect_submodules('config')
|
||||||
|
|
||||||
|
# PySide6 相关隐藏导入
|
||||||
|
hiddenimports += ['PySide6.QtCore', 'PySide6.QtGui', 'PySide6.QtWidgets']
|
||||||
|
|
||||||
|
a = Analysis(
|
||||||
|
['Main.py'],
|
||||||
|
pathex=['.'],
|
||||||
|
binaries=[],
|
||||||
|
datas=[
|
||||||
|
('assets', 'assets'),
|
||||||
|
('data', 'data'),
|
||||||
|
('config', 'config'),
|
||||||
|
('bin', 'bin'),
|
||||||
|
('ui', 'ui'),
|
||||||
|
('workers', 'workers'),
|
||||||
|
('core', 'core'),
|
||||||
|
('utils', 'utils'),
|
||||||
|
],
|
||||||
|
hiddenimports=hiddenimports,
|
||||||
|
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='FRAISEMOE_Addons_Installer_NEXT',
|
||||||
|
debug=False,
|
||||||
|
bootloader_ignore_signals=False,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
upx_exclude=[],
|
||||||
|
runtime_tmpdir=None,
|
||||||
|
console=False,
|
||||||
|
disable_windowed_traceback=False,
|
||||||
|
argv_emulation=False,
|
||||||
|
target_arch=None,
|
||||||
|
codesign_identity=None,
|
||||||
|
entitlements_file=None,
|
||||||
|
icon=os.path.join('assets', 'images', 'ICO', 'icon.ico'),
|
||||||
|
)
|
||||||
@@ -4,12 +4,12 @@ import datetime
|
|||||||
|
|
||||||
# 配置信息
|
# 配置信息
|
||||||
app_data = {
|
app_data = {
|
||||||
"APP_VERSION": "1.4.0",
|
"APP_VERSION": "1.4.2",
|
||||||
"APP_NAME": "FRAISEMOE Addons Installer NEXT",
|
"APP_NAME": "FRAISEMOE Addons Installer NEXT",
|
||||||
"TEMP": "TEMP",
|
"TEMP": "TEMP",
|
||||||
"CACHE": "FRAISEMOE",
|
"CACHE": "FRAISEMOE",
|
||||||
"PLUGIN": "PLUGIN",
|
"PLUGIN": "PLUGIN",
|
||||||
"CONFIG_URL": "aHR0cHM6Ly9hcGkuMncyLnRvcC9hcGkvb3V5YW5ncWlxaS9uZWtvcGFyYS9kb3dubG9hZF91cmwuanNvbg==",
|
"CONFIG_URL": "aHR0cHM6Ly9uZWtvcGFyYS1hcGkub3ZvZmlzaC5jb20vYXBpL291eWFuZ3FpcWkvbmVrb3BhcmEvZG93bmxvYWRfdXJsLmpzb24=",
|
||||||
"UA_TEMPLATE": "Mozilla/5.0 (Linux debian12 FraiseMoe2-Accept-Next) Gecko/20100101 Firefox/114.0 FraiseMoe2/{}",
|
"UA_TEMPLATE": "Mozilla/5.0 (Linux debian12 FraiseMoe2-Accept-Next) Gecko/20100101 Firefox/114.0 FraiseMoe2/{}",
|
||||||
"game_info": {
|
"game_info": {
|
||||||
"NEKOPARA Vol.1": {
|
"NEKOPARA Vol.1": {
|
||||||
|
|||||||
@@ -204,7 +204,12 @@ class OfflineModeManager:
|
|||||||
# 同步更新UI菜单中的模式选择状态
|
# 同步更新UI菜单中的模式选择状态
|
||||||
if hasattr(self.main_window, 'ui_manager'):
|
if hasattr(self.main_window, 'ui_manager'):
|
||||||
ui_manager = self.main_window.ui_manager
|
ui_manager = self.main_window.ui_manager
|
||||||
if hasattr(ui_manager, 'online_mode_action') and hasattr(ui_manager, 'offline_mode_action'):
|
# 使用专门的同步方法确保菜单状态正确更新
|
||||||
|
if hasattr(ui_manager, 'sync_work_mode_menu_state'):
|
||||||
|
ui_manager.sync_work_mode_menu_state()
|
||||||
|
elif hasattr(ui_manager, 'online_mode_action') and hasattr(ui_manager, 'offline_mode_action'):
|
||||||
|
# 兼容旧版本的直接设置方式
|
||||||
|
if ui_manager.online_mode_action and ui_manager.offline_mode_action:
|
||||||
ui_manager.online_mode_action.setChecked(not enabled)
|
ui_manager.online_mode_action.setChecked(not enabled)
|
||||||
ui_manager.offline_mode_action.setChecked(enabled)
|
ui_manager.offline_mode_action.setChecked(enabled)
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,13 @@ class UIManager:
|
|||||||
self.disable_auto_restore_action = self.menu_builder.disable_auto_restore_action
|
self.disable_auto_restore_action = self.menu_builder.disable_auto_restore_action
|
||||||
self.disable_pre_hash_action = self.menu_builder.disable_pre_hash_action
|
self.disable_pre_hash_action = self.menu_builder.disable_pre_hash_action
|
||||||
|
|
||||||
|
# 保存对工作模式菜单项的引用,确保能正确同步状态
|
||||||
|
self.online_mode_action = self.menu_builder.online_mode_action
|
||||||
|
self.offline_mode_action = self.menu_builder.offline_mode_action
|
||||||
|
|
||||||
|
# 在菜单创建完成后,强制同步一次工作模式状态
|
||||||
|
self.sync_work_mode_menu_state()
|
||||||
|
|
||||||
# 为了向后兼容性,添加委托方法
|
# 为了向后兼容性,添加委托方法
|
||||||
def create_progress_window(self, title, initial_text="准备中..."):
|
def create_progress_window(self, title, initial_text="准备中..."):
|
||||||
"""创建进度窗口(委托给dialog_factory)"""
|
"""创建进度窗口(委托给dialog_factory)"""
|
||||||
@@ -84,6 +91,39 @@ class UIManager:
|
|||||||
"""显示菜单(委托给menu_builder)"""
|
"""显示菜单(委托给menu_builder)"""
|
||||||
return self.menu_builder.show_menu(menu, button)
|
return self.menu_builder.show_menu(menu, button)
|
||||||
|
|
||||||
|
def sync_work_mode_menu_state(self):
|
||||||
|
"""同步工作模式菜单状态,确保菜单选择状态与实际工作模式一致"""
|
||||||
|
try:
|
||||||
|
# 检查是否有离线模式管理器和菜单项
|
||||||
|
if not hasattr(self.main_window, 'offline_mode_manager') or not self.main_window.offline_mode_manager:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not hasattr(self, 'online_mode_action') or not hasattr(self, 'offline_mode_action'):
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.online_mode_action or not self.offline_mode_action:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 获取当前离线模式状态
|
||||||
|
is_offline_mode = self.main_window.offline_mode_manager.is_in_offline_mode()
|
||||||
|
|
||||||
|
# 同步菜单选择状态
|
||||||
|
self.online_mode_action.setChecked(not is_offline_mode)
|
||||||
|
self.offline_mode_action.setChecked(is_offline_mode)
|
||||||
|
|
||||||
|
# 记录同步操作(仅在调试模式下)
|
||||||
|
if hasattr(self.main_window, 'config') and self.main_window.config.get('debug_mode', False):
|
||||||
|
from utils.logger import setup_logger
|
||||||
|
logger = setup_logger("ui_manager")
|
||||||
|
logger.debug(f"已同步工作模式菜单状态: 离线模式={is_offline_mode}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# 静默处理异常,避免影响程序正常运行
|
||||||
|
if hasattr(self.main_window, 'config') and self.main_window.config.get('debug_mode', False):
|
||||||
|
from utils.logger import setup_logger
|
||||||
|
logger = setup_logger("ui_manager")
|
||||||
|
logger.debug(f"同步工作模式菜单状态时出错: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -207,6 +207,10 @@ class MainWindow(QMainWindow):
|
|||||||
else:
|
else:
|
||||||
self.window_manager.change_window_state(self.window_manager.STATE_ERROR)
|
self.window_manager.change_window_state(self.window_manager.STATE_ERROR)
|
||||||
|
|
||||||
|
# 确保工作模式菜单状态与实际状态同步
|
||||||
|
if hasattr(self, 'ui_manager') and hasattr(self.ui_manager, 'sync_work_mode_menu_state'):
|
||||||
|
self.ui_manager.sync_work_mode_menu_state()
|
||||||
|
|
||||||
def set_start_button_enabled(self, enabled, installing=False):
|
def set_start_button_enabled(self, enabled, installing=False):
|
||||||
"""[过渡方法] 设置按钮状态,将调用委托给WindowManager
|
"""[过渡方法] 设置按钮状态,将调用委托给WindowManager
|
||||||
|
|
||||||
|
|||||||
@@ -410,7 +410,7 @@ class Ui_MainWindows(object):
|
|||||||
self.start_install_text.setText("开始安装")
|
self.start_install_text.setText("开始安装")
|
||||||
self.start_install_text.setFont(self.custom_font)
|
self.start_install_text.setFont(self.custom_font)
|
||||||
self.start_install_text.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
self.start_install_text.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
self.start_install_text.setStyleSheet("letter-spacing: 1px;")
|
self.start_install_text.setStyleSheet("color: #333333; letter-spacing: 1px;")
|
||||||
|
|
||||||
# 点击区域透明按钮
|
# 点击区域透明按钮
|
||||||
self.start_install_btn = QPushButton(self.button_container)
|
self.start_install_btn = QPushButton(self.button_container)
|
||||||
@@ -444,7 +444,7 @@ class Ui_MainWindows(object):
|
|||||||
self.toggle_patch_text.setText("禁/启用补丁")
|
self.toggle_patch_text.setText("禁/启用补丁")
|
||||||
self.toggle_patch_text.setFont(self.custom_font)
|
self.toggle_patch_text.setFont(self.custom_font)
|
||||||
self.toggle_patch_text.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
self.toggle_patch_text.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
self.toggle_patch_text.setStyleSheet("letter-spacing: 1px;")
|
self.toggle_patch_text.setStyleSheet("color: #333333; letter-spacing: 1px;")
|
||||||
|
|
||||||
# 点击区域透明按钮
|
# 点击区域透明按钮
|
||||||
self.toggle_patch_btn = QPushButton(self.toggle_patch_container)
|
self.toggle_patch_btn = QPushButton(self.toggle_patch_container)
|
||||||
@@ -478,7 +478,7 @@ class Ui_MainWindows(object):
|
|||||||
self.uninstall_text.setText("卸载补丁")
|
self.uninstall_text.setText("卸载补丁")
|
||||||
self.uninstall_text.setFont(self.custom_font)
|
self.uninstall_text.setFont(self.custom_font)
|
||||||
self.uninstall_text.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
self.uninstall_text.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
self.uninstall_text.setStyleSheet("letter-spacing: 1px;")
|
self.uninstall_text.setStyleSheet("color: #333333; letter-spacing: 1px;")
|
||||||
|
|
||||||
# 点击区域透明按钮
|
# 点击区域透明按钮
|
||||||
self.uninstall_btn = QPushButton(self.uninstall_container)
|
self.uninstall_btn = QPushButton(self.uninstall_container)
|
||||||
@@ -513,7 +513,7 @@ class Ui_MainWindows(object):
|
|||||||
self.exit_text.setText("退出程序")
|
self.exit_text.setText("退出程序")
|
||||||
self.exit_text.setFont(self.custom_font)
|
self.exit_text.setFont(self.custom_font)
|
||||||
self.exit_text.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
self.exit_text.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
self.exit_text.setStyleSheet("letter-spacing: 1px;")
|
self.exit_text.setStyleSheet("color: #333333; letter-spacing: 1px;")
|
||||||
|
|
||||||
# 点击区域透明按钮
|
# 点击区域透明按钮
|
||||||
self.exit_btn = QPushButton(self.exit_container)
|
self.exit_btn = QPushButton(self.exit_container)
|
||||||
|
|||||||
@@ -105,7 +105,9 @@ class ExtractionThread(QThread):
|
|||||||
debug_logger.debug(f"压缩包内容分析:")
|
debug_logger.debug(f"压缩包内容分析:")
|
||||||
debug_logger.debug(f"- 文件总数: {len(file_list)}")
|
debug_logger.debug(f"- 文件总数: {len(file_list)}")
|
||||||
for i, f in enumerate(file_list):
|
for i, f in enumerate(file_list):
|
||||||
debug_logger.debug(f" {i+1}. {f} - 类型: {'文件夹' if f.endswith('/') or f.endswith('\\') else '文件'}")
|
is_folder = f.endswith('/') or f.endswith('\\')
|
||||||
|
file_type = '文件夹' if is_folder else '文件'
|
||||||
|
debug_logger.debug(f" {i+1}. {f} - 类型: {file_type}")
|
||||||
|
|
||||||
update_progress(20, f"正在分析 {self.game_version} 的补丁文件...")
|
update_progress(20, f"正在分析 {self.game_version} 的补丁文件...")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user