n8n-nodes-comfyui-media
Version:
n8n node to integrate with ComfyUI stable diffusion workflows for image to video conversion
147 lines • 6.62 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ComfyuiWfToMedia = void 0;
const n8n_workflow_1 = require("n8n-workflow");
const apiClient_1 = require("./apiClient");
const poller_1 = require("./poller");
const workflowService_1 = require("./workflowService");
class ComfyuiWfToMedia {
constructor() {
this.description = {
displayName: 'ComfyUI Wf to Media',
name: 'comfyuiWfToMedia',
icon: 'file:comfyui.svg',
group: ['transform'],
version: 1,
description: 'Convert Wf to medias using ComfyUI workflow',
defaults: {
name: 'ComfyUI Wf to Media',
},
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: '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 workflow = this.getNodeParameter('workflow', 0);
const timeout = this.getNodeParameter('timeout', 0);
const wf = workflowService_1.WorkflowService.parse(workflow);
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((out) => out.type === 'output' || out.type === 'temp')
.map((out) => ({
...out,
url: `${apiUrl}/view?filename=${out.filename}&subfolder=${out.subfolder || ''}&type=${out.type}`,
}));
if (mediaOutputs.length === 0) {
throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: '[ComfyUI] No media outputs found' });
}
const videoOutputs = mediaOutputs.filter(o => o.filename.endsWith('.webp') || o.filename.endsWith('.mp4') || o.filename.endsWith('.gif'));
const imageOutputs = mediaOutputs.filter(o => o.filename.endsWith('.png') || o.filename.endsWith('.jpg') || o.filename.endsWith('.jpeg'));
const results = [];
const downloadAndWrap = async (output, fileType) => {
const res = await this.helpers.request({
method: 'GET',
url: output.url,
encoding: null,
resolveWithFullResponse: true,
});
if (res.statusCode === 404) {
throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: `File not found at ${output.url}` });
}
const buffer = Buffer.from(res.body);
const base64Data = buffer.toString('base64');
const fileSize = Math.round(buffer.length / 1024 * 10) / 10 + ' kB';
let mimeType = 'application/octet-stream';
if (output.filename.endsWith('.mp4'))
mimeType = 'video/mp4';
else if (output.filename.endsWith('.gif'))
mimeType = 'image/gif';
else if (output.filename.endsWith('.webp'))
mimeType = 'image/webp';
else if (output.filename.endsWith('.png'))
mimeType = 'image/png';
else if (output.filename.endsWith('.jpg') || output.filename.endsWith('.jpeg'))
mimeType = 'image/jpeg';
results.push({
json: {
mimeType,
fileName: output.filename,
data: base64Data,
status: promptResult.status,
},
binary: {
data: {
fileName: output.filename,
data: base64Data,
fileType,
fileSize,
fileExtension: output.filename.split('.').pop(),
mimeType,
},
},
});
};
for (const v of videoOutputs)
await downloadAndWrap(v, 'video');
for (const i of imageOutputs)
await downloadAndWrap(i, 'image');
return [results];
}
catch (err) {
throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: err.message });
}
}
}
exports.ComfyuiWfToMedia = ComfyuiWfToMedia;
//# sourceMappingURL=ComfyuiWfToMedia.node.js.map