feat(1.6.2): Update README to include preview volume slider for Video Result Node

This commit is contained in:
Alejandro Leal
2026-09-01 15:26:23 +02:00
parent c25c295222
commit e5e5ef5715
4 changed files with 92 additions and 2 deletions
+1 -1
View File
@@ -28,7 +28,7 @@ Combining the "Preview Image" and "Save Image" nodes of comfyUI.
### Video Result
Same as ComfyUI’s Save Video, plus a toggle to preview without saving.
Same as ComfyUI’s Save Video, plus a toggle to preview without saving and a slider to set the preview volume.
![Video Result](./examples/video_result_node.png)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 37 KiB

+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "comfyui-astrocorp-nodes"
description = "A collection of personal ComfyUI nodes designed to enhance and automate workflows."
version = "1.6.1"
version = "1.6.2"
license = {file = "LICENSE"}
dependencies = []
+90
View File
@@ -0,0 +1,90 @@
import { app } from "../../scripts/app.js";
const _NODE = "VideoResultNode";
const _WIDGET = "volume";
const _DEFAULT = 50;
const nodes = new Set();
const getVolume = (node) => {
const percent = node.widgets?.find((x) => x.name === _WIDGET)?.value;
if (typeof percent !== "number") return null;
return Math.min(Math.max(percent, 0), 100) / 100;
};
// El reproductor cuelga del DOM widget (nodos de canvas) o del elemento del nodo (nodos Vue).
const getRoot = (node) => node.videoContainer ?? document.querySelector(`[data-node-id="${node.id}"]`);
const findNode = (video) => {
const nodeId = video.closest("[data-node-id]")?.dataset?.nodeId;
for (const node of nodes) {
if (node.videoContainer?.contains(video)) return node;
if (nodeId !== undefined && String(node.id) === nodeId) return node;
}
return null;
};
const setVolume = (video, node) => {
const volume = getVolume(node);
if (volume !== null) video.volume = volume;
};
app.registerExtension({
name: "AstroCorp.VideoResultWidget",
setup() {
// Cada generación monta un <video> nuevo, siempre al 100%.
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
for (const added of mutation.addedNodes) {
if (!(added instanceof HTMLElement)) continue;
const videos = added instanceof HTMLVideoElement ? [added] : added.querySelectorAll("video");
for (const video of videos) {
const node = findNode(video);
if (node) setVolume(video, node);
}
}
}
});
observer.observe(document.body, { childList: true, subtree: true });
},
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name !== _NODE) return;
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
onNodeCreated?.apply(this, arguments);
nodes.add(this);
this.addWidget(
"slider",
_WIDGET,
_DEFAULT,
() => getRoot(this)?.querySelectorAll("video").forEach((video) => setVolume(video, this)),
{ min: 0, max: 100, step2: 1, precision: 0 }
);
this.setSize(this.computeSize(this.size));
this.setDirtyCanvas(true, false);
};
const onRemoved = nodeType.prototype.onRemoved;
nodeType.prototype.onRemoved = function () {
nodes.delete(this);
onRemoved?.apply(this, arguments);
};
},
});