Skip to content

Commit

Permalink
queue/q2 expanded LOOP/STOP options
Browse files Browse the repository at this point in the history
QUEUEs will signal true (TRIGGER) on complete unless halted
allow raw GLSL node to show size output
help html css cleanup for long descriptions
  • Loading branch information
Amorano committed Sep 9, 2024
1 parent 9b80937 commit d4cddce
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 24 deletions.
5 changes: 1 addition & 4 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,12 +567,9 @@ def json2html(json_dict: dict) -> str:
for param_key, param_meta in v.items():
typ = param_meta.get('type', 'UNKNOWN').upper()
typ = ', '.join([x.strip() for x in typ.split(',')])
typ = '<br>'.join(textwrap.wrap(typ, 42))
tool = param_meta.get("tooltips", '')
tool = '<br>'.join(textwrap.wrap(tool, 42))
default = html.escape(str(param_meta.get('default', '')))
ch = ', '.join(param_meta.get('choice', []))
ch = '<br>'.join(textwrap.wrap(ch, 42))
rows.append(HTML_input_row.substitute(
param_key=html.escape(param_key),
type=typ,
Expand All @@ -590,7 +587,7 @@ def json2html(json_dict: dict) -> str:
output_rows = []
for k, v in json_dict['output_parameters'].items():
tool = Lexicon._tooltipsDB.get(k, "")
tool = '<br>'.join(textwrap.wrap(tool, 65))
# tool = '<br>'.join(textwrap.wrap(tool, 65))
output_rows.append(HTML_output_row.substitute(
name=html.escape(k),
type=html.escape(v),
Expand Down
44 changes: 33 additions & 11 deletions core/utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from loguru import logger

from comfy.utils import ProgressBar
from nodes import interrupt_processing
from folder_paths import get_output_directory

from Jovimetrix import JOV_TYPE_ANY, ROOT, JOV_TYPE_IMAGE, DynamicInputType, \
Expand Down Expand Up @@ -518,8 +519,8 @@ def run(self, **kw) -> Tuple[int, list]:

class QueueBaseNode(JOVBaseNode):
CATEGORY = f"JOVIMETRIX 🔺🟩🔵/{JOV_CATEGORY}"
RETURN_TYPES = (JOV_TYPE_ANY, JOV_TYPE_ANY, "STRING", "INT", "INT")
RETURN_NAMES = (Lexicon.ANY_OUT, Lexicon.QUEUE, Lexicon.CURRENT, Lexicon.INDEX, Lexicon.TOTAL, )
RETURN_TYPES = (JOV_TYPE_ANY, JOV_TYPE_ANY, "STRING", "INT", "INT", "BOOLEAN")
RETURN_NAMES = (Lexicon.ANY_OUT, Lexicon.QUEUE, Lexicon.CURRENT, Lexicon.INDEX, Lexicon.TOTAL, Lexicon.TRIGGER, )
VIDEO_FORMATS = image_formats() + ['.wav', '.mp3', '.webm', '.mp4', '.avi', '.wmv', '.mkv', '.mov', '.mxf']

@classmethod
Expand All @@ -535,8 +536,10 @@ def INPUT_TYPES(cls) -> dict:
Lexicon.VALUE: ("INT", {"mij": 0, "default": 0, "tooltips": "The current index for the current queue item"}),
Lexicon.WAIT: ("BOOLEAN", {"default": False, "tooltips":"Hold the item at the current queue index"}),
Lexicon.RESET: ("BOOLEAN", {"default": False, "tooltips":"Reset the queue back to index 1"}),
Lexicon.BATCH: ("BOOLEAN", {"default": False, "tooltips":"Load all items, if they are loadable items, i.e. batch load images from the Queue's list"}),
Lexicon.BATCH: ("BOOLEAN", {"default": False, "tooltips":"Load all items, if they are loadable items, i.e. batch load images from the Queue's list. This can consume a lot of memory depending on the list size and each item size."}),
Lexicon.RECURSE: ("BOOLEAN", {"default": False}),
Lexicon.LOOP: ("BOOLEAN", {"default": False, "tooltips":"If the queue should loop around the end when reached. If `False`, at the end of the Queue, if there are more iterations, it will just send the previous image."}),
Lexicon.STOP: ("BOOLEAN", {"default": False, "tooltips":"When the Queue is out of items, send a `HALT` to ComfyUI."}),
}
})
return Lexicon._parse(d, cls)
Expand Down Expand Up @@ -638,18 +641,31 @@ def run(self, ident, **kw) -> Tuple[Any, List[str], str, int, int]:
if self.__previous:
self.__previous = self.process(self.__previous)

# make sure we have more to process if are a single fire queue
stop = parse_param(kw, Lexicon.STOP, EnumConvertType.BOOLEAN, False)[0]
if stop and self.__index >= self.__len:
interrupt_processing()
return self.__previous, self.__q, self.__current, self.__index_last+1, self.__len

if (wait := parse_param(kw, Lexicon.WAIT, EnumConvertType.BOOLEAN, False))[0] == True:
self.__index = self.__index_last

self.__index = max(0, self.__index) % self.__len
# otherwise loop around the end
loop = parse_param(kw, Lexicon.LOOP, EnumConvertType.BOOLEAN, False)[0]
if loop == True:
self.__index %= self.__len
else:
self.__index = max(0, self.__len-1)

self.__current = self.__q[self.__index]
data = self.__previous
self.__index_last = self.__index
info = f"QUEUE #{ident} [{self.__current}] ({self.__index})"
batched = False
if wait == True:
info += f" PAUSED"
else:
if parse_param(kw, Lexicon.BATCH, EnumConvertType.BOOLEAN, False)[0] == True:
if (batched := parse_param(kw, Lexicon.BATCH, EnumConvertType.BOOLEAN, False)[0]) == True:
data = []
mw, mh, mc = 0, 0, 0
pbar = ProgressBar(self.__len)
Expand Down Expand Up @@ -678,6 +694,8 @@ def run(self, ident, **kw) -> Tuple[Any, List[str], str, int, int]:

self.__previous = data
comfy_message(ident, "jovi-queue-ping", self.status)
if stop and batched:
interrupt_processing()
return data, self.__q, self.__current, self.__index_last+1, self.__len

@property
Expand Down Expand Up @@ -707,6 +725,7 @@ def INPUT_TYPES(cls) -> dict:
2: (Lexicon.CURRENT, {"tooltips":"Current item selected from the Queue list as a string"}),
3: (Lexicon.INDEX, {"tooltips":"Current index for the selected item in the Queue list"}),
4: (Lexicon.TOTAL, {"tooltips":"Total items in the current Queue List"}),
5: (Lexicon.TRIGGER, {"tooltips":"Send a True signal when the queue end index is reached"}),
}
})
return Lexicon._parse(d, cls)
Expand All @@ -722,8 +741,8 @@ def run(self, ident, **kw) -> Tuple[Any, List[str], str, int, int]:

