mirror of
https://github.com/justUmen/Bjornulf_custom_nodes.git
synced 2026-03-21 20:52:11 -03:00
0.77
This commit is contained in:
@@ -26,4 +26,52 @@ app.registerExtension({
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
app.registerExtension({
|
||||
name: "Bjornulf.LoadCivitAILinks",
|
||||
async nodeCreated(node) {
|
||||
if (node.comfyClass === "Bjornulf_LoadCivitAILinks") {
|
||||
// Add a refresh button widget
|
||||
const refreshButton = node.addWidget(
|
||||
"button",
|
||||
"Refresh File List",
|
||||
null,
|
||||
() => {
|
||||
fetch("/get_civitai_links_files", {
|
||||
method: "POST",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
if (data.success) {
|
||||
// Update the dropdown with the new file list
|
||||
const dropdownWidget = node.widgets.find(w => w.name === "selected_file");
|
||||
if (dropdownWidget) {
|
||||
dropdownWidget.options.values = ["Not selected", ...data.files];
|
||||
dropdownWidget.value = "Not selected";
|
||||
app.ui.dialog.show(
|
||||
"[LoadCivitAILinks] File list refreshed successfully!"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
app.ui.dialog.show(
|
||||
`[LoadCivitAILinks] Failed to refresh file list: ${
|
||||
data.error || "Unknown error"
|
||||
}`
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(
|
||||
"[LoadCivitAILinks] Error fetching links files:",
|
||||
error
|
||||
);
|
||||
app.ui.dialog.show(
|
||||
"[LoadCivitAILinks] An error occurred while refreshing the file list."
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
81
web/js/audio_preview.js
Normal file
81
web/js/audio_preview.js
Normal file
@@ -0,0 +1,81 @@
|
||||
import { api } from '../../../scripts/api.js';
|
||||
import { app } from "../../../scripts/app.js";
|
||||
|
||||
// Function to display the audio preview
|
||||
function displayAudioPreview(component, filename, category, autoplay, mute, loop) {
|
||||
let audioWidget = component._audioWidget;
|
||||
|
||||
// Create the audio widget if it doesn't exist
|
||||
if (!audioWidget) {
|
||||
const container = document.createElement("div");
|
||||
|
||||
// Add the DOM widget to the component
|
||||
audioWidget = component.addDOMWidget("Bjornulf", "preview", container, {
|
||||
serialize: false,
|
||||
hideOnZoom: false,
|
||||
getValue() {
|
||||
return container.value;
|
||||
},
|
||||
setValue(v) {
|
||||
container.value = v;
|
||||
},
|
||||
});
|
||||
|
||||
// Initialize widget properties
|
||||
audioWidget.value = { hidden: false, paused: false, params: {} };
|
||||
audioWidget.parentElement = document.createElement("div");
|
||||
audioWidget.parentElement.className = "audio_preview";
|
||||
audioWidget.parentElement.style.width = "100%";
|
||||
audioWidget.parentElement.style.marginBottom = "50px";
|
||||
container.appendChild(audioWidget.parentElement);
|
||||
|
||||
// Create the audio element
|
||||
audioWidget.audioElement = document.createElement("audio");
|
||||
audioWidget.audioElement.controls = true;
|
||||
audioWidget.audioElement.style.width = "100%";
|
||||
|
||||
// Hide the audio player on error
|
||||
audioWidget.audioElement.addEventListener("error", () => {
|
||||
audioWidget.parentElement.hidden = true;
|
||||
});
|
||||
|
||||
audioWidget.parentElement.hidden = audioWidget.value.hidden;
|
||||
audioWidget.parentElement.appendChild(audioWidget.audioElement);
|
||||
component._audioWidget = audioWidget; // Store for reuse
|
||||
}
|
||||
|
||||
// Set audio source and properties
|
||||
const params = {
|
||||
"filename": filename,
|
||||
"subfolder": category,
|
||||
"type": "temp",
|
||||
"rand": Math.random().toString().slice(2, 12) // Cache-busting random parameter
|
||||
};
|
||||
|
||||
const urlParams = new URLSearchParams(params);
|
||||
audioWidget.audioElement.src = `api/view?${urlParams.toString()}`;
|
||||
audioWidget.audioElement.autoplay = autoplay && !audioWidget.value.paused && !audioWidget.value.hidden;
|
||||
audioWidget.audioElement.loop = loop;
|
||||
}
|
||||
|
||||
// Register the extension
|
||||
app.registerExtension({
|
||||
name: "Bjornulf.AudioPreview",
|
||||
async beforeRegisterNodeDef(nodeType, nodeData, appInstance) {
|
||||
if (nodeData?.name === "Bjornulf_AudioPreview") {
|
||||
// Define behavior when the node executes
|
||||
nodeType.prototype.onExecuted = function(data) {
|
||||
const autoplay = this.widgets.find(w => w.name === "autoplay")?.value ?? false;
|
||||
const loop = this.widgets.find(w => w.name === "loop")?.value ?? false;
|
||||
displayAudioPreview(this, data.audio[0], data.audio[1], autoplay, loop);
|
||||
};
|
||||
|
||||
// Override computeSize to set a fixed height
|
||||
nodeType.prototype.computeSize = function() {
|
||||
const size = LiteGraph.LGraphNode.prototype.computeSize.call(this);
|
||||
size[1] = 150; // Fixed height of 150px
|
||||
return size;
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
53
web/js/fix_face.js
Normal file
53
web/js/fix_face.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import { app } from "../../../scripts/app.js";
|
||||
|
||||
app.registerExtension({
|
||||
name: "Bjornulf.FixFace",
|
||||
async nodeCreated(node) {
|
||||
if (node.comfyClass === "Bjornulf_FixFace") {
|
||||
const updateInputs = () => {
|
||||
const initialWidth = node.size[0];
|
||||
const numFacesWidget = node.widgets.find(w => w.name === "number_of_faces");
|
||||
if (!numFacesWidget) return;
|
||||
|
||||
const numFaces = numFacesWidget.value;
|
||||
|
||||
// Initialize node.inputs if it doesn't exist
|
||||
if (!node.inputs) {
|
||||
node.inputs = [];
|
||||
}
|
||||
|
||||
// Filter existing FACE_SETTINGS inputs
|
||||
const existingInputs = node.inputs.filter(input => input.name.startsWith('FACE_SETTINGS_'));
|
||||
|
||||
// Add or remove inputs based on number_of_faces
|
||||
if (existingInputs.length < numFaces) {
|
||||
for (let i = existingInputs.length + 1; i <= numFaces; i++) {
|
||||
const inputName = `FACE_SETTINGS_${i}`;
|
||||
if (!node.inputs.find(input => input.name === inputName)) {
|
||||
node.addInput(inputName, "FACE_SETTINGS");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
node.inputs = node.inputs.filter(input => !input.name.startsWith('FACE_SETTINGS_') ||
|
||||
parseInt(input.name.split('_')[2]) <= numFaces);
|
||||
}
|
||||
|
||||
node.setSize(node.computeSize());
|
||||
node.size[0] = initialWidth; // Keep width fixed
|
||||
};
|
||||
|
||||
// Move number_of_faces widget to the top and set callback
|
||||
const numFacesWidget = node.widgets.find(w => w.name === "number_of_faces");
|
||||
if (numFacesWidget) {
|
||||
node.widgets = [numFacesWidget, ...node.widgets.filter(w => w !== numFacesWidget)];
|
||||
numFacesWidget.callback = () => {
|
||||
updateInputs();
|
||||
app.graph.setDirtyCanvas(true);
|
||||
};
|
||||
}
|
||||
|
||||
// Initial update after node creation
|
||||
setTimeout(updateInputs, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,122 +1,135 @@
|
||||
import { app } from "../../../scripts/app.js";
|
||||
import { api } from "../../../scripts/api.js";
|
||||
|
||||
// Helper function to construct image URLs for ComfyUI
|
||||
function imageDataToUrl(data) {
|
||||
return api.apiURL(
|
||||
`/view?filename=${encodeURIComponent(data.filename)}&type=${data.type}&subfolder=${data.subfolder}${app.getPreviewFormatParam()}`
|
||||
`/view?filename=${encodeURIComponent(data.filename)}&type=${
|
||||
data.type
|
||||
}&subfolder=${data.subfolder}` + app.getPreviewFormatParam()
|
||||
);
|
||||
}
|
||||
|
||||
app.registerExtension({
|
||||
name: "Bjornulf.FourImageViewer",
|
||||
async nodeCreated(node) {
|
||||
// Ensure this applies only to the specific node type
|
||||
if (node.comfyClass !== "Bjornulf_FourImageViewer") return;
|
||||
|
||||
const marginTop = 90;
|
||||
const verticalOffset = -30;
|
||||
const minSize = 256; // Minimum size for the node
|
||||
const maxSize = 2048; // Maximum size for the node
|
||||
node.size = [512, 512 + marginTop];
|
||||
node.images = new Array(4).fill(null);
|
||||
const padding = 10;
|
||||
// Constants for layout and sizing
|
||||
const marginTop = 90; // Space at the top for node UI elements
|
||||
const verticalOffset = -30; // Adjustment for canvas positioning
|
||||
const minSize = 256; // Minimum size of the node
|
||||
const maxSize = 2048; // Maximum size of the node
|
||||
const padding = 10; // Padding around the image area
|
||||
|
||||
// Add resize handles
|
||||
// Initialize node properties
|
||||
node.size = [512, 512 + marginTop];
|
||||
node.data = {
|
||||
images: new Array(4).fill(null), // Array to hold up to 4 images
|
||||
sliderX: null, // X position of the vertical slider
|
||||
sliderY: null, // Y position of the horizontal slider
|
||||
};
|
||||
|
||||
// Enable resizing
|
||||
node.flags |= LiteGraph.RESIZABLE;
|
||||
|
||||
node.onResize = function(size) {
|
||||
// Ensure square aspect ratio (excluding marginTop)
|
||||
const minDimension = Math.max(minSize, Math.min(size[0], size[1] - marginTop));
|
||||
// Handle resizing to maintain square aspect ratio
|
||||
node.onResize = function (size) {
|
||||
const minDimension = Math.max(
|
||||
minSize,
|
||||
Math.min(size[0], size[1] - marginTop)
|
||||
);
|
||||
const maxDimension = Math.min(maxSize, minDimension);
|
||||
size[0] = maxDimension;
|
||||
size[1] = maxDimension + marginTop;
|
||||
|
||||
// Update slider positions proportionally
|
||||
|
||||
const fullImgWidth = size[0] - 3 * padding;
|
||||
const fullImgHeight = size[1] - padding - marginTop;
|
||||
|
||||
// Only update sliders if they exist (node has been initialized)
|
||||
if (node.hasOwnProperty('sliderX')) {
|
||||
|
||||
// Update slider positions proportionally
|
||||
if (node.data.hasOwnProperty("sliderX")) {
|
||||
const oldWidth = node.size[0] - 3 * padding;
|
||||
const oldHeight = node.size[1] - padding - marginTop;
|
||||
|
||||
// Calculate relative positions (0 to 1)
|
||||
const relativeX = (node.sliderX - padding) / oldWidth;
|
||||
const relativeY = (node.sliderY - marginTop) / oldHeight;
|
||||
|
||||
// Update slider positions
|
||||
node.sliderX = padding + (fullImgWidth * relativeX);
|
||||
node.sliderY = marginTop + (fullImgHeight * relativeY);
|
||||
const relativeX = (node.data.sliderX - padding) / oldWidth;
|
||||
const relativeY = (node.data.sliderY - marginTop) / oldHeight;
|
||||
node.data.sliderX = padding + fullImgWidth * relativeX;
|
||||
node.data.sliderY = marginTop + fullImgHeight * relativeY;
|
||||
} else {
|
||||
// Initial slider positions
|
||||
node.sliderX = padding + fullImgWidth / 2;
|
||||
node.sliderY = marginTop + fullImgHeight / 2;
|
||||
node.data.sliderX = padding + fullImgWidth / 2;
|
||||
node.data.sliderY = marginTop + fullImgHeight / 2;
|
||||
}
|
||||
|
||||
|
||||
node.size = size;
|
||||
return size;
|
||||
};
|
||||
|
||||
// Full area where images get drawn
|
||||
const fullImgWidth = node.size[0] - 3 * padding;
|
||||
const fullImgHeight = node.size[1] - padding - marginTop;
|
||||
node.sliderX = padding + fullImgWidth / 2;
|
||||
node.sliderY = marginTop + fullImgHeight / 2;
|
||||
|
||||
node.onMouseDown = function(e) {
|
||||
// Handle mouse down to move sliders
|
||||
node.onMouseDown = function (e) {
|
||||
const rect = node.getBounding();
|
||||
const [clickX, clickY] = [
|
||||
e.canvasX - rect[0],
|
||||
e.canvasY - rect[1] + verticalOffset
|
||||
e.canvasY - rect[1] + verticalOffset,
|
||||
];
|
||||
|
||||
const imgWidth = rect[2] - 3 * padding;
|
||||
const imgHeight = rect[3] - padding - marginTop;
|
||||
const xStart = padding;
|
||||
const xEnd = xStart + imgWidth;
|
||||
const yStart = marginTop;
|
||||
const yEnd = yStart + imgHeight;
|
||||
|
||||
if (clickX >= xStart && clickX <= xEnd && clickY >= yStart && clickY <= yEnd) {
|
||||
const hasImage2 = node.images[1] !== null;
|
||||
const hasImage3 = node.images[2] !== null;
|
||||
const hasImage4 = node.images[3] !== null;
|
||||
const xStart = padding;
|
||||
const xEnd = xStart + (node.size[0] - 3 * padding);
|
||||
const yStart = marginTop;
|
||||
const yEnd = yStart + (node.size[1] - padding - marginTop);
|
||||
|
||||
if (
|
||||
clickX >= xStart &&
|
||||
clickX <= xEnd &&
|
||||
clickY >= yStart &&
|
||||
clickY <= yEnd
|
||||
) {
|
||||
const hasImage2 = node.data.images[1] !== null;
|
||||
const hasImage3 = node.data.images[2] !== null;
|
||||
const hasImage4 = node.data.images[3] !== null;
|
||||
|
||||
// Lock sliderY to bottom if only two images are present
|
||||
if (hasImage2 && !hasImage3 && !hasImage4) {
|
||||
node.sliderY = yEnd;
|
||||
node.data.sliderY = yEnd;
|
||||
}
|
||||
node.sliderX = Math.max(xStart, Math.min(clickX, xEnd));
|
||||
node.sliderY = hasImage3 || hasImage4
|
||||
? Math.max(yStart, Math.min(clickY, yEnd))
|
||||
: yEnd;
|
||||
|
||||
node.data.sliderX = Math.max(xStart, Math.min(clickX, xEnd));
|
||||
node.data.sliderY =
|
||||
hasImage3 || hasImage4
|
||||
? Math.max(yStart, Math.min(clickY, yEnd))
|
||||
: yEnd;
|
||||
|
||||
app.graph.setDirtyCanvas(true, true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
node.onExecuted = async function(message) {
|
||||
node.images = new Array(4).fill(null);
|
||||
// Load images when the node is executed
|
||||
node.onExecuted = async function (message) {
|
||||
node.data.images = new Array(4).fill(null);
|
||||
for (let i = 1; i <= 4; i++) {
|
||||
const images = message[`images_${i}`] || [];
|
||||
if (images.length) {
|
||||
const imgData = images[0];
|
||||
const img = new Image();
|
||||
img.src = imageDataToUrl(imgData);
|
||||
await new Promise(resolve => (img.onload = img.onerror = resolve));
|
||||
node.images[i - 1] = img;
|
||||
await new Promise((resolve) => (img.onload = img.onerror = resolve));
|
||||
node.data.images[i - 1] = img;
|
||||
}
|
||||
}
|
||||
app.graph.setDirtyCanvas(true, true);
|
||||
};
|
||||
|
||||
node.onDrawForeground = function(ctx) {
|
||||
const padding = 10;
|
||||
// Render images and sliders
|
||||
node.onDrawForeground = function (ctx) {
|
||||
const xStart = padding;
|
||||
const xEnd = xStart + (node.size[0] - 3 * padding);
|
||||
const yStart = marginTop;
|
||||
const yEnd = yStart + (node.size[1] - padding - marginTop);
|
||||
const fullImgWidth = node.size[0] - 3 * padding;
|
||||
const fullImgHeight = node.size[1] - padding - marginTop;
|
||||
|
||||
|
||||
// Calculate fitted rectangle for image display
|
||||
function getFittedDestRect(dx, dy, dWidth, dHeight, targetRatio) {
|
||||
let newWidth = dWidth;
|
||||
let newHeight = dWidth / targetRatio;
|
||||
@@ -128,18 +141,34 @@ app.registerExtension({
|
||||
const offsetY = dy + (dHeight - newHeight) / 2;
|
||||
return [offsetX, offsetY, newWidth, newHeight];
|
||||
}
|
||||
|
||||
|
||||
// Draw a cropped image within specified bounds
|
||||
function drawCroppedImage(img, dx, dy, dWidth, dHeight) {
|
||||
if (!img) return;
|
||||
let targetRatio = dWidth / dHeight;
|
||||
if (node.images[0] && node.images[0].naturalWidth && node.images[0].naturalHeight) {
|
||||
targetRatio = node.images[0].naturalWidth / node.images[0].naturalHeight;
|
||||
if (
|
||||
node.data.images[0] &&
|
||||
node.data.images[0].naturalWidth &&
|
||||
node.data.images[0].naturalHeight
|
||||
) {
|
||||
targetRatio =
|
||||
node.data.images[0].naturalWidth /
|
||||
node.data.images[0].naturalHeight;
|
||||
}
|
||||
|
||||
const [ndx, ndy, ndWidth, ndHeight] = getFittedDestRect(dx, dy, dWidth, dHeight, targetRatio);
|
||||
|
||||
|
||||
const [ndx, ndy, ndWidth, ndHeight] = getFittedDestRect(
|
||||
dx,
|
||||
dy,
|
||||
dWidth,
|
||||
dHeight,
|
||||
targetRatio
|
||||
);
|
||||
|
||||
const imgRatio = img.naturalWidth / img.naturalHeight;
|
||||
let sx = 0, sy = 0, sWidth = img.naturalWidth, sHeight = img.naturalHeight;
|
||||
let sx = 0,
|
||||
sy = 0,
|
||||
sWidth = img.naturalWidth,
|
||||
sHeight = img.naturalHeight;
|
||||
if (imgRatio > targetRatio) {
|
||||
sWidth = img.naturalHeight * targetRatio;
|
||||
sx = (img.naturalWidth - sWidth) / 2;
|
||||
@@ -147,64 +176,139 @@ app.registerExtension({
|
||||
sHeight = img.naturalWidth / targetRatio;
|
||||
sy = (img.naturalHeight - sHeight) / 2;
|
||||
}
|
||||
ctx.drawImage(img, sx, sy, sWidth, sHeight, ndx, ndy, ndWidth, ndHeight);
|
||||
ctx.drawImage(
|
||||
img,
|
||||
sx,
|
||||
sy,
|
||||
sWidth,
|
||||
sHeight,
|
||||
ndx,
|
||||
ndy,
|
||||
ndWidth,
|
||||
ndHeight
|
||||
);
|
||||
}
|
||||
|
||||
const connectedImages = node.images.slice(1).filter(img => img !== null).length;
|
||||
|
||||
|
||||
const connectedImages = node.data.images
|
||||
.slice(1)
|
||||
.filter((img) => img !== null).length;
|
||||
|
||||
if (connectedImages === 0) {
|
||||
if (node.images[0]) {
|
||||
drawCroppedImage(node.images[0], xStart, yStart, fullImgWidth, fullImgHeight);
|
||||
// Single image display
|
||||
if (node.data.images[0]) {
|
||||
drawCroppedImage(
|
||||
node.data.images[0],
|
||||
xStart,
|
||||
yStart,
|
||||
fullImgWidth,
|
||||
fullImgHeight
|
||||
);
|
||||
}
|
||||
} else if (connectedImages === 1 && node.images[1]) {
|
||||
const splitX = node.sliderX;
|
||||
} else if (connectedImages === 1 && node.data.images[1]) {
|
||||
// Two images with vertical split
|
||||
const splitX = node.data.sliderX;
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.rect(xStart, yStart, splitX - xStart, fullImgHeight);
|
||||
ctx.clip();
|
||||
drawCroppedImage(node.images[0], xStart, yStart, fullImgWidth, fullImgHeight);
|
||||
drawCroppedImage(
|
||||
node.data.images[0],
|
||||
xStart,
|
||||
yStart,
|
||||
fullImgWidth,
|
||||
fullImgHeight
|
||||
);
|
||||
ctx.restore();
|
||||
|
||||
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.rect(splitX, yStart, xEnd - splitX, fullImgHeight);
|
||||
ctx.clip();
|
||||
drawCroppedImage(node.images[1], xStart, yStart, fullImgWidth, fullImgHeight);
|
||||
drawCroppedImage(
|
||||
node.data.images[1],
|
||||
xStart,
|
||||
yStart,
|
||||
fullImgWidth,
|
||||
fullImgHeight
|
||||
);
|
||||
ctx.restore();
|
||||
} else {
|
||||
// Three or four images with quadrants
|
||||
const drawQuadrant = (imgIndex, clipX, clipY, clipW, clipH) => {
|
||||
if (!node.images[imgIndex]) return;
|
||||
if (!node.data.images[imgIndex]) return;
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.rect(clipX, clipY, clipW, clipH);
|
||||
ctx.clip();
|
||||
drawCroppedImage(node.images[imgIndex], xStart, yStart, fullImgWidth, fullImgHeight);
|
||||
drawCroppedImage(
|
||||
node.data.images[imgIndex],
|
||||
xStart,
|
||||
yStart,
|
||||
fullImgWidth,
|
||||
fullImgHeight
|
||||
);
|
||||
ctx.restore();
|
||||
};
|
||||
|
||||
drawQuadrant(0, xStart, yStart, node.sliderX - xStart, node.sliderY - yStart);
|
||||
drawQuadrant(1, node.sliderX, yStart, xEnd - node.sliderX, node.sliderY - yStart);
|
||||
|
||||
if (node.images[3] === null) {
|
||||
drawQuadrant(2, xStart, node.sliderY, xEnd - xStart, yEnd - node.sliderY);
|
||||
|
||||
drawQuadrant(
|
||||
0,
|
||||
xStart,
|
||||
yStart,
|
||||
node.data.sliderX - xStart,
|
||||
node.data.sliderY - yStart
|
||||
);
|
||||
drawQuadrant(
|
||||
1,
|
||||
node.data.sliderX,
|
||||
yStart,
|
||||
xEnd - node.data.sliderX,
|
||||
node.data.sliderY - yStart
|
||||
);
|
||||
|
||||
if (node.data.images[3] === null) {
|
||||
drawQuadrant(
|
||||
2,
|
||||
xStart,
|
||||
node.data.sliderY,
|
||||
xEnd - xStart,
|
||||
yEnd - node.data.sliderY
|
||||
);
|
||||
} else {
|
||||
drawQuadrant(2, xStart, node.sliderY, node.sliderX - xStart, yEnd - node.sliderY);
|
||||
drawQuadrant(3, node.sliderX, node.sliderY, xEnd - node.sliderX, yEnd - node.sliderY);
|
||||
drawQuadrant(
|
||||
2,
|
||||
xStart,
|
||||
node.data.sliderY,
|
||||
node.data.sliderX - xStart,
|
||||
yEnd - node.data.sliderY
|
||||
);
|
||||
drawQuadrant(
|
||||
3,
|
||||
node.data.sliderX,
|
||||
node.data.sliderY,
|
||||
xEnd - node.data.sliderX,
|
||||
yEnd - node.data.sliderY
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Draw sliders
|
||||
ctx.strokeStyle = "#FFF";
|
||||
ctx.lineWidth = 1;
|
||||
if (connectedImages > 0) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(node.sliderX, yStart);
|
||||
ctx.lineTo(node.sliderX, yEnd);
|
||||
if (node.data.images[3] === null && node.data.images[2] !== null) {
|
||||
ctx.moveTo(node.data.sliderX, yStart);
|
||||
ctx.lineTo(node.data.sliderX, node.data.sliderY);
|
||||
} else {
|
||||
ctx.moveTo(node.data.sliderX, yStart);
|
||||
ctx.lineTo(node.data.sliderX, yEnd);
|
||||
}
|
||||
if (connectedImages >= 2) {
|
||||
ctx.moveTo(xStart, node.sliderY);
|
||||
ctx.lineTo(xEnd, node.sliderY);
|
||||
ctx.moveTo(xStart, node.data.sliderY);
|
||||
ctx.lineTo(xEnd, node.data.sliderY);
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
47
web/js/load_text.js
Normal file
47
web/js/load_text.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import { app } from "../../../scripts/app.js";
|
||||
|
||||
app.registerExtension({
|
||||
name: "Bjornulf.LoadTextFromFolder",
|
||||
async nodeCreated(node) {
|
||||
if (node.comfyClass === "Bjornulf_LoadTextFromFolder") {
|
||||
// Add a refresh button widget
|
||||
// Assuming this is inside your node's setup function
|
||||
const refreshButton = node.addWidget(
|
||||
"button",
|
||||
"Refresh File List",
|
||||
null,
|
||||
() => {
|
||||
fetch("/get_text_files", {
|
||||
method: "POST",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
if (data.success) {
|
||||
// Update the dropdown with the new file list
|
||||
node.widgets[0].options.values = data.files; // Assuming the dropdown is the first widget
|
||||
node.widgets[0].value = data.files[0] || ""; // Set default value
|
||||
app.ui.dialog.show(
|
||||
"[LoadTextFromFolder] File list refreshed successfully!"
|
||||
);
|
||||
} else {
|
||||
app.ui.dialog.show(
|
||||
`[LoadTextFromFolder] Failed to refresh file list: ${
|
||||
data.error || "Unknown error"
|
||||
}`
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(
|
||||
"[LoadTextFromFolder] Error fetching text files:",
|
||||
error
|
||||
);
|
||||
app.ui.dialog.show(
|
||||
"[LoadTextFromFolder] An error occurred while refreshing the file list."
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
58
web/js/math_node.js
Normal file
58
web/js/math_node.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import { app } from "../../../scripts/app.js";
|
||||
|
||||
app.registerExtension({
|
||||
name: "Bjornulf.MathNode",
|
||||
async nodeCreated(node) {
|
||||
if (node.comfyClass === "Bjornulf_MathNode") {
|
||||
const updateInputs = () => {
|
||||
const initialWidth = node.size[0];
|
||||
const numInputsWidget = node.widgets.find(w => w.name === "num_inputs");
|
||||
if (!numInputsWidget) return;
|
||||
|
||||
const numInputs = numInputsWidget.value;
|
||||
|
||||
// Initialize node.inputs if it doesn't exist
|
||||
if (!node.inputs) {
|
||||
node.inputs = [];
|
||||
}
|
||||
|
||||
// Filter existing value inputs
|
||||
const existingInputs = node.inputs.filter(input => input.name.startsWith("value_"));
|
||||
|
||||
// Add new inputs if needed
|
||||
if (existingInputs.length < numInputs) {
|
||||
for (let i = existingInputs.length + 1; i <= numInputs; i++) {
|
||||
const inputName = `value_${i}`;
|
||||
if (!node.inputs.find(input => input.name === inputName)) {
|
||||
node.addInput(inputName); // Type is defined in Python
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove excess inputs if too many
|
||||
else {
|
||||
node.inputs = node.inputs.filter(input =>
|
||||
!input.name.startsWith("value_") ||
|
||||
parseInt(input.name.split("_")[1]) <= numInputs
|
||||
);
|
||||
}
|
||||
|
||||
// Adjust node size while preserving width
|
||||
node.setSize(node.computeSize());
|
||||
node.size[0] = initialWidth;
|
||||
};
|
||||
|
||||
// Ensure num_inputs widget is at the top and set its callback
|
||||
const numInputsWidget = node.widgets.find(w => w.name === "num_inputs");
|
||||
if (numInputsWidget) {
|
||||
node.widgets = [numInputsWidget, ...node.widgets.filter(w => w !== numInputsWidget)];
|
||||
numInputsWidget.callback = () => {
|
||||
updateInputs();
|
||||
app.graph.setDirtyCanvas(true);
|
||||
};
|
||||
}
|
||||
|
||||
// Perform initial input update after node creation
|
||||
setTimeout(updateInputs, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,44 +1,44 @@
|
||||
import { app } from "../../../scripts/app.js";
|
||||
// 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");
|
||||
// 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");
|
||||
|
||||
// Store the initial node size
|
||||
let prevSize = [...node.size];
|
||||
let stableCount = 0;
|
||||
const minStableFrames = 3; // Number of frames the size must remain stable
|
||||
// // 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);
|
||||
}
|
||||
} else {
|
||||
// Size changed, reset counter and update prevSize
|
||||
prevSize = [...node.size];
|
||||
stableCount = 0;
|
||||
requestAnimationFrame(checkSizeStable);
|
||||
}
|
||||
};
|
||||
// // 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);
|
||||
// }
|
||||
// } 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);
|
||||
}
|
||||
});
|
||||
// // Start checking after a short delay to allow node initialization
|
||||
// setTimeout(() => {
|
||||
// requestAnimationFrame(checkSizeStable);
|
||||
// }, 5000);
|
||||
// }
|
||||
// });
|
||||
|
||||
@@ -7,10 +7,10 @@ app.registerExtension({
|
||||
async nodeCreated(node) {
|
||||
if (node.comfyClass === "Bjornulf_OllamaTalk") {
|
||||
// Set seed widget to hidden input
|
||||
const seedWidget = node.widgets.find((w) => w.name === "seed");
|
||||
if (seedWidget) {
|
||||
seedWidget.type = "HIDDEN";
|
||||
}
|
||||
// const seedWidget = node.widgets.find((w) => w.name === "seed");
|
||||
// if (seedWidget) {
|
||||
// seedWidget.type = "HIDDEN";
|
||||
// }
|
||||
|
||||
// Function to update the Reset Button text
|
||||
const updateResetButtonTextNode = () => {
|
||||
|
||||
186
web/js/style_selector.js
Normal file
186
web/js/style_selector.js
Normal file
@@ -0,0 +1,186 @@
|
||||
// // style_selector.js
|
||||
// import { app } from "../../../scripts/app.js";
|
||||
|
||||
// app.registerExtension({
|
||||
// name: "Bjornulf.StyleSelector",
|
||||
// async nodeCreated(node) {
|
||||
// // Only apply to the Bjornulf_StyleSelector node
|
||||
// if (node.comfyClass !== "Bjornulf_StyleSelector") return;
|
||||
|
||||
// // Find the widgets for LOOP_random_LIST and LOOP_style_LIST
|
||||
// const loopRandomWidget = node.widgets.find(w => w.name === "LOOP_random_LIST");
|
||||
// const loopStyleWidget = node.widgets.find(w => w.name === "LOOP_style_LIST");
|
||||
|
||||
// // Check if widgets exist to avoid errors
|
||||
// if (!loopRandomWidget || !loopStyleWidget) {
|
||||
// console.error("LOOP widgets not found in Bjornulf_StyleSelector node.");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Function to toggle the other widget off when one is turned on
|
||||
// const toggleExclusive = (widgetToToggle, otherWidget) => {
|
||||
// if (widgetToToggle.value === true) {
|
||||
// otherWidget.value = false;
|
||||
// }
|
||||
// };
|
||||
|
||||
// // Add event listeners to handle toggling
|
||||
// loopRandomWidget.callback = () => {
|
||||
// toggleExclusive(loopRandomWidget, loopStyleWidget);
|
||||
// };
|
||||
|
||||
// loopStyleWidget.callback = () => {
|
||||
// toggleExclusive(loopStyleWidget, loopRandomWidget);
|
||||
// };
|
||||
|
||||
// // Ensure initial state has only one enabled (if both are true, disable one)
|
||||
// if (loopRandomWidget.value && loopStyleWidget.value) {
|
||||
// loopStyleWidget.value = false; // Default to disabling LOOP_style_LIST
|
||||
// }
|
||||
|
||||
// // Find the category and style widgets
|
||||
// const categoryWidget = node.widgets.find(w => w.name === "category");
|
||||
// const styleWidget = node.widgets.find(w => w.name === "style");
|
||||
|
||||
// // Define categories and styles (must match the Python file)
|
||||
// const BRANCHES = {
|
||||
// "Painting": [
|
||||
// "Renaissance", "Baroque", "Rococo", "Neoclassicism",
|
||||
// "Romanticism", "Realism", "Impressionism", "Post-Impressionism",
|
||||
// "Expressionism", "Fauvism", "Cubism", "Futurism", "Dadaism",
|
||||
// "Surrealism", "Abstract Expressionism", "Pop Art", "Op Art",
|
||||
// "Minimalism"
|
||||
// ],
|
||||
// "Photography": [
|
||||
// "Black and White", "Color", "Vintage", "Sepia Tone", "HDR",
|
||||
// "Long Exposure", "Macro", "Portrait", "Landscape", "Street",
|
||||
// "Fashion", "Analog Film", "Cinematic"
|
||||
// ],
|
||||
// "Digital Art": [
|
||||
// "Digital Painting", "Vector Art", "Pixel Art", "Fractal Art",
|
||||
// "Algorithmic Art", "Glitch Art"
|
||||
// ],
|
||||
// "3D Rendering": [
|
||||
// "Low Poly", "Voxel", "Isometric", "Ray Tracing"
|
||||
// ],
|
||||
// "Illustration": [
|
||||
// "Line Art", "Cartoon", "Comic Book", "Manga", "Anime",
|
||||
// "Technical Illustration", "Botanical Illustration",
|
||||
// "Architectural Rendering", "Concept Art", "Storyboard Art"
|
||||
// ],
|
||||
// };
|
||||
|
||||
// // Function to update the style dropdown based on the selected category
|
||||
// const updateStyles = () => {
|
||||
// const selectedCategory = categoryWidget.value;
|
||||
// const styles = BRANCHES[selectedCategory] || [];
|
||||
// styleWidget.options.values = styles;
|
||||
// if (styles.length > 0) {
|
||||
// styleWidget.value = styles[0]; // Set to the first style
|
||||
// } else {
|
||||
// styleWidget.value = ""; // Fallback if no styles
|
||||
// }
|
||||
// node.setDirtyCanvas(true); // Refresh the UI
|
||||
// };
|
||||
|
||||
// // Initialize the style dropdown
|
||||
// updateStyles();
|
||||
|
||||
// // Update the style dropdown whenever the category changes
|
||||
// categoryWidget.callback = updateStyles;
|
||||
// }
|
||||
// });
|
||||
import { app } from "../../../scripts/app.js";
|
||||
|
||||
app.registerExtension({
|
||||
name: "Bjornulf.StyleSelector",
|
||||
async nodeCreated(node) {
|
||||
if (node.comfyClass !== "Bjornulf_StyleSelector") return;
|
||||
|
||||
// Find loop widgets
|
||||
const loopRandomWidget = node.widgets.find(w => w.name === "LOOP_random_LIST");
|
||||
const loopStyleWidget = node.widgets.find(w => w.name === "LOOP_style_LIST");
|
||||
const loopSequentialWidget = node.widgets.find(w => w.name === "LOOP_SEQUENTIAL");
|
||||
|
||||
// Function to toggle the other widget off when one is turned on
|
||||
const toggleExclusive = (widgetToToggle, otherWidget) => {
|
||||
if (widgetToToggle.value === true) {
|
||||
otherWidget.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Add event listeners to handle toggling
|
||||
loopRandomWidget.callback = () => {
|
||||
toggleExclusive(loopRandomWidget, loopStyleWidget);
|
||||
};
|
||||
loopStyleWidget.callback = () => {
|
||||
toggleExclusive(loopStyleWidget, loopRandomWidget);
|
||||
};
|
||||
|
||||
// Ensure initial state has only one enabled (if both are true, disable one)
|
||||
if (loopRandomWidget.value && loopStyleWidget.value) {
|
||||
loopStyleWidget.value = false; // Default to disabling LOOP_style_LIST
|
||||
}
|
||||
|
||||
// Add reset button for style list counter
|
||||
const styleResetButton = node.addWidget(
|
||||
"button",
|
||||
"Reset Style Counter",
|
||||
null,
|
||||
async () => {
|
||||
try {
|
||||
const response = await fetch("/reset_style_list_counter", { method: "POST" });
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
app.ui.dialog.show("[Style Selector] Style counter reset successfully.");
|
||||
} else {
|
||||
app.ui.dialog.show("[Style Selector] Failed to reset style counter.");
|
||||
}
|
||||
} catch (error) {
|
||||
app.ui.dialog.show("[Style Selector] Error resetting style counter.");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Add reset button for model list counter
|
||||
const modelResetButton = node.addWidget(
|
||||
"button",
|
||||
"Reset Model Counter",
|
||||
null,
|
||||
async () => {
|
||||
try {
|
||||
const response = await fetch("/reset_model_list_counter", { method: "POST" });
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
app.ui.dialog.show("[Style Selector] Model counter reset successfully.");
|
||||
} else {
|
||||
app.ui.dialog.show("[Style Selector] Failed to reset model counter.");
|
||||
}
|
||||
} catch (error) {
|
||||
app.ui.dialog.show("[Style Selector] Error resetting model counter.");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Function to update visibility of reset buttons
|
||||
const updateButtonVisibility = () => {
|
||||
const sequentialEnabled = loopSequentialWidget.value;
|
||||
styleResetButton.type = sequentialEnabled && loopStyleWidget.value ? "button" : "hidden";
|
||||
modelResetButton.type = sequentialEnabled && loopRandomWidget.value ? "button" : "hidden";
|
||||
};
|
||||
|
||||
// Initial update of button visibility
|
||||
setTimeout(updateButtonVisibility, 0);
|
||||
|
||||
// Update visibility when widgets change
|
||||
loopSequentialWidget.callback = updateButtonVisibility;
|
||||
loopStyleWidget.callback = () => {
|
||||
toggleExclusive(loopStyleWidget, loopRandomWidget);
|
||||
updateButtonVisibility();
|
||||
};
|
||||
loopRandomWidget.callback = () => {
|
||||
toggleExclusive(loopRandomWidget, loopStyleWidget);
|
||||
updateButtonVisibility();
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -31,7 +31,8 @@ app.registerExtension({
|
||||
// Function to update voices based on selected language
|
||||
const updateVoicesForLanguage = async (selectedLanguage) => {
|
||||
try {
|
||||
const response = await fetch('/bjornulf_xtts_get_voices', {
|
||||
// const response = await fetch('/bjornulf_xtts_get_voices', {
|
||||
const response = await fetch('/bjornulf_TTS_get_voices', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import { api } from '../../../scripts/api.js';
|
||||
import { app } from "../../../scripts/app.js";
|
||||
|
||||
function displayVideoPreview(component, filename, category, autoplay, mute) {
|
||||
// Function to display the video preview
|
||||
function displayVideoPreview(component, filename, category, autoplay, mute, loop) {
|
||||
let videoWidget = component._videoWidget;
|
||||
|
||||
// Create the video widget if it doesn't exist
|
||||
if (!videoWidget) {
|
||||
// Create the widget if it doesn't exist
|
||||
var container = document.createElement("div");
|
||||
const container = document.createElement("div");
|
||||
const currentNode = component;
|
||||
|
||||
// Add the DOM widget to the component
|
||||
videoWidget = component.addDOMWidget("videopreview", "preview", container, {
|
||||
serialize: false,
|
||||
hideOnZoom: false,
|
||||
@@ -17,73 +21,83 @@ function displayVideoPreview(component, filename, category, autoplay, mute) {
|
||||
container.value = v;
|
||||
},
|
||||
});
|
||||
|
||||
// Define how the widget computes its size
|
||||
videoWidget.computeSize = function(width) {
|
||||
if (this.aspectRatio && !this.parentElement.hidden) {
|
||||
let height = (currentNode.size[0] - 20) / this.aspectRatio + 10;
|
||||
if (!(height > 0)) {
|
||||
height = 0;
|
||||
}
|
||||
return [width, height];
|
||||
return [width, height > 0 ? height : 0];
|
||||
}
|
||||
return [width, -4];
|
||||
};
|
||||
|
||||
// Initialize widget properties
|
||||
videoWidget.value = { hidden: false, paused: false, params: {} };
|
||||
videoWidget.parentElement = document.createElement("div");
|
||||
videoWidget.parentElement.className = "video_preview";
|
||||
videoWidget.parentElement.style['width'] = "100%";
|
||||
videoWidget.parentElement.style.width = "100%";
|
||||
container.appendChild(videoWidget.parentElement);
|
||||
|
||||
// Create the video element
|
||||
videoWidget.videoElement = document.createElement("video");
|
||||
videoWidget.videoElement.controls = true;
|
||||
videoWidget.videoElement.loop = false;
|
||||
videoWidget.videoElement.muted = false;
|
||||
videoWidget.videoElement.style['width'] = "100%";
|
||||
videoWidget.videoElement.style.width = "100%";
|
||||
|
||||
// Update aspect ratio when metadata is loaded
|
||||
videoWidget.videoElement.addEventListener("loadedmetadata", () => {
|
||||
videoWidget.aspectRatio = videoWidget.videoElement.videoWidth / videoWidget.videoElement.videoHeight;
|
||||
adjustSize(component);
|
||||
});
|
||||
|
||||
// Hide the video on error
|
||||
videoWidget.videoElement.addEventListener("error", () => {
|
||||
videoWidget.parentElement.hidden = true;
|
||||
adjustSize(component);
|
||||
});
|
||||
|
||||
videoWidget.parentElement.hidden = videoWidget.value.hidden;
|
||||
videoWidget.videoElement.autoplay = !videoWidget.value.paused && !videoWidget.value.hidden;
|
||||
videoWidget.videoElement.hidden = false;
|
||||
videoWidget.parentElement.appendChild(videoWidget.videoElement);
|
||||
component._videoWidget = videoWidget; // Store the widget for future reference
|
||||
component._videoWidget = videoWidget; // Store for reuse
|
||||
}
|
||||
|
||||
// Update the video source
|
||||
let params = {
|
||||
// Set video source and properties
|
||||
const params = {
|
||||
"filename": filename,
|
||||
"subfolder": category,
|
||||
"type": "output",
|
||||
"rand": Math.random().toString().slice(2, 12)
|
||||
"rand": Math.random().toString().slice(2, 12) // Cache-busting random parameter
|
||||
};
|
||||
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()}`;
|
||||
videoWidget.videoElement.src = `api/view?${urlParams.toString()}`;
|
||||
|
||||
adjustSize(component); // Adjust the component size
|
||||
const urlParams = new URLSearchParams(params);
|
||||
videoWidget.videoElement.src = `api/view?${urlParams.toString()}`;
|
||||
videoWidget.videoElement.muted = mute;
|
||||
videoWidget.videoElement.autoplay = autoplay && !videoWidget.value.paused && !videoWidget.value.hidden;
|
||||
videoWidget.videoElement.loop = loop;
|
||||
|
||||
// Adjust the component size after setting the video
|
||||
adjustSize(component);
|
||||
}
|
||||
|
||||
// Function to adjust the component size
|
||||
function adjustSize(component) {
|
||||
component.setSize([component.size[0], component.computeSize([component.size[0], component.size[1]])[1]]);
|
||||
const newSize = component.computeSize([component.size[0], component.size[1]]);
|
||||
component.setSize([component.size[0], newSize[1]]);
|
||||
component?.graph?.setDirtyCanvas(true);
|
||||
}
|
||||
|
||||
// Register the extension
|
||||
app.registerExtension({
|
||||
name: "Bjornulf.VideoPreview",
|
||||
async beforeRegisterNodeDef(nodeType, nodeData, appInstance) {
|
||||
if (nodeData?.name == "Bjornulf_VideoPreview") {
|
||||
nodeType.prototype.onExecuted = function (data) {
|
||||
if (nodeData?.name === "Bjornulf_VideoPreview") {
|
||||
nodeType.prototype.onExecuted = function(data) {
|
||||
// Retrieve widget values with defaults
|
||||
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);
|
||||
const loop = this.widgets.find(w => w.name === "loop")?.value ?? false;
|
||||
|
||||
// Display the video preview with the retrieved values
|
||||
displayVideoPreview(this, data.video[0], data.video[1], autoplay, mute, loop);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user