diff --git a/CHANGELOG.md b/CHANGELOG.md index 95db019..d8ce24f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,21 @@ --- +## [1.10.3] - 2026-04-13 + +### 修复 +- 香蕉节点修复返回2张图、灰色图片问题 +- 修复 SSL 证书报错,统一由【保存图像】节点保存 + +### 新增 +- 支持【立刻取消】生图请求,可立即重新运行 +- 支持工作流历史记录恢复 +- 并发上限提升,批量生图速度大幅提升 +- 全能LLM新增视频/文档分析、流式实时预览 +- Seedance 2.0 新增多图及视频URL参考(优化中) + +--- + ## [Unreleased] ### Added ✨ diff --git a/__init__.py b/__init__.py index 1694e60..e5b60dd 100644 --- a/__init__.py +++ b/__init__.py @@ -15,8 +15,7 @@ try: notify_update_available() # TODO: 测试用,改回 if check_for_updates(): notify_update_available() - if check_for_updates(): - notify_new_version() + notify_new_version() # TODO: 测试用,改回 if check_for_updates(): notify_new_version() except Exception: # 静默失败,不影响插件加载 pass diff --git a/utils/update_checker.py b/utils/update_checker.py index 416482d..7275ea7 100644 --- a/utils/update_checker.py +++ b/utils/update_checker.py @@ -72,18 +72,40 @@ def check_for_updates() -> bool: def get_update_changelog() -> list: - """获取远程新版本的 commit 摘要(最多3条)""" + """从远程 CHANGELOG.md 最新版本块中提取更新内容(最多3条)""" try: plugin_dir = os.path.dirname(os.path.dirname(__file__)) + # 读取远程最新的 CHANGELOG.md result = subprocess.run( - ['git', 'log', 'HEAD..origin/main', '--pretty=format:%s', '--no-merges'], + ['git', 'show', 'origin/main:CHANGELOG.md'], 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] + lines = result.stdout.splitlines() + + # 找到第一个版本块(## [x.x.x]) + in_block = False + items = [] + for line in lines: + if line.startswith('## [') and not line.startswith('## [Unreleased]'): + if in_block: + break # 遇到下一个版本块,停止 + in_block = True + continue + if in_block: + stripped = line.strip() + # 提取有实际内容的行(跳过标题、空行、分隔线) + if stripped and not stripped.startswith('#') and not stripped.startswith('---') and not stripped.startswith('- '): + # 去掉 markdown 列表符号和加粗 + text = stripped.lstrip('- ').replace('**', '').strip() + if text and len(text) > 3: + items.append(text) + if len(items) >= 3: + break + + return items except Exception: return [] @@ -91,7 +113,6 @@ def get_update_changelog() -> list: def notify_new_version(): """检测到新版本时,推送蓝色更新通知弹框""" changelog = get_update_changelog() - print("[o1key] 检测到新版本,准备推送更新通知") try: import threading @@ -103,22 +124,16 @@ def notify_new_version(): "o1key.new_version", {"changelog": changelog} ) - print("[o1key] 新版本通知已发送到前端") - except Exception as e: - print(f"[o1key] 发送新版本通知失败: {e}") + except Exception: + pass - threading.Timer(5.0, _send).start() + threading.Timer(3.0, _send).start() except Exception: pass def notify_update_available(): - """通知用户有更新可用(前端弹窗 + 控制台)""" - current_version = get_current_version() - version_str = f" (当前版本: {current_version})" if current_version else "" - - print(f"[comfyui_o1key] 有新版本可用{version_str}") - + """通知用户有更新可用(前端弹窗)""" try: import threading from server import PromptServer @@ -129,11 +144,9 @@ def notify_update_available(): "o1key.update_available", {"message": "欢迎使用o1key工作流,祝您马年,马上有福,马上有钱,马到成功!!!"} ) - print("[o1key] 更新通知已发送到前端") - except Exception as e: - print(f"[o1key] 发送通知失败: {e}") + except Exception: + pass - # 延迟 5 秒发送,确保前端 WebSocket 已连接 - threading.Timer(5.0, _send).start() + threading.Timer(3.0, _send).start() except Exception: pass diff --git a/version.txt b/version.txt index 460c8b9..d9c8fd4 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -v1.10.2 +v1.10.3 diff --git a/web/js/updateNotifier.js b/web/js/updateNotifier.js index 09cf5e9..d525d33 100644 --- a/web/js/updateNotifier.js +++ b/web/js/updateNotifier.js @@ -1,5 +1,27 @@ import { api } from "../../../scripts/api.js"; +function startCountdown(toast, closeBtn, seconds, accentColor) { + let remaining = seconds; + closeBtn.textContent = `× ${remaining}s`; + + const interval = setInterval(() => { + remaining--; + if (remaining <= 0) { + clearInterval(interval); + toast.style.transition = "opacity 0.4s ease"; + toast.style.opacity = "0"; + setTimeout(() => toast.remove(), 400); + } else { + closeBtn.textContent = `× ${remaining}s`; + } + }, 1000); + + closeBtn.onclick = () => { + clearInterval(interval); + toast.remove(); + }; +} + api.addEventListener("o1key.update_available", (event) => { const message = event.detail?.message || "欢迎使用o1key工作流"; @@ -9,7 +31,6 @@ api.addEventListener("o1key.update_available", (event) => { from { opacity: 0; transform: translateY(16px) scale(0.97); } to { opacity: 1; transform: translateY(0) scale(1); } } - .o1key-toast-close:hover { color: #fff !important; } `; document.head.appendChild(style); @@ -31,30 +52,14 @@ api.addEventListener("o1key.update_available", (event) => { `; const header = document.createElement("div"); - header.style.cssText = ` - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 10px; - `; + header.style.cssText = `display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px;`; const title = document.createElement("span"); title.textContent = "🐴 o1key 工作流"; title.style.cssText = `font-weight: bold; font-size: 13px; color: #82e0aa; letter-spacing: 0.5px;`; const closeBtn = document.createElement("button"); - closeBtn.textContent = "×"; - closeBtn.className = "o1key-toast-close"; - closeBtn.style.cssText = ` - background: none; - border: none; - color: #82e0aa; - font-size: 20px; - cursor: pointer; - padding: 0; - line-height: 1; - `; - closeBtn.onclick = () => toast.remove(); + closeBtn.style.cssText = `background: none; border: none; color: #82e0aa; font-size: 13px; cursor: pointer; padding: 0; line-height: 1;`; header.appendChild(title); header.appendChild(closeBtn); @@ -70,6 +75,8 @@ api.addEventListener("o1key.update_available", (event) => { toast.appendChild(divider); toast.appendChild(text); document.body.appendChild(toast); + + startCountdown(toast, closeBtn, 5, "#82e0aa"); }); api.addEventListener("o1key.new_version", (event) => { @@ -81,7 +88,6 @@ api.addEventListener("o1key.new_version", (event) => { 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); @@ -94,7 +100,7 @@ api.addEventListener("o1key.new_version", (event) => { color: #d6eaf8; border: 1px solid #2e86c1; border-radius: 12px; - padding: 18px 20px 16px 20px; + padding: 12px 16px; 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); @@ -103,40 +109,39 @@ api.addEventListener("o1key.new_version", (event) => { `; const header = document.createElement("div"); - header.style.cssText = `display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px;`; + header.style.cssText = `display: flex; align-items: center; justify-content: space-between;`; 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(); + closeBtn.style.cssText = `background: none; border: none; color: #7fb3d3; font-size: 13px; cursor: pointer; padding: 0; line-height: 1;`; 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;`; + divider.style.cssText = `height: 1px; background: rgba(46,134,193,0.3); margin: 8px 0;`; + + toast.appendChild(header); + toast.appendChild(divider); 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;`; + line.style.cssText = `margin-bottom: 4px; font-size: 12px; 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;`; + more.style.cssText = `color: #7fb3d3; font-size: 12px; margin-top: 2px;`; body.appendChild(more); - toast.appendChild(header); - toast.appendChild(divider); toast.appendChild(body); document.body.appendChild(toast); + + startCountdown(toast, closeBtn, 5, "#7fb3d3"); });