{
  "id": "xmAuFjXa3liK7mPf",
  "name": "Extend high-quality video with audio and upload to TikTok",
  "tags": [],
  "nodes": [
    {
      "id": "c82960d6-8b1f-48e2-a84d-31b8c696d62b",
      "name": "Get status",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        352,
        304
      ],
      "parameters": {
        "url": "=https://queue.fal.run/fal-ai/ltx-2.3-quality/requests/{{ $('Extend Video').item.json.request_id }}/status ",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "63d87635-e969-4f30-af27-c8e7c2589f98",
      "name": "Wait 60 sec.",
      "type": "n8n-nodes-base.wait",
      "position": [
        128,
        304
      ],
      "parameters": {
        "amount": 60
      },
      "typeVersion": 1.1
    },
    {
      "id": "4c356f32-e870-443f-8f06-f74c122e323b",
      "name": "Completed?",
      "type": "n8n-nodes-base.if",
      "position": [
        576,
        304
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "383d112e-2cc6-4dd4-8985-f09ce0bd1781",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": "COMPLETED"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "f204e596-305d-4b56-b18a-a79b5d04a74f",
      "name": "Get Url Video",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        800,
        304
      ],
      "parameters": {
        "url": "=https://queue.fal.run/fal-ai/ltx-2.3-quality/requests/{{ $json.request_id }}",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "b173393a-38c7-44b8-8dd0-ee110e025eed",
      "name": "Get File Video",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        480,
        736
      ],
      "parameters": {
        "url": "={{ $('Get Url Video').item.json.video.url }}",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "7f79eccd-234b-4ff5-b612-a04ad5d7afab",
      "name": "HTTP Request",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        784,
        736
      ],
      "parameters": {
        "url": "https://api.upload-post.com/api/upload",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "multipart-form-data",
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "title",
              "value": "={{ $('Generate title').item.json.message.content }}"
            },
            {
              "name": "user",
              "value": "YOUR_USERNAME"
            },
            {
              "name": "platform[]",
              "value": "tiktok"
            },
            {
              "name": "video",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "data"
            }
          ]
        },
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "4a9016c9-3cfb-451e-a094-3f4013b5f472",
      "name": "Generate title",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        128,
        736
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-5",
          "cachedResultName": "GPT-5"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "=Input: {{ $('Webhook').item.json.prompt }}"
            },
            {
              "role": "system",
              "content": "You are a Video SEO expert specialized in creating engaging and optimized titles.\n\nYour task is to generate an effective title for a YouTube video based on the user's video description.\n\nGUIDELINES:\n- Maximum 60 characters to avoid truncation\n- Use relevant keywords for SEO\n- Make the title catchy and clickable\n- Avoid excessive or misleading clickbait\n- Consider the target audience of the content\n- Use numbers, questions, or power words when appropriate\n- IMPORTANT: Generate the title in the same language as the input description\n\nOUTPUT FORMAT:\nProvide only the title, without additional explanations.\n\nEXAMPLE:\nInput: \"Tutorial video on how to cook perfect pasta carbonara\"\nOutput: \"PERFECT Carbonara in 10 Minutes - Chef's Secrets\""
            }
          ]
        }
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "caf17b45-c529-4728-abb7-caf23dd39a9d",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -656,
        528
      ],
      "parameters": {
        "path": "b959bf44-74f9-4497-bde2-f2bcf89a9bec",
        "options": {},
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "c348aaa0-ef72-4389-a931-0d89ffcde089",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        48,
        128
      ],
      "parameters": {
        "color": 7,
        "width": 944,
        "height": 336,
        "content": "## Monitor Rendering Status\n\nThe workflow periodically checks the status of the rendering job on Fal until the video generation is complete. If the job is still running, it waits before checking again."
      },
      "typeVersion": 1
    },
    {
      "id": "24831faf-79c7-4012-a878-1dd2e66c6f91",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        48,
        -688
      ],
      "parameters": {
        "color": 7,
        "width": 736,
        "height": 784,
        "content": "## MY NEW YOUTUBE CHANNEL\n\ud83d\udc49 [Subscribe to my new **YouTube channel**](https://youtube.com/@n3witalia). Here I\u2019ll share videos and Shorts with practical tutorials and **FREE templates for n8n**.\n\n[![image](https://n3wstorage.b-cdn.net/n3witalia/youtube-n8n-cover.jpg)](https://youtube.com/@n3witalia)"
      },
      "typeVersion": 1
    },
    {
      "id": "79eb34bc-13a9-485a-9b95-fc9de644ddcd",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        64,
        528
      ],
      "parameters": {
        "color": 7,
        "width": 592,
        "height": 368,
        "content": "## Prepare the Final Video\n\nOnce the rendering is finished, the workflow retrieves the generated video URL, creates an SEO-friendly title using OpenAI, and downloads the final video file.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "d886b374-e349-4d4d-9ff0-df1266289fba",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        688,
        528
      ],
      "parameters": {
        "color": 7,
        "width": 304,
        "height": 368,
        "content": "## Publish to TikTok \n\nThe completed video is uploaded to [Upload-Post](https://www.upload-post.com/?linkId=lp_144414&sourceId=n3witalia&tenantId=upload-post-app) through its API, and the workflow returns the upload response to the original webhook request."
      },
      "typeVersion": 1
    },
    {
      "id": "b74ddc52-6e63-42e4-a996-294da3b07720",
      "name": "On form submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -656,
        336
      ],
      "parameters": {
        "options": {},
        "formTitle": "Extend video with audio",
        "formFields": {
          "values": [
            {
              "fieldName": "video_url",
              "fieldLabel": "Video Url"
            },
            {
              "fieldName": "prompt",
              "fieldLabel": "Prompt"
            }
          ]
        }
      },
      "typeVersion": 2.6
    },
    {
      "id": "21f866ab-6f12-4f09-8c70-8f3fd3df4c65",
      "name": "Set vars",
      "type": "n8n-nodes-base.set",
      "position": [
        -432,
        432
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "c1ed0b7f-c8a1-4658-a223-89bd1fa294a7",
              "name": "video_url",
              "type": "string",
              "value": "={{ $json.video_url }}"
            },
            {
              "id": "567c97fc-dd74-490b-82de-b4dca3156bf8",
              "name": "prompt",
              "type": "string",
              "value": "={{ $json.prompt }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "17aca2e2-6be2-4699-9a0f-e5655ad1f9fc",
      "name": "Extend Video",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -176,
        432
      ],
      "parameters": {
        "url": "https://queue.fal.run/fal-ai/ltx-2.3-quality/extend-video/lora",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n     \"prompt\": \"{{ $json.prompt }}\",\n     \"video_url\": \"{{ $json.video_url }}\",\n     \"extend_direction\": \"forward\",\n     \"num_frames\": 121,\n     \"num_context_frames\": 25,\n     \"end_image_strength\": 1,\n     \"resolution\": \"auto\",\n     \"match_input_fps\": true,\n     \"frames_per_second\": 24,\n     \"video_strength\": 1,\n     \"num_inference_steps\": 15,\n     \"guidance_scale\": 1,\n     \"generate_audio\": true,\n     \"negative_prompt\": \"color distortion, overexposure, static, blurry details, subtitles, style, artwork, painting, frame, still, dim overall tone, worst quality, low quality, JPEG compression artifacts, ugly, mutilated, extra fingers, poorly drawn hands, poorly drawn face, deformed, disfigured, malformed limbs, fused fingers, motionless frame, cluttered background, three legs, crowded background, walking backwards\",\n     \"enable_prompt_expansion\": true,\n     \"enable_safety_checker\": true,\n     \"video_quality\": \"high\",\n     \"video_write_mode\": \"balanced\",\n     \"loras\": [\n       {\n         \"path\": \"https://huggingface.co/lovis93/crt-animation-terminal-ltx-2.3-lora/resolve/main/crtanim_4000.safetensors\",\n         \"scale\": 1,\n         \"transformer\": \"both\"\n       }\n     ]\n   }",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "62c98ab2-5d6e-41c6-83ae-17ce650da82d",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -736,
        -688
      ],
      "parameters": {
        "width": 768,
        "height": 784,
        "content": "# Extend high-quality video with audio and upload to TikTok\n\n## How it works\n\n1. The workflow starts from either a webhook or form submission and maps the incoming video URL and prompt into variables.\n2. It sends a request to Fal to extend the video, then waits and polls the job status until the render is complete.\n3. Once finished, it fetches the generated video URL and generates a title with OpenAI.\n4. It downloads the final video file and uploads it to [Upload-Post](https://www.upload-post.com/?linkId=lp_144414&sourceId=n3witalia&tenantId=upload-post-app), preparing the asset for TikTok distribution.\n\n## Setup steps\n\n- [ ] Configure the webhook and form trigger settings so the workflow can be started from the intended source.\n- [ ] Add the Fal API request details for the video extension endpoint, including any required authentication or headers.\n- [ ] Verify the polling interval and status-check URL used by the wait/status loop match the Fal job API.\n- [ ] Connect and authorize the OpenAI credentials used by the title-generation node.\n- [ ] Confirm the upload-post API endpoint and any required auth for the final file upload.\n- [ ] Map the incoming form/webhook payload fields to the `video_url` and `prompt` variables in the Set node.\n\n## Customization\n\nYou can customize the polling delay, prompt template, title style, and final upload destination if you want different throughput or branding."
      },
      "typeVersion": 1
    },
    {
      "id": "5a8fb462-ec46-4bc6-adf5-8d499402c5e4",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -736,
        128
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 768,
        "content": "## Capture input and set variables\\n\\nEntry triggers receive the request or form submission and normalize the incoming payload into `video_url` and `prompt` for downstream processing."
      },
      "typeVersion": 1
    },
    {
      "id": "5af63235-dce1-4064-914f-bc15660c3683",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -272,
        128
      ],
      "parameters": {
        "color": 7,
        "width": 304,
        "height": 768,
        "content": "## Submit video extension job\\n\\nThis cluster sends the initial Fal request to extend the video, then moves into the status-check loop for asynchronous completion."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "e868cb37-4e37-486a-8564-36d8de612ed8",
  "nodeGroups": [],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Set vars",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set vars": {
      "main": [
        [
          {
            "node": "Extend Video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Completed?": {
      "main": [
        [
          {
            "node": "Get Url Video",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait 60 sec.",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get status": {
      "main": [
        [
          {
            "node": "Completed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extend Video": {
      "main": [
        [
          {
            "node": "Wait 60 sec.",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request": {
      "main": [
        []
      ]
    },
    "Wait 60 sec.": {
      "main": [
        [
          {
            "node": "Get status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Url Video": {
      "main": [
        [
          {
            "node": "Generate title",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate title": {
      "main": [
        [
          {
            "node": "Get File Video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get File Video": {
      "main": [
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On form submission": {
      "main": [
        [
          {
            "node": "Set vars",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}