아래 JSON은 바로 import 가능한 형태입니다.

 아래 JSON은 바로 import 가능한 형태입니다.

구성은 요청하신 대로:

  • 1편(episode=1): 즉시 발행
  • 2편~N편publishAt 시간까지 대기 후 자동 발행

import 후 꼭 수정할 것

  1. Set Config 노드의 blogId
  2. HTTP Request 노드의 OAuth2 Credential 연결 (googleOAuth2Api)
  3. Set Posts 노드의 원고 데이터
{
"name": "Blogger Series Auto Publisher (Ep1 now, Ep2+ queued)",
"nodes": [
{
"parameters": {},
"id": "manualTrigger",
"name": "Manual Trigger",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
240,
300
]
},
{
"parameters": {
"keepOnlySet": true,
"values": {
"string": [
{
"name": "blogId",
"value": "YOUR_BLOGGER_BLOG_ID"
}
]
}
},
"id": "setConfig",
"name": "Set Config",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
460,
300
]
},
{
"parameters": {
"keepOnlySet": true,
"values": {
"string": [
{
"name": "postsJson",
"value": "[\n {\n \"episode\": 1,\n \"title\": \"1편 제목\",\n \"intro\": \"1편 인트로\",\n \"sections\": [\n { \"h2\": \"소제목 1\", \"body\": \"본문 1\" },\n { \"h2\": \"소제목 2\", \"body\": \"본문 2\" },\n { \"h2\": \"소제목 3\", \"body\": \"본문 3\" }\n ],\n \"summary\": \"1편 요약\",\n \"next_preview\": \"다음 편 예고\",\n \"publishAt\": \"2026-04-15T09:00:00+09:00\"\n },\n {\n \"episode\": 2,\n \"title\": \"2편 제목\",\n \"intro\": \"2편 인트로\",\n \"sections\": [\n { \"h2\": \"소제목 1\", \"body\": \"본문 1\" },\n { \"h2\": \"소제목 2\", \"body\": \"본문 2\" },\n { \"h2\": \"소제목 3\", \"body\": \"본문 3\" }\n ],\n \"summary\": \"2편 요약\",\n \"next_preview\": \"다음 편 예고\",\n \"publishAt\": \"2026-04-16T09:00:00+09:00\"\n }\n]"
}
]
}
},
"id": "setPosts",
"name": "Set Posts",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
680,
300
]
},
{
"parameters": {
"jsCode": "const blogId = $json.blogId;\nconst raw = $json.postsJson;\nlet posts = [];\n\ntry {\n posts = JSON.parse(raw);\n} catch (e) {\n throw new Error('postsJson 파싱 실패: ' + e.message);\n}\n\nif (!Array.isArray(posts) || posts.length === 0) {\n throw new Error('postsJson은 비어있지 않은 배열이어야 합니다.');\n}\n\nposts.sort((a,b) => Number(a.episode) - Number(b.episode));\n\nfunction buildContent(p) {\n const sections = (p.sections || []).slice(0,4);\n const sectionHtml = sections.map(s => `<h2>${s.h2}</h2><p>${s.body}</p>`).join('\\n');\n\n return `\n<p>${p.intro || ''}</p>\n${sectionHtml}\n<h2>결론(요약)</h2>\n<p>${p.summary || ''}</p>\n<p><strong>다음 편 예고:</strong> ${p.next_preview || ''}</p>\n<hr/>\n<p>읽어주셔서 감사합니다. 다음 편에서 더 실무적인 내용으로 이어가겠습니다.</p>\n`.trim();\n}\n\nreturn posts.map(p => ({\n json: {\n blogId,\n episode: Number(p.episode),\n title: p.title,\n publishAt: p.publishAt,\n content: buildContent(p)\n }\n}));"
},
"id": "codePrepare",
"name": "Prepare Posts",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
920,
300
]
},
{
"parameters": {
"conditions": {
"number": [
{
"value1": "={{$json.episode}}",
"operation": "equal",
"value2": 1
}
]
}
},
"id": "ifEpisode1",
"name": "IF Episode 1",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
1140,
300
]
},
{
"parameters": {
"authentication": "oAuth2",
"url": "=https://www.googleapis.com/blogger/v3/blogs/{{$json.blogId}}/posts?isDraft=false",
"options": {},
"responseFormat": "json",
"requestMethod": "POST",
"jsonParameters": true,
"sendBody": true,
"specifyBody": "json",
"bodyParametersJson": "={\n \"kind\": \"blogger#post\",\n \"title\": $json.title,\n \"content\": $json.content\n}"
},
"id": "publishNow",
"name": "Publish Now (Episode 1)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1380,
200
],
"credentials": {
"googleOAuth2Api": {
"id": "YOUR_GOOGLE_OAUTH2_CREDENTIAL_ID",
"name": "Google OAuth2 account"
}
}
},
{
"parameters": {
"resume": "specificTime",
"dateTime": "={{$json.publishAt}}"
},
"id": "waitUntil",
"name": "Wait Until publishAt",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
1380,
400
]
},
{
"parameters": {
"authentication": "oAuth2",
"url": "=https://www.googleapis.com/blogger/v3/blogs/{{$json.blogId}}/posts?isDraft=false",
"options": {},
"responseFormat": "json",
"requestMethod": "POST",
"jsonParameters": true,
"sendBody": true,
"specifyBody": "json",
"bodyParametersJson": "={\n \"kind\": \"blogger#post\",\n \"title\": $json.title,\n \"content\": $json.content\n}"
},
"id": "publishScheduled",
"name": "Publish Scheduled (Episode 2+)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1620,
400
],
"credentials": {
"googleOAuth2Api": {
"id": "YOUR_GOOGLE_OAUTH2_CREDENTIAL_ID",
"name": "Google OAuth2 account"
}
}
},
{
"parameters": {
"mode": "append"
},
"id": "mergeResults",
"name": "Merge Results",
"type": "n8n-nodes-base.merge",
"typeVersion": 3.1,
"position": [
1860,
300
]
}
],
"connections": {
"Manual Trigger": {
"main": [
[
{
"node": "Set Config",
"type": "main",
"index": 0
}
]
]
},
"Set Config": {
"main": [
[
{
"node": "Set Posts",
"type": "main",
"index": 0
}
]
]
},
"Set Posts": {
"main": [
[
{
"node": "Prepare Posts",
"type": "main",
"index": 0
}
]
]
},
"Prepare Posts": {
"main": [
[
{
"node": "IF Episode 1",
"type": "main",
"index": 0
}
]
]
},
"IF Episode 1": {
"main": [
[
{
"node": "Publish Now (Episode 1)",
"type": "main",
"index": 0
}
],
[
{
"node": "Wait Until publishAt",
"type": "main",
"index": 0
}
]
]
},
"Publish Now (Episode 1)": {
"main": [
[
{
"node": "Merge Results",
"type": "main",
"index": 0
}
]
]
},
"Wait Until publishAt": {
"main": [
[
{
"node": "Publish Scheduled (Episode 2+)",
"type": "main",
"index": 0
}
]
]
},
"Publish Scheduled (Episode 2+)": {
"main": [
[
{
"node": "Merge Results",
"type": "main",
"index": 1
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "1"
}

빠른 사용 순서

  • n8n Import
  • Set Config.blogId 수정
  • HTTP Request 노드 두 개에 Google OAuth2 Credential 연결
  • Set Posts.postsJson에 1~8편 데이터 넣기
  • 실행

원하면 다음으로 제가 지금 만든 8편 원고를 이 JSON의 postsJson에 맞춰 완성본으로 채운 버전까지 만들어드리겠습니다.

댓글

이 블로그의 인기 게시물

n8n자동화 첫걸음 - JSON으로 만든글을 자동화 해보자