Youtube_Automation
工作流概述
这是一个包含33个节点的复杂工作流,主要用于自动化处理各种任务。
工作流源代码
{
"id": "wLbJ7rE6vQzizCp2",
"meta": {
"instanceId": "5ce52989094be90be3b3bdd9ed9cee1d7ce1fcecaa598afaec4a50646d32e291",
"templateCredsSetupCompleted": true
},
"name": "Youtube_Automation",
"tags": [
{
"id": "5eZb3e5PJspoJjVN",
"name": "Privat",
"createdAt": "2025-02-22T09:31:58.972Z",
"updatedAt": "2025-02-22T09:31:58.972Z"
},
{
"id": "fSDcaaN3w5sV5e3S",
"name": "Templates",
"createdAt": "2025-02-23T15:20:47.262Z",
"updatedAt": "2025-02-23T15:20:47.262Z"
}
],
"nodes": [
{
"id": "2001b9ca-f76b-437e-90a9-16c0d17accef",
"name": "Fetch Latest Videos",
"type": "n8n-nodes-base.youTube",
"position": [
-60,
40
],
"parameters": {
"limit": 1,
"filters": {},
"options": {
"order": "date"
},
"resource": "video"
},
"credentials": {
"youTubeOAuth2Api": {
"id": "cpgVAMXp8iMLXwKW",
"name": "Private Pres"
}
},
"typeVersion": 1
},
{
"id": "e8857adf-63ec-4612-aa49-cd77130a6728",
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"position": [
160,
40
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "1a8cf640-caf4-4163-a658-400714702314",
"name": "YT Title",
"type": "@n8n/n8n-nodes-langchain.openAi",
"disabled": true,
"position": [
2220,
120
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4.1-nano",
"cachedResultName": "GPT-4.1-NANO"
},
"options": {},
"messages": {
"values": [
{
"role": "system",
"content": "Du bist ein professioneller Texter für SEO-optimierte YouTube-Titel."
},
{
"content": "=Schreib mir einen passenden SEO Youtube Titel für das Transkript folgendes Videotranskriptes. Gib mir nur den Titel sonst nichts. Maximal 100 Character also halte dich kurz.
{{ $('Adjust Transcript Format').item.json.transcript }}"
}
]
}
},
"credentials": {
"openAiApi": {
"id": "ftBgqCi1fD1fFEZq",
"name": "Midgard#1"
}
},
"typeVersion": 1.7
},
{
"id": "ec6e5d83-d8c8-417e-8df0-86634feef3e6",
"name": "Create Description",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
1920,
80
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4.1-nano",
"cachedResultName": "GPT-4.1-NANO"
},
"options": {},
"messages": {
"values": [
{
"role": "system",
"content": "Du bist ein professioneller Texteschreiber.
Du erhältst das Transkript eines wirtschaftsbezogenen Videos und erstellst eine ausführlichere aber auch nicht zu lange Zusammenfassung (mit Absätzen) darüber, worum es geht.
Schreibe eine ausführlichere Zusammenfassung (mit Absätzen) über den Inhalt des Podcasts.
Dein Output wird für die Youtube Video Beschreibung verwendet. Also starte mit sowas wie: \"In diesem Video...\" oder \"In dieser Folge...\".
Schreibe aus meiner Perspektive also Sachen wie \"meine Meinung\" oder \"meiner Ansicht nach\"... aus der Ich- Perspektive aber niemals sowas wie \"In dieser Folge lerne ich...\" oder so ähnlich, denn ich erkläre stets den Inhalt bzw. diskutiere darüber. DU SCHREIBST NIEMALS SOWAS WIE \"DER SPRECHER SAGT\"!!! Immer aus meiner Position heraus.
Wichtig: Verwende klare und dominante Aussagen, wie sie im Transkript formuliert sind. Vermeide neutrale oder unsichere Formulierungen wie \"es könnte\", \"ich vermute, dass\", \"möglicherweise\" oder ähnliche Phrasen. Die Aussagen sollen selbstbewusst und eindeutig sein, um die Inhalte des Podcasts kraftvoll zu vermitteln.
Füge einige wenige (2-4) Emojis an wo es sich anbietet.
Ende den Post mit 2-5 passenden Hashtags. Die Hashtags sollten grob sein also sowas wie #wirtschaft #geld #gold oder so ähnlich - je nachdem was passt.
"
},
{
"content": "=Hier ist das Transkript:
{{ $json.transcript }}"
}
]
}
},
"credentials": {
"openAiApi": {
"id": "ftBgqCi1fD1fFEZq",
"name": "Midgard#1"
}
},
"typeVersion": 1.7
},
{
"id": "f59d950b-4e29-4a41-8756-85ea7814b3d3",
"name": "When clicking ‘Test workflow’",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-2260,
300
],
"parameters": {},
"typeVersion": 1
},
{
"id": "27ef7d44-7cca-417f-8177-b5b896a79aa0",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
2660,
-20
],
"parameters": {
"color": 3,
"width": 220,
"content": "### 🎥Title is kept from the upload, alternatively you can just add the YT Title module in the mix
# 👇🏻
"
},
"typeVersion": 1
},
{
"id": "8d763312-35f0-4d53-a210-1e0e22a06323",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1920,
-140
],
"parameters": {
"color": 3,
"height": 200,
"content": "# Adjust the Prompts 👉🏻
# 👇🏻"
},
"typeVersion": 1
},
{
"id": "9e7f22d5-7776-4bc4-a274-963cb8c8810c",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-540,
-560
],
"parameters": {
"color": 5,
"width": 620,
"height": 420,
"content": "# Youtube Video Description/Tags/etc. Automation
👉🏻 **Repos**: [github.com/JimPresting](https://github.com/JimPresting) 🛠️
👉🏻 **YouTube**: [youtube.com/@StardawnAI](https://www.youtube.com/@StardawnAI) 🎥
Stay up to date for guides on Github repos and tutorials on YouTube! 🚀
**Note:** By default, this takes only the latest video and adjusts the values. If you upload multiple videos within a day or even at once within one hour, you need to set that value higher, but bear in mind that if you set it to a high number, it will process older, already published videos. Using the *Publish After* option can't be recommended as it might lead to errors with scheduled videos.
You can also detach the *Remove Duplicates* node from the ongoing nodes and set the limit of the *Get All Videos* node to *Return all*. This way, everything that has already been uploaded will not be returned in the future. To undo this, you can select *Clear Database* in the *Remove Duplicates* node.
"
},
"typeVersion": 1
},
{
"id": "4c5667cf-f8a9-45ab-876b-3a6b5730484c",
"name": "2.5FlashPrev",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
2220,
0
],
"parameters": {
"options": {},
"modelName": "models/gemini-2.5-flash-preview-04-17"
},
"credentials": {
"googlePalmApi": {
"id": "clmB8ZYJMHaHmnsu",
"name": "Stardawn#1"
}
},
"typeVersion": 1
},
{
"id": "7c73cc89-ea8e-42b3-a1c9-2dc493026216",
"name": "YT Tags",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
2220,
-120
],
"parameters": {
"text": "=Nun folgt das eigentliche Thema/Transkript. Gib mir die Youtube Tags dafür:
{{ $('Adjust Transcript Format').item.json.transcript }}",
"options": {
"systemMessage": "You will get the transcript of a Youtube video for which you should generate matching tags (YOU NEED TO separate it by comma).
Based on the topic/transcript of the video generate YouTube tags. These tags should be very general about the topics. Give multiple matching YouTube Tags that improve SEO for the video.
Example:
if the video is about why gold is a good investment you will for example not use gold investments as a tag but rather just gold
The tags (if appropriate) should be in German as the channel content is in German.
Return just the tags one word by one separated via Comma.
Dieses Video handelt vom zukünftigen Goldpreis und davon, wie er die Renditen von performanten Vermögenswerten wie Aktien und Anleihen in ihrer angepassten Rendite beeinflusst.
Erwartetet output:
Goldpreis, zukünftiger Goldpreis, Goldinvestitionen, Vermögensrenditen, Aktien und Anleihen, Investitionsrenditen, angepasste Rendite, Goldmarkt, Finanzmärkte, Goldpreisprognose, Wirtschaftstrends, Investieren in Gold, Aktienmarktanalyse, Anleihenmarkt, Anlagestrategien, Inflation und Gold, Gold vs. Aktien, Finanzanalyse, Edelmetalle, Portfoliomanagement, Marktausblick, Investmenttipps
"
},
"promptType": "define"
},
"typeVersion": 1.9
},
{
"id": "e8782ac7-ca31-4a5f-a9f1-62548f56407d",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2340,
-140
],
"parameters": {
"color": 4,
"width": 2000,
"height": 660,
"content": "# 📅Scheduling Logic⏰
"
},
"typeVersion": 1
},
{
"id": "33d289eb-c989-4c8d-b387-405f31ba11d6",
"name": "3s",
"type": "n8n-nodes-base.wait",
"position": [
2920,
140
],
"webhookId": "1e75fe1f-e553-4530-a8bc-5e64208a1184",
"parameters": {
"amount": 3
},
"typeVersion": 1.1
},
{
"id": "19337563-a349-485d-a064-32f58c8fde90",
"name": "gettitle",
"type": "n8n-nodes-base.youTube",
"position": [
-780,
200
],
"parameters": {
"options": {},
"videoId": "={{ $json.videoId }}",
"resource": "video",
"operation": "get"
},
"credentials": {
"youTubeOAuth2Api": {
"id": "cpgVAMXp8iMLXwKW",
"name": "Private Pres"
}
},
"typeVersion": 1
},
{
"id": "da93ff18-8d19-45ab-b268-dbbebcb86719",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1040,
-140
],
"parameters": {
"color": 5,
"width": 180,
"content": "## Code only returns the videos that are not listed"
},
"typeVersion": 1
},
{
"id": "71e9606c-4b6e-4b49-b3ec-bd9bd261f7a9",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-600,
-80
],
"parameters": {
"color": 3,
"width": 220,
"height": 260,
"content": "## Video needs to be set to private TOGETHER with the PublishAt parameter in order for it to work."
},
"typeVersion": 1
},
{
"id": "c5a240aa-b705-4219-b293-da4ae0168350",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
1320,
-140
],
"parameters": {
"color": 3,
"width": 280,
"height": 240,
"content": "### Video needs to be Unlisted or Published in order for the scraper to be able to get the transcript
### ADJUST YOUR APIFY API TOKEN HERE
# 👇🏻"
},
"typeVersion": 1
},
{
"id": "5fb12ed7-8992-424d-86e0-7c8cd0f0b9d3",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-80,
-140
],
"parameters": {
"color": 4,
"width": 3200,
"height": 660,
"content": "# Generate Description, Tags, etc. 🖌️📝 #️⃣"
},
"typeVersion": 1
},
{
"id": "33b865ef-ec2e-4349-bbba-d76d41345fe3",
"name": "Set Publish Date",
"type": "n8n-nodes-base.youTube",
"position": [
-600,
280
],
"parameters": {
"title": "={{ $json.snippet.title }}",
"videoId": "={{ $json.id }}",
"resource": "video",
"operation": "update",
"categoryId": "25",
"regionCode": "DE",
"updateFields": {
"publishAt": "={{ $('Loop over All Videos not Published').item.json.publishAt }}",
"privacyStatus": "private"
}
},
"credentials": {
"youTubeOAuth2Api": {
"id": "cpgVAMXp8iMLXwKW",
"name": "Private Pres"
}
},
"typeVersion": 1
},
{
"id": "9a228886-c91a-44f7-b894-e23095166efc",
"name": "Every Day",
"type": "n8n-nodes-base.scheduleTrigger",
"disabled": true,
"position": [
-2260,
60
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 14,
"triggerAtMinute": 22
}
]
}
},
"typeVersion": 1.2
},
{
"id": "c0277051-f146-43f7-a2cd-36739d933209",
"name": "Get Videos to reschedule",
"type": "n8n-nodes-base.youTube",
"position": [
-1880,
40
],
"parameters": {
"limit": 2,
"filters": {},
"options": {
"order": "date"
},
"resource": "video"
},
"credentials": {
"youTubeOAuth2Api": {
"id": "cpgVAMXp8iMLXwKW",
"name": "Private Pres"
}
},
"typeVersion": 1
},
{
"id": "5cf3813b-931b-4c0a-84fe-4edd3d55a99a",
"name": "Get video Ids seperated",
"type": "n8n-nodes-base.code",
"position": [
-1660,
40
],
"parameters": {
"jsCode": "// Extract video IDs from YouTube search results
// This function processes all input items and creates separate items for each videoId
// Initialize empty array for our result items
const resultItems = [];
// Process each input item
for (const item of items) {
// Check if the item has a valid structure
if (item.json && item.json.id && item.json.id.videoId) {
// Create a new item for each videoId
resultItems.push({
json: {
videoId: item.json.id.videoId
}
});
}
}
// Return each videoId as a separate item that can be processed individually
return resultItems;"
},
"typeVersion": 2
},
{
"id": "8131b388-b842-4c46-b82b-e53283d938ed",
"name": "Loop over Video IDs",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-1440,
40
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "665cb406-f6b9-4ba4-82fa-daa1141eb0a3",
"name": "Get Video Data",
"type": "n8n-nodes-base.youTube",
"position": [
-1220,
60
],
"parameters": {
"options": {},
"videoId": "={{ $json.videoId }}",
"resource": "video",
"operation": "get"
},
"credentials": {
"youTubeOAuth2Api": {
"id": "cpgVAMXp8iMLXwKW",
"name": "Private Pres"
}
},
"typeVersion": 1
},
{
"id": "3d366fb3-f579-46f0-9254-8d4c1612038e",
"name": "Return Private Videos",
"type": "n8n-nodes-base.code",
"position": [
-1220,
-120
],
"parameters": {
"jsCode": "// Utility function to get next Friday at 17:00 UTC in YouTube ISO 8601 format (YYYY-MM-DDTHH:mm:ssZ)
function getNextFridayUTC(startDate, weekOffset = 0) {
const date = new Date(startDate); // Work with a copy
const currentUTCDay = date.getUTCDay(); // 0 for Sunday, ..., 5 for Friday
const daysUntilFriday = (5 - currentUTCDay + 7) % 7; // Calculate days to next Friday
date.setUTCDate(date.getUTCDate() + daysUntilFriday + (weekOffset * 7));
date.setUTCHours(17, 0, 0, 0); // Set time to 17:00:00.000 UTC
// toISOString() returns \"YYYY-MM-DDTHH:mm:ss.sssZ\"
// We split at '.' to remove milliseconds and add 'Z' back for \"YYYY-MM-DDTHH:mm:ssZ\"
return date.toISOString().split('.')[0] + \"Z\";
}
// INPUT `items` is an array from n8n.
// Each item.json is expected to be a YouTube video object from a previous node.
const videosToSchedule = items.filter(item =>
item.json &&
item.json.status &&
(item.json.status.privacyStatus === \"unlisted\" || item.json.status.privacyStatus === \"private\")
// Adjust this filter if you only want to process \"unlisted\" or only \"private\" videos
);
if (videosToSchedule.length === 0) {
// console.log(\"No videos found matching the filter criteria.\");
return []; // Return empty array if no videos to schedule
}
// Sort videos by their original published/uploaded date (snippet.publishedAt), earliest first.
videosToSchedule.sort((a, b) => {
const dateA = new Date(a.json?.snippet?.publishedAt || '1970-01-01T00:00:00Z');
const dateB = new Date(b.json?.snippet?.publishedAt || '1970-01-01T00:00:00Z');
return dateA - dateB;
});
const now = new Date(); // Current date to calculate future Fridays
// Map the filtered and sorted videos to the desired output structure for the YouTube update node.
const scheduledItems = videosToSchedule.map((item, index) => {
const videoData = item.json; // The actual video data object
const scheduleDate = getNextFridayUTC(now, index); // Calculate the publishAt date
return {
json: { // This is the structure the next n8n YouTube node will receive
videoId: videoData.id, // ID of the video to update
publishAt: scheduleDate, // The calculated schedule time: YYYY-MM-DDTHH:mm:ssZ
title: videoData.snippet?.title || \"Untitled Video\", // Keep original title or use a default
// --- CRITICAL PARAMETERS FOR THE YOUTUBE API ---
privacy: \"private\", // **MUST BE 'private' FOR 'publishAt' TO WORK!**
// The API requires the video to be set to private when scheduling.
// **VERY LIKELY REQUIRED: selfDeclaredMadeForKids**
// You MUST tell YouTube if the video is made for kids or not.
// Get it from existing data if available, otherwise set a default.
selfDeclaredMadeForKids: videoData.status?.selfDeclaredMadeForKids === true ? true : false,
// **POSSIBLY REQUIRED: categoryId (if updating snippet like title)**
// categoryId: videoData.snippet?.categoryId || \"YOUR_DEFAULT_CATEGORY_ID\",
// e.g., \"10\" for Music, \"22\" for People & Blogs.
// Check YouTube API docs for category IDs.
// (Optional) You can include other fields like description if you want to update them
// description: videoData.snippet?.description || \"\"
}
};
});
return scheduledItems; // Return the array of video objects to be processed"
},
"typeVersion": 2,
"alwaysOutputData": true
},
{
"id": "bb3e90ae-ff3f-4c22-b920-d1a99a1f99e8",
"name": "4s",
"type": "n8n-nodes-base.wait",
"position": [
-260,
240
],
"webhookId": "7d5c70f8-a592-4634-8c5a-0fbd0cebf6a4",
"parameters": {
"amount": 4
},
"typeVersion": 1.1
},
{
"id": "f67c7668-71eb-42e6-b385-f66f9e5e80eb",
"name": "Loop over All Videos not Published",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-1020,
60
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "f98b1399-7970-4585-8f2a-be897562fa40",
"name": "get video id",
"type": "n8n-nodes-base.set",
"position": [
380,
80
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "c2e2eecd-ca73-40c9-a364-4713030ab451",
"name": "id.videoId",
"type": "string",
"value": "={{ $json.id.videoId }}"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "6b907512-945b-4c1e-8a97-b14409ddfcaa",
"name": "Remove Duplicates from previous Runs",
"type": "n8n-nodes-base.removeDuplicates",
"position": [
600,
80
],
"parameters": {
"options": {},
"operation": "removeItemsSeenInPreviousExecutions",
"dedupeValue": "={{ $json.id.videoId }}"
},
"typeVersion": 2,
"alwaysOutputData": false
},
{
"id": "d6c7152e-e508-43c3-8748-ba12652ac117",
"name": "new video?",
"type": "n8n-nodes-base.if",
"position": [
820,
80
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "adfea7c7-ed64-4e1e-a9c3-dc5e33aa1147",
"operator": {
"type": "array",
"operation": "notExists",
"singleValue": true
},
"leftValue": "={{$('Remove Duplicates from previous Runs').all() }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "d1c31718-4a26-4108-a618-f67cfb87053c",
"name": "getLatestVideoID",
"type": "n8n-nodes-base.youTube",
"position": [
1000,
160
],
"parameters": {
"options": {},
"videoId": "={{ $('get video id').item.json.id.videoId }}",
"resource": "video",
"operation": "get"
},
"credentials": {
"youTubeOAuth2Api": {
"id": "cpgVAMXp8iMLXwKW",
"name": "Private Pres"
}
},
"typeVersion": 1,
"alwaysOutputData": true
},
{
"id": "66814975-e4a5-4c23-9bf2-c8d30d96c122",
"name": "Get Transcript",
"type": "n8n-nodes-base.httpRequest",
"position": [
1320,
120
],
"parameters": {
"url": "=https://api.apify.com/v2/acts/pintostudio~youtube-transcript-scraper/run-sync-get-dataset-items",
"method": "POST",
"options": {},
"jsonBody": "={
\"videoUrl\": \"https://www.youtube.com/watch?v={{ $json.id }}\"
}",
"sendBody": true,
"sendQuery": true,
"specifyBody": "json",
"queryParameters": {
"parameters": [
{
"name": "token",
"value": "YOURAPITOKEN"
}
]
}
},
"typeVersion": 4.2,
"alwaysOutputData": false
},
{
"id": "fd355571-8c74-4d31-972e-13f737aaec05",
"name": "Adjust Transcript Format",
"type": "n8n-nodes-base.code",
"position": [
1600,
120
],
"parameters": {
"jsCode": "const items = $input.all();
const transcriptStrings = items.flatMap(item => {
const dataArray = item.json.data;
if (!dataArray || !Array.isArray(dataArray)) {
return [];
}
const segmentTexts = dataArray.map(segment => {
if (segment && typeof segment.text === 'string') {
return segment.text;
} else {
return '';
}
});
return segmentTexts;
});
const transcript = transcriptStrings.join(' ');
return [
{
json: {
transcript: transcript,
},
},
];"
},
"typeVersion": 2
},
{
"id": "7b69339f-aa12-430e-ba21-b85a0db596b5",
"name": "Update Video's Metadata",
"type": "n8n-nodes-base.youTube",
"position": [
2660,
140
],
"parameters": {
"title": "={{ $('Fetch Latest Videos').first().json.snippet.title }}",
"videoId": "={{ $('getLatestVideoID').first().json.id }}",
"resource": "video",
"operation": "update",
"categoryId": "25",
"regionCode": "DE",
"updateFields": {
"tags": "={{ $('YT Tags').first().json.message.content }}",
"description": "={{ $('Create Description').first().json.message.content }}
Diese textbasierte Zusammenfassung des Videos wurde automatisch mit dem KI-Modell gpt-4.1-nano erstellt.]
"
}
},
"credentials": {
"youTubeOAuth2Api": {
"id": "cpgVAMXp8iMLXwKW",
"name": "Private Pres"
}
},
"typeVersion": 1
}
],
"active": true,
"pinData": {},
"settings": {
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": "RhPW7iLQQJGJZqQQ",
"executionOrder": "v1"
},
"versionId": "268a8dc5-0408-458c-9dff-d7c91b223b76",
"connections": {
"3s": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"4s": {
"main": [
[
{
"node": "Fetch Latest Videos",
"type": "main",
"index": 0
}
]
]
},
"YT Tags": {
"main": [
[
{
"node": "Update Video's Metadata",
"type": "main",
"index": 0
}
]
]
},
"YT Title": {
"main": [
[]
]
},
"gettitle": {
"main": [
[
{
"node": "Set Publish Date",
"type": "main",
"index": 0
}
]
]
},
"Every Day": {
"main": [
[
{
"node": "Get Videos to reschedule",
"type": "main",
"index": 0
}
]
]
},
"new video?": {
"main": [
[],
[
{
"node": "getLatestVideoID",
"type": "main",
"index": 0
}
]
]
},
"2.5FlashPrev": {
"ai_languageModel": [
[
{
"node": "YT Tags",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"get video id": {
"main": [
[
{
"node": "Remove Duplicates from previous Runs",
"type": "main",
"index": 0
}
]
]
},
"Get Transcript": {
"main": [
[
{
"node": "Adjust Transcript Format",
"type": "main",
"index": 0
}
]
]
},
"Get Video Data": {
"main": [
[
{
"node": "Loop over Video IDs",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[],
[
{
"node": "get video id",
"type": "main",
"index": 0
}
]
]
},
"Set Publish Date": {
"main": [
[
{
"node": "Loop over All Videos not Published",
"type": "main",
"index": 0
}
]
]
},
"getLatestVideoID": {
"main": [
[
{
"node": "Get Transcript",
"type": "main",
"index": 0
}
]
]
},
"Create Description": {
"main": [
[
{
"node": "YT Tags",
"type": "main",
"index": 0
},
{
"node": "YT Title",
"type": "main",
"index": 0
}
]
]
},
"Fetch Latest Videos": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Loop over Video IDs": {
"main": [
[
{
"node": "Return Private Videos",
"type": "main",
"index": 0
}
],
[
{
"node": "Get Video Data",
"type": "main",
"index": 0
}
]
]
},
"Return Private Videos": {
"main": [
[
{
"node": "Loop over All Videos not Published",
"type": "main",
"index": 0
}
]
]
},
"Get video Ids seperated": {
"main": [
[
{
"node": "Loop over Video IDs",
"type": "main",
"index": 0
}
]
]
},
"Update Video's Metadata": {
"main": [
[
{
"node": "3s",
"type": "main",
"index": 0
}
]
]
},
"Adjust Transcript Format": {
"main": [
[
{
"node": "Create Description",
"type": "main",
"index": 0
}
]
]
},
"Get Videos to reschedule": {
"main": [
[
{
"node": "Get video Ids seperated",
"type": "main",
"index": 0
}
]
]
},
"When clicking ‘Test workflow’": {
"main": [
[
{
"node": "Get Videos to reschedule",
"type": "main",
"index": 0
}
]
]
},
"Loop over All Videos not Published": {
"main": [
[
{
"node": "4s",
"type": "main",
"index": 0
}
],
[
{
"node": "gettitle",
"type": "main",
"index": 0
}
]
]
},
"Remove Duplicates from previous Runs": {
"main": [
[
{
"node": "new video?",
"type": "main",
"index": 0
}
]
]
}
}
}
功能特点
- 自动检测新邮件
- AI智能内容分析
- 自定义分类规则
- 批量处理能力
- 详细的处理日志
技术分析
节点类型及作用
- Youtube
- Splitinbatches
- @N8N/N8N Nodes Langchain.Openai
- Manualtrigger
- Stickynote
复杂度评估
配置难度:
维护难度:
扩展性:
实施指南
前置条件
- 有效的Gmail账户
- n8n平台访问权限
- Google API凭证
- AI分类服务订阅
配置步骤
- 在n8n中导入工作流JSON文件
- 配置Gmail节点的认证信息
- 设置AI分类器的API密钥
- 自定义分类规则和标签映射
- 测试工作流执行
- 配置定时触发器(可选)
关键参数
| 参数名称 | 默认值 | 说明 |
|---|---|---|
| maxEmails | 50 | 单次处理的最大邮件数量 |
| confidenceThreshold | 0.8 | 分类置信度阈值 |
| autoLabel | true | 是否自动添加标签 |
最佳实践
优化建议
- 定期更新AI分类模型以提高准确性
- 根据邮件量调整处理批次大小
- 设置合理的分类置信度阈值
- 定期清理过期的分类规则
安全注意事项
- 妥善保管API密钥和认证信息
- 限制工作流的访问权限
- 定期审查处理日志
- 启用双因素认证保护Gmail账户
性能优化
- 使用增量处理减少重复工作
- 缓存频繁访问的数据
- 并行处理多个邮件分类任务
- 监控系统资源使用情况
故障排除
常见问题
邮件未被正确分类
检查AI分类器的置信度阈值设置,适当降低阈值或更新训练数据。
Gmail认证失败
确认Google API凭证有效且具有正确的权限范围,重新进行OAuth授权。
调试技巧
- 启用详细日志记录查看每个步骤的执行情况
- 使用测试邮件验证分类逻辑
- 检查网络连接和API服务状态
- 逐步执行工作流定位问题节点
错误处理
工作流包含以下错误处理机制:
- 网络超时自动重试(最多3次)
- API错误记录和告警
- 处理失败邮件的隔离机制
- 异常情况下的回滚操作