This workflow corresponds to n8n.io template #13088 — we link there as the canonical source.
This workflow follows the Agent → Form Trigger recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "99MN7VP3D8TqxHIL",
"name": "Wave Music Video Generation",
"tags": [],
"nodes": [
{
"id": "33d618d5-4a8a-4755-85e5-7c62001ace19",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
0
],
"parameters": {
"color": 7,
"width": 832,
"height": 256,
"content": "## Input Data & Directory Initialization\nCollect user input from the form and initialize a working directory using ffmpeg-api. This directory will be used to store videos, audio files, and intermediate assets throughout the workflow"
},
"typeVersion": 1
},
{
"id": "65f3273d-849d-4159-9747-c9d8c63eb174",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
256
],
"parameters": {
"color": 6,
"width": 1184,
"height": 320,
"content": "## Download Background Video\nGenerate a storage path, download the background video from the provided URL, upload it to ffmpeg-api storage, and retrieve the processed video reference for later merging."
},
"typeVersion": 1
},
{
"id": "e159a727-f664-4d03-90ab-c8c78e820d9f",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
576
],
"parameters": {
"color": 7,
"width": 1968,
"height": 368,
"content": "## AI Music Generation (Suno)\nUse an AI agent to convert the user\u2019s music theme into structured Suno prompts, generate multiple songs, poll for completion, and log song metadata for downstream processing."
},
"typeVersion": 1
},
{
"id": "0cac5fe9-94ad-4455-90ff-eb9054867131",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
944
],
"parameters": {
"color": 6,
"width": 1968,
"height": 272,
"content": "## Download Songs & Merge Audio + Video\nDownload generated songs, upload them to ffmpeg-api storage, concatenate multiple tracks into a long-form audio file, and merge the final audio with the background video"
},
"typeVersion": 1
},
{
"id": "ac2af494-38c3-442e-ba2a-2f21e97e9b2c",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
1216
],
"parameters": {
"color": 7,
"width": 1968,
"height": 448,
"content": "## Auto Upload to YouTube"
},
"typeVersion": 1
},
{
"id": "35dbd224-ad12-4f0e-9d53-a8c60b5978f8",
"name": "Suno Wave Music Input Form",
"type": "n8n-nodes-base.formTrigger",
"position": [
416,
80
],
"parameters": {
"options": {},
"formTitle": "Song Input",
"formFields": {
"values": [
{
"fieldLabel": "Music theme",
"requiredField": true
},
{
"fieldType": "file",
"fieldLabel": "Video URL"
},
{
"fieldLabel": "Number of tracks",
"requiredField": true
}
]
},
"formDescription": "Provide music details for the background video"
},
"typeVersion": 2.3
},
{
"id": "31d465a6-ea5e-4764-97d1-79f3d0dc4087",
"name": "Create Working Directory (ffmpeg-api)",
"type": "n8n-nodes-base.httpRequest",
"position": [
608,
80
],
"parameters": {
"url": "https://api.ffmpeg-api.com/directory",
"method": "POST",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.3
},
{
"id": "2563f1c6-8e41-444b-9019-d58caf54a581",
"name": "Prepare Video Path (ffmpeg-api)",
"type": "n8n-nodes-base.httpRequest",
"position": [
432,
368
],
"parameters": {
"url": "https://api.ffmpeg-api.com/file",
"method": "POST",
"options": {},
"sendBody": true,
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "file_name",
"value": "Video_Youtube"
},
{
"name": "dir_id",
"value": "={{ $json.directory.id }}"
}
]
},
"genericAuthType": "httpHeaderAuth"
},
"typeVersion": 4.3
},
{
"id": "e0996abe-671f-4df9-86bf-dbf2cd709138",
"name": "Download Background Video",
"type": "n8n-nodes-base.httpRequest",
"position": [
624,
368
],
"parameters": {
"url": "={{ $('Suno Wave Music Input Form').item.json['Video URL'] }}",
"options": {
"response": {
"response": {
"responseFormat": "file",
"outputPropertyName": "Video"
}
}
}
},
"typeVersion": 4.3
},
{
"id": "34f89d6f-af12-406d-a867-eda612cbe80d",
"name": "Upload Video to Workspace (ffmpeg-api)",
"type": "n8n-nodes-base.httpRequest",
"position": [
800,
368
],
"parameters": {
"url": "={{ $('Prepare Video Path (ffmpeg-api)').item.json.upload.url }}",
"method": "PUT",
"options": {},
"sendBody": true,
"contentType": "binaryData",
"inputDataFieldName": "Video"
},
"typeVersion": 4.3
},
{
"id": "a2c526ad-f434-4f66-b525-b6b001f0cf30",
"name": "Retrieve Uploaded Video",
"type": "n8n-nodes-base.httpRequest",
"position": [
992,
368
],
"parameters": {
"url": "=https://api.ffmpeg-api.com/file/{{ $('Prepare Video Path (ffmpeg-api)').item.json.file.file_path }}",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"typeVersion": 4.3
},
{
"id": "497703e7-8b5d-4f40-b71a-d1d4135425a3",
"name": "Generate Music Prompts (AI Agent)",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
384,
688
],
"parameters": {
"text": "=make a song with {{ $('Suno Wave Music Input Form').item.json['Number of tracks'] }} songs\n\nReference Music Prompt:\n{{ $('Suno Wave Music Input Form').item.json['Music theme'] }}",
"options": {
"systemMessage": "=ROLE:\nYou are an expert music prompt engineer.\n\nYour task is to carefully read the reference music prompt provided by the user and use it as the core inspiration to generate multiple song prompts.\nDo NOT change, reinterpret, or override the user\u2019s instructions.\nAlways honor User Instructions as the highest priority.\n\n---\n\nTASK:\nGenerate a JSON array containing exactly 5 song prompt objects.\n\nEach object represents ONE unique song prompt inspired by the reference music prompt.\n\n---\n\nRULES:\n- Always generate EXACTLY 5 songs.\n- Number the songs sequentially from 1 to 5.\n- Each song prompt must be unique while staying consistent with the reference music style, mood, and genre.\n- Do NOT include explanations, markdown, comments, or any text outside the JSON array.\n\n---\n\nOUTPUT FORMAT:\nReturn ONLY valid JSON in the following structure:\n\n[\n {\n \"song\": 1,\n \"song_prompt\": \"detailed music prompt here\"\n },\n {\n \"song\": 2,\n \"song_prompt\": \"detailed music prompt here\"\n },\n {\n \"song\": 3,\n \"song_prompt\": \"detailed music prompt here\"\n },\n {\n \"song\": 4,\n \"song_prompt\": \"detailed music prompt here\"\n },\n {\n \"song\": 5,\n \"song_prompt\": \"detailed music prompt here\"\n }\n]\n"
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 3
},
{
"id": "9304490a-eafb-417f-b9c8-76858901f232",
"name": "Gemini LLM",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
288,
784
],
"parameters": {
"options": {},
"modelName": "models/gemini-3-flash-preview"
},
"typeVersion": 1
},
{
"id": "525a92b0-8fae-45cf-8c06-487a93b546a4",
"name": "Music Prompt Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
560,
816
],
"parameters": {
"jsonSchemaExample": "{\n \"songs\": [\n {\n \"song\": 1,\n \"song_prompt\": \"string\"\n }\n ]\n}\n"
},
"typeVersion": 1.3
},
{
"id": "ec9cd4fd-54fd-4303-89bd-ab799732b0a1",
"name": "Split Music Requests",
"type": "n8n-nodes-base.splitOut",
"position": [
704,
688
],
"parameters": {
"options": {},
"fieldToSplitOut": "output.songs"
},
"typeVersion": 1
},
{
"id": "f7cf0234-12bb-4f22-9cde-b58594a6cafb",
"name": "Create Song (Suno API)",
"type": "n8n-nodes-base.httpRequest",
"position": [
880,
688
],
"parameters": {
"url": "https://api.kie.ai/api/v1/generate",
"method": "POST",
"options": {},
"sendBody": true,
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "prompt",
"value": "={{ $json.song_prompt }}"
},
{
"name": "customMode",
"value": "false"
},
{
"name": "instrumental",
"value": "true"
},
{
"name": "model",
"value": "V5"
},
{
"name": "callBackUrl",
"value": "https://api.example.com/callback"
}
]
},
"genericAuthType": "httpHeaderAuth"
},
"typeVersion": 4.2
},
{
"id": "96b93ccc-2d63-443c-8640-9fa95102dea0",
"name": "Wait for Song Rendering",
"type": "n8n-nodes-base.wait",
"position": [
1120,
688
],
"parameters": {},
"typeVersion": 1.1
},
{
"id": "a5506c2c-f559-40f5-a20f-b7efa0df227e",
"name": "Get Generated Song",
"type": "n8n-nodes-base.httpRequest",
"position": [
1312,
688
],
"parameters": {
"url": "https://api.kie.ai/api/v1/generate/record-info ",
"options": {},
"sendQuery": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"queryParameters": {
"parameters": [
{
"name": "taskId",
"value": "={{ $json.data.taskId }}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "3e511dad-cd05-4dec-ab95-e4d22b6701c6",
"name": "Check Song Status",
"type": "n8n-nodes-base.if",
"position": [
1488,
688
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "b4ea379e-3541-4d2b-9421-f0c962c8d5e8",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.status }}",
"rightValue": "SUCCESS"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "d2ed0a72-11e7-44f8-896a-9eaf4f837ee9",
"name": "Log Song Metadata",
"type": "n8n-nodes-base.googleSheets",
"position": [
1696,
688
],
"parameters": {
"columns": {
"value": {
"Duration": "={{ $json.data.response.sunoData[0].duration }}",
"Song_URL": "={{ $json.data.response.sunoData[0].audioUrl }}",
"Tilte_Song": "={{ $json.data.response.sunoData[0].title }}{{ $json.data.response.sunoData[0].title }}"
},
"schema": [
{
"id": "Theme",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Theme",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Tilte_Song",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Tilte_Song",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Duration",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Duration",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Song_URL",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Song_URL",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1TAcHusIWoBOurWslWE1jTCwsncAmBRFkeD87FVefIZQ/edit#gid=0",
"cachedResultName": "Trang t\u00ednh1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1TAcHusIWoBOurWslWE1jTCwsncAmBRFkeD87FVefIZQ",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1TAcHusIWoBOurWslWE1jTCwsncAmBRFkeD87FVefIZQ/edit?usp=drivesdk",
"cachedResultName": "Suno Log"
}
},
"typeVersion": 4.7
},
{
"id": "a4eaeee0-ac3a-4e8b-8af2-e6705f279772",
"name": "Prepare Audio Path (ffmpeg-api)",
"type": "n8n-nodes-base.httpRequest",
"position": [
560,
1040
],
"parameters": {
"url": "https://api.ffmpeg-api.com/file",
"method": "POST",
"options": {},
"sendBody": true,
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "file_name",
"value": "={{ $json.Tilte_Song }}_{{ $execution.id }}"
},
{
"name": "dir_id",
"value": "={{ $('Create Working Directory (ffmpeg-api)').item.json.directory.id }}"
}
]
},
"genericAuthType": "httpHeaderAuth"
},
"typeVersion": 4.3
},
{
"id": "2d9a9cf9-a8e2-46b1-8ab1-99c21eb7dac1",
"name": "Download Song Audio",
"type": "n8n-nodes-base.httpRequest",
"position": [
752,
1040
],
"parameters": {
"url": "={{ $('Log Song Metadata').item.json.Song_URL }}",
"options": {
"response": {
"response": {
"responseFormat": "file",
"outputPropertyName": "={{ $json.file.file_name }}"
}
}
}
},
"typeVersion": 4.3
},
{
"id": "9cffa6cc-0626-457a-b538-fc531bd33399",
"name": "Upload Song to Workspace (ffmpeg-api)",
"type": "n8n-nodes-base.httpRequest",
"position": [
928,
1040
],
"parameters": {
"url": "={{ $('Prepare Audio Path (ffmpeg-api)').item.json.upload.url }}",
"method": "PUT",
"options": {},
"sendBody": true,
"contentType": "binaryData",
"inputDataFieldName": "=Cellular DawnCellular Dawn_727"
},
"typeVersion": 4.3
},
{
"id": "f499745e-345a-446f-bb3e-62136db269af",
"name": "Retrieve Uploaded Song",
"type": "n8n-nodes-base.httpRequest",
"position": [
1088,
1040
],
"parameters": {
"url": "=https://api.ffmpeg-api.com/file/{{ $('Prepare Audio Path (ffmpeg-api)').item.json.file.file_path }}",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"typeVersion": 4.3
},
{
"id": "899ccfb9-757a-4823-9a67-af37b2baccf4",
"name": "Aggregate Audio Tracks",
"type": "n8n-nodes-base.aggregate",
"position": [
1312,
1040
],
"parameters": {
"options": {},
"fieldsToAggregate": {
"fieldToAggregate": [
{
"fieldToAggregate": "file_info.file_path"
}
]
}
},
"typeVersion": 1
},
{
"id": "3b36abd8-ad09-4561-aa2a-d47afb8ecae5",
"name": "Concatenate Audio Tracks",
"type": "n8n-nodes-base.code",
"position": [
1504,
1040
],
"parameters": {
"jsCode": "// Loop over input items and add a new field called 'myNewField' to the JSON of each one\n// 1. L\u1ea5y \u0111\u01b0\u1eddng d\u1eabn Video \u0111\u00e3 upload (gi\u1ea3 s\u1eed l\u1ea5y t\u1eeb node Upload Video)\nconst videoPath =$('Retrieve Uploaded Video').first().json.file_info.file_path ; \n\n// 2. L\u1ea5y danh s\u00e1ch nh\u1ea1c t\u1eeb node Aggregate\nconst songs = $input.first().json.file_path; \n\n// 3. T\u1ea1o inputs: Video \u0111\u1ee9ng \u0111\u1ea7u (index 0), sau \u0111\u00f3 l\u00e0 c\u00e1c b\u00e0i nh\u1ea1c\nconst apiInputs = [\n {\n file_path: videoPath,\n options: [\"-stream_loop\", \"-1\"] // L\u1eb7p l\u1ea1i video v\u00f4 h\u1ea1n cho \u0111\u1ebfn khi h\u1ebft nh\u1ea1c\n },\n ...songs.map(path => ({ file_path: path }))\n];\n\n// 4. T\u1ea1o chu\u1ed7i filter concat audio (b\u1eaft \u0111\u1ea7u t\u1eeb index 1 v\u00ec index 0 l\u00e0 video)\nlet audioNodes = \"\";\nfor (let i = 1; i <= songs.length; i++) {\n audioNodes += `[${i}:a]`;\n}\nconst filterComplex = `${audioNodes}concat=n=${songs.length}:v=0:a=1[aout]`;\n\nreturn {\n ffmpeg_job: {\n task: {\n inputs: apiInputs,\n filter_complex: filterComplex,\n outputs: [\n {\n file: \"final_sleep_music_video.mp4\",\n options: [\n \"-map\", \"0:v:0\", // L\u1ea5y h\u00ecnh \u1ea3nh t\u1eeb video n\u1ec1n\n \"-map\", \"[aout]\", // L\u1ea5y \u00e2m thanh \u0111\u00e3 n\u1ed1i\n \"-c:v\", \"libx264\",\n \"-preset\", \"veryfast\",\n \"-shortest\" // T\u1ef1 \u0111\u1ed9ng d\u1eebng khi nh\u1ea1c k\u1ebft th\u00fac (~22 ph\u00fat)\n ]\n }\n ]\n }\n }\n};"
},
"typeVersion": 2
},
{
"id": "19aeff49-8eb7-4735-bd8d-788a84f2aaee",
"name": "Merge Audio with Video (ffmpeg-api)",
"type": "n8n-nodes-base.httpRequest",
"position": [
1696,
1040
],
"parameters": {
"url": "https://api.ffmpeg-api.com/ffmpeg/process",
"method": "POST",
"options": {},
"jsonBody": "={{ JSON.stringify($json.ffmpeg_job, null, 2) }}",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"typeVersion": 4.3
},
{
"id": "ef34a12b-91db-4361-a854-8ffd0df86492",
"name": "Generate SEO Title & Description",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
784,
1296
],
"parameters": {
"text": "=\n\nREFERENCE TITLE:\n\n{{ $('Suno Wave Music Input Form').item.json['Music Theme'] }}",
"options": {
"systemMessage": "=You are a YouTube Content Optimization Agent.\n\nYour task is to transform ONE winning video title into a complete content package.\n\nINPUT:\n- One \u201cwinning title\u201d provided by the user.\n\nOUTPUT:\nGenerate EXACTLY 3 sections in the following order:\n\n\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\n1. OPTIMIZED TITLE\n\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\n- Rewrite the input title to be clearer, stronger, and more clickable\n- Under 70 characters\n- Focus on ONE main benefit or outcome\n- Simple, natural\n- Optimized for YouTube SEO\n\n\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\n2. VIDEO DESCRIPTION\n\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\n- 3\u20135 short paragraphs\n- First 2 lines must strongly hook the viewer\n- Clearly explain:\n \u2022 The problem being solved\n \u2022 Who the video is for\n \u2022 What result the viewer will get\n- Natural keyword usage\n- No emojis\n- Do NOT include hashtags inside the description\n\n\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\n3. HASHTAGS\n\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\u2013\n- 10\u201315 hashtags\n- Each hashtag MUST start with #\n- All lowercase\n- Separated ONLY by semicolons (;)\n- Optimized for YouTube search and Shorts discovery\n\nIMPORTANT RULES:\n- Do NOT add explanations or notes\n- Do NOT repeat sentences across sections\n- Output ONLY the 3 sections\n- Write in Vietnamese\n"
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 3
},
{
"id": "0f9fbac0-2f0c-4ba7-85d4-3bc96fa4f2cc",
"name": "Gemini LLM1",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
704,
1456
],
"parameters": {
"options": {},
"modelName": "models/gemini-3-flash-preview"
},
"typeVersion": 1
},
{
"id": "139d3a66-81e9-4ab4-96f0-323c6c293195",
"name": "YouTube Metadata Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
960,
1472
],
"parameters": {
"jsonSchemaExample": "{\n \n \"title\": \"string\",\n \"description\": \"string\",\n \"hashtags\": \"string\"\n \n}"
},
"typeVersion": 1.3
},
{
"id": "6b6c6c16-d6d7-432c-848d-fba7467a8796",
"name": "Publish YouTube Video",
"type": "@blotato/n8n-nodes-blotato.blotato",
"position": [
1120,
1296
],
"parameters": {
"options": {},
"platform": "youtube",
"accountId": {
"__rl": true,
"mode": "list",
"value": "22282",
"cachedResultUrl": "https://backend.blotato.com/v2/accounts/22282",
"cachedResultName": "xAI Giang ( GiangVT)"
},
"postContentText": "={{ $json.output.description }}\n{{ $json.output.hashtags }}",
"postContentMediaUrls": "={{ $('Upload Media On Blotato').item.json.url }}",
"postCreateYoutubeOptionTitle": "={{ $json.output.title }}",
"postCreateYoutubeOptionContainsSyntheticMedia": true
},
"typeVersion": 2
},
{
"id": "e4270d03-5681-4c9c-ace6-272b6f439ff4",
"name": "Upload Media On Blotato",
"type": "@blotato/n8n-nodes-blotato.blotato",
"position": [
544,
1296
],
"parameters": {
"mediaUrl": "={{ $json.result[0].download_url }}",
"resource": "media"
},
"typeVersion": 2
},
{
"id": "2f5591c0-9b4c-45c1-8fea-e5dea8c9cdaf",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-608,
0
],
"parameters": {
"width": 576,
"height": 1152,
"content": "# \ud83d\udee0\ufe0f Workflow Setup Guide\n\nAuthor: [GiangxAI](https://www.youtube.com/@giangxai.official)\n\n## How it works \n- Music themes, background video URLs, and track counts are submitted via an input form \n- A working directory is created using ffmpeg-api to manage all assets \n- An AI agent generates structured Suno music prompts from the theme \n- Suno creates multiple music tracks and the workflow waits for completion \n- All tracks are concatenated into a long-form audio file \n- The final audio is merged with the background video using ffmpeg-api \n- The completed video is uploaded and published to YouTube automatically \n\nThe entire workflow runs end to end without manual editing or intervention once configured.\n\n---\n\n## Setup guide [n8n](https://n8n.partnerlinks.io/giangxai)\n- Connect an AI model (Gemini) for music prompt generation and SEO metadata \n- Add Suno API credentials for AI music generation by [Kie ai](https://kie.ai?ref=f8cec88ea15f9ecbff52ccbafa41dd6e).\n- Configure ffmpeg-api for path creation, file uploads, audio concatenation, and video merging [FFmpeg-API](https://ffmpeg-api.com)\n- Connect your YouTube account for automated uploads by [Blotato](https://blotato.com/?ref=giang9s)\n- Review and customize the input form fields if needed \n\nSetup is straightforward and does not require video editing or coding experience.\n\n\n"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "74a36699-f375-43f3-9e03-b08b82303967",
"connections": {
"Gemini LLM": {
"ai_languageModel": [
[
{
"node": "Generate Music Prompts (AI Agent)",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Gemini LLM1": {
"ai_languageModel": [
[
{
"node": "Generate SEO Title & Description",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Check Song Status": {
"main": [
[
{
"node": "Log Song Metadata",
"type": "main",
"index": 0
}
],
[
{
"node": "Wait for Song Rendering",
"type": "main",
"index": 0
}
]
]
},
"Log Song Metadata": {
"main": [
[
{
"node": "Prepare Audio Path (ffmpeg-api)",
"type": "main",
"index": 0
}
]
]
},
"Get Generated Song": {
"main": [
[
{
"node": "Check Song Status",
"type": "main",
"index": 0
}
]
]
},
"Download Song Audio": {
"main": [
[
{
"node": "Upload Song to Workspace (ffmpeg-api)",
"type": "main",
"index": 0
}
]
]
},
"Split Music Requests": {
"main": [
[
{
"node": "Create Song (Suno API)",
"type": "main",
"index": 0
}
]
]
},
"Aggregate Audio Tracks": {
"main": [
[
{
"node": "Concatenate Audio Tracks",
"type": "main",
"index": 0
}
]
]
},
"Create Song (Suno API)": {
"main": [
[
{
"node": "Wait for Song Rendering",
"type": "main",
"index": 0
}
]
]
},
"Retrieve Uploaded Song": {
"main": [
[
{
"node": "Aggregate Audio Tracks",
"type": "main",
"index": 0
}
]
]
},
"Retrieve Uploaded Video": {
"main": [
[
{
"node": "Generate Music Prompts (AI Agent)",
"type": "main",
"index": 0
}
]
]
},
"Upload Media On Blotato": {
"main": [
[
{
"node": "Generate SEO Title & Description",
"type": "main",
"index": 0
}
]
]
},
"Wait for Song Rendering": {
"main": [
[
{
"node": "Get Generated Song",
"type": "main",
"index": 0
}
]
]
},
"YouTube Metadata Parser": {
"ai_outputParser": [
[
{
"node": "Generate SEO Title & Description",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Concatenate Audio Tracks": {
"main": [
[
{
"node": "Merge Audio with Video (ffmpeg-api)",
"type": "main",
"index": 0
}
]
]
},
"Download Background Video": {
"main": [
[
{
"node": "Upload Video to Workspace (ffmpeg-api)",
"type": "main",
"index": 0
}
]
]
},
"Music Prompt Output Parser": {
"ai_outputParser": [
[
{
"node": "Generate Music Prompts (AI Agent)",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Suno Wave Music Input Form": {
"main": [
[
{
"node": "Create Working Directory (ffmpeg-api)",
"type": "main",
"index": 0
}
]
]
},
"Prepare Audio Path (ffmpeg-api)": {
"main": [
[
{
"node": "Download Song Audio",
"type": "main",
"index": 0
}
]
]
},
"Prepare Video Path (ffmpeg-api)": {
"main": [
[
{
"node": "Download Background Video",
"type": "main",
"index": 0
}
]
]
},
"Generate SEO Title & Description": {
"main": [
[
{
"node": "Publish YouTube Video",
"type": "main",
"index": 0
}
]
]
},
"Generate Music Prompts (AI Agent)": {
"main": [
[
{
"node": "Split Music Requests",
"type": "main",
"index": 0
}
]
]
},
"Merge Audio with Video (ffmpeg-api)": {
"main": [
[
{
"node": "Upload Media On Blotato",
"type": "main",
"index": 0
}
]
]
},
"Create Working Directory (ffmpeg-api)": {
"main": [
[
{
"node": "Prepare Video Path (ffmpeg-api)",
"type": "main",
"index": 0
}
]
]
},
"Upload Song to Workspace (ffmpeg-api)": {
"main": [
[
{
"node": "Retrieve Uploaded Song",
"type": "main",
"index": 0
}
]
]
},
"Upload Video to Workspace (ffmpeg-api)": {
"main": [
[
{
"node": "Retrieve Uploaded Video",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
httpHeaderAuth
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow automatically creates hours-long wave music videos by combining AI-generated music from Suno with a background video, fully automated using n8n and ffmpeg-api.
Source: https://n8n.io/workflows/13088/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
🚀 Stop Editing. Start Automating. Turn a simple spreadsheet of text into a limitless stream of viral video content.
This workflow automatically creates AI product review videos from a product image and short description using n8n and Veo 3.
Summary
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.
This n8n workflow converts a YouTube video into a polished, email-ready newsletter. It scrapes the transcript, extracts a thumbnail/logo and brand color theme, uses multiple AI agents to (1) clean & s