Update to 7.8

7.8
This commit is contained in:
chrisgoringe
2026-03-26 11:44:27 +11:00
committed by GitHub
14 changed files with 118 additions and 37 deletions
+50 -25
View File
@@ -8,12 +8,39 @@
Check out [Image Picker](https://github.com/chrisgoringe/cg-image-filter) for another way to make some workflows smoother.
# What is Anything Everywhere?
The `Anything Everywhere` node takes one or more inputs and sends the data to other nodes that need it.
You can connect as many inputs to an `Anything Everywhere` node as you like, and there are a range of ways
to control where the data will be sent.
Here's the standard ComfyUI template modified to use `AnythingEverywhere`
|workflow|output image you can drop into Comfy|
|-|-|
|![simple](docs/simple-example.png)|![simple](docs/simple-example-image.png)|
The `MODEL`, `CLIP`, and `VAE` are automatically broadcast to all the places they are needed.
Doesn't make much difference in this simple case, but with complex workflows it really does.
This is what the default wan 2.2 s2v video workflow looks like:
|before|after|
|-|-|
|![before](docs/before.png)|![after](docs/after.png)|
# Getting started
Drop [this workflow](docs/UE_example.json) into Comfy, and take a look at how it works.
# Common Questions
## How do I get positive and negative conditionings to work?
Connect both to a single UE node, and then rename the inputs. See [here](https://github.com/chrisgoringe/cg-use-everywhere/issues/317#issuecomment-3663225670).
Or use node broadcasting, as in the [example workflow](docs/UE_example.json)
## Why doesn't it work with reroutes / primitives?
Nodes which dynamically work out their data type are a real problem that isn't worth the complexity to fix. See [here](https://github.com/chrisgoringe/cg-use-everywhere/tree/main#primitives-and-reroutes) for more info.
@@ -24,6 +51,12 @@ Yes. See Combo Clone node [here](https://github.com/chrisgoringe/cg-use-everywhe
# Recent Changes
## 7.8
- Added regex match of outputs to the repeated types options
- Fixed issues with the new ComfyUI autogrow inputs
- Fixed API export to save with real links [389](https://github.com/chrisgoringe/cg-use-everywhere/issues/389)
## 7.7
- Added "Apply to unrepeated output" options
@@ -37,7 +70,7 @@ Yes. See Combo Clone node [here](https://github.com/chrisgoringe/cg-use-everywhe
- Added "Send to Any" option in restrictions
<details>
<summary>Older changes since 7.0</summary>
<summary>Older changes</summary>
## 7.5
@@ -85,27 +118,6 @@ Bugfixes:
</details>
# What is Anything Everywhere?
The `Anything Everywhere` node takes one or more inputs and sends the data to other nodes that need it.
You can connect as many inputs to an `Anything Everywhere` node as you like, and there are a range of ways
to control where the data will be sent.
Here's the standard ComfyUI template modified to use `AnythingEverywhere`
|workflow|output image you can drop into Comfy|
|-|-|
|![simple](docs/simple-example.png)|![simple](docs/simple-example-image.png)|
The `MODEL`, `CLIP`, and `VAE` are automatically broadcast to all the places they are needed.
Doesn't make much difference in this simple case, but with complex workflows it really does.
This is what the default wan 2.2 s2v video workflow looks like:
|before|after|
|-|-|
|![before](docs/before.png)|![after](docs/after.png)|
# Any node broadcasting
<details>
@@ -153,6 +165,9 @@ either the name of the input slot on the target node, or the name of the target
The `match start` and `match end` options require that the input names match from the start (or end) for the full length of the shorter:
so you can match `seed` to `seed` or `noise_seed` by naming the `Anything Everywhere` input `seed` and selecting `Match end of input names`.
You can also give the output a name which is a regex, and select `Regex match of input names` - so if your output is named `prompt|text` it
will match inputs named `prompt` or `text`.
If `Apply to Unrepeated` is set to `Yes`, the `Repeated Types` rule will be applied to all outputs, whether or not they are repeated.
`Send To Any`(default 'no') can be used to allow this node to send data to inputs with the `Any` type.
@@ -214,13 +229,13 @@ Animation takes quite a lot of processing, so don't use it unless you really nee
Any node that is capable of broadcasting data (a UE node, or another node to which broadcasting has been added) is marked with a circle in the top left hand corner.
If the circle is green, the node has no additional restrictions on where data will be sent;
if it is red, it has one or more restrictions (which you can see by hovering your mouse over it, or by editing restrictions
if it is yellow, it has one or more restrictions (which you can see by hovering your mouse over it, or by editing restrictions
with the option on the right click menu, or by double clicking the node).
If the node is actually sending data, the circle (red or green) is bold; if the node is capable of sending but is not actually making
If the node is actually sending data, the circle (red or yellow) is bold; if the node is capable of sending but is not actually making
and connections, it is muted.
![redgreen](docs/redgreen.png)
![redgreen](docs/yellowgreen.png)
</details>
<details>
@@ -242,6 +257,16 @@ here `merged` can broadcast, but isn't, `x` can broadcast and is, and `y` is set
</details>
<details>
<summary>Conflicts show up in red</summary>
If two (or more) broadcasters with the same priority could send to the same input, the input will be marked with a red cross.
If UE links are being shown all possible links are shown in red. Here two model loaders are broadcasting...
![conflict](docs/conflict.png)
</details>
# Special Case Nodes
<details>
+1 -1
View File
@@ -1,7 +1,7 @@
from comfy_api.latest import ComfyExtension, io
from .use_everywhere import SeedEverywhere, AnythingEverywhere, AnythingSomewhere, AnythingEverywhereTriplet, SimpleString, ComboClone, AnythingEverywherePrompts
UE_VERSION = "7.7.1"
UE_VERSION = "7.8"
WEB_DIRECTORY = "./js"
__all__ = [ "WEB_DIRECTORY"]
File diff suppressed because one or more lines are too long
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

+1
View File
@@ -32,6 +32,7 @@ export function language_changed(is_now, was_before) {
i18n("Match start of input names"),
i18n("Match end of input names"),
i18n("Inputs matches target node name"),
i18n("Regex match of input names"),
]
GROUP_RESTRICTION_OPTIONS = [
+1 -1
View File
@@ -1,4 +1,4 @@
export const VERSION = "7.7.1"
export const VERSION = "7.8"
class Shared {
constructor() {
+12
View File
@@ -275,6 +275,18 @@ app.registerExtension({
return await shared.graphAnalyser.call_function_with_modified_graph( original_graphToPrompt )
}
/*
Find the Export as API function and wrap it
*/
const export_workflow_api = app.extensionManager.command.commands.find((c)=>(c.id=='Comfy.ExportWorkflowAPI'))
if (export_workflow_api) {
const original = export_workflow_api.function
export_workflow_api.function = async function () {
await shared.graphAnalyser.call_function_with_modified_graph( ()=>{ original.apply(this, arguments)} )
}
}
/*
Modifications to the canvas
- listen for set-graph to mark the link list as out of date when we open or close a subgraph
+14
View File
@@ -38,6 +38,20 @@ function _convert_to_links(ue, added_links, removed_links) {
});
}
export function remove_comfyDynamic_autogrow(graph) {
graph.nodes.filter((node)=>(node.comfyDynamic?.autogrow)).forEach((node)=>{
node.__ue_removed_comfyDynamic_autogrow = node.comfyDynamic.autogrow
node.comfyDynamic.autogrow = {}
})
const restorer = function() {
graph.nodes.filter((node)=>(node.__ue_removed_comfyDynamic_autogrow)).forEach((node)=>{
node.comfyDynamic.autogrow = node.__ue_removed_comfyDynamic_autogrow
node.__ue_removed_comfyDynamic_autogrow = undefined
})
}
return { restorer:restorer }
}
export function convert_to_links(ues, control_node, graph) {
if (control_node) {
if (!graph) graph = control_node.graph
+17 -3
View File
@@ -152,10 +152,15 @@ function validity_errors(params) {
}
export class Ambiguity {
constructor( data ) {
Object.assign(this, data)
this.matches = []
}
/*
name : display_name of node
id : node.id
input : input.name
graph : the graph the node is in
matches : [
{
type : m[i].controller.type,
@@ -237,16 +242,17 @@ export class UseEverywhereList {
if (matches.length>1) {
matches.sort((a,b) => b.priority-a.priority);
if(matches[0].priority == matches[1].priority) {
const msg = new Ambiguity()
Object.assign(msg, { name:display_name(node), id:node.id, input:input.name, matches:[] })
const msg = new Ambiguity( { name:display_name(node), id:node.id, input:input.name, graph:(node.graph || node.subgraph) } )
matches.filter((m)=>(m.priority == matches[0].priority)).forEach((m)=>{
var ni = node.inputs?.findIndex((i)=>(i==input))
if (ni==undefined) ni = node.allSlots?.findIndex((i)=>(i==input))
msg.matches.push( {
type : m.controller.type,
id : m.controller.id,
index : m.control_node_input_index,
node : node,
node_index : node.inputs.findIndex((i)=>(i==input))
node_index : ni
})
})
@@ -363,6 +369,14 @@ export class UseEverywhereList {
return (target_name == input_name)
}
}
if (rule == 4) { // 4 input as regex matches input
additional_requirement = (target_input, _) => {
const re = new RegExp(input_name)
const target_name = target_input.label || target_input.name
return re.exec(target_name)
}
}
}
this.add_ue(node, i, connection.type, [connection.link.origin_id.toString(), connection.link.origin_slot], input_regex, additional_requirement);
}
+2 -1
View File
@@ -1,6 +1,6 @@
import { UseEverywhereList } from "./use_everywhere_classes.js";
import { node_is_live, is_connected, is_UEnode, Logger, Pausable, node_can_broadcast } from "./use_everywhere_utilities.js";
import { convert_to_links } from "./use_everywhere_apply.js";
import { convert_to_links, remove_comfyDynamic_autogrow } from "./use_everywhere_apply.js";
import { app } from "../../scripts/app.js";
import { settingsCache } from "./use_everywhere_cache.js";
import { is_connectable } from "./use_everywhere_settings.js";
@@ -23,6 +23,7 @@ class GraphAnalyser extends Pausable {
Logger.log_problem(`modify_graph called but no ues could be obtained for ${graph.id}`)
console.trace()
}
this.mods.push( remove_comfyDynamic_autogrow(graph) )
const modifications = convert_to_links( ues, null, graph )
this.mods.push( modifications );
if (!graph.extra) graph.extra = {}
+18 -5
View File
@@ -194,13 +194,26 @@ export class LinkRenderController extends Pausable {
highlight_subgraph_node_connections(subgraph, ctx) {
if (!settingsCache.getSettingValue('Use Everywhere.Graphics.highlight')) return;
this.ue_list.all_connected_inputs(subgraph.outputNode).forEach((ue_connection)=>{
const pos2 = subgraph?.outputNode?.slots[ue_connection.input_index]?.pos;
const node = subgraph?.outputNode
const ue_connections = this.ue_list.all_connected_inputs(subgraph.outputNode)
ue_connections.forEach((ue_connection)=>{
const pos2 = node.slots[ue_connection.input_index]?.pos;
if (pos2) {
drawcircle(ctx, pos2, CONNECTED_1, 5, "first", {strokeStyle:LGraphCanvas.link_type_colors[ue_connection.type]})
drawcircle(ctx, pos2, CONNECTED_2, 4, "last")
}
})
shared.graphAnalyser.ambiguities.filter((ambiguity)=>(ambiguity.id==-20)).forEach((ambiguity)=>{
const index = ambiguity.matches[0]?.node_index
const pos2 = node.slots[index]?.pos
if (pos2) {
drawcross(ctx, pos2, AMBIGUITY, 7)
}
})
}
highlight_ue_connections(node, ctx) {
@@ -336,13 +349,13 @@ export class LinkRenderController extends Pausable {
shared.graphAnalyser.ambiguities.forEach((ambiguity)=>{
ambiguity.matches.forEach((m)=>{
if (app.canvas.node_over == m.node) {
if (app.canvas.node_over == m.node || ambiguity.id==-20 && ambiguity.graph.outputNode?.isPointerOver) {
this._render_ue_link(
{
graph : m.node.graph,
graph : ambiguity.graph,
sending_to : m.node,
input_index : m.node_index,
control_node : m.node.graph.getNodeById(m.id),
control_node : ambiguity.graph.getNodeById(m.id),
control_node_input_index : m.index,
type : m.type,
}, ctx, 0, "#F00")
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "cg-use-everywhere"
description = "A set of nodes that allow data to be 'broadcast' to some or all unconnected inputs. Greatly reduces link spaghetti."
version = "7.7.1"
version = "7.8"
license = { file = "LICENSE" }
dependencies = [
"comfyui-frontend-package>=1.25.0"