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 →
{
"name": "YouTube Shorts Otomasyonu - Haftal\u0131k E\u011flenceli Video",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": 1,
"triggerAtHour": 10
}
]
}
},
"id": "schedule-trigger",
"name": "Haftal\u0131k Zamanlay\u0131c\u0131",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
0,
0
]
},
{
"parameters": {
"method": "POST",
"url": "https://api.openai.com/v1/chat/completions",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "openAiApi",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"model\": \"gpt-4o\",\n \"response_format\": { \"type\": \"json_object\" },\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"Sen bir YouTube Shorts i\u00e7erik \u00fcreticisisin. T\u00fcrk\u00e7e, e\u011flenceli, viral olabilecek k\u0131sa video scriptleri yaz\u0131yorsun. Her seferinde rastgele bir tema se\u00e7: ilgin\u00e7 bilgiler (fun facts), komedi/abs\u00fcrt humor, motivasyon, bilim, tarih, psikoloji, hayvan d\u00fcnyas\u0131, uzay, teknoloji. Script maksimum 50 saniye okunacak uzunlukta olmal\u0131. Enerjik, samimi ve dikkat \u00e7ekici bir dil kullan. Cevab\u0131n\u0131 JSON format\u0131nda ver.\"\n },\n {\n \"role\": \"user\",\n \"content\": \"Yeni bir YouTube Shorts videosu i\u00e7in i\u00e7erik \u00fcret. JSON format\u0131nda \u015funlar\u0131 ver:\\n- title: T\u00fcrk\u00e7e video ba\u015fl\u0131\u011f\u0131 (dikkat \u00e7ekici, max 60 karakter)\\n- script: T\u00fcrk\u00e7e seslendirme scripti (max 50 saniye okunacak, k\u0131sa c\u00fcmleler)\\n- search_keywords: \u0130ngilizce 3 arama kelimesi (Pexels stock video aramak i\u00e7in, virg\u00fclle ayr\u0131lm\u0131\u015f)\\n- description: T\u00fcrk\u00e7e YouTube a\u00e7\u0131klamas\u0131 (2-3 c\u00fcmle + hashtag'ler)\\n- tags: T\u00fcrk\u00e7e YouTube etiketleri (virg\u00fclle ayr\u0131lm\u0131\u015f, 5-8 adet)\\n- category: Videonun kategorisi (fun_fact, comedy, motivation, science, history, psychology, animals, space, tech)\"\n }\n ]\n}",
"options": {
"timeout": 30000
}
},
"id": "openai-generate-content",
"name": "AI Konu ve Script \u00dcret",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
300,
0
],
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"mode": "raw",
"jsonOutput": "={{ JSON.parse($json.choices[0].message.content) }}",
"options": {}
},
"id": "parse-ai-response",
"name": "AI Cevab\u0131n\u0131 Parse Et",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
520,
0
]
},
{
"parameters": {
"method": "POST",
"url": "https://api.openai.com/v1/audio/speech",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "openAiApi",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"model\": \"tts-1\",\n \"input\": \"{{ $json.script }}\",\n \"voice\": \"nova\",\n \"response_format\": \"mp3\",\n \"speed\": 1.05\n}",
"options": {
"response": {
"response": {
"responseFormat": "file",
"outputPropertyName": "audioData"
}
},
"timeout": 60000
}
},
"id": "openai-tts",
"name": "Seslendirme (TTS)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
740,
0
],
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"command": "=mkdir -p /tmp/youtube-shorts && echo '{{ $('AI Konu ve Script \u00dcret').item.json.choices[0].message.content }}' > /tmp/youtube-shorts/content.json && echo 'directory_ready'"
},
"id": "prepare-directory",
"name": "Dizin Haz\u0131rla",
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [
740,
250
]
},
{
"parameters": {
"operation": "toFile",
"fileName": "voiceover.mp3",
"options": {}
},
"id": "save-audio",
"name": "Ses Dosyas\u0131 Kaydet",
"type": "n8n-nodes-base.convertToFile",
"typeVersion": 1.1,
"position": [
960,
0
]
},
{
"parameters": {
"command": "=cat /tmp/youtube-shorts/content.json | python3 -c \"\nimport json, sys\ndata = json.load(sys.stdin)\nkw = data.get('search_keywords', 'nature,landscape,abstract')\nprint(kw.split(',')[0].strip())\n\""
},
"id": "extract-keyword",
"name": "Arama Kelimesi \u00c7\u0131kar",
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [
960,
250
]
},
{
"parameters": {
"method": "GET",
"url": "=https://api.pexels.com/videos/search?query={{ encodeURIComponent($('extract-keyword').item.json.stdout.trim()) }}&orientation=portrait&size=medium&per_page=3",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"options": {
"timeout": 30000
}
},
"id": "pexels-search",
"name": "Pexels Video Ara",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1180,
250
],
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"command": "=# Pexels videolar\u0131n\u0131 indir\nmkdir -p /tmp/youtube-shorts/clips\n\n# JSON'dan video URL'lerini \u00e7\u0131kar ve indir\nVIDEOS='{{ JSON.stringify($json.videos) }}'\n\necho \"$VIDEOS\" | python3 -c \"\nimport json, sys, subprocess\n\nvideos = json.load(sys.stdin)\ndownloaded = 0\n\nfor i, video in enumerate(videos[:3]):\n # En uygun HD portrait video dosyas\u0131n\u0131 bul\n files = video.get('video_files', [])\n best = None\n for f in files:\n w = f.get('width', 0)\n h = f.get('height', 0)\n if h > w and h <= 1920: # Portrait ve max 1080p\n if best is None or h > best.get('height', 0):\n best = f\n if best is None and files:\n best = files[0]\n if best:\n url = best['link']\n subprocess.run(['curl', '-sL', '-o', f'/tmp/youtube-shorts/clips/clip_{i}.mp4', url], timeout=120)\n downloaded += 1\n print(f'Downloaded clip_{i}.mp4')\n\nprint(f'Total downloaded: {downloaded}')\n\" 2>&1",
"options": {
"timeout": 180000
}
},
"id": "download-videos",
"name": "Videolar\u0131 \u0130ndir",
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [
1400,
250
]
},
{
"parameters": {
"command": "=# Ses dosyas\u0131n\u0131 kaydet\ncp /tmp/youtube-shorts/voiceover.mp3 /tmp/youtube-shorts/audio.mp3 2>/dev/null || true\n\n# Ses s\u00fcresini al\nAUDIO_DURATION=$(ffprobe -v error -show_entries format=duration -of csv=p=0 /tmp/youtube-shorts/audio.mp3 2>/dev/null | cut -d. -f1)\nif [ -z \"$AUDIO_DURATION\" ] || [ \"$AUDIO_DURATION\" -eq 0 ]; then\n AUDIO_DURATION=30\nfi\n\n# Max 59 saniye (Shorts limiti)\nif [ \"$AUDIO_DURATION\" -gt 59 ]; then\n AUDIO_DURATION=59\nfi\n\necho \"Audio duration: ${AUDIO_DURATION}s\"\n\n# Mevcut klipleri listele\nCLIPS=$(ls /tmp/youtube-shorts/clips/clip_*.mp4 2>/dev/null | sort)\nCLIP_COUNT=$(echo \"$CLIPS\" | wc -l)\n\nif [ \"$CLIP_COUNT\" -eq 0 ]; then\n echo 'ERROR: No clips found'\n exit 1\nfi\n\necho \"Found $CLIP_COUNT clips\"\n\n# Her klibi 9:16 format\u0131na \u00e7evir ve s\u00fcreyi e\u015fit b\u00f6l\nPER_CLIP_DURATION=$((AUDIO_DURATION / CLIP_COUNT))\nIDX=0\nfor CLIP in $CLIPS; do\n ffmpeg -y -i \"$CLIP\" \\\n -vf \"scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,setsar=1\" \\\n -t $PER_CLIP_DURATION \\\n -an \\\n -c:v libx264 -preset ultrafast -crf 23 \\\n \"/tmp/youtube-shorts/clips/processed_${IDX}.mp4\" 2>/dev/null\n IDX=$((IDX + 1))\ndone\n\necho \"Processed $IDX clips\"\n\n# Klipleri birle\u015ftirmek i\u00e7in concat dosyas\u0131 olu\u015ftur\n> /tmp/youtube-shorts/clips/concat.txt\nfor i in $(seq 0 $((IDX - 1))); do\n echo \"file 'processed_${i}.mp4'\" >> /tmp/youtube-shorts/clips/concat.txt\ndone\n\n# Klipleri birle\u015ftir\nffmpeg -y -f concat -safe 0 -i /tmp/youtube-shorts/clips/concat.txt \\\n -c:v libx264 -preset ultrafast -crf 23 \\\n /tmp/youtube-shorts/video_only.mp4 2>/dev/null\n\n# Ba\u015fl\u0131k metnini oku\nTITLE=$(python3 -c \"\nimport json\nwith open('/tmp/youtube-shorts/content.json') as f:\n data = json.load(f)\nprint(data.get('title', 'E\u011flenceli Video'))\n\" 2>/dev/null || echo 'E\u011flenceli Video')\n\n# Video + ses + ba\u015fl\u0131k overlay birle\u015ftir\nffmpeg -y \\\n -i /tmp/youtube-shorts/video_only.mp4 \\\n -i /tmp/youtube-shorts/audio.mp3 \\\n -filter_complex \"\n [0:v]drawtext=text='${TITLE}':fontsize=42:fontcolor=white:borderw=3:bordercolor=black:x=(w-text_w)/2:y=h*0.08:enable='between(t,0,4)'[v]\n \" \\\n -map \"[v]\" -map 1:a \\\n -c:v libx264 -preset medium -crf 20 \\\n -c:a aac -b:a 192k \\\n -t $AUDIO_DURATION \\\n -shortest \\\n -movflags +faststart \\\n /tmp/youtube-shorts/final_short.mp4 2>/dev/null\n\n# Sonu\u00e7 kontrol\u00fc\nif [ -f /tmp/youtube-shorts/final_short.mp4 ]; then\n FILESIZE=$(du -h /tmp/youtube-shorts/final_short.mp4 | cut -f1)\n DURATION=$(ffprobe -v error -show_entries format=duration -of csv=p=0 /tmp/youtube-shorts/final_short.mp4 2>/dev/null)\n echo \"SUCCESS: Final video created - Size: $FILESIZE, Duration: ${DURATION}s\"\n echo \"/tmp/youtube-shorts/final_short.mp4\"\nelse\n echo 'ERROR: Failed to create final video'\n exit 1\nfi",
"options": {
"timeout": 300000
}
},
"id": "ffmpeg-combine",
"name": "FFmpeg Video Birle\u015ftir",
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [
1620,
250
]
},
{
"parameters": {
"command": "cat /tmp/youtube-shorts/final_short.mp4 | base64"
},
"id": "read-final-video",
"name": "Final Videoyu Oku",
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [
1840,
250
]
},
{
"parameters": {
"operation": "toBinary",
"sourceProperty": "stdout",
"options": {
"fileName": "youtube_short.mp4",
"mimeType": "video/mp4",
"encoding": "base64"
}
},
"id": "convert-to-binary",
"name": "Binary'ye \u00c7evir",
"type": "n8n-nodes-base.convertToFile",
"typeVersion": 1.1,
"position": [
2060,
250
]
},
{
"parameters": {
"resource": "video",
"operation": "upload",
"title": "={{ $('parse-ai-response').item.json.title }} #Shorts",
"categoryId": "22",
"options": {
"description": "={{ $('parse-ai-response').item.json.description }}\n\n#Shorts #YouTube #E\u011flence #T\u00fcrk\u00e7e",
"tags": "={{ $('parse-ai-response').item.json.tags }}",
"privacyStatus": "public",
"defaultLanguage": "tr"
}
},
"id": "youtube-upload",
"name": "YouTube'a Y\u00fckle",
"type": "n8n-nodes-base.youTube",
"typeVersion": 1,
"position": [
2280,
250
],
"credentials": {
"youTubeOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"command": "rm -rf /tmp/youtube-shorts && echo 'Cleanup complete'"
},
"id": "cleanup",
"name": "Temizlik",
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [
2500,
250
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "status",
"name": "status",
"value": "=Video ba\u015far\u0131yla y\u00fcklendi! Ba\u015fl\u0131k: {{ $('parse-ai-response').item.json.title }}",
"type": "string"
},
{
"id": "uploaded_at",
"name": "uploaded_at",
"value": "={{ $now.toISO() }}",
"type": "string"
}
]
},
"options": {}
},
"id": "final-status",
"name": "Durum Bilgisi",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
2720,
250
]
}
],
"connections": {
"Haftal\u0131k Zamanlay\u0131c\u0131": {
"main": [
[
{
"node": "AI Konu ve Script \u00dcret",
"type": "main",
"index": 0
}
]
]
},
"AI Konu ve Script \u00dcret": {
"main": [
[
{
"node": "AI Cevab\u0131n\u0131 Parse Et",
"type": "main",
"index": 0
}
]
]
},
"AI Cevab\u0131n\u0131 Parse Et": {
"main": [
[
{
"node": "Seslendirme (TTS)",
"type": "main",
"index": 0
},
{
"node": "Dizin Haz\u0131rla",
"type": "main",
"index": 0
}
]
]
},
"Seslendirme (TTS)": {
"main": [
[
{
"node": "Ses Dosyas\u0131 Kaydet",
"type": "main",
"index": 0
}
]
]
},
"Ses Dosyas\u0131 Kaydet": {
"main": [
[
{
"node": "FFmpeg Video Birle\u015ftir",
"type": "main",
"index": 0
}
]
]
},
"Dizin Haz\u0131rla": {
"main": [
[
{
"node": "Arama Kelimesi \u00c7\u0131kar",
"type": "main",
"index": 0
}
]
]
},
"Arama Kelimesi \u00c7\u0131kar": {
"main": [
[
{
"node": "Pexels Video Ara",
"type": "main",
"index": 0
}
]
]
},
"Pexels Video Ara": {
"main": [
[
{
"node": "Videolar\u0131 \u0130ndir",
"type": "main",
"index": 0
}
]
]
},
"Videolar\u0131 \u0130ndir": {
"main": [
[
{
"node": "FFmpeg Video Birle\u015ftir",
"type": "main",
"index": 0
}
]
]
},
"FFmpeg Video Birle\u015ftir": {
"main": [
[
{
"node": "Final Videoyu Oku",
"type": "main",
"index": 0
}
]
]
},
"Final Videoyu Oku": {
"main": [
[
{
"node": "Binary'ye \u00c7evir",
"type": "main",
"index": 0
}
]
]
},
"Binary'ye \u00c7evir": {
"main": [
[
{
"node": "YouTube'a Y\u00fckle",
"type": "main",
"index": 0
}
]
]
},
"YouTube'a Y\u00fckle": {
"main": [
[
{
"node": "Temizlik",
"type": "main",
"index": 0
}
]
]
},
"Temizlik": {
"main": [
[
{
"node": "Durum Bilgisi",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"saveManualExecutions": true,
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": ""
},
"staticData": null,
"tags": [
{
"name": "youtube",
"createdAt": "2026-03-02T00:00:00.000Z",
"updatedAt": "2026-03-02T00:00:00.000Z"
},
{
"name": "automation",
"createdAt": "2026-03-02T00:00:00.000Z",
"updatedAt": "2026-03-02T00:00:00.000Z"
},
{
"name": "shorts",
"createdAt": "2026-03-02T00:00:00.000Z",
"updatedAt": "2026-03-02T00:00:00.000Z"
}
],
"triggerCount": 1
}
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.
httpHeaderAuthopenAiApiyouTubeOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
YouTube Shorts Otomasyonu - Haftalık Eğlenceli Video. Uses httpRequest, executeCommand, youTube. Scheduled trigger; 15 nodes.
Source: https://github.com/ahmetmertkarakoc/n8n/blob/2dc434801978fe73f0e49152e07a9a281b6000bb/workflows/youtube-shorts-automation.json — 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.
📘 Multi-Photo Facebook Post (Windows Directory) – How to Use ✅ Requirements To run this automation, make sure you have the following:
This workflow automatically mirrors your YouTube to TikTok and Instagram, so you don’t have to manually download and re-upload your content across platforms.
Are you a cord-cutter? Do you find yourself looking through the many titles of videos uploaded to Youtube, just to find the ones you want to watch? Even when you subscribe to the channels you like, do
Automatically upload your Instagram videos to YouTube with configurable time gaps between each upload, using n8n Tables for deduplication. Fetches recent Instagram posts via the Meta Graph API and fil
This n8n template acts as your automated social media data analyst. Instead of manually checking your analytics across different dashboards every week, this workflow scrapes your latest stats, calcula