diff --git a/__init__.py b/__init__.py index 739b414..1694e60 100644 --- a/__init__.py +++ b/__init__.py @@ -11,9 +11,12 @@ Comfyui_o1key - ComfyUI 自定义节点集合 # 检查更新(仅在启动时检查一次) try: - from .utils.update_checker import check_for_updates, notify_update_available + from .utils.update_checker import check_for_updates, notify_update_available, notify_new_version notify_update_available() # TODO: 测试用,改回 if check_for_updates(): notify_update_available() + + if check_for_updates(): + notify_new_version() except Exception: # 静默失败,不影响插件加载 pass diff --git a/utils/update_checker.py b/utils/update_checker.py index b0ae28f..416482d 100644 --- a/utils/update_checker.py +++ b/utils/update_checker.py @@ -71,6 +71,47 @@ def check_for_updates() -> bool: return False +def get_update_changelog() -> list: + """获取远程新版本的 commit 摘要(最多3条)""" + try: + plugin_dir = os.path.dirname(os.path.dirname(__file__)) + result = subprocess.run( + ['git', 'log', 'HEAD..origin/main', '--pretty=format:%s', '--no-merges'], + cwd=plugin_dir, + capture_output=True, + text=True, + encoding='utf-8' + ) + lines = [l.strip() for l in result.stdout.strip().splitlines() if l.strip()] + return lines[:3] + except Exception: + return [] + + +def notify_new_version(): + """检测到新版本时,推送蓝色更新通知弹框""" + changelog = get_update_changelog() + print("[o1key] 检测到新版本,准备推送更新通知") + + try: + import threading + from server import PromptServer + + def _send(): + try: + PromptServer.instance.send_sync( + "o1key.new_version", + {"changelog": changelog} + ) + print("[o1key] 新版本通知已发送到前端") + except Exception as e: + print(f"[o1key] 发送新版本通知失败: {e}") + + threading.Timer(5.0, _send).start() + except Exception: + pass + + def notify_update_available(): """通知用户有更新可用(前端弹窗 + 控制台)""" current_version = get_current_version() diff --git a/web/js/updateNotifier.js b/web/js/updateNotifier.js index cdf1707..09cf5e9 100644 --- a/web/js/updateNotifier.js +++ b/web/js/updateNotifier.js @@ -71,3 +71,72 @@ api.addEventListener("o1key.update_available", (event) => { toast.appendChild(text); document.body.appendChild(toast); }); + +api.addEventListener("o1key.new_version", (event) => { + const changelog = event.detail?.changelog || []; + + const style = document.createElement("style"); + style.textContent = ` + @keyframes o1key-slide-in { + from { opacity: 0; transform: translateY(16px) scale(0.97); } + to { opacity: 1; transform: translateY(0) scale(1); } + } + .o1key-update-close:hover { color: #fff !important; } + `; + document.head.appendChild(style); + + const toast = document.createElement("div"); + toast.style.cssText = ` + position: fixed; + bottom: 148px; + left: 28px; + background: linear-gradient(135deg, #0a1628 0%, #0d2b4e 60%, #1a4a7a 100%); + color: #d6eaf8; + border: 1px solid #2e86c1; + border-radius: 12px; + padding: 18px 20px 16px 20px; + font-size: 14px; + z-index: 100000; + box-shadow: 0 6px 24px rgba(46,134,193,0.35), 0 2px 8px rgba(0,0,0,0.5); + max-width: 340px; + animation: o1key-slide-in 0.4s cubic-bezier(.22,.68,0,1.2); + `; + + const header = document.createElement("div"); + header.style.cssText = `display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px;`; + + const title = document.createElement("span"); + title.textContent = "🔔 检测到有新版本发布!"; + title.style.cssText = `font-weight: bold; font-size: 13px; color: #7fb3d3; letter-spacing: 0.5px;`; + + const closeBtn = document.createElement("button"); + closeBtn.textContent = "×"; + closeBtn.className = "o1key-update-close"; + closeBtn.style.cssText = `background: none; border: none; color: #7fb3d3; font-size: 20px; cursor: pointer; padding: 0; line-height: 1;`; + closeBtn.onclick = () => toast.remove(); + + header.appendChild(title); + header.appendChild(closeBtn); + + const divider = document.createElement("div"); + divider.style.cssText = `height: 1px; background: rgba(46,134,193,0.3); margin-bottom: 10px;`; + + const body = document.createElement("div"); + const items = changelog.length > 0 ? changelog : ["暂无更新说明"]; + items.forEach(item => { + const line = document.createElement("div"); + line.textContent = `• ${item}`; + line.style.cssText = `margin-bottom: 4px; font-size: 13px; line-height: 1.6; color: #d6eaf8;`; + body.appendChild(line); + }); + + const more = document.createElement("div"); + more.textContent = "..."; + more.style.cssText = `color: #7fb3d3; font-size: 13px; margin-top: 4px;`; + body.appendChild(more); + + toast.appendChild(header); + toast.appendChild(divider); + toast.appendChild(body); + document.body.appendChild(toast); +});