{
"name": "Content Pipeline - BlendedFamilyKitchen",
"nodes": [
{
"parameters": {
"rule": {
"interval": [{"field": "minutes", "minutesInterval": 30}]
}
},
"id": "cp-trigger",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [-200, 300]
},
{
"parameters": {
"method": "POST",
"url": "http://192.168.2.200:5000/webapi/entry.cgi",
"sendQuery": true,
"queryParameters": {
"parameters": [
{"name": "api", "value": "SYNO.API.Auth"},
{"name": "version", "value": "6"},
{"name": "method", "value": "login"},
{"name": "account", "value": "={{$env.NAS_USER}}"},
{"name": "passwd", "value": "={{$env.NAS_PASS}}"},
{"name": "session", "value": "FileStation"},
{"name": "format", "value": "sid"}
]
}
},
"id": "cp-nas-login",
"name": "HTTP - NAS Login",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [40, 300]
},
{
"parameters": {
"url": "http://192.168.2.200:5000/webapi/entry.cgi",
"sendQuery": true,
"queryParameters": {
"parameters": [
{"name": "api", "value": "SYNO.FileStation.List"},
{"name": "version", "value": "2"},
{"name": "method", "value": "list"},
{"name": "folder_path", "value": "/BlendedFamilyKitchen/raw"},
{"name": "_sid", "value": "={{$json.data.sid}}"}
]
}
},
"id": "cp-poll-nas",
"name": "HTTP - Poll NAS for New Files",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [280, 300]
},
{
"parameters": {
"conditions": {
"options": {"caseSensitive": true, "leftValue": ""},
"conditions": [
{
"id": "cond-files",
"leftValue": "={{$json.data.files.length}}",
"rightValue": "0",
"operator": {"type": "number", "operation": "gt"}
}
],
"combinator": "and"
}
},
"id": "cp-if-files",
"name": "IF - New Files Found?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [520, 300]
},
{
"parameters": {
"options": {}
},
"id": "cp-split-batch",
"name": "Split In Batches",
"type": "n8n-nodes-base.splitInBatches",
"typeVersion": 3,
"position": [740, 300]
},
{
"parameters": {
"mode": "manual",
"duplicateItem": false,
"assignments": {
"assignments": [
{"id": "a1", "name": "filename", "value": "={{$json.name}}", "type": "string"},
{"id": "a2", "name": "filepath", "value": "={{$json.path}}", "type": "string"},
{"id": "a3", "name": "filesize_mb", "value": "={{Math.round($json.additional.size / 1048576 * 100) / 100}}", "type": "number"},
{"id": "a4", "name": "created", "value": "={{$json.additional.time.crtime}}", "type": "string"},
{"id": "a5", "name": "nas_sid", "value": "={{$('HTTP - NAS Login').item.json.data.sid}}", "type": "string"}
]
}
},
"id": "cp-set-meta",
"name": "Set - Extract File Metadata",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [960, 300]
},
{
"parameters": {
"url": "http://192.168.2.200:5000/webapi/entry.cgi",
"sendQuery": true,
"queryParameters": {
"parameters": [
{"name": "api", "value": "SYNO.FileStation.Download"},
{"name": "version", "value": "2"},
{"name": "method", "value": "download"},
{"name": "path", "value": "={{$json.filepath}}"},
{"name": "_sid", "value": "={{$json.nas_sid}}"}
]
},
"options": {"timeout": 300000}
},
"id": "cp-download",
"name": "HTTP - Download Raw Video",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [1200, 300]
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:8080/api/ffmpeg/extract-audio",
"sendBody": true,
"bodyParameters": {
"parameters": [
{"name": "input_file", "value": "={{$json.filepath}}"},
{"name": "output_format", "value": "wav"},
{"name": "sample_rate", "value": "16000"}
]
},
"options": {"timeout": 120000}
},
"id": "cp-extract-audio",
"name": "HTTP - Extract Audio (FFmpeg)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [1440, 300]
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:9000/asr",
"sendQuery": true,
"queryParameters": {
"parameters": [
{"name": "output", "value": "srt"},
{"name": "language", "value": "en"},
{"name": "word_timestamps", "value": "true"}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{"name": "audio_file", "value": "={{$json.audio_path}}"}
]
},
"options": {"timeout": 300000}
},
"id": "cp-whisper",
"name": "HTTP - Transcribe Audio (Whisper)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [1680, 300]
},
{
"parameters": {
"method": "POST",
"url": "https://api.anthropic.com/v1/messages",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{"name": "x-api-key", "value": "={{$env.CLAUDE_API_KEY}}"},
{"name": "anthropic-version", "value": "2023-06-01"},
{"name": "content-type", "value": "application/json"}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\"model\":\"claude-sonnet-4-20250514\",\"max_tokens\":1024,\"system\":\"You are a TikTok content strategist for BlendedFamilyKitchen, a blended family cooking channel. Generate engaging hooks, captions, and hashtags for cooking videos.\",\"messages\":[{\"role\":\"user\",\"content\":\"Based on this video transcript, generate:\\n1. Three hook options (short, punchy, first 3 seconds)\\n2. A TikTok caption (under 150 chars, engaging, with CTA)\\n3. 10 relevant hashtags\\n4. Best posting time suggestion\\n\\nTranscript:\\n\" + $json.transcript}]}",
"options": {"timeout": 60000}
},
"id": "cp-ai-hooks",
"name": "HTTP - Generate Hooks & Caption (AI)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [1920, 300]
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:8080/api/ffmpeg/normalize-video",
"sendBody": true,
"bodyParameters": {
"parameters": [
{"name": "input_file", "value": "={{$json.video_path}}"},
{"name": "target_resolution", "value": "1080x1920"},
{"name": "aspect_ratio", "value": "9:16"},
{"name": "color_correction", "value": "brightness=0.06:contrast=1.1:saturation=1.2"},
{"name": "audio_normalize", "value": "true"},
{"name": "codec", "value": "h264"},
{"name": "bitrate", "value": "6M"}
]
},
"options": {"timeout": 300000}
},
"id": "cp-normalize",
"name": "HTTP - Normalize Video (FFmpeg)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [2160, 300]
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:8080/api/ffmpeg/burn-captions",
"sendBody": true,
"bodyParameters": {
"parameters": [
{"name": "input_file", "value": "={{$json.normalized_video_path}}"},
{"name": "srt_file", "value": "={{$json.srt_path}}"},
{"name": "style", "value": "FontSize=24,PrimaryColour=&HFFFFFF,OutlineColour=&H000000,BorderStyle=3,Outline=2,Alignment=2"},
{"name": "position", "value": "bottom-third"}
]
},
"options": {"timeout": 300000}
},
"id": "cp-captions",
"name": "HTTP - Burn Captions (FFmpeg)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [2400, 300]
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:8080/api/ffmpeg/mix-audio",
"sendBody": true,
"bodyParameters": {
"parameters": [
{"name": "input_file", "value": "={{$json.captioned_video_path}}"},
{"name": "music_file", "value": "={{$json.selected_music_track}}"},
{"name": "music_volume", "value": "-20dB"},
{"name": "fade_in", "value": "2"},
{"name": "fade_out", "value": "3"}
]
},
"options": {"timeout": 300000}
},
"id": "cp-mix-music",
"name": "HTTP - Mix Background Music (FFmpeg)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [2640, 300]
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:8080/api/ffmpeg/extract-thumbnail",
"sendBody": true,
"bodyParameters": {
"parameters": [
{"name": "input_file", "value": "={{$json.final_video_path}}"},
{"name": "method", "value": "scene-detection"},
{"name": "output_format", "value": "jpg"},
{"name": "quality", "value": "95"}
]
},
"options": {"timeout": 60000}
},
"id": "cp-thumbnail",
"name": "HTTP - Extract Thumbnail (FFmpeg)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [2880, 300]
},
{
"parameters": {
"method": "POST",
"url": "http://192.168.2.200:5000/webapi/entry.cgi",
"sendQuery": true,
"queryParameters": {
"parameters": [
{"name": "api", "value": "SYNO.FileStation.Upload"},
{"name": "version", "value": "2"},
{"name": "method", "value": "upload"},
{"name": "path", "value": "/BlendedFamilyKitchen/processed"},
{"name": "_sid", "value": "={{$json.nas_sid}}"}
]
},
"options": {"timeout": 300000}
},
"id": "cp-upload-nas",
"name": "HTTP - Upload Enhanced Video to NAS",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [3120, 300]
},
{
"parameters": {
"url": "https://apify.com/api/v2/acts/novi~tiktok-music-trend-api/runs/last/dataset/items",
"sendQuery": true,
"queryParameters": {
"parameters": [
{"name": "token", "value": "={{$env.APIFY_API_TOKEN}}"},
{"name": "limit", "value": "5"}
]
},
"options": {"timeout": 30000}
},
"id": "cp-trending",
"name": "HTTP - Scrape Trending Sounds",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [3360, 300]
},
{
"parameters": {
"mode": "manual",
"duplicateItem": false,
"assignments": {
"assignments": [
{"id": "s1", "name": "trending_sounds", "value": "={{$json}}", "type": "string"},
{"id": "s2", "name": "curated_picks", "value": "=[{\"name\":\"Sunny Kitchen Vibes\",\"mood\":\"upbeat-cooking\",\"file\":\"/BlendedFamilyKitchen/music/upbeat/sunny_kitchen.mp3\"},{\"name\":\"Family Dinner Warmth\",\"mood\":\"cozy-family\",\"file\":\"/BlendedFamilyKitchen/music/cozy/family_dinner.mp3\"},{\"name\":\"Kids in the Kitchen\",\"mood\":\"fun-kids\",\"file\":\"/BlendedFamilyKitchen/music/fun/kids_cooking.mp3\"}]", "type": "string"}
]
}
},
"id": "cp-format-sounds",
"name": "Set - Format Sound Suggestions",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [3600, 300]
},
{
"parameters": {
"method": "POST",
"url": "https://api.telegram.org/bot{{$env.TELEGRAM_BOT_TOKEN}}/sendMessage",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\"chat_id\":\"{{$env.CLOE_CHAT_ID}}\",\"parse_mode\":\"HTML\",\"text\":\"\\ud83c\\udfac New Video Ready: {{$('Set - Extract File Metadata').item.json.filename}}\\n\\n\\ud83d\\udcdd AI-Generated Caption:\\n{{$('HTTP - Generate Hooks & Caption (AI)').item.json.caption}}\\n\\n\\ud83c\\udfa3 Hook Options (reply 1, 2, or 3):\\n1. {{$('HTTP - Generate Hooks & Caption (AI)').item.json.hooks[0]}}\\n2. {{$('HTTP - Generate Hooks & Caption (AI)').item.json.hooks[1]}}\\n3. {{$('HTTP - Generate Hooks & Caption (AI)').item.json.hooks[2]}}\\n\\n\\ud83c\\udfb5 Trending Now:\\n{{$json.trending_sounds_formatted}}\\n\\n\\ud83c\\udf73 Kitchen Picks:\\n{{$json.curated_picks_formatted}}\\n\\n\\u23f0 Suggested Post Time: {{$('HTTP - Generate Hooks & Caption (AI)').item.json.best_time}}\",\"reply_markup\":{\"inline_keyboard\":[[{\"text\":\"\\u2705 Approve\",\"callback_data\":\"approve\"},{\"text\":\"\\u270f\\ufe0f Edit\",\"callback_data\":\"edit\"}],[{\"text\":\"\\u23f0 Schedule\",\"callback_data\":\"schedule\"},{\"text\":\"\\u274c Reject\",\"callback_data\":\"reject\"}]]}}",
"options": {"timeout": 30000}
},
"id": "cp-notify-cloe",
"name": "HTTP - Send Cloe Preview (Telegram)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [3840, 300]
},
{
"parameters": {
"httpMethod": "POST",
"path": "cloe-response",
"responseMode": "responseNode",
"options": {}
},
"id": "cp-webhook-cloe",
"name": "Webhook - Cloe Response",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [4080, 300],
"webhookId": "cloe-response-001"
},
{
"parameters": {
"rules": {
"rules": [
{"outputIndex": 0, "value": "approve"},
{"outputIndex": 1, "value": "edit"},
{"outputIndex": 2, "value": "schedule"},
{"outputIndex": 3, "value": "reject"}
]
},
"dataType": "string",
"value1": "={{$json.body.action}}"
},
"id": "cp-switch-decision",
"name": "Switch - Cloe Decision",
"type": "n8n-nodes-base.switch",
"typeVersion": 3.2,
"position": [4320, 300]
},
{
"parameters": {
"method": "POST",
"url": "https://open.tiktokapis.com/v2/post/publish/content/init/",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{"name": "Authorization", "value": "Bearer {{$env.TIKTOK_ACCESS_TOKEN}}"},
{"name": "Content-Type", "value": "application/json"}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\"post_info\":{\"title\":\"{{$('HTTP - Generate Hooks & Caption (AI)').item.json.caption}}\",\"privacy_level\":\"SELF_ONLY\",\"disable_duet\":false,\"disable_stitch\":false,\"disable_comment\":false},\"source_info\":{\"source\":\"PULL_FROM_URL\",\"video_url\":\"{{$('HTTP - Upload Enhanced Video to NAS').item.json.video_url}}\"}}",
"options": {"timeout": 60000}
},
"id": "cp-tiktok-post",
"name": "HTTP - Post to TikTok",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [4620, 100]
},
{
"parameters": {
"method": "POST",
"url": "https://open.tiktokapis.com/v2/post/publish/content/init/",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{"name": "Authorization", "value": "Bearer {{$env.TIKTOK_ACCESS_TOKEN}}"},
{"name": "Content-Type", "value": "application/json"}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\"post_info\":{\"title\":\"{{$('HTTP - Generate Hooks & Caption (AI)').item.json.caption}}\",\"privacy_level\":\"SELF_ONLY\",\"schedule_time\":\"{{$('HTTP - Generate Hooks & Caption (AI)').item.json.best_time}}\"},\"source_info\":{\"source\":\"PULL_FROM_URL\",\"video_url\":\"{{$('HTTP - Upload Enhanced Video to NAS').item.json.video_url}}\"}}",
"options": {"timeout": 60000}
},
"id": "cp-tiktok-schedule",
"name": "HTTP - Schedule TikTok Post",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [4620, 300]
},
{
"parameters": {
"method": "POST",
"url": "http://192.168.2.200:5000/webapi/entry.cgi",
"sendQuery": true,
"queryParameters": {
"parameters": [
{"name": "api", "value": "SYNO.FileStation.CopyMove"},
{"name": "version", "value": "3"},
{"name": "method", "value": "start"},
{"name": "path", "value": "={{$('Set - Extract File Metadata').item.json.filepath}}"},
{"name": "dest_folder_path", "value": "/BlendedFamilyKitchen/archive"},
{"name": "remove_src", "value": "true"},
{"name": "_sid", "value": "={{$('Set - Extract File Metadata').item.json.nas_sid}}"}
]
}
},
"id": "cp-archive",
"name": "HTTP - Archive Original",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [4860, 200]
},
{
"parameters": {
"method": "POST",
"url": "https://api.telegram.org/bot{{$env.TELEGRAM_BOT_TOKEN}}/sendMessage",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\"chat_id\":\"{{$env.CLOE_CHAT_ID}}\",\"text\":\"\\u274c Video rejected: {{$('Set - Extract File Metadata').item.json.filename}}\\nArchived without posting.\"}",
"options": {}
},
"id": "cp-reject-notify",
"name": "HTTP - Notify Rejection (Telegram)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [4620, 500]
},
{
"parameters": {
"method": "POST",
"url": "https://api.telegram.org/bot{{$env.TELEGRAM_BOT_TOKEN}}/sendMessage",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\"chat_id\":\"{{$env.CLOE_CHAT_ID}}\",\"text\":\"\\u270f\\ufe0f Please reply with your edited caption for: {{$('Set - Extract File Metadata').item.json.filename}}\\nI'll update and re-send for approval.\"}",
"options": {}
},
"id": "cp-edit-prompt",
"name": "HTTP - Prompt Edit (Telegram)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [4620, 700]
},
{
"parameters": {},
"id": "cp-error-trigger",
"name": "Error Trigger",
"type": "n8n-nodes-base.errorTrigger",
"typeVersion": 1,
"position": [2200, 700]
},
{
"parameters": {
"method": "POST",
"url": "https://api.telegram.org/bot{{$env.TELEGRAM_BOT_TOKEN}}/sendMessage",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\"chat_id\":\"{{$env.JORDAN_CHAT_ID}}\",\"parse_mode\":\"HTML\",\"text\":\"\\ud83d\\udea8 Content Pipeline Error\\n\\nNode: {{$json.execution.error.node.name}}\\nError: {{$json.execution.error.message}}\\nTime: {{new Date().toLocaleString('en-US', {timeZone: 'America/Denver'})}}\\nWorkflow: Content Pipeline - BlendedFamilyKitchen\"}",
"options": {}
},
"id": "cp-error-notify",
"name": "HTTP - Notify Error (Telegram)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [2440, 700]
},
{
"parameters": {
"content": "\ud83d\udcc2 NAS DROP ZONE \u2014 File Detection\n\nFOLDER STRUCTURE ON NAS (192.168.2.200):\n/BlendedFamilyKitchen/\n \u251c\u2500\u2500 raw/ \u2190 Cloe drops videos here\n \u251c\u2500\u2500 processing/ \u2190 Temp during AI processing\n \u251c\u2500\u2500 processed/ \u2190 Enhanced videos ready for review\n \u251c\u2500\u2500 archive/ \u2190 Originals after posting\n \u2514\u2500\u2500 music/ \u2190 Curated background tracks\n\nSYNOLOGY FILESTATION API:\n\u2022 Login: POST /webapi/entry.cgi\n api=SYNO.API.Auth&method=login&account=&passwd=&session=FileStation&format=sid\n\u2022 List: GET /webapi/entry.cgi\n api=SYNO.FileStation.List&method=list&folder_path=/BlendedFamilyKitchen/raw&_sid=\n\u2022 Download: GET /webapi/entry.cgi\n api=SYNO.FileStation.Download&method=download&path=&_sid=\n\u2022 Upload: POST /webapi/entry.cgi\n api=SYNO.FileStation.Upload&method=upload&path=&_sid=\n\nFLOW:\n1. Schedule Trigger fires every 30 min\n2. Login to NAS \u2192 get session ID\n3. Poll /raw folder for new files\n4. IF files found \u2192 Split In Batches to process each\n5. Extract metadata (name, path, size, created time)\n\nINFRA TODO:\n\u25a1 Create NAS API user with limited FileStation permissions\n\u25a1 Create folder structure on NAS\n\u25a1 Set n8n env vars: NAS_USER, NAS_PASS\n\u25a1 Test with a sample .mp4 drop",
"height": 620,
"width": 560,
"color": 4
},
"id": "cp-sticky-nas",
"name": "Sticky - NAS Drop Zone",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [-220, -80]
},
{
"parameters": {
"content": "\ud83e\udd16 AI PROCESSING PIPELINE\n\nAll processing runs on Docker services (CT 113 or VM).\nEach step is a separate API call for modularity and debugging.\n\nSERVICES NEEDED:\n\u2022 FFmpeg API \u2014 HTTP wrapper around FFmpeg\n - Docker: jrottenberg/ffmpeg or custom FastAPI wrapper\n - Endpoint: http://:8080/api/ffmpeg/\n - Actions: extract-audio, normalize-video, burn-captions, mix-audio, extract-thumbnail\n\n\u2022 Whisper \u2014 OpenAI Whisper for transcription\n - Docker: onerahmet/openai-whisper-asr-webservice\n - Endpoint: POST http://:9000/asr?output=srt\n - Returns: .srt subtitle file + raw transcript\n\n\u2022 Claude API \u2014 Hook generation and caption writing\n - POST to api.anthropic.com/v1/messages\n - System: TikTok content strategist for BlendedFamilyKitchen\n - Returns: 3 hook options, caption, 10 hashtags, best posting time\n\nPROCESSING CHAIN:\n1. Download raw video from NAS\n2. Extract audio \u2192 WAV (16kHz for Whisper)\n3. Transcribe \u2192 .srt captions + raw text\n4. AI generates hooks, caption, hashtags from transcript\n5. Normalize video \u2192 9:16, 1080x1920, warm color correction\n6. Burn captions \u2192 White bold, black outline, bottom-third\n7. Mix background music \u2192 curated track at -20dB, fade in/out\n8. Extract thumbnail \u2192 best frame via scene detection\n9. Upload enhanced video to NAS /processed folder\n\nFFMPEG SETTINGS:\n\u2022 Color: brightness=0.06, contrast=1.1, saturation=1.2\n\u2022 Codec: H.264, 6Mbps bitrate\n\u2022 Captions: FontSize=24, white with black outline\n\u2022 Music: -20dB volume, 2s fade-in, 3s fade-out\n\nINFRA TODO:\n\u25a1 Deploy FFmpeg API container on CT 113\n\u25a1 Deploy Whisper container (CPU fine for <5min videos)\n\u25a1 Set n8n env var: CLAUDE_API_KEY\n\u25a1 Create Claude prompt template\n\u25a1 Test full chain with sample 60-second video",
"height": 780,
"width": 560,
"color": 6
},
"id": "cp-sticky-ai",
"name": "Sticky - AI Processing Pipeline",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [1180, -120]
},
{
"parameters": {
"content": "\ud83c\udfb5 TRENDING SOUNDS & MUSIC STRATEGY\n\nTWO SOURCES OF AUDIO SUGGESTIONS:\n\n1. TRENDING SOUNDS (scraped per-run):\n \u2022 Apify TikTok Music Trend API or similar scraper\n \u2022 GET top 5 currently trending sounds\n \u2022 Filter for family-friendly content\n \u2022 Presented as suggestions \u2014 Cloe picks if appropriate\n \u2022 She applies chosen sound in TikTok app before posting\n\n2. CURATED KITCHEN LIBRARY (pre-loaded on NAS):\n \u2022 10-20 royalty-free tracks in /BlendedFamilyKitchen/music/\n \u2022 Categories: upbeat-cooking, cozy-family, fun-kids, chill-prep\n \u2022 One auto-mixed at low volume as background\n \u2022 Cloe can swap or remove via her Telegram response\n\nMUSIC LIBRARY:\n/BlendedFamilyKitchen/music/\n \u251c\u2500\u2500 upbeat/ \u2190 energetic cooking montages\n \u251c\u2500\u2500 cozy/ \u2190 family dinner, slow-cook content\n \u251c\u2500\u2500 fun/ \u2190 kids helping, bloopers, reactions\n \u2514\u2500\u2500 chill/ \u2190 meal prep, quiet kitchen moments\n\nKEY PRINCIPLE:\nFor cooking content, sizzle and narration ARE the primary audio.\nBackground music is subtle enhancement, not the focus.\nTrending sounds work better for reaction/family-moment content.\nCloe maintains full creative control over final audio choice.\n\nTODO:\n\u25a1 Source 10-20 royalty-free tracks (Pixabay, Epidemic Sound free tier)\n\u25a1 Upload to NAS music folders\n\u25a1 Set up Apify actor or alt trending sounds scraper\n\u25a1 Set n8n env var: APIFY_API_TOKEN\n\u25a1 Build category-matching logic (video mood \u2192 music mood)",
"height": 660,
"width": 560,
"color": 3
},
"id": "cp-sticky-music",
"name": "Sticky - Trending Sounds & Music",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [3340, -100]
},
{
"parameters": {
"content": "\ud83d\udcf1 CLOE APPROVAL FLOW \u2014 Creative Control\n\nCloe receives a Telegram message for EVERY processed video:\n\nMESSAGE FORMAT:\n\ud83c\udfac New Video Ready: [filename]\n\n\ud83d\udcdd AI-Generated Caption:\n[caption text with hashtags]\n\n\ud83c\udfa3 Hook Options (reply 1, 2, or 3):\n1. \"[hook option 1]\"\n2. \"[hook option 2]\"\n3. \"[hook option 3]\"\n\n\ud83c\udfb5 Trending Now:\n \ud83d\udd25 [sound 1] \u2014 [artist]\n \ud83d\udd25 [sound 2] \u2014 [artist]\n \ud83d\udd25 [sound 3] \u2014 [artist]\n\n\ud83c\udf73 Kitchen Picks:\n \ud83c\udf73 [curated 1] \u2014 [mood]\n \ud83c\udf73 [curated 2] \u2014 [mood]\n \ud83c\udf73 [curated 3] \u2014 [mood]\n\n\u23f0 Suggested Post Time: [optimal time]\n\nINLINE KEYBOARD:\n[ \u2705 Approve ] [ \u270f\ufe0f Edit ]\n[ \u23f0 Schedule ] [ \u274c Reject ]\n\nRESPONSE ROUTING:\n\u2022 Approve \u2192 Post immediately to TikTok with AI caption\n\u2022 Edit \u2192 Bot asks for modified caption, then re-approve\n\u2022 Schedule \u2192 Post at AI-suggested optimal time\n\u2022 Reject \u2192 Archive without posting, notify Jordan\n\nWEBHOOK:\nCloe's button press triggers callback to:\nhttp://192.168.2.113:5678/webhook/cloe-response\nPayload: {action, video_id, hook_choice, sound_choice}\n\nSETUP TODO:\n\u25a1 Set n8n env vars: TELEGRAM_BOT_TOKEN, CLOE_CHAT_ID, JORDAN_CHAT_ID\n\u25a1 Configure Telegram bot webhook for callbacks\n\u25a1 Test approval flow with a mock video",
"height": 740,
"width": 560,
"color": 2
},
"id": "cp-sticky-approval",
"name": "Sticky - Cloe Approval Flow",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [3820, -120]
},
{
"parameters": {
"content": "\u26a0\ufe0f ERROR HANDLING\n\nSTRATEGY:\n\u2022 Error Trigger catches ANY node failure in the workflow\n\u2022 Sends details to Jordan via Telegram (not Cloe \u2014 keep her flow clean)\n\u2022 Includes: failed node name, error message, timestamp\n\nNOTIFICATION FORMAT:\n\ud83d\udea8 Content Pipeline Error\nNode: [failed_node]\nError: [message]\nTime: [timestamp MST]\nWorkflow: Content Pipeline - BlendedFamilyKitchen\n\nRETRY LOGIC (future enhancement):\n\u2022 FFmpeg failures \u2192 retry once with default/safe settings\n\u2022 NAS connection failures \u2192 retry 3x with 30s backoff\n\u2022 Whisper timeout \u2192 retry with smaller chunk size\n\u2022 API failures (TikTok, Claude) \u2192 hold for manual retry\n\nSETUP TODO:\n\u25a1 Set n8n env var: JORDAN_CHAT_ID\n\u25a1 Test error trigger with intentional failure\n\u25a1 Add retry nodes in future iteration",
"height": 420,
"width": 480,
"color": 1
},
"id": "cp-sticky-error",
"name": "Sticky - Error Handling",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [2180, 620]
}
],
"connections": {
"Schedule Trigger": {
"main": [[{"node": "HTTP - NAS Login", "type": "main", "index": 0}]]
},
"HTTP - NAS Login": {
"main": [[{"node": "HTTP - Poll NAS for New Files", "type": "main", "index": 0}]]
},
"HTTP - Poll NAS for New Files": {
"main": [[{"node": "IF - New Files Found?", "type": "main", "index": 0}]]
},
"IF - New Files Found?": {
"main": [
[{"node": "Split In Batches", "type": "main", "index": 0}],
[]
]
},
"Split In Batches": {
"main": [
[{"node": "Set - Extract File Metadata", "type": "main", "index": 0}],
[]
]
},
"Set - Extract File Metadata": {
"main": [[{"node": "HTTP - Download Raw Video", "type": "main", "index": 0}]]
},
"HTTP - Download Raw Video": {
"main": [[{"node": "HTTP - Extract Audio (FFmpeg)", "type": "main", "index": 0}]]
},
"HTTP - Extract Audio (FFmpeg)": {
"main": [[{"node": "HTTP - Transcribe Audio (Whisper)", "type": "main", "index": 0}]]
},
"HTTP - Transcribe Audio (Whisper)": {
"main": [[{"node": "HTTP - Generate Hooks & Caption (AI)", "type": "main", "index": 0}]]
},
"HTTP - Generate Hooks & Caption (AI)": {
"main": [[{"node": "HTTP - Normalize Video (FFmpeg)", "type": "main", "index": 0}]]
},
"HTTP - Normalize Video (FFmpeg)": {
"main": [[{"node": "HTTP - Burn Captions (FFmpeg)", "type": "main", "index": 0}]]
},
"HTTP - Burn Captions (FFmpeg)": {
"main": [[{"node": "HTTP - Mix Background Music (FFmpeg)", "type": "main", "index": 0}]]
},
"HTTP - Mix Background Music (FFmpeg)": {
"main": [[{"node": "HTTP - Extract Thumbnail (FFmpeg)", "type": "main", "index": 0}]]
},
"HTTP - Extract Thumbnail (FFmpeg)": {
"main": [[{"node": "HTTP - Upload Enhanced Video to NAS", "type": "main", "index": 0}]]
},
"HTTP - Upload Enhanced Video to NAS": {
"main": [[{"node": "HTTP - Scrape Trending Sounds", "type": "main", "index": 0}]]
},
"HTTP - Scrape Trending Sounds": {
"main": [[{"node": "Set - Format Sound Suggestions", "type": "main", "index": 0}]]
},
"Set - Format Sound Suggestions": {
"main": [[{"node": "HTTP - Send Cloe Preview (Telegram)", "type": "main", "index": 0}]]
},
"HTTP - Send Cloe Preview (Telegram)": {
"main": [[{"node": "Webhook - Cloe Response", "type": "main", "index": 0}]]
},
"Webhook - Cloe Response": {
"main": [[{"node": "Switch - Cloe Decision", "type": "main", "index": 0}]]
},
"Switch - Cloe Decision": {
"main": [
[{"node": "HTTP - Post to TikTok", "type": "main", "index": 0}],
[{"node": "HTTP - Prompt Edit (Telegram)", "type": "main", "index": 0}],
[{"node": "HTTP - Schedule TikTok Post", "type": "main", "index": 0}],
[{"node": "HTTP - Notify Rejection (Telegram)", "type": "main", "index": 0}]
]
},
"HTTP - Post to TikTok": {
"main": [[{"node": "HTTP - Archive Original", "type": "main", "index": 0}]]
},
"HTTP - Schedule TikTok Post": {
"main": [[{"node": "HTTP - Archive Original", "type": "main", "index": 0}]]
},
"Error Trigger": {
"main": [[{"node": "HTTP - Notify Error (Telegram)", "type": "main", "index": 0}]]
}
},
"settings": {
"executionOrder": "v1"
}
}