First commit
This commit is contained in:
107
js/vibevoice_wrapper_ui.js
Normal file
107
js/vibevoice_wrapper_ui.js
Normal file
@ -0,0 +1,107 @@
|
||||
// custom_nodes/YourPkg/js/vibevoice_wrapper_ui.js
|
||||
import { app } from "../../scripts/app.js";
|
||||
|
||||
app.registerExtension({
|
||||
name: "vibevoice.wrapper.ui",
|
||||
|
||||
async beforeRegisterNodeDef(nodeType, nodeData) {
|
||||
const isWrapper =
|
||||
nodeType?.comfyClass === "VibeVoiceTTS_Wrapper" ||
|
||||
nodeData?.name === "VibeVoice TTS (Chunked Wrapper)";
|
||||
if (!isWrapper) return;
|
||||
|
||||
const origOnCreated = nodeType.prototype.onNodeCreated;
|
||||
nodeType.prototype.onNodeCreated = function () {
|
||||
origOnCreated?.apply(this, arguments);
|
||||
// only set up handlers here; do NOT mutate slots yet
|
||||
wireUpHandlers(this);
|
||||
};
|
||||
|
||||
function wireUpHandlers(node) {
|
||||
const findW = (n) => node.widgets?.find((w) => w.name === n);
|
||||
const wNum = findW("num_speakers");
|
||||
const wChunk = findW("chunk_lines");
|
||||
const wLines = findW("lines_per_chunk");
|
||||
|
||||
function ensureSpeakerInputs(count) {
|
||||
// add missing inputs
|
||||
for (let i = 1; i <= count; i++) {
|
||||
const name = `speaker_${i}_voice`;
|
||||
if (node.findInputSlot(name) === -1) node.addInput(name, "AUDIO");
|
||||
}
|
||||
// remove extras
|
||||
for (let i = count + 1; i <= 4; i++) {
|
||||
const name = `speaker_${i}_voice`;
|
||||
const idx = node.findInputSlot(name);
|
||||
if (idx !== -1) node.removeInput(idx);
|
||||
}
|
||||
}
|
||||
|
||||
// guard: only mutate once node.graph exists (prevents NullGraphError)
|
||||
function safeMutate(fn) {
|
||||
const doIt = () => {
|
||||
if (!node.graph) {
|
||||
// defer until the node is actually attached to a graph
|
||||
setTimeout(doIt, 0);
|
||||
return;
|
||||
}
|
||||
fn();
|
||||
app.graph.setDirtyCanvas(true, true);
|
||||
};
|
||||
doIt();
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
const n = Math.max(1, Math.min(4, Number(wNum?.value ?? 1)));
|
||||
safeMutate(() => ensureSpeakerInputs(n));
|
||||
|
||||
if (wLines) wLines.hidden = !(wChunk?.value);
|
||||
}
|
||||
|
||||
// robust wiring (some frontends only call one of these)
|
||||
if (wNum) { wNum.callback = refresh; wNum.onChange = refresh; }
|
||||
if (wChunk) { wChunk.callback = refresh; wChunk.onChange = refresh; }
|
||||
|
||||
// don’t call refresh yet; node may not be in graph during configure
|
||||
node.__vv_refresh = refresh;
|
||||
}
|
||||
},
|
||||
|
||||
// Called for brand-new nodes added from the menu (node has a graph here)
|
||||
async nodeCreated(node) {
|
||||
if (
|
||||
node?.comfyClass === "VibeVoiceTTS_Wrapper" ||
|
||||
node?.title === "VibeVoice TTS (Chunked Wrapper)"
|
||||
) {
|
||||
// next tick to ensure widgets fully exist
|
||||
setTimeout(() => node.__vv_refresh?.(), 0);
|
||||
}
|
||||
},
|
||||
|
||||
// Called when nodes are created as part of loading a workflow
|
||||
loadedGraphNode(node) {
|
||||
if (
|
||||
node?.comfyClass === "VibeVoiceTTS_Wrapper" ||
|
||||
node?.title === "VibeVoice TTS (Chunked Wrapper)"
|
||||
) {
|
||||
setTimeout(() => node.__vv_refresh?.(), 0);
|
||||
}
|
||||
},
|
||||
|
||||
// After the graph finishes configuring (safe point to mutate slots)
|
||||
async afterConfigureGraph() {
|
||||
// final pass in case anything was deferred
|
||||
for (const node of app.graph._nodes) {
|
||||
if (
|
||||
node?.comfyClass === "VibeVoiceTTS_Wrapper" ||
|
||||
node?.title === "VibeVoice TTS (Chunked Wrapper)"
|
||||
) {
|
||||
node.__vv_refresh?.();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async setup() {
|
||||
console.log("[vibevoice.wrapper.ui] setup complete");
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user