diff --git a/fetch_filter.py b/fetch_filter.py index 9ca1a33..e55afc4 100644 --- a/fetch_filter.py +++ b/fetch_filter.py @@ -4,6 +4,8 @@ from typing import Dict, Tuple class FetchMeFilter: + MAX_CODEX = 10 + @classmethod def INPUT_TYPES(cls): return { @@ -11,14 +13,8 @@ class FetchMeFilter: "text": ("STRING", {"forceInput": True}), }, "optional": { - "codex_1": ("DICT",), - "codex_2": ("DICT",), - "codex_3": ("DICT",), - "codex_4": ("DICT",), - "codex_5": ("DICT",), - "codex_6": ("DICT",), - "codex_7": ("DICT",), - "codex_8": ("DICT",), + f"codex_{idx}": ("DICT",) + for idx in range(1, cls.MAX_CODEX + 1) }, } @@ -43,6 +39,8 @@ class FetchMeFilter: codex_6: Dict | None = None, codex_7: Dict | None = None, codex_8: Dict | None = None, + codex_9: Dict | None = None, + codex_10: Dict | None = None, ) -> Tuple[str]: out = "" if text is None else str(text) @@ -55,6 +53,8 @@ class FetchMeFilter: self._merge_codex(merged, codex_6) self._merge_codex(merged, codex_7) self._merge_codex(merged, codex_8) + self._merge_codex(merged, codex_9) + self._merge_codex(merged, codex_10) for key, value in merged.items(): token = str(key) diff --git a/js/fetch_theme.js b/js/fetch_theme.js index 6dd0149..18add18 100644 --- a/js/fetch_theme.js +++ b/js/fetch_theme.js @@ -13,6 +13,8 @@ const FILTER_INPUT_LABELS = { codex_6: "codex_VI", codex_7: "codex_VII", codex_8: "codex_VIII", + codex_9: "codex_IX", + codex_10: "codex_X", }; function applyBrandColor(node) { @@ -35,6 +37,17 @@ function relabelInputs(node, labels) { } } +function codexIndex(name) { + if (typeof name !== "string") { + return null; + } + const match = /^codex_(\d+)$/.exec(name); + if (!match) { + return null; + } + return Number(match[1]); +} + function keyIndex(name) { if (typeof name !== "string") { return null; @@ -136,6 +149,68 @@ function installDynamicKeyFields(node) { refresh(); } +function installDynamicFilterInputs(node) { + if (!Array.isArray(node.inputs) || node.inputs.length === 0 || node._fetchDynamicCodexInstalled) { + return; + } + + const allInputs = [...node.inputs]; + const codexEntries = allInputs + .map((input, pos) => ({ input, idx: codexIndex(input?.name), pos })) + .filter((entry) => Number.isFinite(entry.idx)) + .sort((a, b) => a.idx - b.idx); + + if (codexEntries.length === 0) { + return; + } + + const firstCodexPos = Math.min(...codexEntries.map((e) => e.pos)); + const lastCodexPos = Math.max(...codexEntries.map((e) => e.pos)); + const prefix = allInputs.slice(0, firstCodexPos); + const suffix = allInputs.slice(lastCodexPos + 1); + const codexInputs = codexEntries.map((e) => e.input); + + const refresh = () => { + let lastConnected = 0; + + for (let i = 0; i < codexInputs.length; i += 1) { + if (codexInputs[i]?.link != null) { + lastConnected = i + 1; + } + } + + const desiredCount = Math.max(1, Math.min(codexInputs.length, lastConnected + 1)); + node.inputs = [...prefix, ...codexInputs.slice(0, desiredCount), ...suffix]; + relabelInputs(node, FILTER_INPUT_LABELS); + + if (typeof node.computeSize === "function" && typeof node.setSize === "function") { + node.setSize(node.computeSize()); + } + node.setDirtyCanvas(true, true); + }; + + const originalConnectionsChange = node.onConnectionsChange; + node.onConnectionsChange = function (...args) { + const result = typeof originalConnectionsChange === "function" + ? originalConnectionsChange.apply(this, args) + : undefined; + refresh(); + return result; + }; + + const originalConfigure = node.onConfigure; + node.onConfigure = function (...args) { + const result = typeof originalConfigure === "function" + ? originalConfigure.apply(this, args) + : undefined; + refresh(); + return result; + }; + + node._fetchDynamicCodexInstalled = true; + refresh(); +} + app.registerExtension({ name: "FetchMe.ThemeAndLabels", nodeCreated(node) { @@ -146,7 +221,7 @@ app.registerExtension({ applyBrandColor(node); if (node.comfyClass === "FetchMeFilter") { - relabelInputs(node, FILTER_INPUT_LABELS); + installDynamicFilterInputs(node); } if (DYNAMIC_KEY_CLASSES.has(node.comfyClass)) {