Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
312e285e47 | ||
|
|
385ee20f78 | ||
|
|
487b3237ee | ||
|
|
145e15a6fd |
@@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
package-lock.json
|
||||
__pycache__
|
||||
eslint.config.js
|
||||
package.json
|
||||
@@ -117,6 +117,9 @@ Using flux klein edit(to make new objects appear) + wan video.
|
||||
|
||||
## Changes
|
||||
|
||||
* v1.0.9: Fixed up warning message for nodes inside the image input / output nodes.
|
||||
* v1.0.8: Add column node. Adds a column, repeats values until it fills the source spreadsheet's rows
|
||||
* v1.0.7: Reverted changes for errors/warnings when running. It wasn't working for KJ get/set nodes.
|
||||
* v1.0.6: Fix missing first image in video. Remove checking errors/warnings when running.
|
||||
* v1.0.5: File list node now uses the input folder as source. Don't crash when numbers in the columns are not correct.
|
||||
* v1.0.4: Added sequence, file list nodes.
|
||||
|
||||
+312
-137
@@ -6,6 +6,8 @@ from server import PromptServer
|
||||
import sys
|
||||
import csv
|
||||
import hashlib
|
||||
import base64
|
||||
import pickle
|
||||
from io import StringIO
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
@@ -62,6 +64,14 @@ class S2VComfy():
|
||||
return cls.get_prompt_dir() / ("%s%06d" % (prefix, max_num+1) )
|
||||
|
||||
|
||||
# Add empty columns if the row does not have the same amount of columns as the header
|
||||
@classmethod
|
||||
def fill_empty_columns(cls, headerRow, from_rows):
|
||||
for from_row in from_rows:
|
||||
if len(from_row) < len(headerRow):
|
||||
from_row += [None] * (len(headerRow) - len(from_row))
|
||||
|
||||
|
||||
last_processed_time = None
|
||||
# Executed after each row
|
||||
class Spreadsheet2VideoProcessImage(io.ComfyNode):
|
||||
@@ -135,24 +145,29 @@ class Spreadsheet2VideoProcessImage(io.ComfyNode):
|
||||
|
||||
|
||||
# The original nodes are replaced with this one so they won't do anything.
|
||||
class Spreadsheet2VideoDoNothing(io.ComfyNode):
|
||||
@classmethod
|
||||
def define_schema(cls) -> io.Schema:
|
||||
return io.Schema(
|
||||
node_id="Spreadsheet2VideoDoNothing",
|
||||
display_name="Internal S2V Do nothing",
|
||||
description="internal node, ignore",
|
||||
category="S2V Internal",
|
||||
inputs=[
|
||||
],
|
||||
outputs=[
|
||||
],
|
||||
hidden=[],
|
||||
)
|
||||
# class Spreadsheet2VideoDoNothing(io.ComfyNode):
|
||||
# @classmethod
|
||||
# def define_schema(cls) -> io.Schema:
|
||||
# return io.Schema(
|
||||
# node_id="Spreadsheet2VideoDoNothing",
|
||||
# display_name="Internal S2V Do nothing",
|
||||
# description="internal node, ignore",
|
||||
# category="S2V Internal",
|
||||
# inputs=[
|
||||
# ],
|
||||
# outputs=[
|
||||
# ],
|
||||
# hidden=[],
|
||||
# )
|
||||
|
||||
@classmethod
|
||||
def execute(cls, **kwargs) -> io.NodeOutput:
|
||||
return io.NodeOutput()
|
||||
# @classmethod
|
||||
# def execute(cls, **kwargs) -> io.NodeOutput:
|
||||
# return io.NodeOutput(
|
||||
# ExecutionBlocker(None)
|
||||
# )
|
||||
|
||||
# def check_lazy_status(self):
|
||||
# return []
|
||||
|
||||
|
||||
# Not executed
|
||||
@@ -223,8 +238,10 @@ class Spreadsheet2VideoInputImage(io.ComfyNode):
|
||||
def check_lazy_status(cls, COLUMN1=None):
|
||||
return []
|
||||
|
||||
# Disabled: If this is enabled the workflow will validate.
|
||||
# But it will run the original nodes that are not in any loop
|
||||
# Hacky fix for node not validating
|
||||
RETURN_TYPES=("IMAGE","*","*","*","*","*","*","*","*","*","*","*","*","*","*")
|
||||
# RETURN_TYPES=("IMAGE","*","*","*","*","*","*","*","*","*","*","*","*","*","*")
|
||||
|
||||
|
||||
class GroupInfo():
|
||||
@@ -233,6 +250,7 @@ class GroupInfo():
|
||||
self.group_name = group_name
|
||||
self.first_input_node_id = first_input_node_id
|
||||
self.output_image_link = None
|
||||
self.restored_nodes = {}
|
||||
|
||||
|
||||
def change_out_node(self, graph):
|
||||
@@ -250,111 +268,6 @@ class GroupInfo():
|
||||
# logging.warning("S2V: Could not find output image node")
|
||||
return found_node
|
||||
|
||||
@classmethod
|
||||
def map_children(cls, prompt):
|
||||
input_node_ids = []
|
||||
child_node_ids = {}
|
||||
for node_id, node in prompt.items():
|
||||
if "inputs" not in node:
|
||||
continue
|
||||
|
||||
for k, v in node["inputs"].items():
|
||||
if not is_link(v):
|
||||
continue
|
||||
|
||||
parent_node_id = v[0]
|
||||
if parent_node_id not in child_node_ids:
|
||||
child_node_ids[parent_node_id] = {"in":[], "out":[]}
|
||||
child_node_ids[parent_node_id]["out"].append(node_id)
|
||||
|
||||
if node_id not in child_node_ids:
|
||||
child_node_ids[node_id] = {"in":[], "out":[]}
|
||||
child_node_ids[node_id]["in"].append(parent_node_id)
|
||||
|
||||
if node["class_type"] == "Spreadsheet2VideoInputImage":
|
||||
input_node_ids.append(node_id)
|
||||
|
||||
return (child_node_ids,input_node_ids)
|
||||
|
||||
@classmethod
|
||||
def add_map_output_by_group_name(cls, group_name_by_output_id, child_node_ids, children, group_name):
|
||||
for child_id in children["out"]:
|
||||
if child_id in group_name_by_output_id:
|
||||
existing_group_name = group_name_by_output_id[child_id]
|
||||
if existing_group_name != group_name:
|
||||
raise ValueError(f"S2V: Node is in both column1 groups, node id:{child_id}, names:{existing_group_name}, {group_name}")
|
||||
|
||||
group_name_by_output_id[child_id] = group_name
|
||||
if child_id not in child_node_ids:
|
||||
logging.error(f"S2V: Cannot find output node id: {child_id}")
|
||||
continue
|
||||
cls.add_map_output_by_group_name(
|
||||
group_name_by_output_id,
|
||||
child_node_ids,
|
||||
child_node_ids[child_id],
|
||||
group_name
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def map_output_by_group_name(cls, group_name_by_output_id, prompt):
|
||||
(child_node_ids, input_node_ids) = cls.map_children(prompt)
|
||||
|
||||
for input_node_id in input_node_ids:
|
||||
inputImageNode = prompt[input_node_id]
|
||||
group_name = cls.get_group_name_from_node(inputImageNode)
|
||||
|
||||
group_name_by_output_id[input_node_id] = group_name
|
||||
cls.add_map_output_by_group_name(
|
||||
group_name_by_output_id,
|
||||
child_node_ids,
|
||||
child_node_ids[input_node_id],
|
||||
group_name
|
||||
)
|
||||
|
||||
return group_name_by_output_id
|
||||
|
||||
@classmethod
|
||||
def get_group_name_from_node(cls, inputImageNode):
|
||||
if inputImageNode is None or "inputs" not in inputImageNode:
|
||||
return None
|
||||
|
||||
group_name = inputImageNode["inputs"]["COLUMN1"].strip()
|
||||
if group_name == "":
|
||||
return None
|
||||
|
||||
return group_name
|
||||
|
||||
@classmethod
|
||||
def map_outputs(cls, prompt):
|
||||
(child_node_ids, input_node_ids) = cls.map_children(prompt)
|
||||
|
||||
group_name_by_output_id = {}
|
||||
cls.map_output_by_group_name(group_name_by_output_id, prompt)
|
||||
|
||||
by_group_name = {}
|
||||
for input_node_id in input_node_ids:
|
||||
inputImageNode = prompt[input_node_id]
|
||||
|
||||
group_name = cls.get_group_name_from_node(inputImageNode)
|
||||
if group_name is None:
|
||||
continue
|
||||
|
||||
if group_name in by_group_name:
|
||||
raise ValueError(f"S2V: Duplicate group names: {group_name}")
|
||||
|
||||
group_info = GroupInfo(input_node_id, group_name)
|
||||
by_group_name[group_name] = group_info
|
||||
|
||||
group_info.add_orig_node_ids(
|
||||
prompt,
|
||||
child_node_ids[input_node_id],
|
||||
child_node_ids,
|
||||
group_name_by_output_id,
|
||||
0
|
||||
)
|
||||
logging.info(f"S2V: group: {group_name}, nodes: {group_info.get_orig_node_ids_count()}")
|
||||
|
||||
return by_group_name
|
||||
|
||||
def add_orig_node_ids(
|
||||
self,
|
||||
@@ -362,10 +275,12 @@ class GroupInfo():
|
||||
children,
|
||||
child_node_ids,
|
||||
group_name_by_output_id,
|
||||
parent_is_out,
|
||||
depth
|
||||
):
|
||||
for child_id in (children["in"] + children["out"]):
|
||||
for (child_id, node_is_out) in ([ [i,False] for i in children["in"]] + [ [i,True] for i in children["out"]]):
|
||||
must_be_group = group_name_by_output_id[child_id] if child_id in group_name_by_output_id else None
|
||||
is_out = parent_is_out and node_is_out
|
||||
|
||||
class_type = prompt[child_id]["class_type"]
|
||||
if (
|
||||
@@ -376,8 +291,8 @@ class GroupInfo():
|
||||
(must_be_group is not None and must_be_group != self.group_name)
|
||||
):
|
||||
pass
|
||||
elif (child_id not in self.orig_node_ids):
|
||||
self.orig_node_ids[child_id] = True
|
||||
elif(child_id not in self.orig_node_ids):
|
||||
self.orig_node_ids[child_id] = is_out
|
||||
|
||||
if child_id in child_node_ids:
|
||||
self.add_orig_node_ids(
|
||||
@@ -385,8 +300,13 @@ class GroupInfo():
|
||||
child_node_ids[child_id],
|
||||
child_node_ids,
|
||||
group_name_by_output_id,
|
||||
is_out,
|
||||
depth+1
|
||||
)
|
||||
elif(is_out is True):
|
||||
# if the node is on the output path ever. It is out.
|
||||
# Cause the path is not processed in any order.
|
||||
self.orig_node_ids[child_id] = is_out
|
||||
|
||||
def get_orig_node_ids_count(self):
|
||||
return len(self.orig_node_ids.keys())
|
||||
@@ -396,7 +316,11 @@ class GroupInfo():
|
||||
|
||||
node_id_map = {}
|
||||
for node_id in contained:
|
||||
original_node = prompt[node_id]
|
||||
if node_id in prompt:
|
||||
original_node = prompt[node_id]
|
||||
else:
|
||||
original_node = self.restored_nodes[node_id]
|
||||
|
||||
new_node = graph.node(original_node["class_type"])
|
||||
new_node.set_override_display_id(node_id)
|
||||
node_id_map[node_id] = (original_node, new_node)
|
||||
@@ -485,9 +409,188 @@ class GroupInfo():
|
||||
logging.warning(f"S2V: not enough columns in row, column: {v[1]}, row: {','.join(row)}")
|
||||
return foundImageInput
|
||||
|
||||
def replace_with_do_nothing(self, prompt):
|
||||
for remove_node_id in self.orig_node_ids.keys():
|
||||
prompt[remove_node_id]['class_type']="Spreadsheet2VideoDoNothing"
|
||||
# def replace_with_do_nothing(self, prompt):
|
||||
# for remove_node_id in self.orig_node_ids.keys():
|
||||
# node = prompt[remove_node_id]
|
||||
# node['class_type']="Spreadsheet2VideoDoNothing"
|
||||
# node['inputs']={}
|
||||
|
||||
@classmethod
|
||||
def restore_group_infos_from_prompt(cls, prompt):
|
||||
by_group_name = {}
|
||||
for node_id, node in prompt.items():
|
||||
if "_meta" not in node:
|
||||
continue
|
||||
|
||||
meta = node["_meta"]
|
||||
if "__group_info" in meta:
|
||||
group_info = pickle.loads(base64.b64decode(meta["__group_info"]))
|
||||
if "__removed" in meta:
|
||||
group_info.restored_nodes = meta["__removed"]
|
||||
by_group_name[group_info.group_name] = group_info
|
||||
if(len(by_group_name.keys()) == 0):
|
||||
return None
|
||||
return by_group_name
|
||||
|
||||
def remove_nodes_from_prompt(self, prompt, exclude_ids):
|
||||
removed = {}
|
||||
|
||||
for node_id, is_out in self.orig_node_ids.items():
|
||||
if node_id in prompt and node_id not in exclude_ids:
|
||||
removed[node_id]= prompt[node_id]
|
||||
del prompt[node_id]
|
||||
return removed
|
||||
|
||||
@classmethod
|
||||
def remove_nodes_in_group_infos(cls, prompt, by_group_name, exclude_ids):
|
||||
for name, group_info in by_group_name.items():
|
||||
input_node = prompt[group_info.first_input_node_id]
|
||||
|
||||
raw_bytes = pickle.dumps(group_info)
|
||||
# base64 encodes the binary data into a clean, portable text string
|
||||
if "_meta" not in input_node:
|
||||
input_node["_meta"] = {}
|
||||
input_node["_meta"]["__group_info"] = base64.b64encode(raw_bytes).decode("utf-8")
|
||||
|
||||
removed = group_info.remove_nodes_from_prompt(prompt, exclude_ids)
|
||||
input_node["_meta"]["__removed"] = removed
|
||||
|
||||
|
||||
class MapOutputs():
|
||||
def __init__(self):
|
||||
self.child_node_ids = {}
|
||||
self.input_node_ids = []
|
||||
|
||||
def map_children(self, prompt):
|
||||
input_node_ids = []
|
||||
child_node_ids = {}
|
||||
for node_id, node in prompt.items():
|
||||
if "inputs" not in node or "class_type" not in node:
|
||||
continue
|
||||
|
||||
for k, v in node["inputs"].items():
|
||||
if not is_link(v):
|
||||
continue
|
||||
|
||||
parent_node_id = v[0]
|
||||
if parent_node_id not in child_node_ids:
|
||||
child_node_ids[parent_node_id] = {"in":[], "out":[]}
|
||||
child_node_ids[parent_node_id]["out"].append(node_id)
|
||||
|
||||
if node_id not in child_node_ids:
|
||||
child_node_ids[node_id] = {"in":[], "out":[]}
|
||||
child_node_ids[node_id]["in"].append(parent_node_id)
|
||||
|
||||
if node["class_type"] == "Spreadsheet2VideoInputImage":
|
||||
input_node_ids.append(node_id)
|
||||
|
||||
self.child_node_ids = child_node_ids
|
||||
self.input_node_ids = input_node_ids
|
||||
return (child_node_ids,input_node_ids)
|
||||
|
||||
def get_group_name_from_node(self, inputImageNode):
|
||||
if inputImageNode is None or "inputs" not in inputImageNode:
|
||||
return None
|
||||
|
||||
group_name = inputImageNode["inputs"]["COLUMN1"].strip()
|
||||
if group_name == "":
|
||||
return None
|
||||
|
||||
return group_name
|
||||
|
||||
def add_map_output_by_group_name(self, group_name_by_output_id, child_node_ids, children, group_name):
|
||||
for child_id in children["out"]:
|
||||
if child_id in group_name_by_output_id:
|
||||
existing_group_name = group_name_by_output_id[child_id]
|
||||
if existing_group_name != group_name:
|
||||
raise ValueError(f"S2V: Node is in both column1 groups, node id:{child_id}, names:{existing_group_name}, {group_name}")
|
||||
|
||||
group_name_by_output_id[child_id] = group_name
|
||||
if child_id not in child_node_ids:
|
||||
logging.error(f"S2V: Cannot find output node id: {child_id}")
|
||||
continue
|
||||
self.add_map_output_by_group_name(
|
||||
group_name_by_output_id,
|
||||
child_node_ids,
|
||||
child_node_ids[child_id],
|
||||
group_name
|
||||
)
|
||||
|
||||
def map_output_by_group_name(self, group_name_by_output_id, prompt):
|
||||
(child_node_ids, input_node_ids) = self.map_children(prompt)
|
||||
|
||||
for input_node_id in input_node_ids:
|
||||
inputImageNode = prompt[input_node_id]
|
||||
group_name = self.get_group_name_from_node(inputImageNode)
|
||||
|
||||
group_name_by_output_id[input_node_id] = group_name
|
||||
self.add_map_output_by_group_name(
|
||||
group_name_by_output_id,
|
||||
child_node_ids,
|
||||
child_node_ids[input_node_id],
|
||||
group_name
|
||||
)
|
||||
|
||||
return group_name_by_output_id
|
||||
|
||||
def map_outputs(self, prompt):
|
||||
(child_node_ids, input_node_ids) = self.map_children(prompt)
|
||||
|
||||
group_name_by_output_id = {}
|
||||
self.map_output_by_group_name(group_name_by_output_id, prompt)
|
||||
|
||||
by_group_name = {}
|
||||
for input_node_id in input_node_ids:
|
||||
inputImageNode = prompt[input_node_id]
|
||||
|
||||
group_name = self.get_group_name_from_node(inputImageNode)
|
||||
if group_name is None:
|
||||
continue
|
||||
|
||||
if group_name in by_group_name:
|
||||
raise ValueError(f"S2V: Duplicate group names: {group_name}")
|
||||
|
||||
group_info = GroupInfo(input_node_id, group_name)
|
||||
by_group_name[group_name] = group_info
|
||||
|
||||
group_info.add_orig_node_ids(
|
||||
prompt,
|
||||
child_node_ids[input_node_id],
|
||||
child_node_ids,
|
||||
group_name_by_output_id,
|
||||
True,
|
||||
0
|
||||
)
|
||||
logging.info(f"S2V: group: {group_name}, nodes: {group_info.get_orig_node_ids_count()}")
|
||||
|
||||
return by_group_name
|
||||
|
||||
|
||||
def mark_parent_nodes(self, mark_dict, node):
|
||||
for parent_id in node["in"]:
|
||||
if parent_id in mark_dict:
|
||||
continue
|
||||
mark_dict[parent_id] = True
|
||||
for node_id in self.child_node_ids:
|
||||
node = self.child_node_ids[node_id]
|
||||
self.mark_parent_nodes(mark_dict, node)
|
||||
|
||||
def nodes_used_by_other_nodes(self, prompt, by_group_name) -> dict[str, bool]:
|
||||
used_by_s2v_ids : dict[str, bool] = {}
|
||||
not_used_by_s2v_ids : dict[str, bool] = {}
|
||||
used_by_other_nodes : dict[str, bool] = {}
|
||||
|
||||
for name, group_info in by_group_name.items():
|
||||
for node_id in group_info.orig_node_ids.keys():
|
||||
used_by_s2v_ids[node_id] = True
|
||||
|
||||
not_used_by_s2v_ids = { k: True for k in prompt.keys() if k not in used_by_s2v_ids }
|
||||
for node_id in not_used_by_s2v_ids:
|
||||
for node_id in self.child_node_ids:
|
||||
node = self.child_node_ids[node_id]
|
||||
self.mark_parent_nodes(used_by_other_nodes, node)
|
||||
return used_by_other_nodes
|
||||
|
||||
|
||||
|
||||
class Spreadsheet2VideoFinalVideo(io.ComfyNode):
|
||||
@@ -576,6 +679,7 @@ class Spreadsheet2VideoFinalVideo(io.ComfyNode):
|
||||
|
||||
if len(waveforms)==0:
|
||||
output_audio["waveform"] = torch.empty(1, 1, 0)
|
||||
output_audio["sample_rate"] = 44100
|
||||
else:
|
||||
output_audio["waveform"] = torch.cat(waveforms, dim=1).unsqueeze(0)
|
||||
|
||||
@@ -673,6 +777,57 @@ class Spreadsheet2VideoFilesList(io.ComfyNode):
|
||||
)
|
||||
|
||||
|
||||
class Spreadsheet2VideoAddColumnSpreadsheet(io.ComfyNode):
|
||||
@classmethod
|
||||
def define_schema(cls) -> io.Schema:
|
||||
return io.Schema(
|
||||
node_id="Spreadsheet2VideoAddColumnSpreadsheet",
|
||||
display_name="Spreadsheet2Video Add column to Spreadsheet",
|
||||
category="Spreadsheet2Video",
|
||||
description="Adds columns to a spreadsheet. Repeats rows if there are not enough. Maximum rows to add is the source spreadsheet",
|
||||
search_aliases=["spreadsheet", "loop", "add", "column"],
|
||||
inputs=[
|
||||
io.String.Input("spreadsheet", multiline=True, tooltip="Comma separated values with a header row. Can use Spreadsheet2Video Load Spreadsheet node."),
|
||||
io.String.Input("spreadsheet_to_add", multiline=True, tooltip="Comma separated values with a header row. The columns to add"),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@classmethod
|
||||
def execute(cls, spreadsheet, spreadsheet_to_add) -> io.NodeOutput:
|
||||
f = StringIO(spreadsheet)
|
||||
reader = csv.reader(f, delimiter=',')
|
||||
headerRow = next(reader)
|
||||
from_rows = list(reader)
|
||||
|
||||
S2VComfy.fill_empty_columns(headerRow, from_rows)
|
||||
|
||||
f = StringIO(spreadsheet_to_add)
|
||||
reader = csv.reader(f, delimiter=',')
|
||||
|
||||
output = StringIO()
|
||||
writer = csv.writer(output)
|
||||
|
||||
addHeaderRow = next(reader)
|
||||
add_rows = list(reader)
|
||||
|
||||
writer.writerow(headerRow + addHeaderRow)
|
||||
|
||||
add_row_upto = 0
|
||||
for from_row in from_rows:
|
||||
add_row_upto = add_row_upto % len(add_rows)
|
||||
add_row = add_rows[add_row_upto]
|
||||
writer.writerow(from_row + add_row)
|
||||
add_row_upto += 1
|
||||
|
||||
return io.NodeOutput(
|
||||
output.getvalue()
|
||||
)
|
||||
|
||||
|
||||
class Spreadsheet2VideoMultiplySpreadsheet(io.ComfyNode):
|
||||
@classmethod
|
||||
def define_schema(cls) -> io.Schema:
|
||||
@@ -698,9 +853,7 @@ class Spreadsheet2VideoMultiplySpreadsheet(io.ComfyNode):
|
||||
headerRow = next(reader)
|
||||
from_rows = list(reader)
|
||||
|
||||
for from_row in from_rows:
|
||||
if len(from_row) < len(headerRow):
|
||||
from_row += [None] * (len(headerRow) - len(from_row))
|
||||
S2VComfy.fill_empty_columns(headerRow, from_rows)
|
||||
|
||||
|
||||
f = StringIO(spreadsheet_to_add)
|
||||
@@ -861,7 +1014,9 @@ class Spreadsheet2VideoNode(io.ComfyNode):
|
||||
# Use StringIO to treat the string as a file
|
||||
f = StringIO(spreadsheet)
|
||||
|
||||
by_group_name = GroupInfo.map_outputs(cls.hidden.prompt)
|
||||
by_group_name = GroupInfo.restore_group_infos_from_prompt(cls.hidden.prompt)
|
||||
if by_group_name is None:
|
||||
by_group_name = MapOutputs().map_outputs(cls.hidden.prompt)
|
||||
used_groups = {}
|
||||
|
||||
reader = csv.reader(f, delimiter=',')
|
||||
@@ -928,9 +1083,11 @@ class Spreadsheet2VideoNode(io.ComfyNode):
|
||||
previous = lastProcessImageNode.out(0)
|
||||
)
|
||||
|
||||
for group_name in used_groups:
|
||||
used_group = by_group_name[group_name]
|
||||
used_group.replace_with_do_nothing(cls.hidden.prompt)
|
||||
# Disabled: If we make the original nodes that are not in the loop DoNothing
|
||||
# Some workflows won't work with this.
|
||||
# for group_name in used_groups:
|
||||
# used_group = by_group_name[group_name]
|
||||
# used_group.replace_with_do_nothing(cls.hidden.prompt)
|
||||
|
||||
return io.NodeOutput(
|
||||
finalVideoNode.out(0),
|
||||
@@ -953,3 +1110,21 @@ class Spreadsheet2VideoNode(io.ComfyNode):
|
||||
return str(random.random())
|
||||
|
||||
|
||||
|
||||
|
||||
def prompt_handler(json_data):
|
||||
try:
|
||||
prompt = json_data["prompt"]
|
||||
map_outputs = MapOutputs()
|
||||
by_group_name = map_outputs.map_outputs(prompt)
|
||||
# remove
|
||||
used_by_other_nodes = map_outputs.nodes_used_by_other_nodes(prompt, by_group_name)
|
||||
GroupInfo.remove_nodes_in_group_infos(prompt, by_group_name, used_by_other_nodes)
|
||||
except Exception:
|
||||
logging.exception("Problem with prompt")
|
||||
return json_data
|
||||
return json_data
|
||||
|
||||
|
||||
PromptServer.instance.add_on_prompt_handler(prompt_handler)
|
||||
|
||||
|
||||
+4
-2
@@ -10,7 +10,8 @@ from .Spreadsheet2VideoNodes import (
|
||||
Spreadsheet2VideoLoadText,
|
||||
Spreadsheet2VideoSequence,
|
||||
Spreadsheet2VideoFilesList,
|
||||
Spreadsheet2VideoDoNothing,
|
||||
# Spreadsheet2VideoDoNothing,
|
||||
Spreadsheet2VideoAddColumnSpreadsheet,
|
||||
Spreadsheet2VideoMultiplySpreadsheet
|
||||
)
|
||||
|
||||
@@ -41,7 +42,8 @@ class Spreadsheet2VideoExtension(ComfyExtension):
|
||||
Spreadsheet2VideoLoadText,
|
||||
Spreadsheet2VideoSequence,
|
||||
Spreadsheet2VideoFilesList,
|
||||
Spreadsheet2VideoDoNothing,
|
||||
# Spreadsheet2VideoDoNothing,
|
||||
Spreadsheet2VideoAddColumnSpreadsheet,
|
||||
Spreadsheet2VideoMultiplySpreadsheet,
|
||||
]
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "spreadsheet2video-comfyui",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "",
|
||||
"license": "ISC",
|
||||
"author": "",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "Spreadsheet2Video-ComfyUI"
|
||||
version = "1.0.6"
|
||||
version = "1.0.9"
|
||||
description = "Use a spreadsheet as input for ComfyUI execution"
|
||||
license = { file = "LICENSE" }
|
||||
dependencies = [
|
||||
|
||||
+69
-101
@@ -12,8 +12,8 @@
|
||||
1166.8738027901068
|
||||
],
|
||||
"size": [
|
||||
312.483984375,
|
||||
158
|
||||
312.453125,
|
||||
193.984375
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
@@ -54,6 +54,8 @@
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "Spreadsheet2Video-ComfyUI",
|
||||
"ver": "145e15a6fd7c2f746444869550ee3c7a25e17126",
|
||||
"Node name for S&R": "Spreadsheet2VideoInputImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
@@ -69,7 +71,7 @@
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
78
|
||||
106
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
@@ -120,23 +122,32 @@
|
||||
1234.79316455834
|
||||
],
|
||||
"size": [
|
||||
264.0162109375,
|
||||
26
|
||||
264,
|
||||
78
|
||||
],
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 72
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"shape": 7,
|
||||
"type": "AUDIO",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"cnr_id": "Spreadsheet2Video-ComfyUI",
|
||||
"ver": "145e15a6fd7c2f746444869550ee3c7a25e17126",
|
||||
"Node name for S&R": "Spreadsheet2VideoOutputImage"
|
||||
}
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
@@ -146,8 +157,8 @@
|
||||
1046.018577649322
|
||||
],
|
||||
"size": [
|
||||
300.440416046162,
|
||||
58
|
||||
300.40625,
|
||||
93.984375
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
@@ -179,8 +190,8 @@
|
||||
1254.2865711858988
|
||||
],
|
||||
"size": [
|
||||
286.73896268632825,
|
||||
58.36471886178333
|
||||
286.71875,
|
||||
93.984375
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
@@ -239,40 +250,6 @@
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"proxyWidgets": [
|
||||
[
|
||||
"27",
|
||||
"text"
|
||||
],
|
||||
[
|
||||
"13",
|
||||
"width"
|
||||
],
|
||||
[
|
||||
"13",
|
||||
"height"
|
||||
],
|
||||
[
|
||||
"28",
|
||||
"unet_name"
|
||||
],
|
||||
[
|
||||
"30",
|
||||
"clip_name"
|
||||
],
|
||||
[
|
||||
"29",
|
||||
"vae_name"
|
||||
],
|
||||
[
|
||||
"3",
|
||||
"steps"
|
||||
],
|
||||
[
|
||||
"3",
|
||||
"control_after_generate"
|
||||
]
|
||||
],
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.3.73",
|
||||
"enableTabs": false,
|
||||
@@ -281,44 +258,33 @@
|
||||
"hasSecondTab": false,
|
||||
"secondTabText": "Send Back",
|
||||
"secondTabOffset": 80,
|
||||
"secondTabWidth": 65
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "EmptyImage",
|
||||
"pos": [
|
||||
1207.965006424334,
|
||||
719.2113395590205
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
130
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.19.3",
|
||||
"Node name for S&R": "EmptyImage"
|
||||
"secondTabWidth": 65,
|
||||
"proxyWidgetErrorQuarantine": [
|
||||
{
|
||||
"originalEntry": [
|
||||
"3",
|
||||
"control_after_generate"
|
||||
],
|
||||
"reason": "missingSubgraphInput",
|
||||
"attemptedAtVersion": 1
|
||||
}
|
||||
],
|
||||
"previewExposures": [
|
||||
{
|
||||
"name": "$$canvas-image-preview",
|
||||
"sourceNodeId": "3",
|
||||
"sourcePreviewName": "$$canvas-image-preview"
|
||||
}
|
||||
]
|
||||
},
|
||||
"widgets_values": [
|
||||
"Latina female with thick wavy hair, harbor boats and pastel houses behind. Breezy seaside light, warm tones, cinematic close-up. ",
|
||||
1024,
|
||||
1024,
|
||||
1,
|
||||
0
|
||||
"z_image_turbo_bf16.safetensors",
|
||||
"qwen_3_4b.safetensors",
|
||||
"FLUX1\\ae.safetensors",
|
||||
8
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -329,11 +295,11 @@
|
||||
704.5518187413677
|
||||
],
|
||||
"size": [
|
||||
140,
|
||||
246
|
||||
225,
|
||||
290
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -342,7 +308,13 @@
|
||||
"link": 4
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.19.3",
|
||||
@@ -362,14 +334,14 @@
|
||||
200
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "first_image",
|
||||
"shape": 7,
|
||||
"type": "IMAGE",
|
||||
"link": 3
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
@@ -379,9 +351,16 @@
|
||||
"links": [
|
||||
4
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "AUDIO",
|
||||
"type": "AUDIO",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "Spreadsheet2Video-ComfyUI",
|
||||
"ver": "145e15a6fd7c2f746444869550ee3c7a25e17126",
|
||||
"Node name for S&R": "Spreadsheet2Video"
|
||||
},
|
||||
"widgets_values": [
|
||||
@@ -390,14 +369,6 @@
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
3,
|
||||
7,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
4,
|
||||
1,
|
||||
@@ -1045,7 +1016,7 @@
|
||||
"secondTabWidth": 65
|
||||
},
|
||||
"widgets_values": [
|
||||
1007068742280709,
|
||||
1045136092634709,
|
||||
"randomize",
|
||||
8,
|
||||
1,
|
||||
@@ -1124,7 +1095,6 @@
|
||||
200
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
@@ -1137,7 +1107,6 @@
|
||||
540
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
@@ -1150,7 +1119,6 @@
|
||||
413.6
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"font_size": 24,
|
||||
"flags": {}
|
||||
}
|
||||
],
|
||||
@@ -1301,13 +1269,13 @@
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 1.1556864978176087,
|
||||
"scale": 1.0506240889250995,
|
||||
"offset": [
|
||||
-1268.0988326073784,
|
||||
-547.481125026469
|
||||
-1381.2506133337172,
|
||||
-628.9646201878417
|
||||
]
|
||||
},
|
||||
"frontendVersion": "1.42.11",
|
||||
"frontendVersion": "1.47.12",
|
||||
"VHS_latentpreview": false,
|
||||
"VHS_latentpreviewrate": 0,
|
||||
"VHS_MetadataImage": true,
|
||||
|
||||
+36
-56
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "8d94793d-f68f-467c-b91c-5a1bad8692ca",
|
||||
"revision": 0,
|
||||
"last_node_id": 11,
|
||||
"last_node_id": 13,
|
||||
"last_link_id": 5,
|
||||
"nodes": [
|
||||
{
|
||||
@@ -12,8 +12,8 @@
|
||||
4133.395402282243
|
||||
],
|
||||
"size": [
|
||||
301.040625,
|
||||
106
|
||||
301.03125,
|
||||
142
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
@@ -43,12 +43,12 @@
|
||||
"id": 7,
|
||||
"type": "Spreadsheet2VideoSequence",
|
||||
"pos": [
|
||||
-830.0402038757348,
|
||||
-832.3603875607462,
|
||||
4853.891607434261
|
||||
],
|
||||
"size": [
|
||||
301.040625,
|
||||
106
|
||||
301.015625,
|
||||
142
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
@@ -82,8 +82,8 @@
|
||||
4400
|
||||
],
|
||||
"size": [
|
||||
301.040625,
|
||||
106
|
||||
301.03125,
|
||||
142
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
@@ -117,8 +117,8 @@
|
||||
4101.516095855725
|
||||
],
|
||||
"size": [
|
||||
247.78345320808046,
|
||||
238.2740203378844
|
||||
247.765625,
|
||||
238.25
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
@@ -142,11 +142,7 @@
|
||||
"ver": "0.24.0",
|
||||
"Node name for S&R": "PreviewAny"
|
||||
},
|
||||
"widgets_values": [
|
||||
null,
|
||||
null,
|
||||
false
|
||||
]
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
@@ -156,8 +152,8 @@
|
||||
4430
|
||||
],
|
||||
"size": [
|
||||
226.80773384673182,
|
||||
212.1823816679189
|
||||
226.796875,
|
||||
212.171875
|
||||
],
|
||||
"flags": {
|
||||
"collapsed": false
|
||||
@@ -183,22 +179,18 @@
|
||||
"ver": "0.24.0",
|
||||
"Node name for S&R": "PreviewAny"
|
||||
},
|
||||
"widgets_values": [
|
||||
null,
|
||||
null,
|
||||
null
|
||||
]
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "Spreadsheet2VideoSequence",
|
||||
"pos": [
|
||||
-827.5216964337976,
|
||||
-829.841880118809,
|
||||
5156.965602783869
|
||||
],
|
||||
"size": [
|
||||
301.040625,
|
||||
106
|
||||
301.015625,
|
||||
142
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
@@ -228,11 +220,11 @@
|
||||
"id": 11,
|
||||
"type": "PreviewAny",
|
||||
"pos": [
|
||||
-469.36544276581486,
|
||||
-471.6856264508262,
|
||||
5404.420565428257
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
225,
|
||||
166
|
||||
],
|
||||
"flags": {},
|
||||
@@ -257,22 +249,18 @@
|
||||
"ver": "0.24.0",
|
||||
"Node name for S&R": "PreviewAny"
|
||||
},
|
||||
"widgets_values": [
|
||||
null,
|
||||
null,
|
||||
null
|
||||
]
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"type": "Spreadsheet2VideoSequence",
|
||||
"pos": [
|
||||
-827.1824057491543,
|
||||
-829.5025894341657,
|
||||
5402.336211698525
|
||||
],
|
||||
"size": [
|
||||
301.040625,
|
||||
106
|
||||
301.015625,
|
||||
142
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
@@ -302,11 +290,11 @@
|
||||
"id": 9,
|
||||
"type": "PreviewAny",
|
||||
"pos": [
|
||||
-469.70473345045866,
|
||||
-472.02491713547,
|
||||
5159.049956513601
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
225,
|
||||
166
|
||||
],
|
||||
"flags": {},
|
||||
@@ -331,21 +319,17 @@
|
||||
"ver": "0.24.0",
|
||||
"Node name for S&R": "PreviewAny"
|
||||
},
|
||||
"widgets_values": [
|
||||
null,
|
||||
null,
|
||||
null
|
||||
]
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "PreviewAny",
|
||||
"pos": [
|
||||
-472.22324089239635,
|
||||
-474.5434245774077,
|
||||
4855.975961163992
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
225,
|
||||
166
|
||||
],
|
||||
"flags": {},
|
||||
@@ -370,11 +354,7 @@
|
||||
"ver": "0.24.0",
|
||||
"Node name for S&R": "PreviewAny"
|
||||
},
|
||||
"widgets_values": [
|
||||
null,
|
||||
null,
|
||||
null
|
||||
]
|
||||
"widgets_values": []
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
@@ -422,14 +402,14 @@
|
||||
"groups": [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Will Error",
|
||||
"title": "Should Error",
|
||||
"bounding": [
|
||||
-891.0076443313377,
|
||||
-893.327828016349,
|
||||
4744.143303391399,
|
||||
1146.6399876260243,
|
||||
883.1031726327501
|
||||
],
|
||||
"color": "#3f789e",
|
||||
"color": "#A88",
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
@@ -448,13 +428,13 @@
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.5131581182307067,
|
||||
"scale": 0.31863081771035706,
|
||||
"offset": [
|
||||
2097.969476454836,
|
||||
-3598.220857052559
|
||||
2004.6716575603311,
|
||||
-3393.3513028960815
|
||||
]
|
||||
},
|
||||
"frontendVersion": "1.45.15",
|
||||
"frontendVersion": "1.48.7",
|
||||
"VHS_latentpreview": false,
|
||||
"VHS_latentpreviewrate": 0,
|
||||
"VHS_MetadataImage": true,
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
{
|
||||
"id": "844d351e-ec61-4bdf-b8d9-26dfd091434b",
|
||||
"revision": 0,
|
||||
"last_node_id": 96,
|
||||
"last_link_id": 189,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 91,
|
||||
"type": "PreviewAny",
|
||||
"pos": [
|
||||
-1.841804357108301,
|
||||
1074.0426332603915
|
||||
],
|
||||
"size": [
|
||||
364.28125,
|
||||
330.375
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "source",
|
||||
"type": "*",
|
||||
"link": 178
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.19.3",
|
||||
"Node name for S&R": "PreviewAny"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 89,
|
||||
"type": "Spreadsheet2VideoMultiplySpreadsheet",
|
||||
"pos": [
|
||||
-585.6675584600498,
|
||||
1069.7731994235164
|
||||
],
|
||||
"size": [
|
||||
400,
|
||||
200
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
178
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "Spreadsheet2Video-ComfyUI",
|
||||
"ver": "7342d3ec4657599baab5be5dd4414663e9d0da1a",
|
||||
"Node name for S&R": "Spreadsheet2VideoMultiplySpreadsheet"
|
||||
},
|
||||
"widgets_values": [
|
||||
"column1,prompt\nworkflow1,One\nworkflow1,Two\nworkflow1,Three\nworkflow1",
|
||||
"sampler\neuler\nheun"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 95,
|
||||
"type": "PreviewAny",
|
||||
"pos": [
|
||||
85.70426079452947,
|
||||
615.0534104526303
|
||||
],
|
||||
"size": [
|
||||
406.703125,
|
||||
308.359375
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "source",
|
||||
"type": "*",
|
||||
"link": 189
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "comfy-core",
|
||||
"ver": "0.19.3",
|
||||
"Node name for S&R": "PreviewAny"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 96,
|
||||
"type": "Spreadsheet2VideoAddColumnSpreadsheet",
|
||||
"pos": [
|
||||
-569.2349843700941,
|
||||
598.1665514472247
|
||||
],
|
||||
"size": [
|
||||
433.046875,
|
||||
327.765625
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
189
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"cnr_id": "Spreadsheet2Video-ComfyUI",
|
||||
"ver": "145e15a6fd7c2f746444869550ee3c7a25e17126",
|
||||
"Node name for S&R": "Spreadsheet2VideoAddColumnSpreadsheet"
|
||||
},
|
||||
"widgets_values": [
|
||||
"column1,prompt\nworkflow1,One\nworkflow1,Two\nworkflow1,Three\nworkflow1,Four\nworkflow1",
|
||||
"sampler\neuler\nheun"
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
178,
|
||||
89,
|
||||
0,
|
||||
91,
|
||||
0,
|
||||
"STRING"
|
||||
],
|
||||
[
|
||||
189,
|
||||
96,
|
||||
0,
|
||||
95,
|
||||
0,
|
||||
"STRING"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.7751878709002787,
|
||||
"offset": [
|
||||
835.409880916017,
|
||||
-212.2218877684238
|
||||
]
|
||||
},
|
||||
"frontendVersion": "1.47.12",
|
||||
"VHS_latentpreview": false,
|
||||
"VHS_latentpreviewrate": 0,
|
||||
"VHS_MetadataImage": true,
|
||||
"VHS_KeepIntermediate": true
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
Reference in New Issue
Block a user