{
  "name": "Automating YouTube Metadata Ai Agent",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        -896,
        224
      ],
      "id": "3228fab7-6c5f-430b-9f57-52723f45e6b0",
      "name": "Schedule Trigger"
    },
    {
      "parameters": {
        "jsCode": "const data = $json.data;\n\nconst segments = data?.transcript?.hi_auto?.custom;\n\nif (!Array.isArray(segments)) {\n  throw new Error(\"Transcript segments not found\");\n}\n\nconst combinedTranscript = segments\n  .map(segment => segment.text)\n  .filter(text => text && text.trim())\n  .join(\" \");\n\nreturn {\n  json: {\n    combinedTranscript\n  }\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        656,
        64
      ],
      "id": "62ceb389-d879-4e26-b7b7-a269195b1404",
      "name": "Combine Transcript",
      "retryOnFail": true
    },
    {
      "parameters": {
        "modelName": "models/gemini-3.5-flash",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1.1,
      "position": [
        864,
        512
      ],
      "id": "3dea86c4-9adf-4d13-a882-2d2c007a4984",
      "name": "Google Gemini Chat Model",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "modelName": "models/gemini-3.5-flash-lite",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1.1,
      "position": [
        1424,
        496
      ],
      "id": "0b7f5736-dc42-49ce-a238-66eddad61fa6",
      "name": "Google Gemini Chat Model1",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "6b083b7b-7bd4-478f-88a1-83f3183cdb49",
              "name": "Video Link",
              "value": "={{ $json['Video Link'] }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -224,
        160
      ],
      "id": "b6aa10b5-ee51-475d-9dcc-91faa5583d15",
      "name": "Extract video URL"
    },
    {
      "parameters": {
        "jsCode": "const input = String($json[\"Video Link\"] ?? \"\").trim();\n\nif (!input) {\n  throw new Error(\"Video Link is empty\");\n}\n\n// Clean escaped characters and quotes\nlet link = input\n  .replace(/\\\\_/g, \"_\")\n  .replace(/\\\\/g, \"\")\n  .replace(/^[\"']|[\"']$/g, \"\")\n  .trim();\n\n// Extract YouTube ID directly\nlet videoId = null;\n\n// youtu.be format\nconst shortMatch = link.match(\n  /(?:https?:)?\\/\\/(?:www\\.)?youtu\\.be\\/([A-Za-z0-9_-]{11})/\n);\n\nif (shortMatch) {\n  videoId = shortMatch[1];\n}\n\n// youtube.com/watch?v= format\nif (!videoId) {\n  const watchMatch = link.match(\n    /[?&]v=([A-Za-z0-9_-]{11})/\n  );\n\n  if (watchMatch) {\n    videoId = watchMatch[1];\n  }\n}\n\nif (!videoId) {\n  throw new Error(\n    `Could not extract YouTube Video ID from: ${input}`\n  );\n}\n\nreturn {\n  json: {\n    videoLink: input,\n    videoId: videoId\n  }\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        0,
        160
      ],
      "id": "368139d5-6bc8-4772-bef0-f9799f48120b",
      "name": "Extract video ID"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $json.combinedTranscript }}",
        "messages": {
          "messageValues": [
            {
              "message": "You are an expert YouTube SEO strategist, professional copywriter, and content marketing specialist.  Your primary task is to analyze the YouTube video transcript provided in the user input and create a highly engaging, professional, SEO-optimized YouTube video description in ENGLISH.  The transcript may be written in Hindi, Hinglish, or mixed languages. You must understand the meaning and context of the transcript and write the final description completely in natural, professional English. \n\n IMPORTANT:\n The transcript is the ONLY source of truth about the video content. Do not invent facts, statistics, claims, names, features, results, tools, or information that are not reasonably supported by the transcript.\n\n CORE OBJECTIVE :\n\n  Create a YouTube description that:  1. Immediately captures the viewer's attention. 2. Clearly explains what the video is about. 3. Communicates the main value and benefits of watching the video. 4. Uses natural YouTube SEO keywords based on the actual transcript. 5. Encourages viewers to watch the complete video. 6. Includes a natural call-to-action. 7. Looks professional and human-written. 8. Is easy to scan on both desktop and mobile. 9. Uses relevant emojis sparingly and professionally. 10. Avoids fake claims and exaggerated promises. 11. Does NOT sound like generic AI-generated content. 12. Does NOT use unnecessary repetition. 13. Does NOT include information that cannot be supported by the transcript. \n\n UNDERSTANDING THE TRANSCRIPT :\n\n First, internally analyze the transcript and identify:  - Main topic - Main purpose of the video - Important concepts discussed - Tools, platforms, technologies, or products mentioned - Main problems discussed - Solutions explained - Key lessons - Important steps or methods - Target audience - Search-intent keywords - Important entities or terminology - The overall value provided to the viewer  Do this analysis internally.  DO NOT show this internal analysis in the final response.  \n\nDESCRIPTION STRUCTURE :\n\n Create the final YouTube description using this structure:  1. OPENING HOOK  Start with 1\u20132 highly engaging sentences.  The opening should create curiosity and clearly communicate why the viewer should care about the video.  Do not use fake clickbait.  Example style:  \"Want to automate your YouTube workflow and save hours of repetitive work? In this video, you'll see how AI and automation can turn a time-consuming content process into a streamlined system.\"  Do not copy this example literally. Generate a hook based on the actual transcript.  --------------------------------------------------  2. VIDEO OVERVIEW  Write a concise paragraph explaining what the video covers.  Mention the most important topics, tools, strategies, or concepts discussed in the transcript.  Make this section useful for both viewers and YouTube search.  --------------------------------------------------  3. WHAT YOU'LL LEARN  Create a short bullet list containing approximately 4\u20137 important things the viewer will learn from the video.  Use clear and concise bullet points.  Example:  \u2022 How the automation workflow works \u2022 How AI processes the video content \u2022 How to generate optimized metadata \u2022 How to connect the required tools \u2022 How to improve the overall content workflow  Only include points supported by the transcript.  --------------------------------------------------  4. WHY WATCH THIS VIDEO  Write 2\u20134 sentences explaining the practical value of the video.  Focus on what problem the video helps solve and who can benefit from watching it.  --------------------------------------------------  5. CALL TO ACTION  End with a natural YouTube CTA.  Encourage viewers to:  \u2022 Like the video \u2022 Subscribe to the channel \u2022 Comment with their thoughts or questions  Do not make the CTA sound repetitive or overly promotional.  Example style:  \"If you found this workflow useful, make sure to like the video and subscribe for more practical AI, automation, and productivity tutorials.\"  Adapt the CTA to the actual topic of the video.  --------------------------------------------------  6. SEO KEYWORDS  At the end, include a short line containing relevant SEO keywords naturally related to the transcript.  Format:  SEO Keywords: keyword 1, keyword 2, keyword 3, keyword 4, keyword 5, keyword 6  Do not keyword-stuff.  Only include keywords that are genuinely relevant to the video.  --------------------------------------------------  7. HASHTAGS  Finish with approximately 5\u201310 highly relevant hashtags.  Example:  #YouTubeAutomation #AI #Automation #AIAutomation #YouTubeTips  Only use hashtags relevant to the actual video. \n\n WRITING STYLE :\n\n  Use the following writing style:  - Professional - Clear - Engaging - Conversational - Confident - Natural - Human-like - Modern - Creator-friendly - SEO-aware  Avoid:  - Robotic language - Generic AI phrases - Excessive adjectives - Excessive emojis - Fake promises - Overly dramatic language - Repetitive keywords - Keyword stuffing - Long unnecessary paragraphs - Unverified claims  Do not repeatedly use phrases such as:  \"Unlock the power of...\" \"Take your content to the next level...\" \"In today's digital world...\" \"Revolutionize your workflow...\" \"Game-changing...\" \"Cutting-edge...\"  unless the transcript genuinely supports such language.  \n\n SEO REQUIREMENTS :\n\nOptimize the description naturally for YouTube search.  Identify important keywords from the transcript and incorporate them naturally into:  - Opening hook - Video overview - Learning points - SEO keywords section - Hashtags where appropriate  Do NOT force keywords into every sentence.  The description should primarily be written for humans, while remaining search-engine friendly.  \n\nACCURACY RULES:\n\n  Never invent:  - Statistics - Revenue figures - Subscriber numbers - Views - Performance results - Case studies - Testimonials - Features - Tools - Integrations - Facts - Names - Dates - Claims about guaranteed success  If something is not clearly supported by the transcript, do not include it.  If the transcript mentions a tool, platform, technology, or method, use its correct name exactly when possible. \n\nLANGUAGE RULE:\n\n  The final output MUST be written in ENGLISH.  Even if the transcript is:  - Hindi - Hinglish - Urdu - Mixed Hindi and English - Another language  understand the content and produce a polished English YouTube description.  Do not translate sentence-by-sentence.  Instead, understand the meaning and rewrite it naturally for an English-speaking YouTube audience. \n\n FORMATTING RULES :\n\n The final response must be CLEAN PLAIN TEXT suitable for directly inserting into a YouTube description.  Use actual line breaks.  DO NOT return JSON.  DO NOT return JavaScript.  DO NOT return Markdown code fences.  DO NOT return escaped newline characters such as:  \\n  DO NOT return:  {   \"description\": \"...\" }  DO NOT put the entire response inside quotation marks.  Use simple headings, paragraphs, and bullet points.  You MAY use:  \u2022 Bullet points - Bullet points Emoji Short section headings  Keep the formatting visually clean.  Do not use HTML.  Do not add explanations about how you generated the description.  Do not say \"Here is your description.\"  Return ONLY the final YouTube description.  \n\n OUTPUT LENGTH :\n\n  Target approximately 250\u2013450 words.  Do not make the description unnecessarily long.  Prioritize useful information and readability over word count.  \n\nQUALITY CONTROL :\n\n Before producing the final response, internally verify:  \u2713 Is the description completely in English? \u2713 Does the opening create curiosity? \u2713 Does it accurately represent the transcript? \u2713 Are the main topics covered? \u2713 Are the learning points useful? \u2713 Are the SEO keywords relevant? \u2713 Are the hashtags relevant? \u2713 Is the CTA natural? \u2713 Is the writing human-like? \u2713 Is there any unsupported claim? \u2713 Is there any unnecessary repetition? \u2713 Are there literal \"\\n\" characters? \u2713 Is the response clean plain text? \u2713 Is the response free from JSON formatting?  If any requirement fails, fix it before returning the final answer.  \n\n EXAMPLE OF DESIRED OUTPUT :\n\n Want to build smarter YouTube workflows without spending hours on repetitive tasks? In this video, you'll discover how AI and automation can help streamline the process and make your content workflow more efficient.  In this tutorial, we explore how an AI-powered workflow can process YouTube content, understand the video transcript, and turn that information into useful content metadata. You'll also see how different automation steps can work together to reduce manual effort and create a more organized content creation system.  What You'll Learn:  \u2022 How the YouTube automation workflow works \u2022 How video transcripts can be processed with AI \u2022 How AI can understand and analyze video content \u2022 How to generate useful YouTube metadata from a transcript \u2022 How automation can reduce repetitive content tasks \u2022 How different tools can work together in an automated workflow  Why Watch This Video?  If you're interested in AI automation, YouTube content creation, or building practical workflows with tools like n8n, this tutorial can help you understand how these technologies can be connected into a useful system. The workflow demonstrates a practical approach to turning raw video information into structured content that can support your YouTube publishing process.  If you found this tutorial useful, don't forget to like the video, subscribe to the channel, and share your thoughts or questions in the comments.  SEO Keywords: YouTube automation, AI YouTube automation, n8n automation, AI workflow, YouTube content automation, YouTube metadata, AI content creation  #YouTubeAutomation #AIAutomation #n8n #AIWorkflow #YouTubeTips #ContentCreation  \n\n FINAL INSTRUCTION :\n\n  Now analyze the user's combined transcript and generate the final YouTube description following every rule above.  Return ONLY the clean, professional YouTube description.\n\nNote:\n\nNever mention an AI model, API, platform, or tool unless it is actually used in the workflow or explicitly mentioned in the transcript."
            }
          ]
        },
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.9,
      "position": [
        864,
        64
      ],
      "id": "52fee165-f37b-45fd-99ce-1febee861b18",
      "name": " LLM Generate Description",
      "onError": "continueErrorOutput",
      "notes": "If AI description generation fails, route the error to the error-handling branch. The workflow should convert the technical AI error into a simple human-readable reason, then update the corresponding Google Sheets row with Failed status and the error reason. Do not stop the entire workflow."
    },
    {
      "parameters": {
        "jsCode": "// Get the LLM response\nconst output = $json.text || $json.output;\n\nif (!output) {\n  throw new Error(\"Description output is missing. Expected 'text' or 'output'.\");\n}\n\n// Convert escaped newlines into real line breaks\nlet description = String(output)\n  .replace(/\\\\n/g, \"\\n\")\n  .replace(/\\r/g, \"\")\n  .trim();\n\n// Remove accidental surrounding quotes\ndescription = description.replace(/^[\"']|[\"']$/g, \"\").trim();\n\n// Clean excessive blank lines\ndescription = description.replace(/\\n{3,}/g, \"\\n\\n\");\n\nreturn [\n  {\n    json: {\n      description: description\n    }\n  }\n];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1216,
        48
      ],
      "id": "64f2a69e-ca26-419f-8829-df1504861b74",
      "name": "Format Description"
    },
    {
      "parameters": {
        "promptType": "=define",
        "text": "={{ $json.description }}\n\nYou are an expert YouTube SEO strategist and viral title copywriter. Based ONLY on the YouTube video description provided in the user input, generate 10 compelling, high-CTR YouTube titles.\n\nRequirements:\n\n>Generate exactly 10 different titles.\n>Keep each title concise, natural, and easy to understand.\n>Make titles curiosity-driven without using misleading clickbait.\n>Highlight the video's main benefit, problem, result, or unique angle.\n>Use relevant keywords naturally for YouTube SEO.\n>Match the actual topic and audience of the video.\n>Avoid fake claims, excessive emojis, ALL CAPS, and unnecessary punctuation.\n>Avoid repeating the same title structure.\n>Make the titles sound human-written and professional.\n>Prioritize titles that create curiosity and encourage clicks.\n>Do not invent information that is not present in the description.\n>Return ONLY the 10 titles, numbered 1\u201310. Do not add explanations, categories, or extra text.\n\nExample output:\n\n>Stop Wasting Time: Automate Your YouTube Channel with AI\n>Build an AI YouTube Automation System with n8n\n>How to Automate YouTube Content Creation Using AI\n>This AI Agent Can Automate Your YouTube Workflow\n>Automate Your YouTube Channel with n8n and AI",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3.1,
      "position": [
        1424,
        48
      ],
      "id": "25901f58-c62a-4a3c-b091-3e5278081ace",
      "name": "Generate 10 Titles",
      "onError": "continueErrorOutput",
      "notes": "If AI title generation fails, route the error to the error-handling branch. Convert the technical AI error into a simple human-readable reason, then update the corresponding Google Sheets row with Failed status and the error reason. Do not stop the entire workflow."
    },
    {
      "parameters": {
        "jsCode": "const output = String($json.output || '');\n\nif (!output.trim()) {\n  throw new Error('AI Agent output is empty');\n}\n\n// Convert literal \\n into real line breaks\nconst cleaned = output\n  .replace(/\\\\n/g, '\\n')\n  .trim();\n\n// Extract numbered titles\nconst titles = cleaned\n  .split(/\\n+/)\n  .map(line => line.trim())\n  .filter(line => /^\\d+\\.\\s*/.test(line))\n  .map(line => line.replace(/^\\d+\\.\\s*/, '').trim())\n  .filter(Boolean);\n\n// Make sure titles were found\nif (titles.length === 0) {\n  throw new Error('No numbered titles found in AI Agent output');\n}\n\n// Put all titles into ONE field\nconst videoTitles = titles\n  .map((title, index) => `${index + 1}. ${title}`)\n  .join('\\n');\n\nreturn [\n  {\n    json: {\n      videoTitles\n    }\n  }\n];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1824,
        -80
      ],
      "id": "3d2fdd08-f160-4220-82bd-b03dd99eff4d",
      "name": "Format Titles"
    },
    {
      "parameters": {
        "sendTo": "areelarshad123@gmail.com",
        "subject": "Today Auto Generated youtube Description and Titles",
        "emailType": "text",
        "message": "={{ $json['Video Link'] }}\n\nDescription:\n{{ $json['Video Description'] }}\n\nTitles:\n{{ $json['Video Titles'] }}",
        "options": {}
      },
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.2,
      "position": [
        2384,
        -64
      ],
      "id": "fa4e53b2-465b-4ba3-a19c-474260627d1c",
      "name": "Set Metadata Email",
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "url": "https://youtube-video-summarizer-gpt-ai.p.rapidapi.com/api/v1/get-transcript-v2",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "video_id",
              "value": "={{ $json.videoId }}"
            },
            {
              "name": "platform",
              "value": "youtube"
            }
          ]
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "x-rapidapi-host",
              "value": "youtube-video-summarizer-gpt-ai.p.rapidapi.com"
            },
            {
              "name": "x-rapidapi-key",
              "value": "faae2fa764mshb672507e903b130p1239cajsnad079cde293c"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {}
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        224,
        160
      ],
      "id": "97d64126-6af4-4543-96dd-10878fe7faf5",
      "name": "Fetch Youtube Transcript",
      "onError": "continueErrorOutput",
      "notes": "If transcript fetch fails, update Google Sheets with Failed status and error message."
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "3218fbb5-a46a-4de1-ab03-19254e755c94",
              "name": "data.transcript",
              "value": "={{ $json.data.transcripts }}",
              "type": "object"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        448,
        64
      ],
      "id": "3e18be2b-85ab-4886-9ad2-3002f369ec00",
      "name": "Extract Transcript Segments"
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "1EHw_-yTyXpJXm9yZJzPqywQSZe1S8n_H04WAweUY6Jg",
          "mode": "list",
          "cachedResultName": "youtube Transcript",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1EHw_-yTyXpJXm9yZJzPqywQSZe1S8n_H04WAweUY6Jg/edit?usp=drivesdk"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Sheet1",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1EHw_-yTyXpJXm9yZJzPqywQSZe1S8n_H04WAweUY6Jg/edit#gid=0"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Status": "Done",
            "Video Titles": "={{ $json.videoTitles }}",
            "Video Description": "={{ $('Format Description').item.json.description }}",
            "Video Link": "={{ $('Extract video URL').item.json['Video Link'] }}",
            "Error Detail": "No error"
          },
          "matchingColumns": [
            "Video Link"
          ],
          "schema": [
            {
              "id": "Video Link",
              "displayName": "Video Link",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "Status",
              "displayName": "Status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Video Description",
              "displayName": "Video Description",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Video Titles",
              "displayName": "Video Titles",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Error Detail",
              "displayName": "Error Detail",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "displayName": "row_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "readOnly": true,
              "removed": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        2128,
        224
      ],
      "id": "c300f681-f7f5-4ee4-9d55-f81d646cb94c",
      "name": "Update row in sheet1",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        -448,
        224
      ],
      "id": "328573ff-c2b6-4700-a068-80031405a408",
      "name": "Process video"
    },
    {
      "parameters": {
        "documentId": {
          "__rl": true,
          "value": "1EHw_-yTyXpJXm9yZJzPqywQSZe1S8n_H04WAweUY6Jg",
          "mode": "list",
          "cachedResultName": "youtube Transcript",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1EHw_-yTyXpJXm9yZJzPqywQSZe1S8n_H04WAweUY6Jg/edit?usp=drivesdk"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Sheet1",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1EHw_-yTyXpJXm9yZJzPqywQSZe1S8n_H04WAweUY6Jg/edit#gid=0"
        },
        "filtersUI": {
          "values": [
            {
              "lookupColumn": "Status",
              "lookupValue": "Next"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        -672,
        224
      ],
      "id": "6dc412ec-0463-4c74-b0a8-50e4bac41657",
      "name": "Get row(s) in sheet",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const error = $json;\n\nlet errorMessage =\n  error?.error?.message ||\n  error?.message ||\n  error?.errorMessage ||\n  \"Unknown error occurred\";\n\nlet simpleReason = \"The transcript could not be fetched.\";\n\nconst msg = String(errorMessage).toLowerCase();\n\nif (msg.includes(\"404\") || msg.includes(\"not found\")) {\n  simpleReason = \"The video or transcript was not found.\";\n} \nelse if (msg.includes(\"403\") || msg.includes(\"forbidden\")) {\n  simpleReason = \"Access to the video or transcript was denied.\";\n} \nelse if (msg.includes(\"401\") || msg.includes(\"unauthorized\")) {\n  simpleReason = \"The API authorization failed.\";\n} \nelse if (msg.includes(\"429\") || msg.includes(\"rate limit\")) {\n  simpleReason = \"Too many API requests. Please try again later.\";\n} \nelse if (msg.includes(\"timeout\") || msg.includes(\"timed out\")) {\n  simpleReason = \"The transcript service took too long to respond.\";\n} \nelse if (msg.includes(\"api\")) {\n  simpleReason = \"The transcript API failed to process the request.\";\n} \nelse if (msg.includes(\"transcript\")) {\n  simpleReason = \"A transcript could not be retrieved for this video.\";\n} \nelse if (msg.includes(\"invalid\") || msg.includes(\"url\")) {\n  simpleReason = \"The YouTube link appears to be invalid.\";\n}\n\nreturn [\n  {\n    json: {\n      status: \"Failed\",\n      errorReason: simpleReason,\n      originalError: errorMessage\n    }\n  }\n];;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        448,
        672
      ],
      "id": "0e06e793-1b0b-43ca-ac18-b0cbb0905aae",
      "name": "Handle Transcript Error"
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "1EHw_-yTyXpJXm9yZJzPqywQSZe1S8n_H04WAweUY6Jg",
          "mode": "list",
          "cachedResultName": "youtube Transcript",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1EHw_-yTyXpJXm9yZJzPqywQSZe1S8n_H04WAweUY6Jg/edit?usp=drivesdk"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Sheet1",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1EHw_-yTyXpJXm9yZJzPqywQSZe1S8n_H04WAweUY6Jg/edit#gid=0"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Video Link": "={{ $('Extract video URL').item.json['Video Link'] }}",
            "Status": "Error",
            "Video Description": "null",
            "Video Titles": "null",
            "Error Detail": "=Error Reason:  {{ $json.errorReason }}\n\nOrignal Error : {{ $json.originalError }}"
          },
          "matchingColumns": [
            "Video Link"
          ],
          "schema": [
            {
              "id": "Video Link",
              "displayName": "Video Link",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "Status",
              "displayName": "Status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Video Description",
              "displayName": "Video Description",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Video Titles",
              "displayName": "Video Titles",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Error Detail",
              "displayName": "Error Detail",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "displayName": "row_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "readOnly": true,
              "removed": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        656,
        672
      ],
      "id": "ff7dd9a1-b52a-4e58-91ba-772485a6e432",
      "name": "Log Transcript Error",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const error = $json;\n\nconst rawError =\n  error?.error?.message ||\n  error?.message ||\n  error?.errorMessage ||\n  error?.details ||\n  \"Unknown AI description generation error\";\n\nconst msg = String(rawError).toLowerCase();\n\nlet errorReason = \"AI could not generate the YouTube description.\";\n\nif (\n  msg.includes(\"429\") ||\n  msg.includes(\"rate limit\") ||\n  msg.includes(\"quota\") ||\n  msg.includes(\"too many requests\")\n) {\n  errorReason = \"AI request limit was reached. Try again later.\";\n}\nelse if (\n  msg.includes(\"timeout\") ||\n  msg.includes(\"timed out\")\n) {\n  errorReason = \"AI took too long to generate the description.\";\n}\nelse if (\n  msg.includes(\"503\") ||\n  msg.includes(\"service unavailable\")\n) {\n  errorReason = \"AI service is temporarily unavailable.\";\n}\nelse if (\n  msg.includes(\"401\") ||\n  msg.includes(\"unauthorized\") ||\n  msg.includes(\"api key\")\n) {\n  errorReason = \"AI API authentication failed. Check the API key.\";\n}\nelse if (\n  msg.includes(\"403\") ||\n  msg.includes(\"forbidden\")\n) {\n  errorReason = \"AI request was denied. Check API permissions or settings.\";\n}\nelse if (\n  msg.includes(\"400\") ||\n  msg.includes(\"invalid request\")\n) {\n  errorReason = \"The AI received an invalid request.\";\n}\nelse if (\n  msg.includes(\"model\") ||\n  msg.includes(\"not found\")\n) {\n  errorReason = \"The selected AI model is unavailable or not found.\";\n}\n\nreturn [\n  {\n    json: {\n      status: \"Failed\",\n      errorReason: errorReason,\n      originalError: String(rawError)\n    }\n  }\n];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1200,
        656
      ],
      "id": "2997b56e-bfb3-4275-bc49-68a7cc44b5bc",
      "name": "Handle Description Error"
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "1EHw_-yTyXpJXm9yZJzPqywQSZe1S8n_H04WAweUY6Jg",
          "mode": "list",
          "cachedResultName": "youtube Transcript",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1EHw_-yTyXpJXm9yZJzPqywQSZe1S8n_H04WAweUY6Jg/edit?usp=drivesdk"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Sheet1",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1EHw_-yTyXpJXm9yZJzPqywQSZe1S8n_H04WAweUY6Jg/edit#gid=0"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Video Link": "={{ $('Extract video URL').item.json['Video Link'] }}",
            "Status": "Error",
            "Video Description": "Null",
            "Video Titles": "Null",
            "Error Detail": "=Error Reason :  {{ $json.errorReason }}\n\nOrignal error : {{ $json.originalError }}"
          },
          "matchingColumns": [
            "Video Link"
          ],
          "schema": [
            {
              "id": "Video Link",
              "displayName": "Video Link",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "Status",
              "displayName": "Status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Video Description",
              "displayName": "Video Description",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Video Titles",
              "displayName": "Video Titles",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Error Detail",
              "displayName": "Error Detail",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "displayName": "row_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "readOnly": true,
              "removed": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        1392,
        656
      ],
      "id": "f43f12fb-b988-4bbc-aae5-ace048d4e3f5",
      "name": "Log Description Error",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const error = $json;\n\nconst rawError =\n  error?.error?.message ||\n  error?.message ||\n  error?.errorMessage ||\n  error?.details ||\n  \"Unknown AI title generation error\";\n\nconst msg = String(rawError).toLowerCase();\n\nlet errorReason = \"AI could not generate YouTube titles.\";\n\nif (\n  msg.includes(\"429\") ||\n  msg.includes(\"rate limit\") ||\n  msg.includes(\"quota\") ||\n  msg.includes(\"too many requests\")\n) {\n  errorReason = \"AI request limit was reached. Try again later.\";\n}\nelse if (\n  msg.includes(\"timeout\") ||\n  msg.includes(\"timed out\")\n) {\n  errorReason = \"AI took too long to generate the titles.\";\n}\nelse if (\n  msg.includes(\"503\") ||\n  msg.includes(\"service unavailable\")\n) {\n  errorReason = \"AI service is temporarily unavailable.\";\n}\nelse if (\n  msg.includes(\"401\") ||\n  msg.includes(\"unauthorized\") ||\n  msg.includes(\"api key\")\n) {\n  errorReason = \"AI API authentication failed. Check the API key.\";\n}\nelse if (\n  msg.includes(\"403\") ||\n  msg.includes(\"forbidden\")\n) {\n  errorReason = \"AI request was denied. Check API permissions or settings.\";\n}\nelse if (\n  msg.includes(\"400\") ||\n  msg.includes(\"invalid request\")\n) {\n  errorReason = \"The AI received an invalid title-generation request.\";\n}\nelse if (\n  msg.includes(\"model\") ||\n  msg.includes(\"not found\")\n) {\n  errorReason = \"The selected AI model is unavailable or not found.\";\n}\n\nreturn [\n  {\n    json: {\n      status: \"Failed\",\n      errorReason: errorReason,\n      originalError: String(rawError)\n    }\n  }\n];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1840,
        672
      ],
      "id": "ce78c3fe-2364-48bb-a49b-0f4d780dfefd",
      "name": "Handle Title Error"
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "1EHw_-yTyXpJXm9yZJzPqywQSZe1S8n_H04WAweUY6Jg",
          "mode": "list",
          "cachedResultName": "youtube Transcript",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1EHw_-yTyXpJXm9yZJzPqywQSZe1S8n_H04WAweUY6Jg/edit?usp=drivesdk"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Sheet1",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1EHw_-yTyXpJXm9yZJzPqywQSZe1S8n_H04WAweUY6Jg/edit#gid=0"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Video Link": "={{ $('Extract video URL').item.json['Video Link'] }}",
            "Status": "Error",
            "Video Description": "Null",
            "Video Titles": "Null",
            "Error Detail": "=Error Reason :  {{ $json.errorReason }}\n\nOrignal error : {{ $json.originalError }}"
          },
          "matchingColumns": [
            "Video Link"
          ],
          "schema": [
            {
              "id": "Video Link",
              "displayName": "Video Link",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "Status",
              "displayName": "Status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Video Description",
              "displayName": "Video Description",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Video Titles",
              "displayName": "Video Titles",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Error Detail",
              "displayName": "Error Detail",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "displayName": "row_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "readOnly": true,
              "removed": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        2048,
        672
      ],
      "id": "0c114cad-9ed4-4e43-9982-4c4ba5ea37a5",
      "name": "Log Title Error",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Get row(s) in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Combine Transcript": {
      "main": [
        [
          {
            "node": " LLM Generate Description",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": " LLM Generate Description",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Generate 10 Titles",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Extract video URL": {
      "main": [
        [
          {
            "node": "Extract video ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract video ID": {
      "main": [
        [
          {
            "node": "Fetch Youtube Transcript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    " LLM Generate Description": {
      "main": [
        [
          {
            "node": "Format Description",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle Description Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Description": {
      "main": [
        [
          {
            "node": "Generate 10 Titles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate 10 Titles": {
      "main": [
        [
          {
            "node": "Format Titles",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle Title Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Titles": {
      "main": [
        [
          {
            "node": "Update row in sheet1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Youtube Transcript": {
      "main": [
        [
          {
            "node": "Extract Transcript Segments",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle Transcript Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Transcript Segments": {
      "main": [
        [
          {
            "node": "Combine Transcript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update row in sheet1": {
      "main": [
        [
          {
            "node": "Set Metadata Email",
            "type": "main",
            "index": 0
          },
          {
            "node": "Process video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process video": {
      "main": [
        [],
        [
          {
            "node": "Extract video URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get row(s) in sheet": {
      "main": [
        [
          {
            "node": "Process video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Handle Transcript Error": {
      "main": [
        [
          {
            "node": "Log Transcript Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Handle Description Error": {
      "main": [
        [
          {
            "node": "Log Description Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Handle Title Error": {
      "main": [
        [
          {
            "node": "Log Title Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate",
    "availableInMCP": false
  },
  "versionId": "836f07c9-3d16-4810-83ac-db46586e3502",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodeGroups": [],
  "id": "7aJHCXKNmLkSDshV",
  "tags": []
}