File size: 6,436 Bytes
1e3b872
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
import { app } from "../../../scripts/app.js";
import { addMenuHandler } from "./common/utils.js";
import { addNode } from "./common/utils.js";

function createKSamplerEntry(node, samplerType, subNodeType = null, isSDXL = false) {
    const samplerLabelMap = {
        "Eff": "KSampler (Efficient)",
        "Adv": "KSampler Adv. (Efficient)",
        "SDXL": "KSampler SDXL (Eff.)"
    };

    const subNodeLabelMap = {
        "XYPlot": "XY Plot",
        "NoiseControl": "Noise Control Script",
        "HiResFix": "HighRes-Fix Script",
        "TiledUpscale": "Tiled Upscaler Script",
        "AnimateDiff": "AnimateDiff Script"
    };

    const nicknameMap = {
        "KSampler (Efficient)": "KSampler",
        "KSampler Adv. (Efficient)": "KSampler(Adv)",
        "KSampler SDXL (Eff.)": "KSampler",
        "XY Plot": "XY Plot",
        "Noise Control Script": "NoiseControl",
        "HighRes-Fix Script": "HiResFix",
        "Tiled Upscaler Script": "TiledUpscale",
        "AnimateDiff Script": "AnimateDiff"
    };

    const kSamplerLabel = samplerLabelMap[samplerType];
    const subNodeLabel = subNodeLabelMap[subNodeType];

    const kSamplerNickname = nicknameMap[kSamplerLabel];
    const subNodeNickname = nicknameMap[subNodeLabel];

    const contentLabel = subNodeNickname ? `${kSamplerNickname} + ${subNodeNickname}` : kSamplerNickname;

    return {
        content: contentLabel,
        callback: function() {
            const kSamplerNode = addNode(kSamplerLabel, node, { shiftX: node.size[0] + 50 });

            // Standard connections for all samplers
            node.connect(0, kSamplerNode, 0);  // MODEL
            node.connect(1, kSamplerNode, 1);  // CONDITIONING+
            node.connect(2, kSamplerNode, 2);  // CONDITIONING-
            
            // Additional connections for non-SDXL
            if (!isSDXL) {
                node.connect(3, kSamplerNode, 3);  // LATENT
                node.connect(4, kSamplerNode, 4);  // VAE
            }

            if (subNodeLabel) {
                const subNode = addNode(subNodeLabel, node, { shiftX: 50, shiftY: node.size[1] + 50 });
                const dependencyIndex = isSDXL ? 3 : 5;
                node.connect(dependencyIndex, subNode, 0);
                subNode.connect(0, kSamplerNode, dependencyIndex);
            }
        },
    };
}

function createStackerNode(node, type) {
    const stackerLabelMap = {
        "LoRA": "LoRA Stacker",
        "ControlNet": "Control Net Stacker"
    };

    const contentLabel = stackerLabelMap[type];

    return {
        content: contentLabel,
        callback: function() {
            const stackerNode = addNode(contentLabel, node);
            
            // Calculate the left shift based on the width of the new node
            const shiftX = -(stackerNode.size[0] + 25);

            stackerNode.pos[0] += shiftX;  // Adjust the x position of the new node

            // Introduce a Y offset of 200 for ControlNet Stacker node
            if (type === "ControlNet") {
                stackerNode.pos[1] += 300;
            }

            // Connect outputs to the Efficient Loader based on type
            if (type === "LoRA") {
                stackerNode.connect(0, node, 0);
            } else if (type === "ControlNet") {
                stackerNode.connect(0, node, 1);
            }
        },
    };
}

function createXYPlotNode(node, type) {
    const contentLabel = "XY Plot";

    return {
        content: contentLabel,
        callback: function() {
            const xyPlotNode = addNode(contentLabel, node);

            // Center the X coordinate of the XY Plot node
            const centerXShift = (node.size[0] - xyPlotNode.size[0]) / 2;
            xyPlotNode.pos[0] += centerXShift;

            // Adjust the Y position to place it below the loader node
            xyPlotNode.pos[1] += node.size[1] + 60;

            // Depending on the node type, connect the appropriate output to the XY Plot node
            if (type === "Efficient") {
                node.connect(6, xyPlotNode, 0);
            } else if (type === "SDXL") {
                node.connect(3, xyPlotNode, 0);
            }
        },
    };
}

function getMenuValues(type, node) {
    const subNodeTypes = [null, "XYPlot", "NoiseControl", "HiResFix", "TiledUpscale", "AnimateDiff"];
    const excludedSubNodeTypes = ["NoiseControl", "HiResFix", "TiledUpscale", "AnimateDiff"];  // Nodes to exclude from the menu

    const menuValues = [];

    // Add the new node types to the menu first for the correct order
    menuValues.push(createStackerNode(node, "LoRA"));
    menuValues.push(createStackerNode(node, "ControlNet"));

    for (const subNodeType of subNodeTypes) {
        // Skip adding submenu items that are in the excludedSubNodeTypes array
        if (!excludedSubNodeTypes.includes(subNodeType)) {
            const menuEntry = createKSamplerEntry(node, type === "Efficient" ? "Eff" : "SDXL", subNodeType, type === "SDXL");
            menuValues.push(menuEntry);
        }
    }

    // Insert the standalone XY Plot option after the KSampler without any subNodeTypes and before any other KSamplers with subNodeTypes
    menuValues.splice(3, 0, createXYPlotNode(node, type));

    return menuValues;
}

function showAddLinkMenuCommon(value, options, e, menu, node, type) {
    const values = getMenuValues(type, node);
    new LiteGraph.ContextMenu(values, {
        event: e,
        callback: null,
        parentMenu: menu,
        node: node
    });
    return false;
}

// Extension Definition
app.registerExtension({
    name: "efficiency.addLinks",
    async beforeRegisterNodeDef(nodeType, nodeData, app) {
        const linkTypes = {
            "Efficient Loader": "Efficient",
            "Eff. Loader SDXL": "SDXL"
        };

        const linkType = linkTypes[nodeData.name];
        
        if (linkType) {
            addMenuHandler(nodeType, function(insertOption) {
                insertOption({
                    content: "⛓ Add link...",
                    has_submenu: true,
                    callback: (value, options, e, menu, node) => showAddLinkMenuCommon(value, options, e, menu, node, linkType)
                });
            });
        }
    },
});