每日MLB投手vs击球手对阵分析(Google Sheets + Telegram)
中级
这是一个Miscellaneous, Multimodal AI领域的自动化工作流,包含 14 个节点。主要使用 Code, Telegram, HttpRequest, GoogleSheets, ScheduleTrigger 等节点。 使用Google Sheets和Telegram的每日MLB投手vs击球手对阵分析
前置要求
- •Telegram Bot Token
- •可能需要目标 API 的认证凭证
- •Google Sheets API 凭证
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"meta": {
"instanceId": "4b9ebdcb82324c7ebd0d3194b3afce46ddeac81826241b95da802461b66d7743"
},
"nodes": [
{
"id": "9a8548ad-12f1-41a7-9226-c8d06806b7b2",
"name": "3. 提取所有玩家 ID",
"type": "n8n-nodes-base.code",
"notes": "who will be playing today.",
"position": [
32,
-128
],
"parameters": {
"jsCode": "const allPlayerIds = new Set();\nconst allGames = items[0].json.dates[0]?.games || [];\n\nif (allGames.length === 0) {\n return [];\n}\n\n// Loop through all games to find every player\nfor (const game of allGames) {\n if (game.teams?.home?.probablePitcher?.id) {\n allPlayerIds.add(game.teams.home.probablePitcher.id);\n }\n if (game.teams?.away?.probablePitcher?.id) {\n allPlayerIds.add(game.teams.away.probablePitcher.id);\n }\n if (game.lineups && Array.isArray(game.lineups.homePlayers)) {\n for (const player of game.lineups.homePlayers) {\n if (player.id) allPlayerIds.add(player.id);\n }\n }\n if (game.lineups && Array.isArray(game.lineups.awayPlayers)) {\n for (const player of game.lineups.awayPlayers) {\n if (player.id) allPlayerIds.add(player.id);\n }\n }\n}\n\nif (allPlayerIds.size === 0) {\n return [];\n}\n\n// We pass the original game data THROUGH this node by adding it to the output\nconst output = items[0].json;\noutput.playerIdsString = Array.from(allPlayerIds).join(',');\nreturn [{ json: output }];"
},
"notesInFlow": true,
"typeVersion": 2
},
{
"id": "a0e5e8f0-e2fe-415e-92f4-cb4e29a6fd72",
"name": "4. 获取批量玩家统计数据",
"type": "n8n-nodes-base.httpRequest",
"position": [
256,
-128
],
"parameters": {
"url": "https://statsapi.mlb.com/api/v1/people",
"options": {},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "personIds",
"value": "={{$json.playerIdsString}}"
},
{
"name": "hydrate",
"value": "stats(group=[pitching,hitting,fielding],type=[season])"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "ff23a51f-3dc8-4b85-97b0-611e0bb6a304",
"name": "2. 获取每日比赛",
"type": "n8n-nodes-base.httpRequest",
"position": [
-176,
-128
],
"parameters": {
"url": "https://statsapi.mlb.com/api/v1/schedule",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "sportId",
"value": "1"
},
{
"name": "date",
"value": "={{ $now.toFormat('yyyy-MM-dd') }}"
},
{
"name": "hydrate",
"value": "probablePitcher,lineups"
}
]
}
},
"typeVersion": 4.1
},
{
"id": "32ccdb2c-0b9d-4af4-9590-c58b9902c31c",
"name": "5. 创建最终对阵行",
"type": "n8n-nodes-base.code",
"notes": "game schedule data and merges it with the detailed player stats",
"position": [
496,
-128
],
"parameters": {
"jsCode": "const allMatchupRows = [];\n\n// Get player stats from the direct input of this node\nconst playerStatsData = items[0].json;\n\n// Get the original game data by looking back at the previous node\nconst scheduleNode = $('3. Extract All Player IDs').first();\nconst originalScheduleData = scheduleNode.json;\nconst games = originalScheduleData.dates[0]?.games || [];\n\nconst playersWithStats = playerStatsData.people || [];\n\nif (games.length === 0 || playersWithStats.length === 0) {\n return [];\n}\n\nconst statsMap = new Map(playersWithStats.map(p => [p.id, p]));\n\nfor (const game of games) {\n\n const gameStartTime = game.gameDate || 'N/A';\n\n // --- Home Pitcher vs Away Batters ---\n const homePitcherId = game.teams?.home?.probablePitcher?.id;\n const awayLineup = game.lineups?.awayPlayers;\n\n if (homePitcherId && Array.isArray(awayLineup)) {\n const pitcherData = statsMap.get(homePitcherId);\n if (pitcherData) {\n for (const batter of awayLineup) {\n const batterData = statsMap.get(batter.id);\n if (batterData) {\n const pitcherStats = pitcherData.stats?.find(s => s.group?.displayName === 'pitching')?.splits[0]?.stat || {};\n const batterStats = batterData.stats?.find(s => s.group?.displayName === 'hitting')?.splits[0]?.stat || {};\n allMatchupRows.push({\n gameStartTime: gameStartTime,\n gameDate: game.officialDate || 'N/A',\n pitcherName: pitcherData.fullName || 'N/A',\n pitcherTeam: game.teams?.home?.team?.name || 'N/A',\n pitcherThrows: pitcherData.pitchHand?.description || 'N/A',\n pitcherERA: pitcherStats.era,\n pitcherSO: pitcherStats.strikeOuts,\n opponent: game.teams?.away?.team?.name || 'N/A',\n batterName: batterData.fullName || 'N/A',\n batterPosition: batter.primaryPosition?.abbreviation || 'N/A',\n batterBats: batterData.batSide?.description || 'N/A',\n batterAVG: batterStats.avg,\n batterOPS: batterStats.ops,\n batterHR: batterStats.homeRuns,\n batterHits: batterStats.hits,\n batterRBI: batterStats.rbi,\n pitcherId: pitcherData.id, // ADDED: Pitcher ID\n batterId: batterData.id, // ADDED: Batter ID\n });\n }\n }\n }\n }\n\n // --- Away Pitcher vs Home Batters ---\n const awayPitcherId = game.teams?.away?.probablePitcher?.id;\n const homeLineup = game.lineups?.homePlayers;\n\n if (awayPitcherId && Array.isArray(homeLineup)) {\n const pitcherData = statsMap.get(awayPitcherId);\n if (pitcherData) {\n for (const batter of homeLineup) {\n const batterData = statsMap.get(batter.id);\n if (batterData) {\n const pitcherStats = pitcherData.stats?.find(s => s.group?.displayName === 'pitching')?.splits[0]?.stat || {};\n const batterStats = batterData.stats?.find(s => s.group?.displayName === 'hitting')?.splits[0]?.stat || {};\n allMatchupRows.push({\n gameStartTime: gameStartTime,\n gameDate: game.officialDate || 'N/A',\n pitcherName: pitcherData.fullName || 'N/A',\n pitcherTeam: game.teams?.away?.team?.name || 'N/A',\n pitcherThrows: pitcherData.pitchHand?.description || 'N/A',\n pitcherERA: pitcherStats.era,\n pitcherSO: pitcherStats.strikeOuts,\n opponent: game.teams?.home?.team?.name || 'N/A',\n batterName: batterData.fullName || 'N/A',\n batterPosition: batter.primaryPosition?.abbreviation || 'N/A',\n batterBats: batterData.batSide?.description || 'N/A',\n batterAVG: batterStats.avg,\n batterOPS: batterStats.ops,\n batterHR: batterStats.homeRuns,\n batterHits: batterStats.hits,\n batterRBI: batterStats.rbi,\n pitcherId: pitcherData.id, // ADDED: Pitcher ID\n batterId: batterData.id, // ADDED: Batter ID\n });\n }\n }\n }\n }\n}\n\nreturn allMatchupRows.map(row => ({ json: row }));"
},
"notesInFlow": true,
"typeVersion": 2,
"alwaysOutputData": true
},
{
"id": "73bac962-fa64-45dc-86bd-671a17488992",
"name": "6. 筛选顶级对阵",
"type": "n8n-nodes-base.code",
"notes": "Pandas to filter and sort before Sheets",
"position": [
736,
-128
],
"parameters": {
"jsCode": "// Convert to Eastern Time using proper timezone handling\nfunction convertToEasternTime(isoString) {\n\tconst date = new Date(isoString);\n\treturn date.toLocaleTimeString('en-US', {\n\t\thour: '2-digit',\n\t\tminute: '2-digit',\n\t\thour12: true,\n\t\ttimeZone: 'America/New_York'\n\t});\n}\n\nconst HEADER_ORDER = [\n\t\"gameDate\",\n\t\"gameStartTime\",\n\t\"pitcherId\",\n\t\"pitcherName\",\n\t\"pitcherTeam\",\n\t\"pitcherSO\",\n\t\"pitcherERA\",\n\t\"pitcherThrows\",\n\t\"batterBats\",\n\t\"opponent\",\n\t\"batterName\",\n\t\"batterAVG\",\n\t\"batterHR\",\n\t\"batterHits\",\n\t\"batterOPS\",\n\t\"batterRBI\",\n\t\"batterId\",\n\t\"batterPosition\"\n];\n\nconst allMatchups = items.map(item => item.json);\n\n// Filter valid rows\nconst valid = allMatchups.filter(m => {\n\tconst era = parseFloat(m.pitcherERA);\n\tconst ops = parseFloat(m.batterOPS);\n\treturn !isNaN(era) && era > 3.33 && !isNaN(ops) && m.gameStartTime;\n});\n\n// Parse and add helper fields\nvalid.forEach(m => {\n\tm.era = parseFloat(m.pitcherERA);\n\tm.ops = parseFloat(m.batterOPS);\n\tm.gameStartObj = new Date(m.gameStartTime);\n});\n\n// Step 1: Get top 9 unique pitchers with highest ERA\nconst seenPitchers = new Set();\nconst topPitchers = [];\n\nvalid\n\t.sort((a, b) => b.era - a.era)\n\t.forEach(m => {\n\t\tif (!seenPitchers.has(m.pitcherName)) {\n\t\t\tseenPitchers.add(m.pitcherName);\n\t\t\ttopPitchers.push(m.pitcherName);\n\t\t}\n\t});\n\nconst top9 = topPitchers.slice(0, 9);\n\n// Step 2: For each of these pitchers, get top 3 batters by OPS\nconst final = [];\n\ntop9.forEach(pitcherName => {\n\tconst matchups = valid.filter(m => m.pitcherName === pitcherName);\n\tconst seenBatters = new Set();\n\tconst topBatters = [];\n\n\tmatchups\n\t\t.sort((a, b) => b.ops - a.ops)\n\t\t.forEach(m => {\n\t\t\tif (!seenBatters.has(m.batterId)) {\n\t\t\t\tseenBatters.add(m.batterId);\n\t\t\t\ttopBatters.push(m);\n\t\t\t}\n\t\t});\n\n\tfinal.push(...topBatters.slice(0, 3));\n});\n\n// Final sort by game start time\nfinal.sort((a, b) => a.gameStartObj - b.gameStartObj);\n\n// Format time and construct output with locked header order\nconst output = final.map(m => {\n\tm.gameStartTime = convertToEasternTime(m.gameStartObj.toISOString());\n\tconst obj = {};\n\tHEADER_ORDER.forEach(key => obj[key] = m[key] ?? '');\n\treturn { json: obj };\n});\n\nreturn output;\n"
},
"notesInFlow": true,
"typeVersion": 2,
"alwaysOutputData": true
},
{
"id": "7d9f19aa-a8a6-4f50-8462-0cad13de6e9c",
"name": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
-480,
-368
],
"parameters": {
"color": 4,
"width": 2316,
"height": 500,
"content": "安打数"
},
"typeVersion": 1
},
{
"id": "38b3c276-1d1e-4ea5-8427-ddb9f6591bbe",
"name": "列顺序",
"type": "n8n-nodes-base.code",
"position": [
944,
-128
],
"parameters": {
"jsCode": "const orderedKeys = [\n \"gameDate\",\n \"gameStartTime\",\n \"pitcherId\",\n \"pitcherName\",\n \"pitcherTeam\",\n \"pitcherSO\",\n \"pitcherERA\",\n \"pitcherThrows\",\n \"batterBats\",\n \"opponent\",\n \"batterName\",\n \"batterAVG\",\n \"batterHR\",\n \"batterHits\",\n \"batterOPS\",\n \"batterRBI\",\n \"batterId\",\n \"batterPosition\"\n];\n\n// fields that should explicitly be numbers\nconst numericKeys = [\n \"pitcherId\",\n \"pitcherSO\",\n \"pitcherERA\",\n \"batterAVG\",\n \"batterHR\",\n \"batterHits\",\n \"batterOPS\",\n \"batterRBI\",\n \"batterId\"\n];\n\n// 🔷 Helper: format to hh:mm AM/PM ET\nfunction toEasternTimeHHMM(value) {\n if (typeof value === 'string' && /^\\d{1,2}:\\d{2}/.test(value)) {\n return value.replace(/:00$/, ''); // clean up trailing :00 if it’s there\n }\n try {\n const utcDate = new Date(value);\n if (isNaN(utcDate.getTime())) return value;\n const options = {\n timeZone: 'America/New_York',\n hour: '2-digit',\n minute: '2-digit',\n hour12: true\n };\n return new Intl.DateTimeFormat('en-US', options).format(utcDate);\n } catch {\n return value;\n }\n}\n\n// Build new list\nconst enriched = items.map(item => {\n const json = { ...item.json };\n\n if (json.gameStartTime) {\n json.gameStartTime = toEasternTimeHHMM(json.gameStartTime);\n }\n\n const output = {};\n for (const key of orderedKeys) {\n let val = json[key] ?? \"\";\n if (numericKeys.includes(key) && val !== \"\") {\n val = Number(val);\n\n // Round batterAVG and batterOPS to .000\n if (key === \"batterAVG\" || key === \"batterOPS\") {\n val = Number(val.toFixed(3));\n }\n }\n output[key] = val;\n }\n\n return { json: output };\n});\n\n// Sort enriched list\nenriched.sort((a, b) => {\n const parseTime = (timeStr) => {\n const [time, meridian] = timeStr.split(' ');\n let [hours, minutes] = time.split(':').map(Number);\n if (meridian === 'PM' && hours !== 12) hours += 12;\n if (meridian === 'AM' && hours === 12) hours = 0;\n return hours * 60 + minutes; // total minutes since midnight\n };\n\n const aTime = parseTime(a.json.gameStartTime);\n const bTime = parseTime(b.json.gameStartTime);\n if (aTime < bTime) return -1;\n if (aTime > bTime) return 1;\n\n const aPitcher = Number(a.json.pitcherId) || 0;\n const bPitcher = Number(b.json.pitcherId) || 0;\n if (aPitcher < bPitcher) return -1;\n if (aPitcher > bPitcher) return 1;\n\n const aOpp = a.json.opponent || \"\";\n const bOpp = b.json.opponent || \"\";\n return aOpp.localeCompare(bOpp);\n});\n\n\nreturn enriched;\n"
},
"typeVersion": 2
},
{
"id": "09b74296-10fa-43a4-8fb4-65a017dd9f78",
"name": "上午 9 点清除",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-400,
-304
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 9
},
{
"triggerAtHour": 9,
"triggerAtMinute": 15
}
]
}
},
"typeVersion": 1.2
},
{
"id": "31005912-843f-4c2f-8614-c92c00404fb8",
"name": "11:02 - 8:02",
"type": "n8n-nodes-base.scheduleTrigger",
"notes": "02 11-20 * * *",
"position": [
-384,
-128
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "02 11-20 * * *"
}
]
}
},
"notesInFlow": true,
"typeVersion": 1
},
{
"id": "e7d4e4e6-09f1-4ce0-820c-a60cd795a858",
"name": "备注:MLB 安打数",
"type": "n8n-nodes-base.stickyNote",
"position": [
288,
-848
],
"parameters": {
"width": 752,
"height": 656,
"content": "MLB\"安打数\"工作流 — 概述"
},
"typeVersion": 1
},
{
"id": "6ef30ef8-0023-42bc-b322-2fffd650894b",
"name": "8. 21 名击球员",
"type": "n8n-nodes-base.code",
"position": [
1408,
-128
],
"parameters": {
"jsCode": "// This code is for an n8n Code node.\n// It assumes the input from the preceding node (which now provides all 27 batters)\n// allows 'items' to contain all batter records.\n\nconsole.log(\"--- Code Node for Telegram Message Start ---\");\n\n// --- Input Processing (same as before to get all 27 batters) ---\nlet allBatterStats = [];\n\n// This block handles both scenarios:\n// 1. If \"Run Once for All Items\" is ON, 'items' contains all incoming records.\n// 2. If an \"Item Lists (Aggregate)\" node precedes this, 'items[0].json' will be the array.\nfor (const item of items) {\n // Scenario A: Item contains a single object (e.g., from a direct data source outputting individual items)\n if (item && typeof item.json === 'object' && item.json !== null && !Array.isArray(item.json)) {\n allBatterStats.push(item.json);\n }\n // Scenario B: Item.json is an array (e.g., from an Item Lists aggregate node, or if a source directly outputs a single array)\n else if (item && Array.isArray(item.json)) {\n allBatterStats.push(...item.json);\n }\n // Fallback: If the item itself (not its .json) is the object, or other unexpected structures\n else if (typeof item === 'object' && item !== null && item.batterName && item.batterHits) {\n allBatterStats.push(item);\n } else {\n console.warn(\"Skipping an input item with an unrecognized structure:\", JSON.stringify(item, null, 2));\n }\n}\n\nconsole.log(\"Total batter stats collected:\", allBatterStats.length);\n\n// Ensure batterHits is a number and filter out invalid entries.\nconst processedBatterStats = allBatterStats.map(batter => {\n const newBatter = { ...batter };\n newBatter.batterHits = typeof batter.batterHits === 'string'\n ? parseFloat(batter.batterHits)\n : batter.batterHits;\n if (isNaN(newBatter.batterHits)) {\n newBatter.batterHits = 0; // Default invalid numbers to 0\n }\n return newBatter;\n}).filter(batter =>\n typeof batter === 'object' &&\n batter !== null &&\n typeof batter.batterHits === 'number' &&\n typeof batter.batterName === 'string' &&\n batter.batterName.trim() !== ''\n);\n\nconsole.log(\"Number of valid and processed batter stats:\", processedBatterStats.length);\n\nif (processedBatterStats.length === 0) {\n console.warn(\"No valid batter stats found. Returning empty message.\");\n return [{ json: { text: \"No batter stats available to display.\" } }];\n}\n\n// Sort the stats by batterHits in descending order.\nprocessedBatterStats.sort((a, b) => b.batterOPS - a.batterOPS);\n\n// Get the top 21 batters.\nconst top21Batters = processedBatterStats.slice(0, 21);\n\nconsole.log(\"Number of top 21 batters selected:\", top21Batters.length);\n\n// --- Telegram Message Formatting ---\n\n// Start the message with a title. Using Markdown for bold.\nlet telegramMessage = \"⚾ **Top 21 Batters by OPS** ⚾\\n\\n\";\n\n// Add each batter to the message string.\ntop21Batters.forEach((batter, index) => {\n // Format each line using Markdown for name and hits.\n // Remember to escape any special Markdown characters in the data if necessary,\n // though typically names and numbers are safe.\n telegramMessage += `${index + 1}. **${batter.batterName}**: ${batter.batterOPS}\\n`;\n});\n\nconsole.log(\"Generated Telegram message length:\", telegramMessage.length);\n\n// --- Return as a single n8n item for the Telegram node ---\n// The Telegram node's 'Text' field will consume the 'text' property from this output.\nreturn [{\n json: {\n message: telegramMessage // This is the single string containing the entire message\n }\n}];"
},
"executeOnce": false,
"typeVersion": 2,
"alwaysOutputData": true
},
{
"id": "5d726f93-c7f4-42d6-b0a0-c0ff8abc159b",
"name": "清除您的表格",
"type": "n8n-nodes-base.googleSheets",
"position": [
-176,
-304
],
"parameters": {
"operation": "clear",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": ""
},
"documentId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "bL32JLOAfaCKsZaj",
"name": "Google Sheets account 2"
}
},
"typeVersion": 4.6
},
{
"id": "29d5c57d-4f31-4fcd-aea0-865341d60d9c",
"name": "7. 更新您的表格",
"type": "n8n-nodes-base.googleSheets",
"onError": "continueErrorOutput",
"position": [
1168,
-128
],
"parameters": {
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": ""
},
"documentId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "bL32JLOAfaCKsZaj",
"name": "Google Sheets account 2"
}
},
"notesInFlow": true,
"retryOnFail": true,
"typeVersion": 4,
"alwaysOutputData": true,
"waitBetweenTries": 5000
},
{
"id": "e9c4377c-93c9-4286-b567-e233e5e65014",
"name": "9. 发送到Telegram聊天机器人",
"type": "n8n-nodes-base.telegram",
"position": [
1600,
-128
],
"webhookId": "3f317a60-e451-4150-9b04-2f9e5427a22d",
"parameters": {
"text": "={{ $json.message }}",
"chatId": "createYourOwnOnTelegram@BOTFather",
"additionalFields": {
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"id": "5HNLqEK3ZgiYkMmw",
"name": "Telegram account"
}
},
"executeOnce": true,
"typeVersion": 1.2
}
],
"pinData": {
"9am Clear": [
{
"Hour": "09",
"Year": "2025",
"Month": "August",
"Minute": "00",
"Second": "32",
"Timezone": "America/New_York (UTC-04:00)",
"timestamp": "2025-08-04T09:00:32.005-04:00",
"Day of week": "Monday",
"Day of month": "04",
"Readable date": "August 4th 2025, 9:00:32 am",
"Readable time": "9:00:32 am"
}
]
},
"connections": {
"9am Clear": {
"main": [
[
{
"node": "Clear your Sheet",
"type": "main",
"index": 0
}
]
]
},
"11:02 - 8:02": {
"main": [
[
{
"node": "2. Get Daily Games",
"type": "main",
"index": 0
}
]
]
},
"Column Order": {
"main": [
[
{
"node": "7. Update Your Sheet",
"type": "main",
"index": 0
}
]
]
},
"8. 21 Hitters": {
"main": [
[
{
"node": "9. sendToTelegramChatbot",
"type": "main",
"index": 0
}
]
]
},
"2. Get Daily Games": {
"main": [
[
{
"node": "3. Extract All Player IDs",
"type": "main",
"index": 0
}
]
]
},
"7. Update Your Sheet": {
"main": [
[
{
"node": "8. 21 Hitters",
"type": "main",
"index": 0
}
]
]
},
"3. Extract All Player IDs": {
"main": [
[
{
"node": "4. Get Batched Player Stats",
"type": "main",
"index": 0
}
]
]
},
"4. Get Batched Player Stats": {
"main": [
[
{
"node": "5. Create Final Matchup Rows",
"type": "main",
"index": 0
}
]
]
},
"6. Filter for Top Matchups": {
"main": [
[
{
"node": "Column Order",
"type": "main",
"index": 0
}
]
]
},
"5. Create Final Matchup Rows": {
"main": [
[
{
"node": "6. Filter for Top Matchups",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
中级 - 杂项, 多模态 AI
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
使用 Gemini、Tavily 和人工审核生成 SEO 优化 WordPress 博客
使用 Gemini、Tavily 和人工审核生成 SEO 优化 WordPress 博客
If
Set
Code
+12
38 节点Aryan Shinde
内容创作
X 推文和 Meta Threads 发布器
使用 Late API 和 Google Sheets 自动发布平台优化内容到 X 和 Threads
If
Set
Code
+6
20 节点Fariez
社交媒体
使用Google Drive存储和Telegram提醒自动化Instagram Reel下载
使用Google Drive存储和Telegram提醒自动化Instagram Reel下载
If
Code
Webhook
+6
11 节点Aryan Shinde
文件管理
使用 HTTP Last-Modified 检查从 Google Sheets 获取职位发布过期和刷新提醒
通过 Google Sheets、HTTP 检查和 Gmail 实现职位发布过期提醒的自动化
If
Set
Code
+6
19 节点WeblineIndia
人力资源
使用GPT-4、Google搜索API和Slack自动化新闻发现与发布
使用GPT-4、Google搜索API和Slack自动化新闻发现与发布
Code
Slack
Http Request
+7
14 节点Kalyxi Ai
杂项
💥 使用 NanoBanana 和 Seedance 创建病毒式广告,通过 upload-post 在社交媒体发布 VIDE II
使用 AI 创建病毒式多媒体广告:NanoBanana、Seedance 和 Suno 用于社交媒体
If
Set
Code
+13
45 节点Dr. Firas
杂项