- Restore __init__.py with full node registration and SQS worker startup - Add missing controllers.py with NilorPreset and NilorGroup nodes - Add missing user_input.py with NilorUserInput_* nodes - Add missing web/js/media_stream.js for MediaStreamOutput UI extensions - Add missing web/js/controllers.js for controller node UI extensions - Add missing worker_consumer.py for SQS job processing - Add missing .env.example for environment configuration - Fixes missing custom nodes and SQS worker functionality on working branch
273 lines
8.3 KiB
JavaScript
273 lines
8.3 KiB
JavaScript
import { app } from "/scripts/app.js";
|
|
|
|
// NilorPreset dynamic inputs extension
|
|
// Adds a new empty _input_hook_N slot whenever the last slot gets connected, up to a hard cap
|
|
|
|
const MAX_INPUTS = 32;
|
|
// Preset controller constants
|
|
const CLASS_TYPE = "NilorPreset";
|
|
const INPUT_PREFIX = "_preset_hook_";
|
|
|
|
function isTargetNode(node) {
|
|
return node && (node.comfyClass === CLASS_TYPE || node.type === CLASS_TYPE);
|
|
}
|
|
|
|
function countHookInputs(node) {
|
|
return (node.inputs || []).filter((i) => i && i.name?.startsWith(INPUT_PREFIX)).length;
|
|
}
|
|
|
|
function nextInputName(node) {
|
|
let index = 1;
|
|
while (index <= MAX_INPUTS) {
|
|
const key = `${INPUT_PREFIX}${index}`;
|
|
if (!node.inputs || !node.inputs.find((i) => i.name === key)) {
|
|
return key;
|
|
}
|
|
index++;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function resizeNode(node) {
|
|
try {
|
|
const size = node.computeSize();
|
|
node.onResize?.(size);
|
|
app.graph?.setDirtyCanvas(true, true);
|
|
} catch (_) {}
|
|
}
|
|
|
|
function ensureAtLeastOneSlot(node) {
|
|
if (!isTargetNode(node)) return;
|
|
if (countHookInputs(node) === 0) {
|
|
const name = `${INPUT_PREFIX}1`;
|
|
node.addInput(name, "CONTROLLER_HOOK");
|
|
resizeNode(node);
|
|
}
|
|
}
|
|
|
|
function growIfLastLinked(node) {
|
|
if (!isTargetNode(node)) return;
|
|
const inputs = (node.inputs || []).filter((i) => i && i.name?.startsWith(INPUT_PREFIX));
|
|
if (inputs.length === 0) return;
|
|
const last = inputs[inputs.length - 1];
|
|
const lastIsLinked = !!last.link;
|
|
if (lastIsLinked && inputs.length < MAX_INPUTS) {
|
|
const name = nextInputName(node);
|
|
if (name) {
|
|
node.addInput(name, "CONTROLLER_HOOK");
|
|
resizeNode(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
function shrinkTrailingUnlinked(node) {
|
|
if (!isTargetNode(node)) return;
|
|
const allInputs = node.inputs || [];
|
|
// Collect indices of hook inputs
|
|
const hookIndices = [];
|
|
for (let i = 0; i < allInputs.length; i++) {
|
|
const inp = allInputs[i];
|
|
if (inp && inp.name && inp.name.startsWith(INPUT_PREFIX)) {
|
|
hookIndices.push(i);
|
|
}
|
|
}
|
|
if (hookIndices.length <= 1) return; // always keep at least one
|
|
|
|
// Find last linked among hook inputs (by position in hookIndices)
|
|
let lastLinkedPos = -1;
|
|
for (let pos = 0; pos < hookIndices.length; pos++) {
|
|
const idx = hookIndices[pos];
|
|
if (allInputs[idx]?.link) lastLinkedPos = pos;
|
|
}
|
|
|
|
const targetHookCount = lastLinkedPos >= 0 ? lastLinkedPos + 1 : 1;
|
|
|
|
// Remove trailing unlinked beyond targetHookCount
|
|
for (let pos = hookIndices.length - 1; pos >= targetHookCount; pos--) {
|
|
const idx = hookIndices[pos];
|
|
const input = node.inputs[idx];
|
|
if (input && !input.link) {
|
|
try {
|
|
node.removeInput(idx);
|
|
} catch (e) {
|
|
console.warn("nilor-preset-dynamic-inputs removeInput error", e);
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
resizeNode(node);
|
|
}
|
|
|
|
app.registerExtension({
|
|
name: "comfy.nilor-nodes.userinputPreset",
|
|
|
|
// Ensure compatibility with saved/loaded graphs
|
|
afterConfigureGraph(graph) {
|
|
try {
|
|
(graph?._nodes || graph?.nodes || []).forEach((n) => {
|
|
if (isTargetNode(n)) {
|
|
ensureAtLeastOneSlot(n);
|
|
shrinkTrailingUnlinked(n);
|
|
growIfLastLinked(n);
|
|
}
|
|
});
|
|
} catch (e) {
|
|
console.warn("nilor-preset-dynamic-inputs afterConfigureGraph error", e);
|
|
}
|
|
},
|
|
|
|
// Patch the prototype so we always react to connection changes
|
|
async beforeRegisterNodeDef(nodeType, nodeData, appInstance) {
|
|
if (nodeData?.name !== CLASS_TYPE) return;
|
|
const original = nodeType.prototype.onConnectionsChange;
|
|
nodeType.prototype.onConnectionsChange = function (type, index, connected, link_info) {
|
|
if (typeof original === "function") {
|
|
original.apply(this, arguments);
|
|
}
|
|
try {
|
|
shrinkTrailingUnlinked(this);
|
|
growIfLastLinked(this);
|
|
} catch (e) {
|
|
console.warn("nilor-preset-dynamic-inputs onConnectionsChange error", e);
|
|
}
|
|
};
|
|
},
|
|
|
|
nodeCreated(node) {
|
|
if (!isTargetNode(node)) return;
|
|
ensureAtLeastOneSlot(node);
|
|
shrinkTrailingUnlinked(node);
|
|
growIfLastLinked(node);
|
|
},
|
|
});
|
|
|
|
|
|
// NilorGroup dynamic inputs extension (mirrors preset behavior)
|
|
const GROUP_CLASS_TYPE = "NilorGroup";
|
|
const GROUP_INPUT_PREFIX = "_group_hook_";
|
|
|
|
function isGroupNode(node) {
|
|
return node && (node.comfyClass === GROUP_CLASS_TYPE || node.type === GROUP_CLASS_TYPE);
|
|
}
|
|
|
|
function countGroupHookInputs(node) {
|
|
return (node.inputs || []).filter((i) => i && i.name?.startsWith(GROUP_INPUT_PREFIX)).length;
|
|
}
|
|
|
|
function nextGroupInputName(node) {
|
|
let index = 1;
|
|
while (index <= MAX_INPUTS) {
|
|
const key = `${GROUP_INPUT_PREFIX}${index}`;
|
|
if (!node.inputs || !node.inputs.find((i) => i.name === key)) {
|
|
return key;
|
|
}
|
|
index++;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function ensureAtLeastOneGroupSlot(node) {
|
|
if (!isGroupNode(node)) return;
|
|
if (countGroupHookInputs(node) === 0) {
|
|
const name = `${GROUP_INPUT_PREFIX}1`;
|
|
node.addInput(name, "CONTROLLER_HOOK");
|
|
resizeNode(node);
|
|
}
|
|
}
|
|
|
|
function growGroupIfLastLinked(node) {
|
|
if (!isGroupNode(node)) return;
|
|
const inputs = (node.inputs || []).filter((i) => i && i.name?.startsWith(GROUP_INPUT_PREFIX));
|
|
if (inputs.length === 0) return;
|
|
const last = inputs[inputs.length - 1];
|
|
const lastIsLinked = !!last.link;
|
|
if (lastIsLinked && inputs.length < MAX_INPUTS) {
|
|
const name = nextGroupInputName(node);
|
|
if (name) {
|
|
node.addInput(name, "CONTROLLER_HOOK");
|
|
resizeNode(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
function shrinkGroupTrailingUnlinked(node) {
|
|
if (!isGroupNode(node)) return;
|
|
const allInputs = node.inputs || [];
|
|
const hookIndices = [];
|
|
for (let i = 0; i < allInputs.length; i++) {
|
|
const inp = allInputs[i];
|
|
if (inp && inp.name && inp.name.startsWith(GROUP_INPUT_PREFIX)) {
|
|
hookIndices.push(i);
|
|
}
|
|
}
|
|
if (hookIndices.length <= 1) return;
|
|
|
|
let lastLinkedPos = -1;
|
|
for (let pos = 0; pos < hookIndices.length; pos++) {
|
|
const idx = hookIndices[pos];
|
|
if (allInputs[idx]?.link) lastLinkedPos = pos;
|
|
}
|
|
|
|
const targetHookCount = lastLinkedPos >= 0 ? lastLinkedPos + 1 : 1;
|
|
|
|
for (let pos = hookIndices.length - 1; pos >= targetHookCount; pos--) {
|
|
const idx = hookIndices[pos];
|
|
const input = node.inputs[idx];
|
|
if (input && !input.link) {
|
|
try {
|
|
node.removeInput(idx);
|
|
} catch (e) {
|
|
console.warn("nilor-group-dynamic-inputs removeInput error", e);
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
resizeNode(node);
|
|
}
|
|
|
|
app.registerExtension({
|
|
name: "comfy.nilor-nodes.userinputGroup",
|
|
|
|
afterConfigureGraph(graph) {
|
|
try {
|
|
(graph?._nodes || graph?.nodes || []).forEach((n) => {
|
|
if (isGroupNode(n)) {
|
|
ensureAtLeastOneGroupSlot(n);
|
|
shrinkGroupTrailingUnlinked(n);
|
|
growGroupIfLastLinked(n);
|
|
}
|
|
});
|
|
} catch (e) {
|
|
console.warn("nilor-group-dynamic-inputs afterConfigureGraph error", e);
|
|
}
|
|
},
|
|
|
|
async beforeRegisterNodeDef(nodeType, nodeData, appInstance) {
|
|
if (nodeData?.name !== GROUP_CLASS_TYPE) return;
|
|
const original = nodeType.prototype.onConnectionsChange;
|
|
nodeType.prototype.onConnectionsChange = function (type, index, connected, link_info) {
|
|
if (typeof original === "function") {
|
|
original.apply(this, arguments);
|
|
}
|
|
try {
|
|
shrinkGroupTrailingUnlinked(this);
|
|
growGroupIfLastLinked(this);
|
|
} catch (e) {
|
|
console.warn("nilor-group-dynamic-inputs onConnectionsChange error", e);
|
|
}
|
|
};
|
|
},
|
|
|
|
nodeCreated(node) {
|
|
if (!isGroupNode(node)) return;
|
|
ensureAtLeastOneGroupSlot(node);
|
|
shrinkGroupTrailingUnlinked(node);
|
|
growGroupIfLastLinked(node);
|
|
},
|
|
});
|
|
|