Files
magicwang1111-Comfyui-Kling…/web/js/kling4DynamicInputs.js
T

91 lines
5.0 KiB
JavaScript

import { app } from "../../../scripts/app.js";
import { updateImageReferences, IMAGE_ORDER_HELP, legacyImageWarning } from "./kling4ImageReferences.js";
const NODE = "Comfyui-Kling-Wrapper Kling 4.0 OmniVideo";
export function stabilizeInputs(node) {
if (node.kling4Stabilizing) return;
node.kling4Stabilizing = true;
try {
const linked = (name) => node.inputs?.some(i => i.name === name && i.link != null);
const base = linked("base_video") || linked("base_video_url") || !!String(node.widgets?.find(w => w.name === "base_video_url")?.value || "").trim();
const legacyVideo = linked("feature_video");
for (const name of ["reference_images", "feature_video"]) {
const index = node.inputs?.findIndex(i => i.name === name && i.link == null);
if (index >= 0) node.removeInput(index);
}
for (const [prefix, type, limit] of [["image", "IMAGE", 10], ["feature_video", "VIDEO", 5 - Number(base) - Number(legacyVideo)]]) {
const pattern = new RegExp(`^${prefix}_(\\d+)$`);
const matches = () => node.inputs.filter(i => pattern.test(i.name));
const connected = matches().filter(i => i.link != null);
const used = new Set(connected.map(i => Number(i.name.match(pattern)[1])));
const legacyImages = prefix === "image" && linked("reference_images");
let available = 1;
while (used.has(available)) available++;
const wanted = !legacyImages && connected.length < limit && available <= (prefix === "image" ? 10 : 5)
? `${prefix}_${available}` : null;
for (let index = node.inputs.length - 1; index >= 0; index--) {
const input = node.inputs[index];
if (pattern.test(input.name) && input.link == null && input.name !== wanted) node.removeInput(index);
}
if (wanted && !node.inputs.some(i => i.name === wanted)) node.addInput(wanted, type);
for (const input of matches()) {
const index = Number(input.name.match(pattern)[1]);
const marker = prefix === "image" ? `image_${index}` : `video_${index + Number(base) + Number(legacyVideo)}`;
input.label = `${input.name} → @${marker}`;
input.kling4Reference = marker;
}
}
const baseInput = node.inputs.find(i => i.name === "base_video");
if (baseInput) baseInput.label = "base_video → @video_1(接入时占用)";
const legacy = node.inputs.find(i => i.name === "feature_video");
if (legacy) legacy.label = `feature_video → @video_${base ? 2 : 1}(旧输入)`;
const images = updateImageReferences(node);
const markers = [...images.markers, ...node.inputs.filter(i => i.name.startsWith("feature_video_") && i.kling4Reference).map(i => i.kling4Reference)];
if (!images.markers.length && !images.uncertain) markers.unshift("image_1");
if (base || legacyVideo) markers.push("video_1");
if (base && legacyVideo) markers.push("video_2");
node.kling4ReferencePreview?.setReferences([...new Set([...markers, "element_1", "voice_1"])],
`${IMAGE_ORDER_HELP} ${images.uncertain ? "上游批次张数未知,后续图片编号将在执行时确定。" : ""} ${base ? "base_video = @video_1;特征视频引用号已后移。" : "未提供 base_video;特征视频从 @video_1 开始。"} 总素材≤15,执行前按实际数量校验。${legacyImageWarning(node)}`);
} finally {
node.kling4Stabilizing = false;
}
node.graph?.setDirtyCanvas(true, true);
}
function schedule(node) {
clearTimeout(node.kling4DynamicTimer);
node.kling4DynamicTimer = setTimeout(() => {
node.kling4DynamicTimer = null;
stabilizeInputs(node);
}, 32);
}
app.registerExtension({
name: "ComfyuiKlingWrapper.Kling4DynamicInputs",
beforeRegisterNodeDef(nodeType, data) {
if (data.name !== NODE) return;
for (const event of ["onNodeCreated", "onConfigure", "onConnectionsChange"]) {
const original = nodeType.prototype[event];
nodeType.prototype[event] = function () {
const result = original?.apply(this, arguments);
schedule(this);
if (event === "onNodeCreated") {
this.kling4RefreshReferences = () => schedule(this);
const widget = this.widgets?.find(w => w.name === "base_video_url");
if (widget) {
const callback = widget.callback;
widget.callback = (...args) => { const result = callback?.apply(widget, args); schedule(this); return result; };
}
}
return result;
};
}
const removed = nodeType.prototype.onRemoved;
nodeType.prototype.onRemoved = function () {
clearTimeout(this.kling4DynamicTimer);
return removed?.apply(this, arguments);
};
},
});