mirror of
https://github.com/justUmen/Bjornulf_custom_nodes.git
synced 2026-03-25 14:25:44 -03:00
0.33
This commit is contained in:
@@ -80,6 +80,7 @@ wget --content-disposition -P /workspace/ComfyUI/models/checkpoints "https://civ
|
|||||||
- **v0.30**: Update the basic Loop node with optional input.
|
- **v0.30**: Update the basic Loop node with optional input.
|
||||||
- **v0.31**: ❗Sorry, Breaking changes for Write/Show text nodes, cleaner system : 1 simple write text and the other is 1 advanced with console and special syntax. Also Show can now manage INT, FLOAT, TEXT.
|
- **v0.31**: ❗Sorry, Breaking changes for Write/Show text nodes, cleaner system : 1 simple write text and the other is 1 advanced with console and special syntax. Also Show can now manage INT, FLOAT, TEXT.
|
||||||
- **v0.32**: Quick rename to avoid breaking loop_text node.
|
- **v0.32**: Quick rename to avoid breaking loop_text node.
|
||||||
|
- **v0.33**: Control random on paused nodes, fix pydub sound bug permissions on Windows.
|
||||||
|
|
||||||
# 📝 Nodes descriptions
|
# 📝 Nodes descriptions
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ from .random_image import RandomImage
|
|||||||
from .loop_model_clip_vae import LoopModelClipVae
|
from .loop_model_clip_vae import LoopModelClipVae
|
||||||
from .write_text_advanced import WriteTextAdvanced
|
from .write_text_advanced import WriteTextAdvanced
|
||||||
from .loop_write_text import LoopWriteText
|
from .loop_write_text import LoopWriteText
|
||||||
|
# from .load_images_from_folder import LoadImagesFromSelectedFolder
|
||||||
# from .show import ShowWhatever
|
# from .show import ShowWhatever
|
||||||
|
|
||||||
# from .pass_preview_image import PassPreviewImage
|
# from .pass_preview_image import PassPreviewImage
|
||||||
@@ -59,6 +60,7 @@ NODE_CLASS_MAPPINGS = {
|
|||||||
# "Bjornulf_CustomStringType": CustomStringType,
|
# "Bjornulf_CustomStringType": CustomStringType,
|
||||||
"Bjornulf_ollamaLoader": ollamaLoader,
|
"Bjornulf_ollamaLoader": ollamaLoader,
|
||||||
"Bjornulf_WriteText": WriteText,
|
"Bjornulf_WriteText": WriteText,
|
||||||
|
# "Bjornulf_LoadImagesFromSelectedFolder": LoadImagesFromSelectedFolder,
|
||||||
# "Bjornulf_ShowWhatever": ShowWhatever,
|
# "Bjornulf_ShowWhatever": ShowWhatever,
|
||||||
"Bjornulf_LoopModelClipVae": LoopModelClipVae,
|
"Bjornulf_LoopModelClipVae": LoopModelClipVae,
|
||||||
# "Bjoenulf_RandomCheckpoint": RandomCheckpoint,
|
# "Bjoenulf_RandomCheckpoint": RandomCheckpoint,
|
||||||
@@ -162,6 +164,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
|||||||
"Bjornulf_TextToSpeech": "🔊 TTS - Text to Speech",
|
"Bjornulf_TextToSpeech": "🔊 TTS - Text to Speech",
|
||||||
"Bjornulf_PickInput": "⏸️🔍 Paused. Select input, Pick one",
|
"Bjornulf_PickInput": "⏸️🔍 Paused. Select input, Pick one",
|
||||||
"Bjornulf_PauseResume": "⏸️ Paused. Resume or Stop ?",
|
"Bjornulf_PauseResume": "⏸️ Paused. Resume or Stop ?",
|
||||||
|
# "Bjornulf_LoadImagesFromSelectedFolder": "📂🖼 Load Images from folder",
|
||||||
}
|
}
|
||||||
|
|
||||||
WEB_DIRECTORY = "./web"
|
WEB_DIRECTORY = "./web"
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import logging
|
|||||||
from pydub import AudioSegment
|
from pydub import AudioSegment
|
||||||
from pydub.playback import play
|
from pydub.playback import play
|
||||||
import os
|
import os
|
||||||
|
import io
|
||||||
|
import sys
|
||||||
|
import random
|
||||||
|
|
||||||
class Everything(str):
|
class Everything(str):
|
||||||
def __ne__(self, __value: object) -> bool:
|
def __ne__(self, __value: object) -> bool:
|
||||||
@@ -18,7 +21,8 @@ class PauseResume:
|
|||||||
def INPUT_TYPES(cls):
|
def INPUT_TYPES(cls):
|
||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
"input": (Everything("*"), {"forceInput": True})
|
"input": (Everything("*"), {"forceInput": True}),
|
||||||
|
"seed": ("INT", {"default": 1}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,11 +32,32 @@ class PauseResume:
|
|||||||
CATEGORY = "Bjornulf"
|
CATEGORY = "Bjornulf"
|
||||||
|
|
||||||
def play_audio(self):
|
def play_audio(self):
|
||||||
audio_file = os.path.join(os.path.dirname(__file__), 'bell.m4a')
|
# Check if the operating system is Windows
|
||||||
sound = AudioSegment.from_file(audio_file, format="m4a")
|
if sys.platform.startswith('win'):
|
||||||
play(sound)
|
try:
|
||||||
|
# Load the audio file into memory
|
||||||
|
audio_file = os.path.join(os.path.dirname(__file__), 'bell.m4a')
|
||||||
|
|
||||||
def loop_resume_or_stop(self, input):
|
# Load the audio segment without writing to any temp files
|
||||||
|
sound = AudioSegment.from_file(audio_file, format="m4a")
|
||||||
|
|
||||||
|
# Export the AudioSegment to a WAV file in memory
|
||||||
|
wav_io = io.BytesIO()
|
||||||
|
sound.export(wav_io, format='wav')
|
||||||
|
wav_data = wav_io.getvalue()
|
||||||
|
|
||||||
|
# Play the WAV data using winsound
|
||||||
|
import winsound
|
||||||
|
winsound.PlaySound(wav_data, winsound.SND_MEMORY)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"An error occurred: {e}")
|
||||||
|
else:
|
||||||
|
audio_file = os.path.join(os.path.dirname(__file__), 'bell.m4a')
|
||||||
|
sound = AudioSegment.from_file(audio_file, format="m4a")
|
||||||
|
play(sound)
|
||||||
|
|
||||||
|
def loop_resume_or_stop(self, input, seed):
|
||||||
|
random.seed(seed)
|
||||||
self.play_audio()
|
self.play_audio()
|
||||||
self.input = input
|
self.input = input
|
||||||
while PauseResume.is_paused and not PauseResume.should_stop:
|
while PauseResume.is_paused and not PauseResume.should_stop:
|
||||||
|
|||||||
@@ -5,12 +5,14 @@ import logging
|
|||||||
from pydub import AudioSegment
|
from pydub import AudioSegment
|
||||||
from pydub.playback import play
|
from pydub.playback import play
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
import io
|
||||||
|
import random
|
||||||
|
|
||||||
class Everything(str):
|
class Everything(str):
|
||||||
def __ne__(self, __value: object) -> bool:
|
def __ne__(self, __value: object) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class PickInput:
|
class PickInput:
|
||||||
is_paused = True
|
is_paused = True
|
||||||
should_stop = False
|
should_stop = False
|
||||||
@@ -21,9 +23,10 @@ class PickInput:
|
|||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
"number_of_inputs": ("INT", {"default": 2, "min": 1, "max": 10, "step": 1}),
|
"number_of_inputs": ("INT", {"default": 2, "min": 1, "max": 10, "step": 1}),
|
||||||
|
"seed": ("INT", {"default": 1}),
|
||||||
},
|
},
|
||||||
"hidden": {
|
"hidden": {
|
||||||
**{f"input_{i}": (Everything("*"), {"forceInput": "True"}) for i in range(2, 11)}
|
**{f"input_{i}": (Everything("*"), {"forceInput": "True"}) for i in range(1, 11)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,11 +36,32 @@ class PickInput:
|
|||||||
CATEGORY = "Bjornulf"
|
CATEGORY = "Bjornulf"
|
||||||
|
|
||||||
def play_audio(self):
|
def play_audio(self):
|
||||||
audio_file = os.path.join(os.path.dirname(__file__), 'bell.m4a')
|
# Check if the operating system is Windows
|
||||||
sound = AudioSegment.from_file(audio_file, format="m4a")
|
if sys.platform.startswith('win'):
|
||||||
play(sound)
|
try:
|
||||||
|
# Load the audio file into memory
|
||||||
|
audio_file = os.path.join(os.path.dirname(__file__), 'bell.m4a')
|
||||||
|
|
||||||
def pick_input(self, **kwargs):
|
# Load the audio segment without writing to any temp files
|
||||||
|
sound = AudioSegment.from_file(audio_file, format="m4a")
|
||||||
|
|
||||||
|
# Export the AudioSegment to a WAV file in memory
|
||||||
|
wav_io = io.BytesIO()
|
||||||
|
sound.export(wav_io, format='wav')
|
||||||
|
wav_data = wav_io.getvalue()
|
||||||
|
|
||||||
|
# Play the WAV data using winsound
|
||||||
|
import winsound
|
||||||
|
winsound.PlaySound(wav_data, winsound.SND_MEMORY)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"An error occurred: {e}")
|
||||||
|
else:
|
||||||
|
audio_file = os.path.join(os.path.dirname(__file__), 'bell.m4a')
|
||||||
|
sound = AudioSegment.from_file(audio_file, format="m4a")
|
||||||
|
play(sound)
|
||||||
|
|
||||||
|
def pick_input(self, seed, **kwargs):
|
||||||
|
random.seed(seed)
|
||||||
logging.info(f"Selected input at the start: {PickInput.selected_input}")
|
logging.info(f"Selected input at the start: {PickInput.selected_input}")
|
||||||
self.play_audio()
|
self.play_audio()
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "bjornulf_custom_nodes"
|
name = "bjornulf_custom_nodes"
|
||||||
description = "Nodes: Ollama, Text to Speech, Combine Texts, Random Texts, Save image for Bjornulf LobeChat, Text with random Seed, Random line from input, Combine images, Image to grayscale (black & white), Remove image Transparency (alpha), Resize Image, ..."
|
description = "Nodes: Ollama, Text to Speech, Combine Texts, Random Texts, Save image for Bjornulf LobeChat, Text with random Seed, Random line from input, Combine images, Image to grayscale (black & white), Remove image Transparency (alpha), Resize Image, ..."
|
||||||
version = "0.32"
|
version = "0.33"
|
||||||
license = {file = "LICENSE"}
|
license = {file = "LICENSE"}
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
|
|||||||
@@ -22,16 +22,12 @@ app.registerExtension({
|
|||||||
})
|
})
|
||||||
.catch(error => console.error('Error:', error));
|
.catch(error => console.error('Error:', error));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Set seed widget to hidden input
|
||||||
|
const seedWidget = node.widgets.find((w) => w.name === "seed");
|
||||||
|
if (seedWidget) {
|
||||||
|
seedWidget.type = "HIDDEN";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// BASIC BUTTON
|
|
||||||
// app.registerExtension({
|
|
||||||
// name: "Bjornulf.PauseResume",
|
|
||||||
// async nodeCreated(node) {
|
|
||||||
// if (node.comfyClass === "Bjornulf_PauseResume") {
|
|
||||||
// node.addWidget("button","Resume","Resume", (...args) => { console.log("lol"); } )
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
@@ -4,33 +4,31 @@ app.registerExtension({
|
|||||||
name: "Bjornulf.PickInput",
|
name: "Bjornulf.PickInput",
|
||||||
async nodeCreated(node) {
|
async nodeCreated(node) {
|
||||||
if (node.comfyClass === "Bjornulf_PickInput") {
|
if (node.comfyClass === "Bjornulf_PickInput") {
|
||||||
|
|
||||||
const updateInputButtons = (numInputs) => {
|
const updateInputButtons = (numInputs) => {
|
||||||
// Remove all existing widgets
|
// Remove only the dynamic widgets (input buttons and stop button)
|
||||||
node.widgets.length = 1;
|
node.widgets = node.widgets.filter((w) => !w.dynamicWidget);
|
||||||
|
|
||||||
// Re-add the number_of_inputs widget
|
|
||||||
// const numInputsWidget = node.addWidget("number", "Number of Inputs", "number_of_inputs", (v) => {
|
|
||||||
// updateInputs();
|
|
||||||
// app.graph.setDirtyCanvas(true);
|
|
||||||
// return v;
|
|
||||||
// }, { min: 1, max: 10, step: 1, precision: 0 });
|
|
||||||
|
|
||||||
// Add new input buttons
|
// Add new input buttons
|
||||||
for (let i = 1; i < numInputs + 1; i++) {
|
for (let i = 1; i <= numInputs; i++) {
|
||||||
node.addWidget("button", `Input ${i}`, `input_button_${i}`, () => {
|
const inputButton = node.addWidget(
|
||||||
fetch(`/bjornulf_select_input_${i}`, { method: "GET" })
|
"button",
|
||||||
.then((response) => response.text())
|
`Input ${i}`,
|
||||||
.then((data) => {
|
`input_button_${i}`,
|
||||||
console.log(`Input ${i} response:`, data);
|
() => {
|
||||||
// You can update the UI here if needed
|
fetch(`/bjornulf_select_input_${i}`, { method: "GET" })
|
||||||
})
|
.then((response) => response.text())
|
||||||
.catch((error) => console.error("Error:", error));
|
.then((data) => {
|
||||||
});
|
console.log(`Input ${i} response:`, data);
|
||||||
|
// You can update the UI here if needed
|
||||||
|
})
|
||||||
|
.catch((error) => console.error("Error:", error));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
inputButton.dynamicWidget = true; // Tag as dynamic
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-add the Stop button
|
// Add the Stop button
|
||||||
node.addWidget("button", "Stop", "Stop", () => {
|
const stopButton = node.addWidget("button", "Stop", "Stop", () => {
|
||||||
fetch("/bjornulf_stop_pick", { method: "GET" })
|
fetch("/bjornulf_stop_pick", { method: "GET" })
|
||||||
.then((response) => response.text())
|
.then((response) => response.text())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
@@ -39,6 +37,7 @@ app.registerExtension({
|
|||||||
})
|
})
|
||||||
.catch((error) => console.error("Error:", error));
|
.catch((error) => console.error("Error:", error));
|
||||||
});
|
});
|
||||||
|
stopButton.dynamicWidget = true; // Tag as dynamic
|
||||||
|
|
||||||
node.setSize(node.computeSize());
|
node.setSize(node.computeSize());
|
||||||
};
|
};
|
||||||
@@ -61,7 +60,6 @@ app.registerExtension({
|
|||||||
input.name.startsWith("input_")
|
input.name.startsWith("input_")
|
||||||
);
|
);
|
||||||
|
|
||||||
// const Everything = Symbol('Everything');
|
|
||||||
// Determine if we need to add or remove inputs
|
// Determine if we need to add or remove inputs
|
||||||
if (existingInputs.length < numInputs) {
|
if (existingInputs.length < numInputs) {
|
||||||
// Add new inputs if not enough existing
|
// Add new inputs if not enough existing
|
||||||
@@ -86,12 +84,6 @@ app.registerExtension({
|
|||||||
node.setSize(node.computeSize());
|
node.setSize(node.computeSize());
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set seed widget to hidden input
|
|
||||||
const seedWidget = node.widgets.find((w) => w.name === "seed");
|
|
||||||
if (seedWidget) {
|
|
||||||
seedWidget.type = "HIDDEN";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move number_of_inputs to the top initially
|
// Move number_of_inputs to the top initially
|
||||||
const numInputsWidget = node.widgets.find(
|
const numInputsWidget = node.widgets.find(
|
||||||
(w) => w.name === "number_of_inputs"
|
(w) => w.name === "number_of_inputs"
|
||||||
@@ -109,6 +101,12 @@ app.registerExtension({
|
|||||||
|
|
||||||
// Delay the initial update to ensure node is fully initialized
|
// Delay the initial update to ensure node is fully initialized
|
||||||
setTimeout(updateInputs, 0);
|
setTimeout(updateInputs, 0);
|
||||||
|
|
||||||
|
// Hide the seed widget
|
||||||
|
const seedWidget = node.widgets.find((w) => w.name === "seed");
|
||||||
|
if (seedWidget) {
|
||||||
|
seedWidget.type = "HIDDEN";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -36,10 +36,10 @@ app.registerExtension({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Set seed widget to hidden input
|
// Set seed widget to hidden input
|
||||||
const seedWidget = node.widgets.find(w => w.name === "seed");
|
// const seedWidget = node.widgets.find(w => w.name === "seed");
|
||||||
if (seedWidget) {
|
// if (seedWidget) {
|
||||||
seedWidget.type = "HIDDEN";
|
// seedWidget.type = "HIDDEN";
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Move number_of_images to the top initially
|
// Move number_of_images to the top initially
|
||||||
const numInputsWidget = node.widgets.find(w => w.name === "number_of_images");
|
const numInputsWidget = node.widgets.find(w => w.name === "number_of_images");
|
||||||
|
|||||||
Reference in New Issue
Block a user