class QueueTooNode(QueueBaseNode):
NAME = "QUEUE TOO (JOV) 🗃"
RETURN_TYPES = ("IMAGE", "IMAGE", "MASK", "STRING", "INT", "INT")
RETURN_NAMES = (Lexicon.IMAGE, Lexicon.RGB, Lexicon.MASK, Lexicon.CURRENT, Lexicon.INDEX, Lexicon.TOTAL, )
RETURN_TYPES = ("IMAGE", "IMAGE", "MASK", "STRING", "INT", "INT", "BOOLEAN")
RETURN_NAMES = (Lexicon.IMAGE, Lexicon.RGB, Lexicon.MASK, Lexicon.CURRENT, Lexicon.INDEX, Lexicon.TOTAL, Lexicon.TRIGGER, )
SORT = 500
DESCRIPTION = """
Manage a queue of specific items: media files. Supports various image and video formats. You can specify the current index for the queue item, enable pausing the queue, or reset it back to the first index. The node outputs the current item in the queue, the entire queue, the current index, and the total number of items in the queue.
Expand All @@ -732,19 +751,21 @@ class QueueTooNode(QueueBaseNode):
@classmethod
def INPUT_TYPES(cls) -> dict:
d = super().INPUT_TYPES()
d = {"optional": {
d = deep_merge(d, {
"optional": {
Lexicon.QUEUE: ("STRING", {"multiline": True, "default": "./res/img/test-a.png"}),
Lexicon.BATCH: ("BOOLEAN", {"default": False, "tooltips":"Load all items, if they are loadable items, i.e. batch load images from the Queue's list"}),
Lexicon.VALUE: ("INT", {"mij": 0, "default": 0, "tooltips": "The current index for the current queue item"}),
Lexicon.RECURSE: ("BOOLEAN", {"default": False}),
Lexicon.STOP: ("BOOLEAN", {"default": False, "tooltips":"When the Queue is out of items, send a `HALT` to ComfyUI."}),
Lexicon.VALUE: ("INT", {"mij": 0, "default": 0, "tooltips": "The current index for the current queue item"}),
Lexicon.WAIT: ("BOOLEAN", {"default": False, "tooltips":"Hold the item at the current queue index"}),
Lexicon.RESET: ("BOOLEAN", {"default": False, "tooltips":"Reset the queue back to index 1"}),
Lexicon.LOOP: ("BOOLEAN", {"default": False, "tooltips":"If the queue should loop around the end when reached. If `False`, at the end of the Queue, if there are more iterations, it will just send the previous image."}),
#
Lexicon.MODE: (EnumScaleMode._member_names_, {"default": EnumScaleMode.MATTE.name}),
Lexicon.WH: ("VEC2INT", {"default": (512, 512), "mij":MIN_IMAGE_SIZE, "label": [Lexicon.W, Lexicon.H]}),
Lexicon.SAMPLE: (EnumInterpolation._member_names_, {"default": EnumInterpolation.LANCZOS4.name}),
Lexicon.MATTE: ("VEC4INT", {"default": (0, 0, 0, 255), "rgb": True}),

},
"outputs": {
0: ("IMAGE", {"tooltips":"Full channel [RGBA] image. If there is an alpha, the image will be masked out with it when using this output."}),
Expand All @@ -753,8 +774,9 @@ def INPUT_TYPES(cls) -> dict:
3: (Lexicon.CURRENT, {"tooltips":"Current item selected from the Queue list as a string"}),
4: (Lexicon.INDEX, {"tooltips":"Current index for the selected item in the Queue list"}),
5: (Lexicon.TOTAL, {"tooltips":"Total items in the current Queue List"}),
6: (Lexicon.TRIGGER, {"tooltips":"Send a True signal when the queue end index is reached"}),
}
}
})
return Lexicon._parse(d, cls)

def run(self, ident, **kw) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, str, int, int]:
Expand Down
27 changes: 21 additions & 6 deletions web/jovimetrix.css
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,8 @@
background: var(--comfy-menu-bg);
color: var(--fg-color);
font: 0.9em monospace;
border-radius: 3px;
border: medium solid var(--border-color);
overflow: auto;
width: 100%;
height: 90vh;
box-sizing: border-box;
scrollbar-width: thin;
scrollbar-color: var(--fg-color) var(--bg-color);
Expand Down Expand Up @@ -189,19 +186,37 @@

.jov-panel-doc table {
width: 100%;
margin: 0px auto;
padding: 0px;
border-collapse: separate;
border-spacing: 0;
border: 1px solid var(--border-color);
}

.jov-panel-doc table td:first-child,
.jov-panel-doc table td:nth-child(2) {
width: 50px;
max-width: 75px;
min-width: 50px;
}

.jov-panel-doc table td:nth-child(3) {
width: auto;
min-width: 150px;
max-width: 350px;
}

.jov-panel-doc table td:nth-child(4),
.jov-panel-doc table td:nth-child(5) {
width: 75px;
max-width: 150px;
min-width: 50px;
}

.jov-panel-doc th, .jov-panel-doc td {
padding: 2px;
text-align: left;
}

.jov-panel-doc th {
text-align: center;
background-color: var(--comfy-input-bg);
color: var(--input-text);
}
Expand Down
2 changes: 1 addition & 1 deletion web/nodes/glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ app.registerExtension({
return;
}

widgetSizeModeHook(nodeType);
widgetSizeModeHook(nodeType, true);

const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = async function () {
Expand Down
4 changes: 4 additions & 0 deletions web/nodes/queue.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,18 @@ app.registerExtension({
const widget_hold = this.widgets.find(w => w.name === '✋🏽');
const widget_reset = this.widgets.find(w => w.name === 'RESET');
const widget_batch = this.widgets.find(w => w.name === 'BATCH');
const widget_loop = this.widgets.find(w => w.name === '🔄');
widget_batch.callback = async() => {
widgetHide(this, widget_value);
widgetHide(this, widget_hold);
widgetHide(this, widget_reset);
widgetHide(this, widget_loop);

if (!widget_batch.value) {
widgetShow(widget_value);
widgetShow(widget_hold);
widgetShow(widget_reset);
widgetShow(widget_loop);
}
nodeFitHeight(this);
}
Expand Down
4 changes: 4 additions & 0 deletions web/nodes/queue_too.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,18 @@ app.registerExtension({
const widget_hold = this.widgets.find(w => w.name === '✋🏽');
const widget_reset = this.widgets.find(w => w.name === 'RESET');
const widget_batch = this.widgets.find(w => w.name === 'BATCH');
const widget_loop = this.widgets.find(w => w.name === '🔄');
widget_batch.callback = async() => {
widgetHide(this, widget_value);
widgetHide(this, widget_hold);
widgetHide(this, widget_reset);
widgetHide(this, widget_loop);

if (!widget_batch.value) {
widgetShow(widget_value);
widgetShow(widget_hold);
widgetShow(widget_reset);
widgetShow(widget_loop);
}
nodeFitHeight(this);
}
Expand Down
4 changes: 2 additions & 2 deletions web/util/util_jov.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { nodeFitHeight } from './util_node.js'
import { widgetShowVector, widget_type_name, widgetHide, widgetShow } from './util_widget.js'

export function widgetSizeModeHook(nodeType) {
export function widgetSizeModeHook(nodeType, always_wh=false) {
const onNodeCreated = nodeType.prototype.onNodeCreated
nodeType.prototype.onNodeCreated = function () {
const me = onNodeCreated?.apply(this);
Expand All @@ -18,7 +18,7 @@ export function widgetSizeModeHook(nodeType) {
widgetHide(this, wh);
widgetHide(this, samp);

if (!['MATTE'].includes(mode.value)) {
if (always_wh || !['MATTE'].includes(mode.value)) {
widgetShow(wh);
}
if (!['CROP', 'MATTE'].includes(mode.value)) {
Expand Down

0 comments on commit d4cddce

Please sign in to comment.