Skip to content

Commit 9f51685

Browse files
committed
feat(updater): 软件一键自动更新 + 启动检查角标
updater.py: - ReleaseInfo/AssetInfo 结构化检查结果,取代旧 tuple - download_update 流式分块下载(64KB chunk, 512KB进度回调),支持重试/取消/代理 - apply_update 生成中转 bat(%TEMP%) detached 启动:等 exe 退出 → PowerShell Expand-Archive 解压 → robocopy 镜像覆盖(/is 强制覆盖 exe, /xd config debug /xf crash.log settings.json 保留用户数据) → 重启 settings_page.py: - 检查更新发现新版本 → 弹窗[立即更新/稍后] → 流式下载带进度可取消 → 下载完成弹[重启并安装] → apply_update + quit - 同步按钮下载时复用为取消入口,_fmt_size 字节进度 - 源码模式(is_frozen=False)拦截: 提示 git pull && uv sync, 不下载不生成 bat - 新增设置项「启动时自动检查软件更新」(默认开) app.py: - _StartupUpdateChecker 后台线程启动静默检查, 有新版本标题栏挂角标 - 退出时正确停线程
1 parent 02c34cf commit 9f51685

3 files changed

Lines changed: 605 additions & 50 deletions

File tree

aao/app.py

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@
2626
from PySide6.QtGui import QCloseEvent
2727

2828
from aao.core.timing.calibration import FullCalibrationData
29+
from aao.resources.updater import ReleaseInfo
2930

3031
_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
3132
if _ROOT not in sys.path:
3233
sys.path.insert(0, _ROOT)
3334

34-
from PySide6.QtCore import Qt, QThread, QTimer # noqa: E402
35+
from PySide6.QtCore import QObject, Qt, QThread, QTimer, Signal # noqa: E402
3536
from PySide6.QtWidgets import ( # noqa: E402
3637
QApplication,
3738
QHBoxLayout,
@@ -90,6 +91,28 @@ def _key_pressed(vk: int) -> bool:
9091
_PAGE_SETTINGS = 3
9192

9293

94+
class _StartupUpdateChecker(QObject):
95+
"""启动时静默检查软件更新(后台线程,不打扰)。
96+
97+
有新版本则发 update_found(ReleaseInfo);无更新/失败静默(只记日志)。
98+
"""
99+
100+
update_found = Signal(object)
101+
102+
def run(self) -> None:
103+
try:
104+
from aao.resources.updater import UpdateChecker
105+
106+
info = UpdateChecker().check_software()
107+
if info is not None and info.has_update:
108+
logger.info("启动检查:发现新版本 v%s", info.version)
109+
self.update_found.emit(info)
110+
elif info is not None:
111+
logger.info("启动检查:已是最新 (v%s)", info.version)
112+
except Exception: # noqa: BLE001
113+
logger.exception("启动更新检查失败")
114+
115+
93116
class MainWindow(QMainWindow):
94117
"""主控台:侧栏导航 + QStackedWidget 内容区。"""
95118

@@ -174,6 +197,25 @@ def __init__(
174197
bg.get("background_image", ""), bg.get("background_opacity", 25) / 100.0
175198
)
176199

200+
# 启动时静默检查软件更新(可关):有新版本则在标题栏挂角标。
201+
self._latest_version: str | None = None # 启动检查发现的新版本号(无则 None)
202+
self._startup_check_thread: QThread | None = None
203+
self._startup_check_worker: _StartupUpdateChecker | None = None
204+
if bg.get("check_update_on_start", True):
205+
self._startup_check_worker = _StartupUpdateChecker()
206+
self._startup_check_thread = QThread()
207+
self._startup_check_worker.moveToThread(self._startup_check_thread)
208+
self._startup_check_thread.started.connect(self._startup_check_worker.run)
209+
self._startup_check_worker.update_found.connect(self._on_startup_update_found)
210+
self._startup_check_worker.update_found.connect(self._startup_check_thread.quit)
211+
self._startup_check_thread.start()
212+
213+
def _on_startup_update_found(self, info: ReleaseInfo) -> None:
214+
"""启动检查发现新版本:标题栏挂角标提示(不弹窗,用户自行去设置页更新)。"""
215+
self._latest_version = info.version
216+
self.setWindowTitle(f"ArknightsAutoOperator [有新版本 v{info.version}]")
217+
logger.info("标题栏已标记新版本提示,前往设置页「检查更新」一键更新")
218+
177219
# --- 新手引导 ---
178220

179221
@staticmethod
@@ -543,13 +585,7 @@ def _reset_window_layout(self) -> None:
543585
def _quit_from_tray(self) -> None:
544586
"""托盘「退出」:停所有 worker + 退出应用。"""
545587
self._force_quit = True
546-
self.hotkey_timer.stop()
547-
self.farm_page.stop_and_wait()
548-
if self.worker is not None:
549-
self.worker.stop()
550-
if self.worker_thread is not None:
551-
self.worker_thread.quit()
552-
self.worker_thread.wait()
588+
self._stop_workers()
553589
self.tray.hide()
554590
QApplication.quit()
555591

@@ -566,14 +602,21 @@ def closeEvent(self, event: QCloseEvent) -> None: # noqa: D401
566602
self._force_quit = True
567603
return
568604
# 真退出(_quit_from_tray 已做清理,或窗口在可见时被强制关闭)
605+
self._stop_workers()
606+
super().closeEvent(event)
607+
608+
def _stop_workers(self) -> None:
609+
"""停所有后台 worker/timer(真退出路径共用)。"""
569610
self.hotkey_timer.stop()
570611
self.farm_page.stop_and_wait()
571612
if self.worker is not None:
572613
self.worker.stop()
573614
if self.worker_thread is not None:
574615
self.worker_thread.quit()
575616
self.worker_thread.wait()
576-
super().closeEvent(event)
617+
if self._startup_check_thread is not None:
618+
self._startup_check_thread.quit()
619+
self._startup_check_thread.wait()
577620

578621

579622
def _ensure_admin() -> None:

0 commit comments

Comments
 (0)