This commit is contained in:
justumen
2025-02-27 18:00:12 +01:00
parent 6a21e32a42
commit 10263f2110
38 changed files with 1965 additions and 432 deletions

View File

@@ -0,0 +1,38 @@
import { app } from "../../../scripts/app.js";
import { api } from "../../../scripts/api.js";
app.registerExtension({
name: "Bjornulf.GlobalSeedManager",
async nodeCreated(node) {
// Ensure the button is added only to RandomSeedNode
if (node.comfyClass !== "Bjornulf_GlobalSeedManager") return;
// Add a button widget to the node
const deleteButton = node.addWidget(
"button", // Widget type
"Delete Seeds LIST", // Button label
null, // Initial value (not needed for buttons)
async () => {
// Ensure the node is still in the graph
if (!node.graph) return;
try {
// Make a POST request to the delete endpoint
const response = await fetch("/delete_random_seeds", {
method: "POST",
});
const data = await response.json();
// Show feedback to the user
if (data.success) {
app.ui.dialog.show("Seeds file deleted successfully.");
} else {
app.ui.dialog.show(`Failed to delete seeds file: ${data.error}`);
}
} catch (error) {
app.ui.dialog.show("An error occurred while deleting the seeds file.");
}
}
);
},
});

View File

@@ -1,80 +1,44 @@
import { app } from "../../../scripts/app.js";
app.registerExtension({
name: "Bjornulf.ImageNoteLoadImage",
async nodeCreated(node) {
// Ensure the node is of the specific class
if (node.comfyClass !== "Bjornulf_ImageNoteLoadImage") return;
console.log("node created");
setTimeout(() => {
// Update widget positions
node.onResize(node.size);
// Refresh all widgets
node.widgets.forEach(w => {
if (w.onShow?.(true)) {
w.onShow?.(false);
// Store the initial node size
let prevSize = [...node.size];
let stableCount = 0;
const minStableFrames = 3; // Number of frames the size must remain stable
// Function to check if the node's size has stabilized
const checkSizeStable = () => {
if (node.size[0] === prevSize[0] && node.size[1] === prevSize[1]) {
stableCount++;
if (stableCount >= minStableFrames) {
// Size has been stable, simulate a resize to trigger layout update
const originalSize = [...node.size];
node.setSize([originalSize[0] + 1, originalSize[1]]); // Slightly increase width
setTimeout(() => {
node.setSize(originalSize); // Revert to original size
app.graph.setDirtyCanvas(true, true); // Trigger canvas redraw
}, 0);
} else {
// Size is stable but not for enough frames yet, check again
requestAnimationFrame(checkSizeStable);
}
});
app.graph.setDirtyCanvas(true, true);
}, 500);
} else {
// Size changed, reset counter and update prevSize
prevSize = [...node.size];
stableCount = 0;
requestAnimationFrame(checkSizeStable);
}
};
// Start checking after a short delay to allow node initialization
setTimeout(() => {
requestAnimationFrame(checkSizeStable);
}, 5000);
}
});
// app.registerExtension({
// name: "Bjornulf.ImageNote",
// async nodeCreated(node) {
// if (node.comfyClass !== "Bjornulf_ImageNote") return;
// // Add Save Note button
// node.addWidget("button", "Save Note", null, () => {
// const imagePathWidget = node.widgets.find(w => w.name === "image_path");
// const noteTextWidget = node.widgets.find(w => w.name === "note_text");
// if (!imagePathWidget?.value) {
// return;
// }
// fetch("/save_note", {
// method: "POST",
// body: JSON.stringify({
// image_path: imagePathWidget.value,
// note_text: noteTextWidget?.value || ""
// }),
// headers: { "Content-Type": "application/json" }
// })
// .then(response => response.json())
// .catch(error => {
// console.error("Error saving note:", error);
// });
// });
// // Add Load Note button
// node.addWidget("button", "Load Note", null, () => {
// const imagePathWidget = node.widgets.find(w => w.name === "image_path");
// if (!imagePathWidget?.value) {
// return;
// }
// fetch("/load_note", {
// method: "POST",
// body: JSON.stringify({ image_path: imagePathWidget.value }),
// headers: { "Content-Type": "application/json" }
// })
// .then(response => response.json())
// .then(data => {
// if (data.success) {
// const noteTextWidget = node.widgets.find(w => w.name === "note_text");
// if (noteTextWidget) {
// noteTextWidget.value = data.note_text;
// // Trigger widget changed event to update UI
// app.graph.setDirtyCanvas(true);
// }
// }
// })
// .catch(error => {
// console.error("Error loading note:", error);
// });
// });
// }
// });

90
web/js/switches.js Normal file
View File

@@ -0,0 +1,90 @@
import { app } from "/scripts/app.js"; // Adjust path based on ComfyUI's structure
app.registerExtension({
name: "Bjornulf.SwitchText",
async nodeCreated(node) {
if (node.comfyClass === "Bjornulf_SwitchText") {
// Store original colors
const originalColor = ""; // Default ComfyUI node color
// Function to update color based on switch value
const updateNodeColor = () => {
const switchWidget = node.widgets?.find(w => w.name === "switch");
if (switchWidget) {
const isTrue = switchWidget.value;
node.color = isTrue ? originalColor : "#640000"; // Red when false
}
};
const updateNodeColorPickMe = () => {
const pickMeWidget = node.widgets?.find(w => w.name === "ONLY_ME_combine_text");
if (pickMeWidget) {
const isPicked = pickMeWidget.value;
node.color = isPicked ? "#000064" : originalColor; // Red when false
}
}
// Initial color update
updateNodeColor();
// Hook into widget value changes
const originalSetValue = node.widgets?.find(w => w.name === "switch")?.callback;
node.widgets.find(w => w.name === "switch").callback = function(value) {
updateNodeColor();
if (originalSetValue) {
originalSetValue.apply(this, arguments);
}
};
// Hook into widget value changes
const originalSetValuePickMe = node.widgets?.find(w => w.name === "ONLY_ME_combine_text")?.callback;
node.widgets.find(w => w.name === "ONLY_ME_combine_text").callback = function(value) {
updateNodeColorPickMe();
if (originalSetValuePickMe) {
originalSetValuePickMe.apply(this, arguments);
}
};
// Cleanup on node removal (optional but good practice)
node.onRemoved = function() {
node.color = originalColor;
};
}
}
});
app.registerExtension({
name: "Bjornulf.SwitchAnything",
async nodeCreated(node) {
if (node.comfyClass === "Bjornulf_SwitchAnything") {
// Store original colors
const originalColor = ""; // Default ComfyUI node color
// Function to update color based on switch value
const updateNodeColor = () => {
const switchWidget = node.widgets?.find(w => w.name === "switch");
if (switchWidget) {
const isTrue = switchWidget.value;
node.color = isTrue ? originalColor : "#640000"; // Red when false
}
};
// Initial color update
updateNodeColor();
// Hook into widget value changes
const originalSetValue = node.widgets?.find(w => w.name === "switch")?.callback;
node.widgets.find(w => w.name === "switch").callback = function(value) {
updateNodeColor();
if (originalSetValue) {
originalSetValue.apply(this, arguments);
}
};
// Cleanup on node removal (optional but good practice)
node.onRemoved = function() {
node.color = originalColor;
};
}
}
});

View File

@@ -1,7 +1,7 @@
import { api } from '../../../scripts/api.js';
import { app } from "../../../scripts/app.js";
function displayVideoPreview(component, filename, category) {
function displayVideoPreview(component, filename, category, autoplay, mute) {
let videoWidget = component._videoWidget;
if (!videoWidget) {
// Create the widget if it doesn't exist
@@ -61,6 +61,10 @@ function displayVideoPreview(component, filename, category) {
"rand": Math.random().toString().slice(2, 12)
};
const urlParams = new URLSearchParams(params);
if(mute) videoWidget.videoElement.muted = true;
else videoWidget.videoElement.muted = false;
if(autoplay) videoWidget.videoElement.autoplay = !videoWidget.value.paused && !videoWidget.value.hidden;
else videoWidget.videoElement.autoplay = false;
videoWidget.videoElement.src = `http://localhost:8188/api/view?${urlParams.toString()}`;
adjustSize(component); // Adjust the component size
@@ -76,8 +80,10 @@ app.registerExtension({
async beforeRegisterNodeDef(nodeType, nodeData, appInstance) {
if (nodeData?.name == "Bjornulf_VideoPreview") {
nodeType.prototype.onExecuted = function (data) {
displayVideoPreview(this, data.video[0], data.video[1]);
const autoplay = this.widgets.find(w => w.name === "autoplay")?.value ?? false;
const mute = this.widgets.find(w => w.name === "mute")?.value ?? true;
displayVideoPreview(this, data.video[0], data.video[1], autoplay, mute);
};
}
}
});
});

View File

@@ -2,56 +2,73 @@ import { app } from "../../../scripts/app.js";
// Helper function to clean up widget DOM elements
function cleanupWidgetDOM(widget) {
if (widget && widget.inputEl) {
if (widget.inputEl.parentElement) {
widget.inputEl.parentElement.remove();
} else {
widget.inputEl.remove();
}
if (widget && widget.inputEl) {
if (widget.inputEl.parentElement) {
widget.inputEl.parentElement.remove();
} else {
widget.inputEl.remove();
}
}
}
function getChainNodes(startNode) {
const nodes = [];
let currentNode = startNode;
const nodes = [];
let currentNode = startNode;
const visitedUpstream = new Set();
// First traverse upstream to find the root node
while (true) {
const input = currentNode.inputs.find(i => i.name === "pickme_chain");
if (input?.link) {
const link = app.graph.links[input.link];
const prevNode = app.graph.getNodeById(link.origin_id);
if (prevNode?.comfyClass === "Bjornulf_WriteTextPickMeChain") {
currentNode = prevNode;
} else {
break;
}
} else {
break;
}
// First traverse upstream to find the root node
while (true) {
if (visitedUpstream.has(currentNode.id)) {
throw new Error(
"Infinite loop detected! Nodes form a circular chain through 'pickme_chain' inputs"
);
}
visitedUpstream.add(currentNode.id);
// Now traverse downstream from root
while (currentNode) {
nodes.push(currentNode);
const output = currentNode.outputs.find(o => o.name === "chain_text");
if (output?.links) {
let nextNode = null;
for (const linkId of output.links) {
const link = app.graph.links[linkId];
const targetNode = app.graph.getNodeById(link.target_id);
if (targetNode?.comfyClass === "Bjornulf_WriteTextPickMeChain") {
nextNode = targetNode;
break;
}
}
currentNode = nextNode;
} else {
break;
}
const input = currentNode.inputs.find((i) => i.name === "pickme_chain");
if (input?.link) {
const link = app.graph.links[input.link];
const prevNode = app.graph.getNodeById(link.origin_id);
if (prevNode?.comfyClass === "Bjornulf_WriteTextPickMeChain") {
currentNode = prevNode;
} else {
break;
}
} else {
break;
}
}
return nodes;
// Now traverse downstream from root
const visitedDownstream = new Set();
while (currentNode) {
if (visitedDownstream.has(currentNode.id)) {
app.ui.dialog.show("Infinite loop detected! Nodes form a circular chain through 'chain_text' outputs");
throw new Error(
"Infinite loop detected! Nodes form a circular chain through 'chain_text' outputs"
);
}
visitedDownstream.add(currentNode.id);
nodes.push(currentNode);
const output = currentNode.outputs.find((o) => o.name === "chain_text");
if (output?.links) {
let nextNode = null;
for (const linkId of output.links) {
const link = app.graph.links[linkId];
const targetNode = app.graph.getNodeById(link.target_id);
if (targetNode?.comfyClass === "Bjornulf_WriteTextPickMeChain") {
nextNode = targetNode;
break;
}
}
currentNode = nextNode;
} else {
break;
}
}
return nodes;
}
function pickNode(node) {
@@ -67,8 +84,6 @@ function pickNode(node) {
app.graph.setDirtyCanvas(true, true);
}
// Rest of the code remains the same as previous working version
function findAndPickNext(removedNode) {
const chainNodes = getChainNodes(removedNode);
const remaining = chainNodes.filter(n => n.id !== removedNode.id);
@@ -76,97 +91,100 @@ function findAndPickNext(removedNode) {
}
app.registerExtension({
name: "Bjornulf.WriteTextPickMeChain",
async nodeCreated(node) {
if (node.comfyClass === "Bjornulf_WriteTextPickMeChain") {
// Store original onRemoved if it exists
const origOnRemoved = node.onRemoved;
// Create widgets in specific order to maintain layout
// const textWidget = node.widgets.find(w => w.name === "text");
// if (textWidget) {
// textWidget.computeSize = function() {
// return [node.size[0] - 20, 150];
// };
// }
name: "Bjornulf.WriteTextPickMeChain",
async nodeCreated(node) {
if (node.comfyClass === "Bjornulf_WriteTextPickMeChain") {
// Store original onRemoved if it exists
const origOnRemoved = node.onRemoved;
// Create widgets in specific order to maintain layout
// const textWidget = node.widgets.find(w => w.name === "text");
// if (textWidget) {
// textWidget.computeSize = function() {
// return [node.size[0] - 20, 150];
// };
// }
// Handle picked widget
let pickedWidget = node.widgets.find(w => w.name === "picked");
if (!pickedWidget) {
pickedWidget = node.addWidget("BOOLEAN", "picked", false, null);
}
pickedWidget.visible = false;
// Handle picked widget
let pickedWidget = node.widgets.find((w) => w.name === "picked");
if (!pickedWidget) {
pickedWidget = node.addWidget("BOOLEAN", "picked", false, null);
}
pickedWidget.visible = false;
// Add button after textarea
const buttonWidget = node.addWidget("button", "PICK ME", null, () => pickNode(node));
buttonWidget.computeSize = function() {
return [node.size[0] - 20, 30];
};
// Add button after textarea
const buttonWidget = node.addWidget("button", "PICK ME", null, () =>
pickNode(node)
);
buttonWidget.computeSize = function () {
return [node.size[0] - 20, 30];
};
// Set initial node size
// node.size = [node.size[0], 200];
// node.size = [200, 200];
setTimeout(() => {
// Update widget positions
node.onResize(node.size);
// Refresh all widgets
node.widgets.forEach(w => {
if (w.onShow?.(true)) {
w.onShow?.(false);
}
});
app.graph.setDirtyCanvas(true, true);
}, 10);
// Set initial node size
// node.size = [node.size[0], 200];
// node.size = [200, 200];
setTimeout(() => {
// Update widget positions
node.onResize(node.size);
// Enhanced cleanup on node removal
node.onRemoved = function() {
// Call original onRemoved if it exists
if (origOnRemoved) {
origOnRemoved.call(this);
}
// Refresh all widgets
node.widgets.forEach((w) => {
if (w.onShow?.(true)) {
w.onShow?.(false);
}
});
// Handle chain updates
if (this.widgets.find(w => w.name === "picked")?.value) {
findAndPickNext(this);
}
app.graph.setDirtyCanvas(true, true);
}, 10);
// Clean up all widgets
for (const widget of this.widgets) {
cleanupWidgetDOM(widget);
}
// Force DOM cleanup and canvas update
if (this.domElement) {
this.domElement.remove();
}
app.graph.setDirtyCanvas(true, true);
};
const updateColors = () => {
const picked = node.widgets.find(w => w.name === "picked")?.value;
node.color = picked ? "#006400" : "";
};
const origSetNodeState = node.setNodeState;
node.setNodeState = function(state) {
origSetNodeState?.apply(this, arguments);
if (state.picked !== undefined) {
const widget = this.widgets.find(w => w.name === "picked");
if (widget) widget.value = state.picked;
}
updateColors();
};
const origGetNodeState = node.getNodeState;
node.getNodeState = function() {
const state = origGetNodeState?.apply(this, arguments) || {};
state.picked = this.widgets.find(w => w.name === "picked")?.value ?? false;
return state;
};
// Force initial layout update
app.graph.setDirtyCanvas(true, true);
// Enhanced cleanup on node removal
node.onRemoved = function () {
// Call original onRemoved if it exists
if (origOnRemoved) {
origOnRemoved.call(this);
}
// Handle chain updates
if (this.widgets.find((w) => w.name === "picked")?.value) {
findAndPickNext(this);
}
// Clean up all widgets
for (const widget of this.widgets) {
cleanupWidgetDOM(widget);
}
// Force DOM cleanup and canvas update
if (this.domElement) {
this.domElement.remove();
}
app.graph.setDirtyCanvas(true, true);
};
const updateColors = () => {
const picked = node.widgets.find((w) => w.name === "picked")?.value;
node.color = picked ? "#006400" : "";
};
const origSetNodeState = node.setNodeState;
node.setNodeState = function (state) {
origSetNodeState?.apply(this, arguments);
if (state.picked !== undefined) {
const widget = this.widgets.find((w) => w.name === "picked");
if (widget) widget.value = state.picked;
}
updateColors();
};
const origGetNodeState = node.getNodeState;
node.getNodeState = function () {
const state = origGetNodeState?.apply(this, arguments) || {};
state.picked =
this.widgets.find((w) => w.name === "picked")?.value ?? false;
return state;
};
// Force initial layout update
app.graph.setDirtyCanvas(true, true);
}
},
});

View File

@@ -0,0 +1,85 @@
import { app } from "../../../scripts/app.js";
// Function to pick a node within its global_pickme_id group
function pickGlobalNode(node) {
const global_pickme_idWidget = node.widgets.find(w => w.name === "global_pickme_id");
const global_pickme_id = global_pickme_idWidget ? global_pickme_idWidget.value : "default";
// Iterate through all nodes in the graph
app.graph._nodes.forEach(n => {
if (n.comfyClass === "Bjornulf_WriteTextPickMeGlobal") {
const nglobal_pickme_idWidget = n.widgets.find(w => w.name === "global_pickme_id");
const nglobal_pickme_id = nglobal_pickme_idWidget ? nglobal_pickme_idWidget.value : "default";
if (nglobal_pickme_id === global_pickme_id) { // Only affect nodes in the same group
const pickedWidget = n.widgets.find(w => w.name === "picked");
if (pickedWidget) {
pickedWidget.value = (n === node); // Pick this node, unpick others in group
}
n.color = (n === node) ? "#006400" : ""; // Green for picked, default otherwise
}
}
});
app.graph.setDirtyCanvas(true, true); // Refresh the canvas
}
app.registerExtension({
name: "Bjornulf.WriteTextPickMeGlobal",
async nodeCreated(node) {
if (node.comfyClass === "Bjornulf_WriteTextPickMeGlobal") {
// Hide the picked widget from the UI
const pickedWidget = node.widgets.find(w => w.name === "picked");
if (pickedWidget && pickedWidget.inputEl) {
pickedWidget.inputEl.style.display = "none";
}
// Add "PICK ME" button
const buttonWidget = node.addWidget("button", "PICK ME", null, () => {
pickGlobalNode(node); // Handle picking within the group
});
buttonWidget.computeSize = function () {
return [node.size[0] - 20, 30]; // Size the button
};
// Function to update node color based on picked state
const updateColors = () => {
const picked = node.widgets.find(w => w.name === "picked")?.value;
node.color = picked ? "#006400" : ""; // Green if picked
};
updateColors(); // Set initial color
// Handle global_pickme_id changes
const global_pickme_idWidget = node.widgets.find(w => w.name === "global_pickme_id");
if (global_pickme_idWidget) {
global_pickme_idWidget.onChange = function() {
const pickedWidget = node.widgets.find(w => w.name === "picked");
if (pickedWidget && pickedWidget.value) {
pickedWidget.value = false; // Unpick if global_pickme_id changes
node.color = "";
app.graph.setDirtyCanvas(true, true);
}
};
}
// State management for saving/loading
const origSetNodeState = node.setNodeState;
node.setNodeState = function (state) {
origSetNodeState?.apply(this, arguments);
if (state.picked !== undefined) {
const widget = this.widgets.find(w => w.name === "picked");
if (widget) widget.value = state.picked;
}
updateColors();
};
const origGetNodeState = node.getNodeState;
node.getNodeState = function () {
const state = origGetNodeState?.apply(this, arguments) || {};
state.picked = this.widgets.find(w => w.name === "picked")?.value ?? false;
return state;
};
// Refresh canvas on load
app.graph.setDirtyCanvas(true, true);
}
}
});