{
  "name": "توییت‌نویس هوشمند X (Gemini) — v2.0",
  "nodes": [
    {
      "parameters": {
        "content": "# 📘 توییت‌نویس هوشمند X — نسخه 2.0\n\n## این ورکفلو چه می‌کند؟\nبا **یک فرم**، توییت یا **رشته‌توییت** حرفه‌ای می‌سازد و در X منتشر می‌کند:\n\n| نوع محتوا | ورودی | نتیجه |\n|---|---|---|\n| **از روی لینک** | لینک مقاله | Gemini مقاله را می‌خواند و توییت/رشته می‌نویسد |\n| **از روی ایده** | یک جمله یا چند نکته | Gemini با لحن انتخابی شما می‌نویسد |\n| **متن خودم** | متن آماده | بدون هوش مصنوعی؛ اگر بلند بود خودکار به رشته تقسیم می‌شود |\n\n✨ امکانات حرفه‌ای:\n- **رشته‌توییت ۳ تا ۵ تایی** که درست زیر هم Reply می‌شوند\n- **شمارش دقیق کاراکتر به روش خود X** (فارسی ۱، ایموجی ۲، لینک ۲۳)\n- **۴ لحن** و **فارسی / English**\n- **پیش‌نمایش** قبل از انتشار و صفحه‌ی نتیجه با لینک توییت\n\n## مسیر کلی\n```\nفرم → نوع؟\n  لینک → خواندن صفحه → استخراج متن ─┐\n  ایده ──────────────────────────────┤→ Gemini (نوشتن) ─┐\n  متن خودم ─────────────────────────────────────────────┤→ آماده‌سازی توییت‌ها\n                                         پیش‌نمایش → صفحه‌ی پیش‌نمایش\n                                         انتشار → حلقه: توییت ۱ → Reply ۲ → … → صفحه‌ی نتیجه\n```\n\n## اعتبارنامه‌ها (فقط ۲ تا)\n| نوع | کجا | مقدار |\n|---|---|---|\n| **X OAuth2 API** | Post Tweet | Client ID / Secret اپ X |\n| Header Auth «Gemini API Key» | Gemini – Write | `x-goog-api-key` = کلید Gemini |\n\n---\nطراحی و آموزش: **مرتضی عظیمی** — mortezaazimi.ir",
        "height": 1260,
        "width": 680,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1300,
        -520
      ],
      "id": "116f25c7-5f41-4ac0-88c6-3e8c65babecd",
      "name": "📘 راهنمای کلی"
    },
    {
      "parameters": {
        "content": "## 1️⃣ فرم و مسیریابی\n\n**X Post Form** — فیلدها:\n- **نوع محتوا** (لینک / ایده / متن خودم)\n- **لینک** — برای حالت لینک (و اگر بخواهید داخل توییت بیاید)\n- **ایده یا متن** — ایده، زاویه‌ی دلخواه، یا متن کامل خودتان\n- **قالب** — تک توییت / رشته‌توییت\n- **لحن** و **زبان**\n- **لینک داخل توییت باشد؟**\n- **بعد از ساخت** — پیش‌نمایش / انتشار\n\n**Route by Mode** هر حالت را به مسیر خودش می‌برد.\n\n⚠️ اسم فیلدهای فرم را عوض نکنید؛ گره‌های بعدی با همین اسم‌ها کار می‌کنند.",
        "height": 800,
        "width": 440,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -600,
        -520
      ],
      "id": "59e95567-4e1d-484b-a88b-20dbc96e60a8",
      "name": "۱ — فرم و مسیر"
    },
    {
      "parameters": {
        "content": "## 2️⃣ نوشتن با هوش مصنوعی\n\n1. **Fetch Page** — صفحه‌ی لینک را دانلود می‌کند (فقط حالت لینک)\n2. **Page → Text** — منو، فوتر و کدها را حذف و متن اصلی مقاله را جدا می‌کند\n3. **Gemini – Write** — توییت یا رشته را با قواعد حرفه‌ای X می‌نویسد:\n   قلاب قوی در توییت اول، یک نکته در هر توییت، دعوت به تعامل در آخر، حداکثر ۲ هشتگ، **بدون ساختن واقعیت**\n\n✏️ قواعد نوشتن در `systemInstruction` بدنه‌ی گره Gemini است.\n💡 مدل پیش‌فرض `gemini-3.5-flash-lite`؛ برای متن قوی‌تر `gemini-3.8-flash`.",
        "height": 440,
        "width": 820,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -140,
        -660
      ],
      "id": "db061ed2-4157-4c10-b862-9a6f1466ce28",
      "name": "۲ — نوشتن با هوش مصنوعی"
    },
    {
      "parameters": {
        "content": "## 3️⃣ آماده‌سازی توییت‌ها\n\n**Prepare Tweets** (کد):\n- شمارش کاراکتر **دقیقاً مثل X**: حروف فارسی و لاتین ۱، ایموجی ۲، هر لینک ۲۳\n- متن بلندِ حالت «متن خودم» را روی جمله‌ها به **رشته‌توییت** تقسیم می‌کند\n- شماره‌گذاری رشته (۱/۴، ۲/۴…)\n- لینک را به آخرین توییت اضافه می‌کند\n- اگر توییتی بلند بود، روی مرز کلمه کوتاهش می‌کند (هیچ‌وقت از ۲۸۰ بیشتر نمی‌شود)",
        "height": 800,
        "width": 420,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        720,
        -520
      ],
      "id": "faf66b86-b1cf-4da8-abd9-eaa7a9374338",
      "name": "۳ — آماده‌سازی"
    },
    {
      "parameters": {
        "content": "## 4️⃣ پیش‌نمایش یا انتشار\n\n**Publish or Preview?**\n- پیش‌نمایش → **Preview Page**: همه‌ی توییت‌ها با تعداد کاراکتر، بدون انتشار\n- انتشار →\n  1. **Split Tweets** — هر توییت یک آیتم\n  2. **Loop Over Items** — یکی‌یکی به‌ترتیب\n  3. **Post Tweet** — توییت اول عادی؛ بقیه **Reply به توییت قبلی** (رشته‌ی واقعی)\n  4. **Result Page** — «منتشر شد» + لینک توییت\n\n💡 Post Tweet با HTTP Request و اعتبارنامه‌ی رسمی **X OAuth2 API** کار می‌کند تا Reply زنجیره‌ای دقیق باشد.\n⚠️ API رایگان X سقف ماهانه برای تعداد پست دارد؛ پلن اپ خود را در developer.x.com ببینید.",
        "height": 1000,
        "width": 1000,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1180,
        -660
      ],
      "id": "71661a56-61f0-4a94-b7a6-4f3a8d2cf84c",
      "name": "۴ — انتشار"
    },
    {
      "parameters": {
        "formTitle": "توییت‌نویس هوشمند X",
        "formDescription": "لینک یک مطلب یا فقط یک ایده بدهید؛ هوش مصنوعی توییت یا رشته‌توییت حرفه‌ای می‌نویسد و منتشر می‌کند. این صفحه را تا پایان کار نبندید.",
        "formFields": {
          "values": [
            {
              "fieldLabel": "نوع محتوا",
              "fieldType": "dropdown",
              "requiredField": true,
              "fieldOptions": {
                "values": [
                  {
                    "option": "تولید با هوش مصنوعی از روی لینک"
                  },
                  {
                    "option": "تولید با هوش مصنوعی از روی ایده"
                  },
                  {
                    "option": "متن خودم (بدون هوش مصنوعی)"
                  }
                ]
              }
            },
            {
              "fieldLabel": "لینک",
              "placeholder": "https://... (برای حالت لینک)"
            },
            {
              "fieldLabel": "ایده یا متن",
              "fieldType": "textarea",
              "placeholder": "ایده، نکته‌ها یا زاویه‌ی دلخواه — یا متن کامل خودتان در حالت «متن خودم»"
            },
            {
              "fieldLabel": "قالب",
              "fieldType": "dropdown",
              "requiredField": true,
              "fieldOptions": {
                "values": [
                  {
                    "option": "تک توییت"
                  },
                  {
                    "option": "رشته‌توییت (۳ تا ۵ توییت)"
                  }
                ]
              }
            },
            {
              "fieldLabel": "لحن",
              "fieldType": "dropdown",
              "requiredField": true,
              "fieldOptions": {
                "values": [
                  {
                    "option": "حرفه‌ای و تحلیلی"
                  },
                  {
                    "option": "صمیمی و خودمانی"
                  },
                  {
                    "option": "الهام‌بخش"
                  },
                  {
                    "option": "طنز ملایم"
                  }
                ]
              }
            },
            {
              "fieldLabel": "زبان",
              "fieldType": "dropdown",
              "requiredField": true,
              "fieldOptions": {
                "values": [
                  {
                    "option": "فارسی"
                  },
                  {
                    "option": "English"
                  }
                ]
              }
            },
            {
              "fieldLabel": "لینک داخل توییت باشد؟",
              "fieldType": "dropdown",
              "fieldOptions": {
                "values": [
                  {
                    "option": "نه"
                  },
                  {
                    "option": "بله، لینک را اضافه کن"
                  }
                ]
              }
            },
            {
              "fieldLabel": "بعد از ساخت",
              "fieldType": "dropdown",
              "requiredField": true,
              "fieldOptions": {
                "values": [
                  {
                    "option": "فقط پیش‌نمایش (منتشر نشود)"
                  },
                  {
                    "option": "منتشر شود"
                  }
                ]
              }
            }
          ]
        },
        "options": {
          "appendAttribution": false,
          "buttonLabel": "ساخت توییت ✨"
        }
      },
      "type": "n8n-nodes-base.formTrigger",
      "typeVersion": 2.2,
      "position": [
        -540,
        -100
      ],
      "id": "275b5fc0-cf37-44ac-b57f-ffcae289b310",
      "name": "X Post Form",
      "webhookId": "b180fece-452e-4ecd-92d3-aedd7ffc1420"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "loose",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "db37d619-a827-490f-81a3-1caf455fe987",
                    "leftValue": "={{ $json['نوع محتوا'] }}",
                    "rightValue": "لینک",
                    "operator": {
                      "type": "string",
                      "operation": "contains"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "From Link"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "loose",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "1e7ac504-fbbd-4123-bc75-f1adcda9cfb3",
                    "leftValue": "={{ $json['نوع محتوا'] }}",
                    "rightValue": "ایده",
                    "operator": {
                      "type": "string",
                      "operation": "contains"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "From Idea"
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "Own Text"
        }
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [
        -320,
        -100
      ],
      "id": "4b19a745-e261-4790-a3c6-25ae8bad041a",
      "name": "Route by Mode"
    },
    {
      "parameters": {
        "url": "={{ $json['لینک'] }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "User-Agent",
              "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36"
            },
            {
              "name": "Accept-Language",
              "value": "fa,en;q=0.8"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "responseFormat": "text"
            }
          },
          "timeout": 20000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -60,
        -320
      ],
      "id": "ec87a37d-f895-4efc-ab8b-f4b3a028b75c",
      "name": "Fetch Page"
    },
    {
      "parameters": {
        "jsCode": "// ─────────────────────────────────────────────────────────────\n// تبدیل HTML صفحه به متن خالص برای Gemini\n// ─────────────────────────────────────────────────────────────\nconst html = String($input.first().json.data || '');\n\nconst pick = re => { const m = html.match(re); return m ? m[1].trim() : ''; };\nconst decode = s => s\n  .replace(/&nbsp;/g, ' ').replace(/&amp;/g, '&').replace(/&quot;/g, '\"').replace(/&#39;|&apos;/g, \"'\")\n  .replace(/&lt;/g, '<').replace(/&gt;/g, '>')\n  .replace(/&#(\\d+);/g, (_, n) => String.fromCodePoint(+n))\n  .replace(/&#x([0-9a-f]+);/gi, (_, n) => String.fromCodePoint(parseInt(n, 16)));\n\nconst pageTitle = decode(pick(/<meta[^>]+property=[\"']og:title[\"'][^>]+content=[\"']([^\"']+)/i) || pick(/<title[^>]*>([\\s\\S]*?)<\\/title>/i));\nconst pageDesc = decode(pick(/<meta[^>]+name=[\"']description[\"'][^>]+content=[\"']([^\"']+)/i));\n\n// اگر <article> یا <main> داشت، فقط همان بخش را برمی‌داریم\nlet body = (html.match(/<article[\\s\\S]*?<\\/article>/i) || html.match(/<main[\\s\\S]*?<\\/main>/i) || [html])[0];\nbody = body\n  .replace(/<(script|style|noscript|svg|nav|footer|header|aside|form|iframe)[\\s\\S]*?<\\/\\1>/gi, ' ')\n  .replace(/<\\/(p|div|h[1-6]|li|br|tr|section)>/gi, '\\n')\n  .replace(/<[^>]+>/g, ' ');\nconst pageText = decode(body).replace(/[ \\t]+/g, ' ').replace(/\\n\\s*\\n+/g, '\\n').trim().slice(0, 15000);\n\nif (pageText.length < 200) throw new Error('متن کافی از این لینک خوانده نشد. ممکن است سایت جلوی ربات‌ها را بگیرد؛ لینک دیگری امتحان کنید.');\nreturn [{ json: { pageTitle, pageDesc, pageText } }];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        160,
        -320
      ],
      "id": "e09c266a-5cd4-4f7c-bbf1-697304053352",
      "name": "Page → Text"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.5-flash-lite:generateContent",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({\n  systemInstruction: { parts: [{ text: \"You are a senior social media strategist who writes high-performing posts on X (Twitter) for businesses.\\nWrite either ONE tweet or a THREAD, as requested.\\n\\nHard rules:\\n- Each tweet must be at most 260 characters (Persian letters count as 1, emojis as 2). Never exceed it.\\n- Write in the requested language and tone. Natural, human, specific. No corporate fluff, no clickbait lies.\\n- First tweet = a strong hook that makes people stop scrolling (a surprising fact, a bold claim backed by the source, or a sharp question).\\n- Thread: 3 to 5 tweets. Each tweet delivers one concrete insight. The last tweet ends with a clear call to action or a question that invites replies. Do NOT add numbering like 1/5; it is added automatically.\\n- Single tweet: one punchy insight + a light call to action.\\n- At most 2 relevant hashtags in the whole output, only if natural. No markdown, no asterisks, no quotes around tweets.\\n- Never invent facts, numbers or quotes that are not in the source. Do not include links; they are added automatically.\\n\\nReturn JSON only: {\\\"tweets\\\": [\\\"...\\\", \\\"...\\\"]}\" }] },\n  contents: [{ role: 'user', parts: [{ text:\n    'Format: ' + ($('X Post Form').item.json['قالب'].includes('رشته') ? 'THREAD (3-5 tweets)' : 'SINGLE TWEET') + '\\n' +\n    'Language: ' + ($('X Post Form').item.json['زبان'] === 'English' ? 'English' : 'Persian (Farsi)') + '\\n' +\n    'Tone: ' + $('X Post Form').item.json['لحن'] + '\\n' +\n    'User idea / notes: ' + ($('X Post Form').item.json['ایده یا متن'] || '-') + '\\n' +\n    (($json.pageText) ? ('\\nSOURCE ARTICLE TITLE: ' + $json.pageTitle + '\\nSOURCE ARTICLE TEXT:\\n' + $json.pageText) : '')\n  }] }],\n  generationConfig: {\n    responseMimeType: 'application/json',\n    responseSchema: { type: 'OBJECT', properties: { tweets: { type: 'ARRAY', items: { type: 'STRING' } } }, required: ['tweets'] }\n  }\n}) }}",
        "options": {
          "timeout": 60000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        400,
        -200
      ],
      "id": "7bae608d-6a8f-4e92-8cbf-f2e2590f074a",
      "name": "Gemini – Write"
    },
    {
      "parameters": {
        "jsCode": "// ─────────────────────────────────────────────────────────────\n// آماده‌سازی توییت‌ها: شمارش دقیق کاراکتر به روش X، تقسیم متن بلند، افزودن لینک\n// ─────────────────────────────────────────────────────────────\nconst f = $('X Post Form').first().json;\nconst mode = String(f['نوع محتوا'] || '');\nconst isOwn = mode.includes('متن خودم');\nconst wantThread = String(f['قالب'] || '').includes('رشته');\nconst link = String(f['لینک'] || '').trim();\nconst addLink = String(f['لینک داخل توییت باشد؟'] || '').startsWith('بله') && /^https?:\\/\\//.test(link);\nconst publish = !String(f['بعد از ساخت'] || '').includes('پیش‌نمایش');\nconst MAX = 280;\n\n// شمارش وزنی X: فارسی/لاتین = ۱، ایموجی و خطوط شرق آسیا = ۲، هر لینک = ۲۳\nfunction xLen(t) {\n  let n = 0;\n  const s = String(t).replace(/https?:\\/\\/\\S+/g, () => { n += 23; return ''; });\n  for (const ch of s) {\n    const c = ch.codePointAt(0);\n    n += (c <= 4351 || (c >= 8192 && c <= 8205) || (c >= 8208 && c <= 8223) || (c >= 8242 && c <= 8247)) ? 1 : 2;\n  }\n  return n;\n}\n// بریدن هوشمند روی مرز کلمه\nfunction fit(t, max) {\n  if (xLen(t) <= max) return t;\n  const words = t.split(/\\s+/); let out = '';\n  for (const w of words) { const nx = out ? out + ' ' + w : w; if (xLen(nx + '…') > max) break; out = nx; }\n  return out.replace(/[،,.؛:\\s]+$/, '') + '…';\n}\n// تقسیم متن بلند به چند توییت (روی پاراگراف و جمله)\nfunction split(text, max) {\n  // هر جمله همراه با جداکننده‌ی بعدش (پاراگراف یا فاصله) نگه داشته می‌شود\n  const parts = []; const re = /[^]*?(?:[.!?؟]+(?=\\s)|$)(\\s*)/g; let mm;\n  const src = String(text).trim();\n  while ((mm = re.exec(src)) && mm[0]) parts.push({ t: mm[0].trim(), br: /\\n/.test(mm[1]) ? '\\n\\n' : ' ' });\n  const out = []; let cur = '', sep = '';\n  for (const { t: p, br } of parts) {\n    if (!p) continue;\n    const nx = cur ? cur + sep + p : p; sep = br;\n    if (xLen(nx) <= max) cur = nx;\n    else { if (cur) out.push(cur); cur = xLen(p) <= max ? p : fit(p, max); }\n  }\n  if (cur) out.push(cur);\n  return out;\n}\n\nlet tweets = [];\nif (isOwn) {\n  const text = String(f['ایده یا متن'] || '').trim();\n  if (!text) throw new Error('فیلد «ایده یا متن» خالی است.');\n  tweets = xLen(text) <= MAX - (addLink ? 25 : 0) ? [text] : split(text, MAX - 8);\n} else {\n  const parts = $input.first().json.candidates?.[0]?.content?.parts || [];\n  const raw = parts.filter(p => p.text && !p.thought).map(p => p.text).join('').replace(/^```(?:json)?/i, '').replace(/```$/, '').trim();\n  let ai;\n  try { ai = JSON.parse(raw); } catch (e) { throw new Error('خروجی Gemini قابل خواندن نبود: ' + raw.slice(0, 200)); }\n  tweets = (ai.tweets || []).map(t => String(t).trim()).filter(Boolean);\n  if (!tweets.length) throw new Error('Gemini توییتی برنگرداند.');\n  if (!wantThread) tweets = [tweets[0]];\n}\n\n// شماره‌گذاری رشته (اگر خودش نداشت)\nif (tweets.length > 1 && !/[0-9۰-۹]+\\s*\\/\\s*[0-9۰-۹]+/.test(tweets[0])) {\n  const fa = n => String(n).replace(/\\d/g, d => '۰۱۲۳۴۵۶۷۸۹'[d]);\n  tweets = tweets.map((t, i) => t + '\\n' + fa(i + 1) + '/' + fa(tweets.length));\n}\n// لینک در آخرین توییت\nif (addLink && !tweets.some(t => t.includes(link))) {\n  const i = tweets.length - 1;\n  tweets[i] = fit(tweets[i], MAX - 25) + '\\n' + link;\n}\ntweets = tweets.map(t => fit(t, MAX));\n\nreturn [{ json: { publish, count: tweets.length, tweets, lengths: tweets.map(xLen) } }];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        800,
        -100
      ],
      "id": "7be57b3f-64c2-4616-8b74-7186f15e65a2",
      "name": "Prepare Tweets"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "c453db90-ce7e-4458-9d4a-680eb4a53a2d",
              "leftValue": "={{ $json.publish }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1020,
        -100
      ],
      "id": "40f11f4f-6d39-495d-a816-abd64883196b",
      "name": "Publish or Preview?"
    },
    {
      "parameters": {
        "jsCode": "// هر توییت یک آیتم جدا می‌شود تا به‌ترتیب منتشر شوند\nreturn $input.first().json.tweets.map((text, index) => ({ json: { index, text } }));\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1240,
        -260
      ],
      "id": "e404efa6-bc8f-4f27-b614-517c6b505c1b",
      "name": "Split Tweets"
    },
    {
      "parameters": {
        "batchSize": 1,
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        1460,
        -260
      ],
      "id": "4df471af-2b06-49e8-b400-9d66b474abda",
      "name": "Loop Over Items"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.x.com/2/tweets",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "twitterOAuth2Api",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify(Object.assign(\n  { text: $json.text },\n  $json.index > 0 ? { reply: { in_reply_to_tweet_id: $('Post Tweet').first(0, $runIndex - 1).json.data.id } } : {}\n)) }}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1700,
        -160
      ],
      "id": "d579e1c9-585d-4794-b920-dd1c9a3a541c",
      "name": "Post Tweet"
    },
    {
      "parameters": {
        "operation": "completion",
        "respondWith": "showText",
        "responseText": "=<div dir=\"rtl\" style=\"font-family:Tahoma,Vazirmatn,sans-serif;max-width:560px;margin:0 auto;padding:16px;color:#0f1419\">\n<h2 style=\"margin:0 0 4px;text-align:center\">👀 پیش‌نمایش {{ $json.count > 1 ? 'رشته‌توییت (' + $json.count + ' توییت)' : 'توییت' }}</h2>\n<p style=\"text-align:center;color:#536471;margin:0 0 16px\">چیزی منتشر نشده. اگر پسندیدید، فرم را با «منتشر شود» دوباره بفرستید.</p>\n{{ $json.tweets.map((t, i) => '<div style=\"border:1px solid #eff3f4;border-radius:16px;padding:14px 16px;margin-bottom:10px;white-space:pre-wrap;line-height:1.9;font-size:15px\">' + t.replace(/</g, '&lt;') + '<div style=\"text-align:left;color:' + ($json.lengths[i] > 270 ? '#f4212e' : '#1d9bf0') + ';font-size:12px;margin-top:6px;direction:ltr\">' + $json.lengths[i] + ' / 280</div></div>').join('') }}\n</div>"
      },
      "type": "n8n-nodes-base.form",
      "typeVersion": 1,
      "position": [
        1240,
        80
      ],
      "id": "cd68bc23-1be5-483c-a901-c1d88d9474fd",
      "name": "Preview Page",
      "webhookId": "794f05b2-52c1-42b9-8ae7-1cf7bb9a9706"
    },
    {
      "parameters": {
        "operation": "completion",
        "respondWith": "showText",
        "responseText": "=<div dir=\"rtl\" style=\"font-family:Tahoma,Vazirmatn,sans-serif;text-align:center;padding:24px;color:#0f1419\">\n<div style=\"font-size:52px;line-height:1\">✅</div>\n<h2 style=\"margin:10px 0 6px\">در X منتشر شد</h2>\n<p style=\"color:#536471;margin:0 0 18px\">{{ $('Prepare Tweets').first().json.count > 1 ? 'رشته‌توییت ' + $('Prepare Tweets').first().json.count + ' تایی شما منتشر شد.' : 'توییت شما منتشر شد.' }}</p>\n<a href=\"https://x.com/i/status/{{ $('Post Tweet').first(0, 0).json.data.id }}\" target=\"_blank\" style=\"display:inline-block;padding:12px 28px;border-radius:999px;background:#0f1419;color:#fff;text-decoration:none;font-weight:bold\">مشاهده در X ↗</a>\n</div>"
      },
      "type": "n8n-nodes-base.form",
      "typeVersion": 1,
      "position": [
        1700,
        -420
      ],
      "id": "b6b7b68b-f47a-4b09-8cb3-ce29261b5968",
      "name": "Result Page",
      "webhookId": "b0d07af9-e084-43d7-a477-1746db9ad256"
    }
  ],
  "pinData": {},
  "connections": {
    "X Post Form": {
      "main": [
        [
          {
            "node": "Route by Mode",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by Mode": {
      "main": [
        [
          {
            "node": "Fetch Page",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Gemini – Write",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Prepare Tweets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Page": {
      "main": [
        [
          {
            "node": "Page → Text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Page → Text": {
      "main": [
        [
          {
            "node": "Gemini – Write",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gemini – Write": {
      "main": [
        [
          {
            "node": "Prepare Tweets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Tweets": {
      "main": [
        [
          {
            "node": "Publish or Preview?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Publish or Preview?": {
      "main": [
        [
          {
            "node": "Split Tweets",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Preview Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Tweets": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [
          {
            "node": "Result Page",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Post Tweet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post Tweet": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "tags": []
}