UNPKG

n8n-nodes-comfyui-media

Version:

n8n node to integrate with ComfyUI stable diffusion workflows for image to video conversion

216 lines 9.64 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ComfyuiVideoToVideo = void 0; const n8n_workflow_1 = require("n8n-workflow"); const form_data_1 = __importDefault(require("form-data")); const apiClient_1 = require("./apiClient"); const inputProviders_1 = require("./inputProviders"); const workflowService_1 = require("./workflowService"); const poller_1 = require("./poller"); class ComfyuiVideoToVideo { constructor() { this.description = { displayName: 'ComfyUI Video to Video', name: 'comfyuiVideoToVideo', icon: 'file:comfyui.svg', group: ['transform'], version: 1, description: 'Convert Video to videos using ComfyUI workflow', defaults: { name: 'ComfyUI Video to Video', }, credentials: [ { name: 'comfyUIApi', required: true, }, ], inputs: ['main'], outputs: ['main'], properties: [ { displayName: 'Workflow JSON', name: 'workflow', type: 'string', typeOptions: { rows: 10, }, default: '', required: true, description: 'The ComfyUI workflow in JSON format', }, { displayName: 'Input Type', name: 'inputType', type: 'options', options: [ { name: 'URL', value: 'url' }, { name: 'Base64', value: 'base64' }, { name: 'Binary', value: 'binary' } ], default: 'url', required: true, }, { displayName: 'Input Image', name: 'inputImage', type: 'string', default: '', required: true, displayOptions: { show: { inputType: ['url', 'base64'], }, }, description: 'URL or base64 data of the input image', }, { displayName: 'Binary Property', name: 'binaryPropertyName', type: 'string', default: 'data', required: true, displayOptions: { show: { inputType: ['binary'], }, }, description: 'Name of the binary property containing the image', }, { displayName: 'Timeout', name: 'timeout', type: 'number', default: 30, description: 'Maximum time in minutes to wait for video generation', }, ], }; } async execute() { var _a; const api = new apiClient_1.N8nApiClient(this.helpers); const credentials = await this.getCredentials('comfyUIApi'); const apiUrl = credentials.apiUrl; const apiKey = credentials.apiKey; const headers = { 'Content-Type': 'application/json' }; if (apiKey) headers['Authorization'] = `Bearer ${apiKey}`; try { const inputType = this.getNodeParameter('inputType', 0); const workflow = this.getNodeParameter('workflow', 0); const timeout = this.getNodeParameter('timeout', 0); let provider; if (inputType === 'url') { const inputImage = this.getNodeParameter('inputImage', 0); provider = new inputProviders_1.UrlInputProvider(api, inputImage); } else if (inputType === 'base64') { const inputImage = this.getNodeParameter('inputImage', 0); provider = new inputProviders_1.Base64InputProvider(inputImage); } else { const binaryPropertyName = this.getNodeParameter('binaryPropertyName', 0); provider = new inputProviders_1.BinaryInputProvider(this.helpers, binaryPropertyName, this.getInputData()); } const buffer = await provider.getBuffer(); const formData = new form_data_1.default(); formData.append('image', buffer, 'input.png'); formData.append('subfolder', ''); formData.append('overwrite', 'true'); const uploadResponse = await api.request({ method: 'POST', url: `${apiUrl}/upload/image`, headers: { ...headers, ...formData.getHeaders() }, body: formData, }); const imageInfo = JSON.parse(uploadResponse); const wf = workflowService_1.WorkflowService.parse(workflow); workflowService_1.WorkflowService.injectImage(wf, imageInfo); const response = await api.request({ method: 'POST', url: `${apiUrl}/prompt`, headers, body: { prompt: wf }, json: true, }); if (!response.prompt_id) throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: 'Failed to get prompt ID' }); const poller = new poller_1.Poller(api, apiUrl, headers); const promptResult = await poller.waitForCompletion(response.prompt_id, timeout); console.log('[ComfyUI] Video generation completed'); if (((_a = promptResult.status) === null || _a === void 0 ? void 0 : _a.status_str) === 'error') { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: '[ComfyUI] Video generation failed' }); } console.log('[ComfyUI] Raw outputs structure:', JSON.stringify(promptResult.outputs, null, 2)); const mediaOutputs = Object.values(promptResult.outputs) .flatMap((nodeOutput) => nodeOutput.images || nodeOutput.gifs || []) .filter((image) => image.type === 'output' || image.type === 'temp') .map((img) => ({ ...img, url: `${apiUrl}/view?filename=${img.filename}&subfolder=${img.subfolder || ''}&type=${img.type}` })); console.log('[ComfyUI] Found media outputs:', mediaOutputs); if (mediaOutputs.length === 0) { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: '[ComfyUI] No media outputs found in results' }); } const videoOutputs = mediaOutputs.filter(output => output.filename.endsWith('.webp') || output.filename.endsWith('.mp4') || output.filename.endsWith('.gif')); if (videoOutputs.length === 0) { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: '[ComfyUI] No video outputs found in results' }); } console.log('[ComfyUI] Found video outputs:', videoOutputs); const videoOutput = videoOutputs[0]; const videoResponse = await this.helpers.request({ method: 'GET', url: videoOutput.url, encoding: null, resolveWithFullResponse: true }); if (videoResponse.statusCode === 404) { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: `Video file not found at ${videoOutput.url}` }); } console.log('[ComfyUI] Using media directly from ComfyUI'); const videoBuffer = Buffer.from(videoResponse.body); const base64Data = videoBuffer.toString('base64'); const fileSize = Math.round(videoBuffer.length / 1024 * 10) / 10 + " kB"; let mimeType = 'image/webp'; let fileExtension = 'webp'; if (videoOutput.filename.endsWith('.mp4')) { mimeType = 'video/mp4'; fileExtension = 'mp4'; } else if (videoOutput.filename.endsWith('.gif')) { mimeType = 'image/gif'; fileExtension = 'gif'; } return [[{ json: { mimeType, fileName: videoOutput.filename, data: base64Data, status: promptResult.status, }, binary: { data: { fileName: videoOutput.filename, data: base64Data, fileType: 'video', fileSize, fileExtension, mimeType } } }]]; } catch (err) { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: err.message }); } } } exports.ComfyuiVideoToVideo = ComfyuiVideoToVideo; //# sourceMappingURL=ComfyuiVideoToVideo.node.js.map