AutomationFlowsWeb Scraping › AI Product Video Generator (windows)

AI Product Video Generator (windows)

AI Product Video Generator (Windows). Uses httpRequest, writeBinaryFile, executeCommand, readBinaryFile. Webhook trigger; 16 nodes.

Webhook trigger★★★★☆ complexity16 nodesHTTP RequestWrite Binary FileExecute CommandRead Binary File
Web Scraping Trigger: Webhook Nodes: 16 Complexity: ★★★★☆ Added:

This workflow follows the Executecommand → HTTP Request 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 →

Download .json
{
  "name": "AI Product Video Generator (Windows)",
  "nodes": [
    {
      "parameters": {
        "path": "ai-product-video",
        "httpMethod": "POST",
        "responseMode": "lastNode",
        "responseData": "allEntries",
        "options": {
          "binaryData": true,
          "binaryPropertyName": "productImage"
        }
      },
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        200,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "// \u2705 \u062a\u062d\u0642\u0642 \u0645\u0646 \u0627\u0644\u0645\u062f\u062e\u0644\u0627\u062a \u0627\u0644\u0645\u0637\u0644\u0648\u0628\u0629\nconst body = $json;\nif (!body.product_name) throw new Error('\u26a0\ufe0f product_name \u0645\u0641\u0642\u0648\u062f');\nif (!body.lang) throw new Error('\u26a0\ufe0f lang (\u0627\u0644\u0644\u063a\u0629) \u0645\u0641\u0642\u0648\u062f\u0629');\nif (!body.tone) throw new Error('\u26a0\ufe0f tone (\u0646\u0628\u0631\u0629 \u0627\u0644\u0646\u0635) \u0645\u0641\u0642\u0648\u062f\u0629');\nconst aspect = body.aspect === '16:9' ? '16:9' : '9:16';\nconst addSubs = !!body.add_subtitles;\nreturn [{ json: { ...body, aspect, add_subtitles: addSubs }, binary: $binary }];"
      },
      "name": "Validate Input",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        460,
        300
      ]
    },
    {
      "parameters": {
        "url": "https://api.openai.com/v1/chat/completions",
        "method": "POST",
        "responseFormat": "json",
        "jsonParameters": true,
        "sendHeaders": true,
        "headerParametersJson": "={\"Authorization\":\"Bearer {{$env.OPENAI_API_KEY}}\",\"Content-Type\":\"application/json\"}",
        "bodyParametersJson": "={\"model\":\"gpt-4o-mini\",\"temperature\":0.8,\"messages\":[{\"role\":\"system\",\"content\":\"\u0627\u0643\u062a\u0628 \u0633\u0643\u0631\u064a\u0628\u062a \u062a\u0633\u0648\u064a\u0642\u064a \u0642\u0635\u064a\u0631 \u0648\u0645\u0642\u0646\u0639 \u0644\u0645\u0646\u062a\u062c\u060c \u0645\u0646 35 \u0625\u0644\u0649 65 \u0643\u0644\u0645\u0629\u060c \u0628\u0627\u0644\u0644\u063a\u0629 {{$json.lang}} \u0648\u0628\u0646\u0628\u0631\u0629 {{$json.tone}}.\"},{\"role\":\"user\",\"content\":\"\u0627\u0633\u0645 \u0627\u0644\u0645\u0646\u062a\u062c: {{$json.product_name}}.\\n\u0627\u0644\u0645\u064a\u0632\u0627\u062a: {{$json.features}}.\"}]}"
      },
      "name": "Generate Script",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 3,
      "position": [
        720,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "const script = $json.choices?.[0]?.message?.content || ''; if(!script) throw new Error('\u0641\u0634\u0644 \u062a\u0648\u0644\u064a\u062f \u0627\u0644\u0646\u0635'); return [{ json: { ...$json, voice_script: script } }];"
      },
      "name": "Extract Script",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        980,
        300
      ]
    },
    {
      "parameters": {
        "url": "https://api.elevenlabs.io/v1/text-to-speech/21m00Tcm4TlvDq8ikWAM",
        "method": "POST",
        "responseFormat": "file",
        "jsonParameters": true,
        "sendHeaders": true,
        "headerParametersJson": "={\"xi-api-key\":\"{{$env.ELEVEN_API_KEY}}\",\"Content-Type\":\"application/json\",\"Accept\":\"audio/mpeg\"}",
        "bodyParametersJson": "={\"text\":\"{{$json.voice_script}}\",\"model_id\":\"eleven_multilingual_v2\",\"voice_settings\":{\"stability\":0.5,\"similarity_boost\":0.75},\"output_format\":\"mp3_44100_128\"}"
      },
      "name": "Generate Voice (TTS)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 3,
      "position": [
        1240,
        300
      ]
    },
    {
      "parameters": {
        "fileName": "C:\\\\n8n_temp\\\\voice.mp3",
        "binaryPropertyName": "data"
      },
      "name": "Save Voice",
      "type": "n8n-nodes-base.writeBinaryFile",
      "typeVersion": 1,
      "position": [
        1500,
        300
      ]
    },
    {
      "parameters": {
        "command": "ffprobe -i C:\\\\n8n_temp\\\\voice.mp3 -show_entries format=duration -v quiet -of csv=p=0"
      },
      "name": "Get Duration",
      "type": "n8n-nodes-base.executeCommand",
      "typeVersion": 1,
      "position": [
        1760,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "const dur = parseFloat(($json.data || '').trim()); return [{ json: { ...$json, duration: isFinite(dur)?dur:20 } }];"
      },
      "name": "Parse Duration",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        2020,
        300
      ]
    },
    {
      "parameters": {
        "command": "bash -lc \"ASPECT='{{$json.aspect}}'; D={{$json.duration}}; if [ \\\"$ASPECT\\\" = \\\"16:9\\\" ]; then SIZE=1920:1080; else SIZE=1080:1920; fi; ffmpeg -y -loop 1 -i C:\\\\n8n_temp\\\\input.jpg -t $D -vf \\\"scale=${SIZE},zoompan=z='min(zoom+0.0008,1.2)':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d=25*$D,fps=25\\\" -c:v libx264 -pix_fmt yuv420p C:\\\\n8n_temp\\\\kb.mp4\""
      },
      "name": "Create Video (Ken Burns)",
      "type": "n8n-nodes-base.executeCommand",
      "typeVersion": 1,
      "position": [
        2280,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "const text = $json.voice_script || ''; const dur = $json.duration || 20; if(!$json.add_subtitles) return [{json:{...$json, skipSubs:true}}]; const lines = text.split(/(?<=[.!\u061f?\u060c])\\s+/).filter(Boolean); const seg = dur/lines.length; const fmt = t=>{const ms=Math.floor((t%1)*1000);const s=Math.floor(t)%60;const m=Math.floor(t/60);return `${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')},${String(ms).padStart(3,'0')}`;}; let srt=''; for(let i=0;i<lines.length;i++){srt+=`${i+1}\\n00:${fmt(i*seg)} --> 00:${fmt((i+1)*seg)}\\n${lines[i]}\\n\\n`;} const data = Buffer.from(srt).toString('base64'); return [{json:{...$json}, binary:{srt:{data,fileName:'subs.srt',mimeType:'text/plain'}}}];"
      },
      "name": "Generate SRT",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        2540,
        300
      ]
    },
    {
      "parameters": {
        "fileName": "C:\\\\n8n_temp\\\\subs.srt",
        "binaryPropertyName": "srt"
      },
      "name": "Save SRT",
      "type": "n8n-nodes-base.writeBinaryFile",
      "typeVersion": 1,
      "position": [
        2800,
        300
      ]
    },
    {
      "parameters": {
        "command": "bash -lc \"if [ -f C:\\\\n8n_temp\\\\bgm.mp3 ]; then ffmpeg -y -i C:\\\\n8n_temp\\\\voice.mp3 -i C:\\\\n8n_temp\\\\bgm.mp3 -filter_complex 'volume=1[a];[1:a]volume=0.2[b];[a][b]amix=inputs=2:duration=first' -c:a aac C:\\\\n8n_temp\\\\mixaudio.aac; else ffmpeg -y -i C:\\\\n8n_temp\\\\voice.mp3 -c:a aac C:\\\\n8n_temp\\\\mixaudio.aac; fi\""
      },
      "name": "Mix Audio",
      "type": "n8n-nodes-base.executeCommand",
      "typeVersion": 1,
      "position": [
        3060,
        300
      ]
    },
    {
      "parameters": {
        "command": "bash -lc \"if [ -f C:\\\\n8n_temp\\\\subs.srt ] && [ $(stat -c%s C:\\\\n8n_temp\\\\subs.srt) -gt 0 ]; then ffmpeg -y -i C:\\\\n8n_temp\\\\kb.mp4 -i C:\\\\n8n_temp\\\\mixaudio.aac -vf subtitles=C:\\\\n8n_temp\\\\subs.srt -c:a aac C:\\\\n8n_temp\\\\burned.mp4; else ffmpeg -y -i C:\\\\n8n_temp\\\\kb.mp4 -i C:\\\\n8n_temp\\\\mixaudio.aac -c:a aac C:\\\\n8n_temp\\\\burned.mp4; fi\""
      },
      "name": "Combine Video + Audio + Subtitles",
      "type": "n8n-nodes-base.executeCommand",
      "typeVersion": 1,
      "position": [
        3320,
        300
      ]
    },
    {
      "parameters": {
        "command": "bash -lc \"if [ -f C:\\\\n8n_temp\\\\logo.png ]; then ffmpeg -y -i C:\\\\n8n_temp\\\\burned.mp4 -i C:\\\\n8n_temp\\\\logo.png -filter_complex 'overlay=main_w-overlay_w-40:40' -c:a copy C:\\\\n8n_temp\\\\final.mp4; else copy C:\\\\n8n_temp\\\\burned.mp4 C:\\\\n8n_temp\\\\final.mp4; fi\""
      },
      "name": "Overlay Logo (optional)",
      "type": "n8n-nodes-base.executeCommand",
      "typeVersion": 1,
      "position": [
        3580,
        300
      ]
    },
    {
      "parameters": {
        "filePath": "C:\\\\n8n_temp\\\\final.mp4",
        "property": "video"
      },
      "name": "Read Final Video",
      "type": "n8n-nodes-base.readBinaryFile",
      "typeVersion": 1,
      "position": [
        3840,
        300
      ]
    },
    {
      "parameters": {
        "responseData": "binary",
        "binaryPropertyName": "video",
        "options": {
          "responseCode": 200,
          "responseHeaders": {
            "Content-Type": "video/mp4",
            "Content-Disposition": "attachment; filename=ai_product_video.mp4"
          }
        }
      },
      "name": "Respond to Webhook (Video)",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        4100,
        300
      ]
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Validate Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Input": {
      "main": [
        [
          {
            "node": "Generate Script",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Script": {
      "main": [
        [
          {
            "node": "Extract Script",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Script": {
      "main": [
        [
          {
            "node": "Generate Voice (TTS)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Voice (TTS)": {
      "main": [
        [
          {
            "node": "Save Voice",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Voice": {
      "main": [
        [
          {
            "node": "Get Duration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Duration": {
      "main": [
        [
          {
            "node": "Parse Duration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Duration": {
      "main": [
        [
          {
            "node": "Create Video (Ken Burns)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Video (Ken Burns)": {
      "main": [
        [
          {
            "node": "Generate SRT",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate SRT": {
      "main": [
        [
          {
            "node": "Save SRT",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save SRT": {
      "main": [
        [
          {
            "node": "Mix Audio",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mix Audio": {
      "main": [
        [
          {
            "node": "Combine Video + Audio + Subtitles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Combine Video + Audio + Subtitles": {
      "main": [
        [
          {
            "node": "Overlay Logo (optional)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Overlay Logo (optional)": {
      "main": [
        [
          {
            "node": "Read Final Video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Final Video": {
      "main": [
        [
          {
            "node": "Respond to Webhook (Video)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

AI Product Video Generator (Windows). Uses httpRequest, writeBinaryFile, executeCommand, readBinaryFile. Webhook trigger; 16 nodes.

Source: https://gist.github.com/itzoldman-max/097ac8f3b3fbab1d304caf77da9d7cec — original creator credit. Request a take-down →

More Web Scraping workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Web Scraping

Sign PDF documents with legally-compliant digital signatures using X.509 certificates. Supports multiple PAdES signature levels (B, T, LT, LTA) with optional visible stamps.

Execute Command, HTTP Request, Read Write File +1
Web Scraping

Track Changes Of Product Prices. Uses htmlExtract, functionItem, httpRequest, writeBinaryFile. Scheduled trigger; 25 nodes.

Html Extract, Function Item, HTTP Request +5
Web Scraping

This workflow automatically tracks changes on specific websites, typically in e-commerce where you want to get information about price changes. Basic knowledge of HTML and JavaScript Execute Command n

Html Extract, Function Item, HTTP Request +5
Web Scraping

extract_swifts. Uses manualTrigger, httpRequest, htmlExtract, splitInBatches. Event-driven trigger; 23 nodes.

HTTP Request, Html Extract, MongoDB +5
Web Scraping

MLOps Pipeline EN-PT. Uses executeCommand, httpRequest, errorTrigger. Webhook trigger; 18 nodes.

Execute Command, HTTP Request, Error Trigger