From 2591d39da363e61027d5f7d052989dd1aec6a434 Mon Sep 17 00:00:00 2001 From: Terry Jia Date: Sat, 24 May 2025 09:01:43 -0400 Subject: [PATCH] add fetch node --- src/extensions/core/apiNode.ts | 97 ++++++++++++++++++++++++++++++++++ src/extensions/core/index.ts | 1 + src/locales/en/main.json | 3 +- 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/extensions/core/apiNode.ts diff --git a/src/extensions/core/apiNode.ts b/src/extensions/core/apiNode.ts new file mode 100644 index 000000000..4b0e7e310 --- /dev/null +++ b/src/extensions/core/apiNode.ts @@ -0,0 +1,97 @@ +import { t } from '@/i18n' +import { api } from '@/scripts/api' +import { app } from '@/scripts/app' +import { useExtensionService } from '@/services/extensionService' +import { useToastStore } from '@/stores/toastStore' + +useExtensionService().registerExtension({ + name: 'Comfy.FetchApi', + + async nodeCreated(node) { + if (node.constructor.comfyClass !== 'FetchApi') return + + const onExecuted = node.onExecuted + const msg = t('toastMessages.unableToFetchFile') + + const downloadFile = async ( + typeValue: string, + subfolderValue: string, + filenameValue: string + ) => { + try { + const params = [ + 'filename=' + encodeURIComponent(filenameValue), + 'type=' + encodeURIComponent(typeValue), + 'subfolder=' + encodeURIComponent(subfolderValue), + app.getRandParam().substring(1) + ].join('&') + + const fetchURL = `/view?${params}` + const response = await api.fetchApi(fetchURL) + + if (!response.ok) { + console.error(response) + useToastStore().addAlert(msg) + return false + } + + const blob = await response.blob() + const downloadFilename = filenameValue + + const url = window.URL.createObjectURL(blob) + const a = document.createElement('a') + a.style.display = 'none' + a.href = url + a.download = downloadFilename + + document.body.appendChild(a) + a.click() + document.body.removeChild(a) + + window.URL.revokeObjectURL(url) + + return true + } catch (error) { + console.error(error) + useToastStore().addAlert(msg) + return false + } + } + + const type = node.widgets?.find((w) => w.name === 'type') + const subfolder = node.widgets?.find((w) => w.name === 'subfolder') + const filename = node.widgets?.find((w) => w.name === 'filename') + + node.onExecuted = function (message: any) { + onExecuted?.apply(this, arguments as any) + + const typeInput = message.result[0] + const subfolderInput = message.result[1] + const filenameInput = message.result[2] + const autoDownload = node.widgets?.find((w) => w.name === 'auto_download') + + if (type && subfolder && filename) { + type.value = typeInput + subfolder.value = subfolderInput + filename.value = filenameInput + + if (autoDownload && autoDownload.value) { + downloadFile(typeInput, subfolderInput, filenameInput) + } + } + } + + node.addWidget('button', 'download', 'download', async () => { + if (type && subfolder && filename) { + await downloadFile( + type.value as string, + subfolder.value as string, + filename.value as string + ) + } else { + console.error(msg) + useToastStore().addAlert(msg) + } + }) + } +}) diff --git a/src/extensions/core/index.ts b/src/extensions/core/index.ts index 0d39c207a..b69140296 100644 --- a/src/extensions/core/index.ts +++ b/src/extensions/core/index.ts @@ -1,3 +1,4 @@ +import './apiNode' import './clipspace' import './contextMenuFilter' import './dynamicPrompts' diff --git a/src/locales/en/main.json b/src/locales/en/main.json index 76cdaab9f..44123f5c6 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -1273,7 +1273,8 @@ "failedToPurchaseCredits": "Failed to purchase credits: {error}", "unauthorizedDomain": "Your domain {domain} is not authorized to use this service. Please contact {email} to add your domain to the whitelist.", "useApiKeyTip": "Tip: Can't access normal login? Use the Comfy API Key option.", - "nothingSelected": "Nothing selected" + "nothingSelected": "Nothing selected", + "unableToFetchFile": "Unable to fetch file" }, "auth": { "apiKey": {