{"updatedAt":"2026-08-21T18:13:02.091Z","createdAt":"2026-04-12T23:18:47.196Z","id":"R1zn1l8zDaVpFSkm","name":"OOeirense - Telegram → Instagram (HTML)","description":null,"active":true,"isArchived":false,"nodes":[{"parameters":{"jsCode":"const response = $input.first().json.body || $input.first().json;\nconst results = response.result || [];\nif (!results.length) { return []; }\nconst msg = results[0];\nconst updateId = msg.update_id;\nconst newOffset = updateId + 1;\nconst staticData = $getWorkflowStaticData('global');\nstaticData.lastUpdateId = newOffset;\nif (msg.message?.from?.is_bot) { return []; }\nconst chatId = String(msg.message?.chat?.id || '');\nif (chatId !== '7769073261') { return []; }\nconst text = msg.message?.text || '';\nconst trimmed = text.trim();\nconst instaMatch = trimmed.match(/^insta\\s+(https?:\\/\\/[^\\s<>\"'\\)]+)/i);\nif (!instaMatch) { return []; }\nconst url = instaMatch[1];\n\n// DEDUP À PROVA DE RACE — lockfile filesystem via mkdir atômico\nconst { execFileSync } = require('child_process');\nconst LOCK_DIR = '/tmp/ooeirense-seen';\nconst TTL_MIN = 360; // 6h\ntry { execFileSync('/bin/mkdir', ['-p', LOCK_DIR]); } catch(e) {}\n\n// Limpa locks antigos (best-effort, não bloqueia)\ntry {\n  execFileSync('/usr/bin/find', [LOCK_DIR, '-maxdepth', '1', '-mindepth', '1', '-type', 'd', '-mmin', '+' + TTL_MIN, '-exec', '/bin/rm', '-rf', '{}', '+'], { timeout: 2000 });\n} catch(e) {}\n\n// Tenta reivindicar o update_id — mkdir sem -p falha se já existe (atômico no fs)\nconst lockPath = LOCK_DIR + '/u' + updateId;\nlet acquired = false;\ntry {\n  execFileSync('/bin/mkdir', [lockPath]);\n  acquired = true;\n} catch(e) {\n  acquired = false;\n}\nif (!acquired) {\n  return [{ json: { url, messageId: msg.message.message_id, updateId, newOffset, duplicate: true, reason: 'concurrent-lock' } }];\n}\n\nreturn [{ json: { url, messageId: msg.message.message_id, updateId, newOffset, duplicate: false } }];\n"},"id":"tg-extract-url","name":"Extrair URL do Telegram","type":"n8n-nodes-base.code","typeVersion":2,"position":[688,304]},{"parameters":{"url":"={{ 'https://r.jina.ai/' + $json.url }}","sendHeaders":true,"headerParameters":{"parameters":[{"name":"Accept","value":"application/json"},{"name":"User-Agent","value":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"}]},"options":{}},"id":"ce8500de-951a-4cfb-b329-4b16e21e0718","name":"Buscar Matéria","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[1408,304]},{"parameters":{"jsCode":"// Jina Reader retorna: { data: { title, description, url, content, metadata } }\nconst response = $input.first().json;\nconst jinaData = response.data || response;\nconst meta = jinaData.metadata || {};\n\n// Jina devolve ARRAY quando a pagina repete a mesma meta tag (dois plugins de SEO\n// no mesmo WordPress). Ex: portalintegracao.com.br duplica og:title/og:description/og:image.\n// Sem normalizar, .replace/.trim quebram com \"is not a function\".\nconst txt = (v) => {\n  if (Array.isArray(v)) v = v.find(x => typeof x === 'string' && x.trim());\n  return typeof v === 'string' ? v : '';\n};\n\nconst articleUrl = $('Extrair URL do Telegram').first().json.url;\nconst emailId = $('Extrair URL do Telegram').first().json.emailId;\n\nlet title = (txt(meta['og:title']) || txt(jinaData.title) || '').replace(/\\s*[-|].*$/, '').trim();\nlet description = (txt(meta['og:description']) || txt(meta.description) || txt(jinaData.description) || '').trim();\nlet imageUrl = txt(meta['og:image']).trim();\nlet content = txt(jinaData.content);\n\n// Detectar bloqueio do Jina (403 / conteudo vazio / pagina de erro)\nconst jinaBlocked =\n  /403 forbidden|access denied|don't have permission/i.test(title) ||\n  /403 forbidden|don't have permission/i.test(content) ||\n  content.trim().length < 300 ||\n  !imageUrl;\n\nif (jinaBlocked) {\n  try {\n    const html = await this.helpers.httpRequest({\n      method: 'GET',\n      url: articleUrl,\n      headers: {\n        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\n        'Accept-Language': 'pt-BR,pt;q=0.9,en;q=0.8',\n      },\n      returnFullResponse: false,\n    });\n    const extractMeta = (html, key) => {\n      let rx = new RegExp('<meta[^>]+(?:property|name)\\\\s*=\\\\s*[\"\\'](' + key + ')[\"\\'][^>]*content\\\\s*=\\\\s*[\"\\']([^\"\\']+)[\"\\']', 'i');\n      let m = html.match(rx);\n      if (m) return m[2];\n      rx = new RegExp('<meta[^>]+content\\\\s*=\\\\s*[\"\\']([^\"\\']+)[\"\\'][^>]*(?:property|name)\\\\s*=\\\\s*[\"\\'](' + key + ')[\"\\']', 'i');\n      m = html.match(rx);\n      return m ? m[1] : '';\n    };\n    title = (extractMeta(html, 'og:title') || extractMeta(html, 'twitter:title') || title).replace(/\\s*[-|].*$/, '').trim();\n    description = extractMeta(html, 'og:description') || extractMeta(html, 'twitter:description') || extractMeta(html, 'description') || description;\n    imageUrl = extractMeta(html, 'og:image') || extractMeta(html, 'twitter:image') || imageUrl;\n    const paras = [];\n    const pRx = /<p[^>]*>([\\s\\S]*?)<\\/p>/gi;\n    let mm;\n    while ((mm = pRx.exec(html)) !== null) {\n      const txt = mm[1].replace(/<[^>]+>/g, '').replace(/&nbsp;/g,' ').replace(/&amp;/g,'&').replace(/&quot;/g,'\"').replace(/&#39;/g,\"'\").trim();\n      if (txt.length > 40) paras.push(txt);\n    }\n    content = paras.join('\\n\\n');\n  } catch (e) {\n    // se fallback falhar, deixa campos como estao\n  }\n}\n\n// Decodificar entidades HTML na URL (ex: &amp; -> &)\nimageUrl = imageUrl.replace(/&amp;/g, '&');\n\n// Se a URL for do gerador de OG do portal (/api/og), extrair a imagem real do parâmetro image=\nif (imageUrl && imageUrl.includes('/api/og')) {\n  const imgParam = imageUrl.match(/[?&]image=([^&]+)/);\n  if (imgParam) imageUrl = decodeURIComponent(imgParam[1]);\n}\n\n// CDN Cloudflare\nif (imageUrl.includes('cdn-cgi/image/')) {\n  const originalMatch = imageUrl.match(/\\/https?:\\/\\/.+$/);\n  if (originalMatch) imageUrl = originalMatch[0].substring(1);\n}\n\n// Fallback imagem no markdown\nif (!imageUrl && content) {\n  const skipPatterns = /logo|social-40|icon|favicon|brand|avatar|banner_site/i;\n  const imgRegex = /!\\[.*?\\]\\((https?:\\/\\/[^\\s)]+\\.(jpg|jpeg|png|webp)[^\\s)]*)\\)/gi;\n  let match;\n  while ((match = imgRegex.exec(content)) !== null) {\n    if (!skipPatterns.test(match[1])) { imageUrl = match[1]; break; }\n  }\n}\n\nconst bodyText = content\n  .replace(/!\\[.*?\\]\\(.*?\\)/g, '')\n  .replace(/\\[([^\\]]+)\\]\\(.*?\\)/g, '$1')\n  .replace(/#{1,6}\\s/g, '')\n  .replace(/[*_]{1,3}/g, '')\n  .replace(/\\n{3,}/g, '\\n\\n')\n  .trim()\n  .substring(0, 3000) || description;\n\nif (!imageUrl || !title || /403 forbidden/i.test(title)) {\n  throw new Error('Falha ao extrair matéria: site bloqueou Jina Reader e fetch direto. Url=' + articleUrl);\n}\n\nreturn [{ json: { url: articleUrl, title, description, imageUrl, bodyText, emailId } }];"},"id":"aab894d9-b32e-46cf-8a06-a99a01e31f86","name":"Extrair Dados da Matéria","type":"n8n-nodes-base.code","typeVersion":2,"position":[1648,304]},{"parameters":{"method":"POST","url":"https://api.openai.com/v1/chat/completions","sendHeaders":true,"headerParameters":{"parameters":[{"name":"Authorization","value":"Bearer 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"},{"name":"Content-Type","value":"application/json"}]},"sendBody":true,"specifyBody":"json","jsonBody":"={{ ({\n  \"model\": \"gpt-4o\",\n  \"temperature\": 0.2,\n  \"max_tokens\": 2048,\n  \"response_format\": { \"type\": \"json_object\" },\n  \"messages\": [\n    {\n      \"role\": \"system\",\n      \"content\": \"Você é editor do portal O Oeirense (Oeiras, Piauí). Sua função é gerar textos jornalísticos a partir de matérias fornecidas.\\n\\nREGRAS INVIOLÁVEIS:\\n1. NUNCA invente datas, dias da semana, horários, nomes de pessoas, cidades ou números. Copie EXATAMENTE do texto fonte.\\n2. Se uma informação NÃO constar no texto fonte, NÃO a mencione.\\n3. O TÍTULO ORIGINAL e a DESCRIÇÃO são as fontes mais confiáveis. O bodyText pode conter trechos de matérias diferentes — use APENAS o que for claramente relacionado ao título.\\n4. Retorne SEMPRE um JSON válido com os campos: chapeu, titulo, subtitulo, legenda.\\n5. Sem markdown, sem negrito, sem hashtags em nenhum campo.\\n\\nESTRATÉGIA EDITORIAL (engajamento):\\n6. ANCORAGEM LOCAL CONDICIONAL: só destaque Oeiras, uma cidade, pessoa ou lugar quando ele for de fato o ASSUNTO da matéria. Se o fato é estadual, nacional ou de outra cidade e não tem ligação direta com Oeiras ou a região, relate o fato como ele é — não force conexão com Oeiras nem invente relevância local. Nunca afirme que algo impacta Oeiras ou os oeirenses se a fonte não trouxer essa ligação.\\n7. TÍTULOS COM GANCHO: quando a matéria tratar de uma cidade, pessoa ou dado numérico específico, prefira começar o título por esse elemento. Quando o fato for amplo ou genérico, faça um título direto sobre o fato, sem forçar um recorte local. Evite aberturas burocráticas como 'Governo anuncia' ou 'Novo programa'.\\n8. LEGENDA ENVOLVENTE: o primeiro parágrafo deve prender a atenção com o fato mais impactante ou surpreendente. Evite abrir com linguagem burocrática ou institucional.\\n9. PERGUNTA FINAL: a pergunta no último parágrafo deve ser específica ao tema da matéria e provocar opinião ou experiência pessoal do leitor. Nunca use perguntas genéricas como 'O que você achou?'.\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": \"Com base na matéria abaixo, gere:\\n\\n1. CHAPÉU: categoria curta (máximo 2 palavras)\\n2. TÍTULO: máximo 80 caracteres, sem ponto final. REGRA: se a matéria TEM COMO FOCO uma cidade do Piauí, pode começar o título pelo nome dela; se tem como foco uma pessoa conhecida, comece pelo nome dela; se tem um número impactante (R$, quantidade, percentual), pode começar por ele. Mas se o assunto é amplo ou de outra localidade, faça um título direto sobre o fato — não force um nome de cidade que não seja o foco. Exemplos bons: 'Oeiras recebe R$ 2,5 milhões para pavimentação', 'Santa Rosa inaugura nova UBS com atendimento 24h'. Exemplos ruins: 'Governo Federal anuncia investimento para cidade do Piauí', 'Novo equipamento é inaugurado em município'.\\n3. SUBTÍTULO: 2 a 3 frases completas com os detalhes mais importantes. MÍNIMO 160 e MÁXIMO 220 caracteres. O leitor deve entender o essencial. Sem ponto final na última frase\\n4. LEGENDA: texto para Instagram. 4 parágrafos:\\n   - P1 (gancho): fato principal com impacto — abra com o dado mais forte ou surpreendente da própria matéria\\n   - P2 (detalhes): contexto e informações complementares\\n   - P3 (significado): por que o fato importa. Se ele afeta Oeiras ou a região, explique esse impacto local; se for de âmbito mais amplo, explique a relevância real do fato sem inventar um efeito local\\n   - P4 (conversa): observação final + pergunta ESPECÍFICA que provoque opinião ou experiência pessoal\\n   Cada parágrafo com 2-3 frases. Sem links, sem CTA genérico, sem hashtags.\\n\\nLEMBRETE: NÃO invente nenhum dado. Use APENAS o que está no texto abaixo.\\n\\nTítulo original: \" + $json.title + \"\\nDescrição: \" + $json.description + \"\\nTexto: \" + ($json.bodyText || '').substring(0, 3000)\n    }\n  ]\n}) }}","options":{}},"id":"57d5fda0-77f8-4a5f-9c75-9775825fae8c","name":"OpenAI - Gerar Textos","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[1888,304]},{"parameters":{"jsCode":"const response = $input.first().json;\nconst content = response.choices[0].message.content;\n\nconst jsonMatch = content.match(/\\{[\\s\\S]*\\}/);\nif (!jsonMatch) throw new Error('JSON não encontrado na resposta da OpenAI: ' + content);\n\nconst parsed = JSON.parse(jsonMatch[0]);\n\nreturn [{\n  json: {\n    chapeu:    parsed.chapeu    || '',\n    titulo:    parsed.titulo    || '',\n    subtitulo: parsed.subtitulo || '',\n    legenda:   parsed.legenda   || '',\n    imageUrl:  $('Extrair Dados da Matéria').first().json.imageUrl,\n    url:       $('Extrair Dados da Matéria').first().json.url,\n    emailId:   $('Extrair Dados da Matéria').first().json.emailId\n  }\n}];"},"id":"78477a9f-5b51-4582-8f8d-17ca8c893219","name":"Parsear Resposta OpenAI","type":"n8n-nodes-base.code","typeVersion":2,"position":[2128,304]},{"parameters":{"url":"={{ $json.imageUrl }}","options":{"response":{"response":{"responseFormat":"file"}}}},"id":"bb000001-0001-0001-0001-000000000001","name":"Baixar Imagem","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[2368,304]},{"parameters":{"jsCode":"const item = $input.first();\nconst binaryKey = Object.keys(item.binary)[0];\nconst binaryMeta = item.binary[binaryKey];\nconst mimeType = binaryMeta.mimeType || 'image/jpeg';\n\n// Debug: mostrar o que binaryMeta contém\nconst metaKeys = Object.keys(binaryMeta);\nconst dataLen = binaryMeta.data ? binaryMeta.data.length : 0;\nconst dataPreview = binaryMeta.data ? binaryMeta.data.substring(0, 120) : 'VAZIO';\n\n// Se data existe e é grande (>500 chars), é base64 real\n// Se é curto, é um ID de filesystem — precisamos do helpers\nlet base64;\n\nif (dataLen > 500) {\n  base64 = binaryMeta.data;\n} else {\n  // Tentar helpers\n  try {\n    const buffer = await this.helpers.getBinaryDataBuffer(0, binaryKey);\n    base64 = buffer.toString('base64');\n  } catch(e) {\n    throw new Error(\n      'Não conseguiu ler binário! ' +\n      'data.length=' + dataLen +\n      ' | data.preview=' + dataPreview +\n      ' | keys=' + metaKeys.join(',') +\n      ' | helpers=' + (typeof this.helpers) +\n      ' | error=' + e.message\n    );\n  }\n}\n\nconst prev = $('Parsear Resposta OpenAI').first().json;\nreturn [{ json: { ...prev, imageBase64: 'data:' + mimeType + ';base64,' + base64 } }];"},"id":"bb000001-0001-0001-0001-000000000002","name":"Converter Base64","type":"n8n-nodes-base.code","typeVersion":2,"position":[2608,304]},{"parameters":{"jsCode":"const prev = $('Parsear Resposta OpenAI').first().json;\nconst { chapeu, titulo, subtitulo, legenda, imageUrl, url, emailId } = prev;\nconst imageBase64 = $json.imageBase64;\n\nconst tLen = (titulo || '').length;\nconst tFS = tLen > 95 ? 46 : tLen > 80 ? 50 : tLen > 60 ? 56 : 62;\nconst sLen = (subtitulo || '').length;\nconst sFS = sLen > 220 ? 28 : sLen > 170 ? 30 : 32;\n\n\nconst html = `<!DOCTYPE html>\n<html lang=\"pt-BR\"><head>\n<meta charset=\"UTF-8\">\n<link href=\"https://fonts.googleapis.com/css2?family=Raleway:wght@400;500;600;700;800;900&display=swap\" rel=\"stylesheet\">\n<style>\n  *{margin:0;padding:0;box-sizing:border-box}\n  html,body{width:1080px;height:1440px;overflow:hidden;font-family:'Raleway',sans-serif;background:#0d1f2d}\n  .post{position:relative;width:1080px;height:1440px;background:#0d1f2d;display:flex;flex-direction:column;overflow:hidden}\n\n  .img-wrap{position:relative;width:100%;height:820px;overflow:hidden;background:#0a0f14;flex-shrink:0}\n  .img-wrap img{width:100%;height:100%;object-fit:cover;object-position:center top;display:block}\n  .img-wrap::after{content:'';position:absolute;left:0;right:0;bottom:0;height:140px;background:linear-gradient(to top,rgba(13,31,45,.35),transparent);pointer-events:none}\n\n  .accent-line{height:4px;width:100%;background:linear-gradient(to right,#127b9d 0%,#3ea081 50%,#62c069 100%);flex-shrink:0}\n\n  .chapeu{position:absolute;left:68px;top:796px;z-index:5;display:inline-flex;align-items:center;gap:14px;padding:14px 28px;background-image:linear-gradient(to right,#127b9d 0%,#3ea081 50%,#62c069 100%);background-size:1080px 100%;background-position:-68px 0;background-repeat:no-repeat;color:#fff;font-size:21px;font-weight:800;letter-spacing:5.2px;text-transform:uppercase;border-radius:4px;box-shadow:0 8px 32px rgba(0,0,0,.35)}\n  .chapeu::before{content:'';width:10px;height:10px;background:#FFDE00;border-radius:50%;flex-shrink:0}\n\n  .content{flex:1;padding:52px 68px 0 68px;display:flex;flex-direction:column;justify-content:flex-start;position:relative;background-color:#0d1f2d;background-image:radial-gradient(circle at 18% 0%,rgba(255,255,255,.035) 0%,transparent 55%)}\n\n  .titulo{font-size:${tFS}px;line-height:1.13;font-weight:900;color:#fff;letter-spacing:-0.6px;margin-bottom:28px;max-width:100%}\n  .subtitulo{font-size:${sFS}px;line-height:1.42;font-weight:400;color:rgba(255,255,255,.72);max-width:100%}\n\n  .footer{position:absolute;bottom:0;left:0;right:0;height:110px;padding:0 68px;display:flex;align-items:center;justify-content:space-between;background:linear-gradient(to right,#127b9d 0%,#3ea081 50%,#62c069 100%)}\n  .footer-url,.footer-handle{font-size:18px;font-weight:700;color:#fff;letter-spacing:0.5px}\n  </style>\n</head>\n<body>\n  <div class=\"post\">\n    <div class=\"img-wrap\"><img src=\"${imageBase64}\"></div>\n    <div class=\"accent-line\"></div>\n    <div class=\"chapeu\">${chapeu}</div>\n    <div class=\"content\">\n      <div>\n        <h1 class=\"titulo\">${titulo}</h1>\n        <p class=\"subtitulo\">${subtitulo}</p>\n      </div>\n      <div class=\"footer\">\n        <span class=\"footer-url\">ooeirense.com.br</span>\n        <span class=\"footer-handle\">@ooeirense</span>\n      </div>\n    </div>\n  </div>\n</body></html>`;\n\nreturn [{ json: { html, chapeu, titulo, subtitulo, legenda, imageUrl, url, emailId } }];"},"id":"7793f67c-b306-4b6d-9c16-3060d84e1512","name":"Montar HTML","type":"n8n-nodes-base.code","typeVersion":2,"position":[2848,304]},{"parameters":{"jsCode":"\nconst html = $json.html;\n\nconst resp = await this.helpers.httpRequest({\n  method: 'POST',\n  url: 'http://127.0.0.1:3099/screenshot',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({ html, width: 1080, height: 1440, filename: `instagram/post_${Date.now()}.png` })\n});\n\nif (!resp.url) throw new Error('Screenshot server erro: ' + JSON.stringify(resp));\nreturn [{ json: { url: resp.url } }];\n"},"id":"f1ac146d-ee8c-4cff-8fdf-2e7d943b43a5","name":"HCTI - HTML para PNG","type":"n8n-nodes-base.code","typeVersion":2,"position":[3088,304],"onError":"continueErrorOutput"},{"parameters":{"jsCode":"// Guarda a URL da imagem gerada e passa os dados anteriores\nconst imagemGerada = $input.first().json.url;\nif (!imagemGerada) throw new Error('HCTI não retornou URL da imagem: ' + JSON.stringify($input.first().json));\n\nreturn [{\n  json: {\n    imagemGerada,\n    legenda:  $('Montar HTML').first().json.legenda,\n    titulo:   $('Montar HTML').first().json.titulo,\n    emailId:  $('Montar HTML').first().json.emailId\n  }\n}];"},"id":"1372e78b-6c7f-42b0-a91f-ad66b241ed49","name":"Capturar URL da Imagem","type":"n8n-nodes-base.code","typeVersion":2,"position":[3328,304]},{"parameters":{"method":"POST","url":"https://graph.facebook.com/v25.0/17841477402712235/media","sendBody":true,"contentType":"form-urlencoded","bodyParameters":{"parameters":[{"name":"image_url","value":"={{ $json.imagemGerada }}"},{"name":"caption","value":"={{ $json.legenda }}"},{"name":"access_token","value":"EAAVw81fCrxUBRLOnGwCYAexfTBk6BLWezW627TNjp4bEQMGBcaCmhWV0TTuNzLl0N9TqDSXniD3ZBSOiwevn9YTXKE7bGBDZBwqAGzRRpeOTmSTEjYvqDZBqV3nv8tLMEKlyCo6Xl23AkX7ZBoJ8t3hjUmh0HIDnIicoFEoEFbOeddWkpxQHHRUnMG0PgQZDZD"}]},"options":{}},"id":"f9194a57-93f8-49e3-ac8a-f1609934aa23","name":"Instagram - Criar Container","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[3568,304],"onError":"continueErrorOutput"},{"parameters":{"amount":30},"id":"cb0968d3-379b-47a3-b7b4-6d117dda59f7","name":"Aguardar Processamento","type":"n8n-nodes-base.wait","typeVersion":1.1,"position":[3808,304],"webhookId":"ooeirense-email-aguardar"},{"parameters":{"method":"POST","url":"https://graph.facebook.com/v25.0/17841477402712235/media_publish","sendBody":true,"contentType":"form-urlencoded","bodyParameters":{"parameters":[{"name":"creation_id","value":"={{ $json.id }}"},{"name":"access_token","value":"EAAVw81fCrxUBRLOnGwCYAexfTBk6BLWezW627TNjp4bEQMGBcaCmhWV0TTuNzLl0N9TqDSXniD3ZBSOiwevn9YTXKE7bGBDZBwqAGzRRpeOTmSTEjYvqDZBqV3nv8tLMEKlyCo6Xl23AkX7ZBoJ8t3hjUmh0HIDnIicoFEoEFbOeddWkpxQHHRUnMG0PgQZDZD"}]},"options":{}},"id":"6ecec3a3-18a2-4479-ad3f-22e0bfd882d4","name":"Instagram - Publicar","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[4048,304],"onError":"continueErrorOutput"},{"parameters":{"jsCode":"const prev = $('Parsear Resposta OpenAI').first().json;\nconst { chapeu, titulo, subtitulo, legenda, imageUrl, url, emailId } = prev;\nconst imageBase64 = $('Converter Base64').first().json.imageBase64;\n\nconst tLen = (titulo || '').length;\nconst tFS = tLen > 95 ? 50 : tLen > 80 ? 56 : tLen > 60 ? 62 : 68;\nconst sLen = (subtitulo || '').length;\nconst sFS = sLen > 220 ? 28 : sLen > 170 ? 30 : 32;\n\n\nconst html = `<!DOCTYPE html>\n<html lang=\"pt-BR\"><head>\n<meta charset=\"UTF-8\">\n<link href=\"https://fonts.googleapis.com/css2?family=Raleway:wght@400;500;600;700;800;900&display=swap\" rel=\"stylesheet\">\n<style>\n  *{margin:0;padding:0;box-sizing:border-box}\n  html,body{width:1080px;height:1920px;overflow:hidden;font-family:'Raleway',sans-serif;background:#0d1f2d}\n  .post{position:relative;width:1080px;height:1920px;background:#0d1f2d;display:flex;flex-direction:column;overflow:hidden}\n\n  .img-wrap{position:relative;width:100%;height:1100px;overflow:hidden;background:#0a0f14;flex-shrink:0}\n  .img-wrap img{width:100%;height:100%;object-fit:cover;object-position:center top;display:block}\n  .img-wrap::after{content:'';position:absolute;left:0;right:0;bottom:0;height:170px;background:linear-gradient(to top,rgba(13,31,45,.35),transparent);pointer-events:none}\n\n  .accent-line{height:4px;width:100%;background:linear-gradient(to right,#127b9d 0%,#3ea081 50%,#62c069 100%);flex-shrink:0}\n\n  .chapeu{position:absolute;left:68px;top:1076px;z-index:5;display:inline-flex;align-items:center;gap:14px;padding:14px 28px;background-image:linear-gradient(to right,#127b9d 0%,#3ea081 50%,#62c069 100%);background-size:1080px 100%;background-position:-68px 0;background-repeat:no-repeat;color:#fff;font-size:21px;font-weight:800;letter-spacing:5.2px;text-transform:uppercase;border-radius:4px;box-shadow:0 8px 32px rgba(0,0,0,.35)}\n  .chapeu::before{content:'';width:10px;height:10px;background:#FFDE00;border-radius:50%;flex-shrink:0}\n\n  .content{flex:1;padding:52px 68px 32px 68px;display:flex;flex-direction:column;position:relative;background-color:#0d1f2d;background-image:radial-gradient(circle at 18% 0%,rgba(255,255,255,.035) 0%,transparent 55%)}\n\n  .titulo{font-size:${tFS}px;line-height:1.13;font-weight:900;color:#fff;letter-spacing:-0.6px;margin-bottom:30px;max-width:100%}\n  .subtitulo{font-size:${sFS}px;line-height:1.45;font-weight:400;color:rgba(255,255,255,.72);max-width:100%}\n  .footer{flex-shrink:0;height:110px;padding:0 68px;display:flex;align-items:center;justify-content:space-between;background:linear-gradient(to right,#127b9d 0%,#3ea081 50%,#62c069 100%)}\n  .footer-url,.footer-handle{font-size:18px;font-weight:700;color:#fff;letter-spacing:0.5px}\n  </style>\n</head>\n<body>\n  <div class=\"post\">\n    <div class=\"img-wrap\"><img src=\"${imageBase64}\"></div>\n    <div class=\"accent-line\"></div>\n    <div class=\"chapeu\">${chapeu}</div>\n    <div class=\"content\">\n      <h1 class=\"titulo\">${titulo}</h1>\n      <p class=\"subtitulo\">${subtitulo}</p>\n    </div>\n    <div class=\"footer\">\n        <span class=\"footer-url\">ooeirense.com.br</span>\n      <span class=\"footer-handle\">@ooeirense</span>\n    </div>\n  </div>\n</body></html>`;\n\nreturn [{ json: { htmlStory: html, chapeu, titulo, subtitulo, legenda, imageUrl, url, emailId } }];"},"id":"eb78bbc3-6f92-491f-a02e-d794a324cd24","name":"Montar HTML Story","type":"n8n-nodes-base.code","typeVersion":2,"position":[4288,304]},{"parameters":{"jsCode":"\nconst html = $json.htmlStory;\n\nconst resp = await this.helpers.httpRequest({\n  method: 'POST',\n  url: 'http://127.0.0.1:3099/screenshot',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({ html, width: 1080, height: 1920, filename: `instagram/story_${Date.now()}.png` })\n});\n\nif (!resp.url) throw new Error('Screenshot server erro: ' + JSON.stringify(resp));\nreturn [{ json: { url: resp.url } }];\n"},"id":"f318a2bf-aa02-4490-ad14-63a79b23bb14","name":"HCTI - Story PNG","type":"n8n-nodes-base.code","typeVersion":2,"position":[4528,304],"onError":"continueErrorOutput"},{"parameters":{"jsCode":"const urlStory = $input.first().json.url;\nif (!urlStory) throw new Error('HCTI não retornou URL do story: ' + JSON.stringify($input.first().json));\nreturn [{ json: { urlStory, emailId: $('Montar HTML Story').first().json.emailId } }];"},"id":"b39c0fe9-31c4-4b1a-9c70-e84be83563bb","name":"Capturar URL Story","type":"n8n-nodes-base.code","typeVersion":2,"position":[4768,304]},{"parameters":{"url":"=https://api.telegram.org/bot8684225036:AAHPUgR6b1y7oN7y5q1FMQ7vcoi3Io9nysE/sendMessage","sendBody":true,"specifyBody":"json","jsonBody":"={{ JSON.stringify({ chat_id: '7769073261', text: '✅ Publicado no @ooeirense!\\n\\n📰 ' + $('Montar HTML').first().json.titulo + '\\n\\nPost + Story publicados com sucesso.', parse_mode: 'HTML' }) }}","options":{}},"id":"tg-confirm","name":"Telegram - Confirmar Publicação","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[5728,304]},{"parameters":{"jsCode":"const prev = $('Extrair URL do Telegram').first().json;\nif (prev.duplicate) { return []; }\nreturn [{ json: { url: prev.url, messageId: prev.messageId } }];"},"id":"pass-url","name":"Repassar URL","type":"n8n-nodes-base.code","typeVersion":2,"position":[1008,304]},{"parameters":{"method":"POST","url":"https://api.telegram.org/bot8684225036:AAHPUgR6b1y7oN7y5q1FMQ7vcoi3Io9nysE/sendMessage","sendBody":true,"specifyBody":"json","jsonBody":"={{ JSON.stringify({ chat_id: '7769073261', text: '❌ <b>Erro ao publicar no @ooeirense</b>\\n\\n' + ($json.error?.message || $json.message || JSON.stringify($json)).substring(0, 300), parse_mode: 'HTML' }) }}","options":{}},"id":"tg-erro-001","name":"Telegram - Erro","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[2896,1296]},{"parameters":{"path":"dispatch-instagram","httpMethod":"POST","responseMode":"onReceived","options":{}},"id":"wh-dispatch-instagram","name":"Webhook Dispatcher","type":"n8n-nodes-base.webhook","typeVersion":2,"position":[208,304],"webhookId":"wh-dispatch-instagram"},{"parameters":{"method":"POST","url":"https://graph.facebook.com/v25.0/17841477402712235/media","sendBody":true,"contentType":"form-urlencoded","bodyParameters":{"parameters":[{"name":"media_type","value":"STORIES"},{"name":"image_url","value":"={{ $json.urlStory }}"},{"name":"access_token","value":"EAAVw81fCrxUBRLOnGwCYAexfTBk6BLWezW627TNjp4bEQMGBcaCmhWV0TTuNzLl0N9TqDSXniD3ZBSOiwevn9YTXKE7bGBDZBwqAGzRRpeOTmSTEjYvqDZBqV3nv8tLMEKlyCo6Xl23AkX7ZBoJ8t3hjUmh0HIDnIicoFEoEFbOeddWkpxQHHRUnMG0PgQZDZD"}]},"options":{}},"id":"story-criar-container","name":"Story - Criar Container","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[5248,304],"onError":"continueErrorOutput"},{"parameters":{"amount":20},"id":"story-aguardar","name":"Story - Aguardar","type":"n8n-nodes-base.wait","typeVersion":1.1,"position":[5488,304],"webhookId":"ooeirense-story-aguardar"},{"parameters":{"method":"POST","url":"https://graph.facebook.com/v25.0/17841477402712235/media_publish","sendBody":true,"contentType":"form-urlencoded","bodyParameters":{"parameters":[{"name":"creation_id","value":"={{ $json.id }}"},{"name":"access_token","value":"EAAVw81fCrxUBRLOnGwCYAexfTBk6BLWezW627TNjp4bEQMGBcaCmhWV0TTuNzLl0N9TqDSXniD3ZBSOiwevn9YTXKE7bGBDZBwqAGzRRpeOTmSTEjYvqDZBqV3nv8tLMEKlyCo6Xl23AkX7ZBoJ8t3hjUmh0HIDnIicoFEoEFbOeddWkpxQHHRUnMG0PgQZDZD"}]},"options":{}},"id":"story-publicar","name":"Story - Publicar","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[5728,304],"onError":"continueErrorOutput"}],"connections":{"Extrair URL do Telegram":{"main":[[{"node":"Repassar URL","type":"main","index":0}]]},"Buscar Matéria":{"main":[[{"node":"Extrair Dados da Matéria","type":"main","index":0}]]},"Extrair Dados da Matéria":{"main":[[{"node":"OpenAI - Gerar Textos","type":"main","index":0}]]},"OpenAI - Gerar Textos":{"main":[[{"node":"Parsear Resposta OpenAI","type":"main","index":0}]]},"Parsear Resposta OpenAI":{"main":[[{"node":"Baixar Imagem","type":"main","index":0}]]},"Baixar Imagem":{"main":[[{"node":"Converter Base64","type":"main","index":0}]]},"Converter Base64":{"main":[[{"node":"Montar HTML","type":"main","index":0}]]},"Montar HTML":{"main":[[{"node":"HCTI - HTML para PNG","type":"main","index":0}]]},"HCTI - HTML para PNG":{"main":[[{"node":"Capturar URL da Imagem","type":"main","index":0}],[{"node":"Telegram - Erro","type":"main","index":0}]]},"Capturar URL da Imagem":{"main":[[{"node":"Instagram - Criar Container","type":"main","index":0}]]},"Instagram - Criar Container":{"main":[[{"node":"Aguardar Processamento","type":"main","index":0}],[{"node":"Telegram - Erro","type":"main","index":0}]]},"Aguardar Processamento":{"main":[[{"node":"Instagram - Publicar","type":"main","index":0}]]},"Instagram - Publicar":{"main":[[{"node":"Montar HTML Story","type":"main","index":0}],[{"node":"Telegram - Erro","type":"main","index":0}]]},"Repassar URL":{"main":[[{"node":"Buscar Matéria","type":"main","index":0}]]},"Webhook Dispatcher":{"main":[[{"node":"Extrair URL do Telegram","type":"main","index":0}]]},"Montar HTML Story":{"main":[[{"node":"HCTI - Story PNG","type":"main","index":0}]]},"HCTI - Story PNG":{"main":[[{"node":"Capturar URL Story","type":"main","index":0}],[{"node":"Telegram - Erro","type":"main","index":0}]]},"Capturar URL Story":{"main":[[{"node":"Story - Criar Container","type":"main","index":0}]]},"Story - Criar Container":{"main":[[{"node":"Story - Aguardar","type":"main","index":0}],[{"node":"Telegram - Erro","type":"main","index":0}]]},"Story - Aguardar":{"main":[[{"node":"Story - Publicar","type":"main","index":0}]]},"Story - Publicar":{"main":[[{"node":"Telegram - Confirmar Publicação","type":"main","index":0}],[{"node":"Telegram - Erro","type":"main","index":0}]]}},"settings":{"executionOrder":"v1","callerPolicy":"workflowsFromSameOwner","availableInMCP":false,"binaryMode":"separate"},"staticData":{"global":{"lastUpdateId":183722663,"seenUrls":{"https://ooeirense.com.br/cidades/a-noticia-mudou-de-endereco-54-ja-se-informam-pelo-meio-digital-37-pela-tv-e-radio-registra-4-da-audiencia-geral":1780843873929}},"node:Poll Telegram":{"recurrenceRules":[]}},"meta":null,"pinData":{},"versionId":"00bb73a4-6125-44e3-ac38-02f1d647406f","activeVersionId":"00bb73a4-6125-44e3-ac38-02f1d647406f","versionCounter":1212,"triggerCount":1,"shared":[{"updatedAt":"2026-04-12T23:18:47.201Z","createdAt":"2026-04-12T23:18:47.201Z","role":"workflow:owner","workflowId":"R1zn1l8zDaVpFSkm","projectId":"lcNbFUrydUsxxeGp","project":{"updatedAt":"2026-05-06T16:07:04.097Z","createdAt":"2026-04-10T15:23:11.499Z","id":"lcNbFUrydUsxxeGp","name":"Ultimo Campos <ultimocampos@gmail.com>","type":"personal","icon":null,"description":null,"creatorId":"7fdfc85d-b5cb-411b-92ad-50cd2ccbad11"}}],"tags":[],"activeVersion":{"updatedAt":"2026-08-21T18:13:02.093Z","createdAt":"2026-08-21T18:13:02.093Z","versionId":"00bb73a4-6125-44e3-ac38-02f1d647406f","workflowId":"R1zn1l8zDaVpFSkm","nodes":[{"parameters":{"jsCode":"const response = $input.first().json.body || $input.first().json;\nconst results = response.result || [];\nif (!results.length) { return []; }\nconst msg = results[0];\nconst updateId = msg.update_id;\nconst newOffset = updateId + 1;\nconst staticData = $getWorkflowStaticData('global');\nstaticData.lastUpdateId = newOffset;\nif (msg.message?.from?.is_bot) { return []; }\nconst chatId = String(msg.message?.chat?.id || '');\nif (chatId !== '7769073261') { return []; }\nconst text = msg.message?.text || '';\nconst trimmed = text.trim();\nconst instaMatch = trimmed.match(/^insta\\s+(https?:\\/\\/[^\\s<>\"'\\)]+)/i);\nif (!instaMatch) { return []; }\nconst url = instaMatch[1];\n\n// DEDUP À PROVA DE RACE — lockfile filesystem via mkdir atômico\nconst { execFileSync } = require('child_process');\nconst LOCK_DIR = '/tmp/ooeirense-seen';\nconst TTL_MIN = 360; // 6h\ntry { execFileSync('/bin/mkdir', ['-p', LOCK_DIR]); } catch(e) {}\n\n// Limpa locks antigos (best-effort, não bloqueia)\ntry {\n  execFileSync('/usr/bin/find', [LOCK_DIR, '-maxdepth', '1', '-mindepth', '1', '-type', 'd', '-mmin', '+' + TTL_MIN, '-exec', '/bin/rm', '-rf', '{}', '+'], { timeout: 2000 });\n} catch(e) {}\n\n// Tenta reivindicar o update_id — mkdir sem -p falha se já existe (atômico no fs)\nconst lockPath = LOCK_DIR + '/u' + updateId;\nlet acquired = false;\ntry {\n  execFileSync('/bin/mkdir', [lockPath]);\n  acquired = true;\n} catch(e) {\n  acquired = false;\n}\nif (!acquired) {\n  return [{ json: { url, messageId: msg.message.message_id, updateId, newOffset, duplicate: true, reason: 'concurrent-lock' } }];\n}\n\nreturn [{ json: { url, messageId: msg.message.message_id, updateId, newOffset, duplicate: false } }];\n"},"id":"tg-extract-url","name":"Extrair URL do Telegram","type":"n8n-nodes-base.code","typeVersion":2,"position":[688,304]},{"parameters":{"url":"={{ 'https://r.jina.ai/' + $json.url }}","sendHeaders":true,"headerParameters":{"parameters":[{"name":"Accept","value":"application/json"},{"name":"User-Agent","value":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"}]},"options":{}},"id":"ce8500de-951a-4cfb-b329-4b16e21e0718","name":"Buscar Matéria","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[1408,304]},{"parameters":{"jsCode":"// Jina Reader retorna: { data: { title, description, url, content, metadata } }\nconst response = $input.first().json;\nconst jinaData = response.data || response;\nconst meta = jinaData.metadata || {};\n\n// Jina devolve ARRAY quando a pagina repete a mesma meta tag (dois plugins de SEO\n// no mesmo WordPress). Ex: portalintegracao.com.br duplica og:title/og:description/og:image.\n// Sem normalizar, .replace/.trim quebram com \"is not a function\".\nconst txt = (v) => {\n  if (Array.isArray(v)) v = v.find(x => typeof x === 'string' && x.trim());\n  return typeof v === 'string' ? v : '';\n};\n\nconst articleUrl = $('Extrair URL do Telegram').first().json.url;\nconst emailId = $('Extrair URL do Telegram').first().json.emailId;\n\nlet title = (txt(meta['og:title']) || txt(jinaData.title) || '').replace(/\\s*[-|].*$/, '').trim();\nlet description = (txt(meta['og:description']) || txt(meta.description) || txt(jinaData.description) || '').trim();\nlet imageUrl = txt(meta['og:image']).trim();\nlet content = txt(jinaData.content);\n\n// Detectar bloqueio do Jina (403 / conteudo vazio / pagina de erro)\nconst jinaBlocked =\n  /403 forbidden|access denied|don't have permission/i.test(title) ||\n  /403 forbidden|don't have permission/i.test(content) ||\n  content.trim().length < 300 ||\n  !imageUrl;\n\nif (jinaBlocked) {\n  try {\n    const html = await this.helpers.httpRequest({\n      method: 'GET',\n      url: articleUrl,\n      headers: {\n        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\n        'Accept-Language': 'pt-BR,pt;q=0.9,en;q=0.8',\n      },\n      returnFullResponse: false,\n    });\n    const extractMeta = (html, key) => {\n      let rx = new RegExp('<meta[^>]+(?:property|name)\\\\s*=\\\\s*[\"\\'](' + key + ')[\"\\'][^>]*content\\\\s*=\\\\s*[\"\\']([^\"\\']+)[\"\\']', 'i');\n      let m = html.match(rx);\n      if (m) return m[2];\n      rx = new RegExp('<meta[^>]+content\\\\s*=\\\\s*[\"\\']([^\"\\']+)[\"\\'][^>]*(?:property|name)\\\\s*=\\\\s*[\"\\'](' + key + ')[\"\\']', 'i');\n      m = html.match(rx);\n      return m ? m[1] : '';\n    };\n    title = (extractMeta(html, 'og:title') || extractMeta(html, 'twitter:title') || title).replace(/\\s*[-|].*$/, '').trim();\n    description = extractMeta(html, 'og:description') || extractMeta(html, 'twitter:description') || extractMeta(html, 'description') || description;\n    imageUrl = extractMeta(html, 'og:image') || extractMeta(html, 'twitter:image') || imageUrl;\n    const paras = [];\n    const pRx = /<p[^>]*>([\\s\\S]*?)<\\/p>/gi;\n    let mm;\n    while ((mm = pRx.exec(html)) !== null) {\n      const txt = mm[1].replace(/<[^>]+>/g, '').replace(/&nbsp;/g,' ').replace(/&amp;/g,'&').replace(/&quot;/g,'\"').replace(/&#39;/g,\"'\").trim();\n      if (txt.length > 40) paras.push(txt);\n    }\n    content = paras.join('\\n\\n');\n  } catch (e) {\n    // se fallback falhar, deixa campos como estao\n  }\n}\n\n// Decodificar entidades HTML na URL (ex: &amp; -> &)\nimageUrl = imageUrl.replace(/&amp;/g, '&');\n\n// Se a URL for do gerador de OG do portal (/api/og), extrair a imagem real do parâmetro image=\nif (imageUrl && imageUrl.includes('/api/og')) {\n  const imgParam = imageUrl.match(/[?&]image=([^&]+)/);\n  if (imgParam) imageUrl = decodeURIComponent(imgParam[1]);\n}\n\n// CDN Cloudflare\nif (imageUrl.includes('cdn-cgi/image/')) {\n  const originalMatch = imageUrl.match(/\\/https?:\\/\\/.+$/);\n  if (originalMatch) imageUrl = originalMatch[0].substring(1);\n}\n\n// Fallback imagem no markdown\nif (!imageUrl && content) {\n  const skipPatterns = /logo|social-40|icon|favicon|brand|avatar|banner_site/i;\n  const imgRegex = /!\\[.*?\\]\\((https?:\\/\\/[^\\s)]+\\.(jpg|jpeg|png|webp)[^\\s)]*)\\)/gi;\n  let match;\n  while ((match = imgRegex.exec(content)) !== null) {\n    if (!skipPatterns.test(match[1])) { imageUrl = match[1]; break; }\n  }\n}\n\nconst bodyText = content\n  .replace(/!\\[.*?\\]\\(.*?\\)/g, '')\n  .replace(/\\[([^\\]]+)\\]\\(.*?\\)/g, '$1')\n  .replace(/#{1,6}\\s/g, '')\n  .replace(/[*_]{1,3}/g, '')\n  .replace(/\\n{3,}/g, '\\n\\n')\n  .trim()\n  .substring(0, 3000) || description;\n\nif (!imageUrl || !title || /403 forbidden/i.test(title)) {\n  throw new Error('Falha ao extrair matéria: site bloqueou Jina Reader e fetch direto. Url=' + articleUrl);\n}\n\nreturn [{ json: { url: articleUrl, title, description, imageUrl, bodyText, emailId } }];"},"id":"aab894d9-b32e-46cf-8a06-a99a01e31f86","name":"Extrair Dados da Matéria","type":"n8n-nodes-base.code","typeVersion":2,"position":[1648,304]},{"parameters":{"method":"POST","url":"https://api.openai.com/v1/chat/completions","sendHeaders":true,"headerParameters":{"parameters":[{"name":"Authorization","value":"Bearer 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"},{"name":"Content-Type","value":"application/json"}]},"sendBody":true,"specifyBody":"json","jsonBody":"={{ ({\n  \"model\": \"gpt-4o\",\n  \"temperature\": 0.2,\n  \"max_tokens\": 2048,\n  \"response_format\": { \"type\": \"json_object\" },\n  \"messages\": [\n    {\n      \"role\": \"system\",\n      \"content\": \"Você é editor do portal O Oeirense (Oeiras, Piauí). Sua função é gerar textos jornalísticos a partir de matérias fornecidas.\\n\\nREGRAS INVIOLÁVEIS:\\n1. NUNCA invente datas, dias da semana, horários, nomes de pessoas, cidades ou números. Copie EXATAMENTE do texto fonte.\\n2. Se uma informação NÃO constar no texto fonte, NÃO a mencione.\\n3. O TÍTULO ORIGINAL e a DESCRIÇÃO são as fontes mais confiáveis. O bodyText pode conter trechos de matérias diferentes — use APENAS o que for claramente relacionado ao título.\\n4. Retorne SEMPRE um JSON válido com os campos: chapeu, titulo, subtitulo, legenda.\\n5. Sem markdown, sem negrito, sem hashtags em nenhum campo.\\n\\nESTRATÉGIA EDITORIAL (engajamento):\\n6. ANCORAGEM LOCAL CONDICIONAL: só destaque Oeiras, uma cidade, pessoa ou lugar quando ele for de fato o ASSUNTO da matéria. Se o fato é estadual, nacional ou de outra cidade e não tem ligação direta com Oeiras ou a região, relate o fato como ele é — não force conexão com Oeiras nem invente relevância local. Nunca afirme que algo impacta Oeiras ou os oeirenses se a fonte não trouxer essa ligação.\\n7. TÍTULOS COM GANCHO: quando a matéria tratar de uma cidade, pessoa ou dado numérico específico, prefira começar o título por esse elemento. Quando o fato for amplo ou genérico, faça um título direto sobre o fato, sem forçar um recorte local. Evite aberturas burocráticas como 'Governo anuncia' ou 'Novo programa'.\\n8. LEGENDA ENVOLVENTE: o primeiro parágrafo deve prender a atenção com o fato mais impactante ou surpreendente. Evite abrir com linguagem burocrática ou institucional.\\n9. PERGUNTA FINAL: a pergunta no último parágrafo deve ser específica ao tema da matéria e provocar opinião ou experiência pessoal do leitor. Nunca use perguntas genéricas como 'O que você achou?'.\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": \"Com base na matéria abaixo, gere:\\n\\n1. CHAPÉU: categoria curta (máximo 2 palavras)\\n2. TÍTULO: máximo 80 caracteres, sem ponto final. REGRA: se a matéria TEM COMO FOCO uma cidade do Piauí, pode começar o título pelo nome dela; se tem como foco uma pessoa conhecida, comece pelo nome dela; se tem um número impactante (R$, quantidade, percentual), pode começar por ele. Mas se o assunto é amplo ou de outra localidade, faça um título direto sobre o fato — não force um nome de cidade que não seja o foco. Exemplos bons: 'Oeiras recebe R$ 2,5 milhões para pavimentação', 'Santa Rosa inaugura nova UBS com atendimento 24h'. Exemplos ruins: 'Governo Federal anuncia investimento para cidade do Piauí', 'Novo equipamento é inaugurado em município'.\\n3. SUBTÍTULO: 2 a 3 frases completas com os detalhes mais importantes. MÍNIMO 160 e MÁXIMO 220 caracteres. O leitor deve entender o essencial. Sem ponto final na última frase\\n4. LEGENDA: texto para Instagram. 4 parágrafos:\\n   - P1 (gancho): fato principal com impacto — abra com o dado mais forte ou surpreendente da própria matéria\\n   - P2 (detalhes): contexto e informações complementares\\n   - P3 (significado): por que o fato importa. Se ele afeta Oeiras ou a região, explique esse impacto local; se for de âmbito mais amplo, explique a relevância real do fato sem inventar um efeito local\\n   - P4 (conversa): observação final + pergunta ESPECÍFICA que provoque opinião ou experiência pessoal\\n   Cada parágrafo com 2-3 frases. Sem links, sem CTA genérico, sem hashtags.\\n\\nLEMBRETE: NÃO invente nenhum dado. Use APENAS o que está no texto abaixo.\\n\\nTítulo original: \" + $json.title + \"\\nDescrição: \" + $json.description + \"\\nTexto: \" + ($json.bodyText || '').substring(0, 3000)\n    }\n  ]\n}) }}","options":{}},"id":"57d5fda0-77f8-4a5f-9c75-9775825fae8c","name":"OpenAI - Gerar Textos","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[1888,304]},{"parameters":{"jsCode":"const response = $input.first().json;\nconst content = response.choices[0].message.content;\n\nconst jsonMatch = content.match(/\\{[\\s\\S]*\\}/);\nif (!jsonMatch) throw new Error('JSON não encontrado na resposta da OpenAI: ' + content);\n\nconst parsed = JSON.parse(jsonMatch[0]);\n\nreturn [{\n  json: {\n    chapeu:    parsed.chapeu    || '',\n    titulo:    parsed.titulo    || '',\n    subtitulo: parsed.subtitulo || '',\n    legenda:   parsed.legenda   || '',\n    imageUrl:  $('Extrair Dados da Matéria').first().json.imageUrl,\n    url:       $('Extrair Dados da Matéria').first().json.url,\n    emailId:   $('Extrair Dados da Matéria').first().json.emailId\n  }\n}];"},"id":"78477a9f-5b51-4582-8f8d-17ca8c893219","name":"Parsear Resposta OpenAI","type":"n8n-nodes-base.code","typeVersion":2,"position":[2128,304]},{"parameters":{"url":"={{ $json.imageUrl }}","options":{"response":{"response":{"responseFormat":"file"}}}},"id":"bb000001-0001-0001-0001-000000000001","name":"Baixar Imagem","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[2368,304]},{"parameters":{"jsCode":"const item = $input.first();\nconst binaryKey = Object.keys(item.binary)[0];\nconst binaryMeta = item.binary[binaryKey];\nconst mimeType = binaryMeta.mimeType || 'image/jpeg';\n\n// Debug: mostrar o que binaryMeta contém\nconst metaKeys = Object.keys(binaryMeta);\nconst dataLen = binaryMeta.data ? binaryMeta.data.length : 0;\nconst dataPreview = binaryMeta.data ? binaryMeta.data.substring(0, 120) : 'VAZIO';\n\n// Se data existe e é grande (>500 chars), é base64 real\n// Se é curto, é um ID de filesystem — precisamos do helpers\nlet base64;\n\nif (dataLen > 500) {\n  base64 = binaryMeta.data;\n} else {\n  // Tentar helpers\n  try {\n    const buffer = await this.helpers.getBinaryDataBuffer(0, binaryKey);\n    base64 = buffer.toString('base64');\n  } catch(e) {\n    throw new Error(\n      'Não conseguiu ler binário! ' +\n      'data.length=' + dataLen +\n      ' | data.preview=' + dataPreview +\n      ' | keys=' + metaKeys.join(',') +\n      ' | helpers=' + (typeof this.helpers) +\n      ' | error=' + e.message\n    );\n  }\n}\n\nconst prev = $('Parsear Resposta OpenAI').first().json;\nreturn [{ json: { ...prev, imageBase64: 'data:' + mimeType + ';base64,' + base64 } }];"},"id":"bb000001-0001-0001-0001-000000000002","name":"Converter Base64","type":"n8n-nodes-base.code","typeVersion":2,"position":[2608,304]},{"parameters":{"jsCode":"const prev = $('Parsear Resposta OpenAI').first().json;\nconst { chapeu, titulo, subtitulo, legenda, imageUrl, url, emailId } = prev;\nconst imageBase64 = $json.imageBase64;\n\nconst tLen = (titulo || '').length;\nconst tFS = tLen > 95 ? 46 : tLen > 80 ? 50 : tLen > 60 ? 56 : 62;\nconst sLen = (subtitulo || '').length;\nconst sFS = sLen > 220 ? 28 : sLen > 170 ? 30 : 32;\n\n\nconst html = `<!DOCTYPE html>\n<html lang=\"pt-BR\"><head>\n<meta charset=\"UTF-8\">\n<link href=\"https://fonts.googleapis.com/css2?family=Raleway:wght@400;500;600;700;800;900&display=swap\" rel=\"stylesheet\">\n<style>\n  *{margin:0;padding:0;box-sizing:border-box}\n  html,body{width:1080px;height:1440px;overflow:hidden;font-family:'Raleway',sans-serif;background:#0d1f2d}\n  .post{position:relative;width:1080px;height:1440px;background:#0d1f2d;display:flex;flex-direction:column;overflow:hidden}\n\n  .img-wrap{position:relative;width:100%;height:820px;overflow:hidden;background:#0a0f14;flex-shrink:0}\n  .img-wrap img{width:100%;height:100%;object-fit:cover;object-position:center top;display:block}\n  .img-wrap::after{content:'';position:absolute;left:0;right:0;bottom:0;height:140px;background:linear-gradient(to top,rgba(13,31,45,.35),transparent);pointer-events:none}\n\n  .accent-line{height:4px;width:100%;background:linear-gradient(to right,#127b9d 0%,#3ea081 50%,#62c069 100%);flex-shrink:0}\n\n  .chapeu{position:absolute;left:68px;top:796px;z-index:5;display:inline-flex;align-items:center;gap:14px;padding:14px 28px;background-image:linear-gradient(to right,#127b9d 0%,#3ea081 50%,#62c069 100%);background-size:1080px 100%;background-position:-68px 0;background-repeat:no-repeat;color:#fff;font-size:21px;font-weight:800;letter-spacing:5.2px;text-transform:uppercase;border-radius:4px;box-shadow:0 8px 32px rgba(0,0,0,.35)}\n  .chapeu::before{content:'';width:10px;height:10px;background:#FFDE00;border-radius:50%;flex-shrink:0}\n\n  .content{flex:1;padding:52px 68px 0 68px;display:flex;flex-direction:column;justify-content:flex-start;position:relative;background-color:#0d1f2d;background-image:radial-gradient(circle at 18% 0%,rgba(255,255,255,.035) 0%,transparent 55%)}\n\n  .titulo{font-size:${tFS}px;line-height:1.13;font-weight:900;color:#fff;letter-spacing:-0.6px;margin-bottom:28px;max-width:100%}\n  .subtitulo{font-size:${sFS}px;line-height:1.42;font-weight:400;color:rgba(255,255,255,.72);max-width:100%}\n\n  .footer{position:absolute;bottom:0;left:0;right:0;height:110px;padding:0 68px;display:flex;align-items:center;justify-content:space-between;background:linear-gradient(to right,#127b9d 0%,#3ea081 50%,#62c069 100%)}\n  .footer-url,.footer-handle{font-size:18px;font-weight:700;color:#fff;letter-spacing:0.5px}\n  </style>\n</head>\n<body>\n  <div class=\"post\">\n    <div class=\"img-wrap\"><img src=\"${imageBase64}\"></div>\n    <div class=\"accent-line\"></div>\n    <div class=\"chapeu\">${chapeu}</div>\n    <div class=\"content\">\n      <div>\n        <h1 class=\"titulo\">${titulo}</h1>\n        <p class=\"subtitulo\">${subtitulo}</p>\n      </div>\n      <div class=\"footer\">\n        <span class=\"footer-url\">ooeirense.com.br</span>\n        <span class=\"footer-handle\">@ooeirense</span>\n      </div>\n    </div>\n  </div>\n</body></html>`;\n\nreturn [{ json: { html, chapeu, titulo, subtitulo, legenda, imageUrl, url, emailId } }];"},"id":"7793f67c-b306-4b6d-9c16-3060d84e1512","name":"Montar HTML","type":"n8n-nodes-base.code","typeVersion":2,"position":[2848,304]},{"parameters":{"jsCode":"\nconst html = $json.html;\n\nconst resp = await this.helpers.httpRequest({\n  method: 'POST',\n  url: 'http://127.0.0.1:3099/screenshot',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({ html, width: 1080, height: 1440, filename: `instagram/post_${Date.now()}.png` })\n});\n\nif (!resp.url) throw new Error('Screenshot server erro: ' + JSON.stringify(resp));\nreturn [{ json: { url: resp.url } }];\n"},"id":"f1ac146d-ee8c-4cff-8fdf-2e7d943b43a5","name":"HCTI - HTML para PNG","type":"n8n-nodes-base.code","typeVersion":2,"position":[3088,304],"onError":"continueErrorOutput"},{"parameters":{"jsCode":"// Guarda a URL da imagem gerada e passa os dados anteriores\nconst imagemGerada = $input.first().json.url;\nif (!imagemGerada) throw new Error('HCTI não retornou URL da imagem: ' + JSON.stringify($input.first().json));\n\nreturn [{\n  json: {\n    imagemGerada,\n    legenda:  $('Montar HTML').first().json.legenda,\n    titulo:   $('Montar HTML').first().json.titulo,\n    emailId:  $('Montar HTML').first().json.emailId\n  }\n}];"},"id":"1372e78b-6c7f-42b0-a91f-ad66b241ed49","name":"Capturar URL da Imagem","type":"n8n-nodes-base.code","typeVersion":2,"position":[3328,304]},{"parameters":{"method":"POST","url":"https://graph.facebook.com/v25.0/17841477402712235/media","sendBody":true,"contentType":"form-urlencoded","bodyParameters":{"parameters":[{"name":"image_url","value":"={{ $json.imagemGerada }}"},{"name":"caption","value":"={{ $json.legenda }}"},{"name":"access_token","value":"EAAVw81fCrxUBRLOnGwCYAexfTBk6BLWezW627TNjp4bEQMGBcaCmhWV0TTuNzLl0N9TqDSXniD3ZBSOiwevn9YTXKE7bGBDZBwqAGzRRpeOTmSTEjYvqDZBqV3nv8tLMEKlyCo6Xl23AkX7ZBoJ8t3hjUmh0HIDnIicoFEoEFbOeddWkpxQHHRUnMG0PgQZDZD"}]},"options":{}},"id":"f9194a57-93f8-49e3-ac8a-f1609934aa23","name":"Instagram - Criar Container","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[3568,304],"onError":"continueErrorOutput"},{"parameters":{"amount":30},"id":"cb0968d3-379b-47a3-b7b4-6d117dda59f7","name":"Aguardar Processamento","type":"n8n-nodes-base.wait","typeVersion":1.1,"position":[3808,304],"webhookId":"ooeirense-email-aguardar"},{"parameters":{"method":"POST","url":"https://graph.facebook.com/v25.0/17841477402712235/media_publish","sendBody":true,"contentType":"form-urlencoded","bodyParameters":{"parameters":[{"name":"creation_id","value":"={{ $json.id }}"},{"name":"access_token","value":"EAAVw81fCrxUBRLOnGwCYAexfTBk6BLWezW627TNjp4bEQMGBcaCmhWV0TTuNzLl0N9TqDSXniD3ZBSOiwevn9YTXKE7bGBDZBwqAGzRRpeOTmSTEjYvqDZBqV3nv8tLMEKlyCo6Xl23AkX7ZBoJ8t3hjUmh0HIDnIicoFEoEFbOeddWkpxQHHRUnMG0PgQZDZD"}]},"options":{}},"id":"6ecec3a3-18a2-4479-ad3f-22e0bfd882d4","name":"Instagram - Publicar","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[4048,304],"onError":"continueErrorOutput"},{"parameters":{"jsCode":"const prev = $('Parsear Resposta OpenAI').first().json;\nconst { chapeu, titulo, subtitulo, legenda, imageUrl, url, emailId } = prev;\nconst imageBase64 = $('Converter Base64').first().json.imageBase64;\n\nconst tLen = (titulo || '').length;\nconst tFS = tLen > 95 ? 50 : tLen > 80 ? 56 : tLen > 60 ? 62 : 68;\nconst sLen = (subtitulo || '').length;\nconst sFS = sLen > 220 ? 28 : sLen > 170 ? 30 : 32;\n\n\nconst html = `<!DOCTYPE html>\n<html lang=\"pt-BR\"><head>\n<meta charset=\"UTF-8\">\n<link href=\"https://fonts.googleapis.com/css2?family=Raleway:wght@400;500;600;700;800;900&display=swap\" rel=\"stylesheet\">\n<style>\n  *{margin:0;padding:0;box-sizing:border-box}\n  html,body{width:1080px;height:1920px;overflow:hidden;font-family:'Raleway',sans-serif;background:#0d1f2d}\n  .post{position:relative;width:1080px;height:1920px;background:#0d1f2d;display:flex;flex-direction:column;overflow:hidden}\n\n  .img-wrap{position:relative;width:100%;height:1100px;overflow:hidden;background:#0a0f14;flex-shrink:0}\n  .img-wrap img{width:100%;height:100%;object-fit:cover;object-position:center top;display:block}\n  .img-wrap::after{content:'';position:absolute;left:0;right:0;bottom:0;height:170px;background:linear-gradient(to top,rgba(13,31,45,.35),transparent);pointer-events:none}\n\n  .accent-line{height:4px;width:100%;background:linear-gradient(to right,#127b9d 0%,#3ea081 50%,#62c069 100%);flex-shrink:0}\n\n  .chapeu{position:absolute;left:68px;top:1076px;z-index:5;display:inline-flex;align-items:center;gap:14px;padding:14px 28px;background-image:linear-gradient(to right,#127b9d 0%,#3ea081 50%,#62c069 100%);background-size:1080px 100%;background-position:-68px 0;background-repeat:no-repeat;color:#fff;font-size:21px;font-weight:800;letter-spacing:5.2px;text-transform:uppercase;border-radius:4px;box-shadow:0 8px 32px rgba(0,0,0,.35)}\n  .chapeu::before{content:'';width:10px;height:10px;background:#FFDE00;border-radius:50%;flex-shrink:0}\n\n  .content{flex:1;padding:52px 68px 32px 68px;display:flex;flex-direction:column;position:relative;background-color:#0d1f2d;background-image:radial-gradient(circle at 18% 0%,rgba(255,255,255,.035) 0%,transparent 55%)}\n\n  .titulo{font-size:${tFS}px;line-height:1.13;font-weight:900;color:#fff;letter-spacing:-0.6px;margin-bottom:30px;max-width:100%}\n  .subtitulo{font-size:${sFS}px;line-height:1.45;font-weight:400;color:rgba(255,255,255,.72);max-width:100%}\n  .footer{flex-shrink:0;height:110px;padding:0 68px;display:flex;align-items:center;justify-content:space-between;background:linear-gradient(to right,#127b9d 0%,#3ea081 50%,#62c069 100%)}\n  .footer-url,.footer-handle{font-size:18px;font-weight:700;color:#fff;letter-spacing:0.5px}\n  </style>\n</head>\n<body>\n  <div class=\"post\">\n    <div class=\"img-wrap\"><img src=\"${imageBase64}\"></div>\n    <div class=\"accent-line\"></div>\n    <div class=\"chapeu\">${chapeu}</div>\n    <div class=\"content\">\n      <h1 class=\"titulo\">${titulo}</h1>\n      <p class=\"subtitulo\">${subtitulo}</p>\n    </div>\n    <div class=\"footer\">\n        <span class=\"footer-url\">ooeirense.com.br</span>\n      <span class=\"footer-handle\">@ooeirense</span>\n    </div>\n  </div>\n</body></html>`;\n\nreturn [{ json: { htmlStory: html, chapeu, titulo, subtitulo, legenda, imageUrl, url, emailId } }];"},"id":"eb78bbc3-6f92-491f-a02e-d794a324cd24","name":"Montar HTML Story","type":"n8n-nodes-base.code","typeVersion":2,"position":[4288,304]},{"parameters":{"jsCode":"\nconst html = $json.htmlStory;\n\nconst resp = await this.helpers.httpRequest({\n  method: 'POST',\n  url: 'http://127.0.0.1:3099/screenshot',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({ html, width: 1080, height: 1920, filename: `instagram/story_${Date.now()}.png` })\n});\n\nif (!resp.url) throw new Error('Screenshot server erro: ' + JSON.stringify(resp));\nreturn [{ json: { url: resp.url } }];\n"},"id":"f318a2bf-aa02-4490-ad14-63a79b23bb14","name":"HCTI - Story PNG","type":"n8n-nodes-base.code","typeVersion":2,"position":[4528,304],"onError":"continueErrorOutput"},{"parameters":{"jsCode":"const urlStory = $input.first().json.url;\nif (!urlStory) throw new Error('HCTI não retornou URL do story: ' + JSON.stringify($input.first().json));\nreturn [{ json: { urlStory, emailId: $('Montar HTML Story').first().json.emailId } }];"},"id":"b39c0fe9-31c4-4b1a-9c70-e84be83563bb","name":"Capturar URL Story","type":"n8n-nodes-base.code","typeVersion":2,"position":[4768,304]},{"parameters":{"url":"=https://api.telegram.org/bot8684225036:AAHPUgR6b1y7oN7y5q1FMQ7vcoi3Io9nysE/sendMessage","sendBody":true,"specifyBody":"json","jsonBody":"={{ JSON.stringify({ chat_id: '7769073261', text: '✅ Publicado no @ooeirense!\\n\\n📰 ' + $('Montar HTML').first().json.titulo + '\\n\\nPost + Story publicados com sucesso.', parse_mode: 'HTML' }) }}","options":{}},"id":"tg-confirm","name":"Telegram - Confirmar Publicação","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[5728,304]},{"parameters":{"jsCode":"const prev = $('Extrair URL do Telegram').first().json;\nif (prev.duplicate) { return []; }\nreturn [{ json: { url: prev.url, messageId: prev.messageId } }];"},"id":"pass-url","name":"Repassar URL","type":"n8n-nodes-base.code","typeVersion":2,"position":[1008,304]},{"parameters":{"method":"POST","url":"https://api.telegram.org/bot8684225036:AAHPUgR6b1y7oN7y5q1FMQ7vcoi3Io9nysE/sendMessage","sendBody":true,"specifyBody":"json","jsonBody":"={{ JSON.stringify({ chat_id: '7769073261', text: '❌ <b>Erro ao publicar no @ooeirense</b>\\n\\n' + ($json.error?.message || $json.message || JSON.stringify($json)).substring(0, 300), parse_mode: 'HTML' }) }}","options":{}},"id":"tg-erro-001","name":"Telegram - Erro","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[2896,1296]},{"parameters":{"path":"dispatch-instagram","httpMethod":"POST","responseMode":"onReceived","options":{}},"id":"wh-dispatch-instagram","name":"Webhook Dispatcher","type":"n8n-nodes-base.webhook","typeVersion":2,"position":[208,304],"webhookId":"wh-dispatch-instagram"},{"parameters":{"method":"POST","url":"https://graph.facebook.com/v25.0/17841477402712235/media","sendBody":true,"contentType":"form-urlencoded","bodyParameters":{"parameters":[{"name":"media_type","value":"STORIES"},{"name":"image_url","value":"={{ $json.urlStory }}"},{"name":"access_token","value":"EAAVw81fCrxUBRLOnGwCYAexfTBk6BLWezW627TNjp4bEQMGBcaCmhWV0TTuNzLl0N9TqDSXniD3ZBSOiwevn9YTXKE7bGBDZBwqAGzRRpeOTmSTEjYvqDZBqV3nv8tLMEKlyCo6Xl23AkX7ZBoJ8t3hjUmh0HIDnIicoFEoEFbOeddWkpxQHHRUnMG0PgQZDZD"}]},"options":{}},"id":"story-criar-container","name":"Story - Criar Container","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[5248,304],"onError":"continueErrorOutput"},{"parameters":{"amount":20},"id":"story-aguardar","name":"Story - Aguardar","type":"n8n-nodes-base.wait","typeVersion":1.1,"position":[5488,304],"webhookId":"ooeirense-story-aguardar"},{"parameters":{"method":"POST","url":"https://graph.facebook.com/v25.0/17841477402712235/media_publish","sendBody":true,"contentType":"form-urlencoded","bodyParameters":{"parameters":[{"name":"creation_id","value":"={{ $json.id }}"},{"name":"access_token","value":"EAAVw81fCrxUBRLOnGwCYAexfTBk6BLWezW627TNjp4bEQMGBcaCmhWV0TTuNzLl0N9TqDSXniD3ZBSOiwevn9YTXKE7bGBDZBwqAGzRRpeOTmSTEjYvqDZBqV3nv8tLMEKlyCo6Xl23AkX7ZBoJ8t3hjUmh0HIDnIicoFEoEFbOeddWkpxQHHRUnMG0PgQZDZD"}]},"options":{}},"id":"story-publicar","name":"Story - Publicar","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[5728,304],"onError":"continueErrorOutput"}],"connections":{"Extrair URL do Telegram":{"main":[[{"node":"Repassar URL","type":"main","index":0}]]},"Buscar Matéria":{"main":[[{"node":"Extrair Dados da Matéria","type":"main","index":0}]]},"Extrair Dados da Matéria":{"main":[[{"node":"OpenAI - Gerar Textos","type":"main","index":0}]]},"OpenAI - Gerar Textos":{"main":[[{"node":"Parsear Resposta OpenAI","type":"main","index":0}]]},"Parsear Resposta OpenAI":{"main":[[{"node":"Baixar Imagem","type":"main","index":0}]]},"Baixar Imagem":{"main":[[{"node":"Converter Base64","type":"main","index":0}]]},"Converter Base64":{"main":[[{"node":"Montar HTML","type":"main","index":0}]]},"Montar HTML":{"main":[[{"node":"HCTI - HTML para PNG","type":"main","index":0}]]},"HCTI - HTML para PNG":{"main":[[{"node":"Capturar URL da Imagem","type":"main","index":0}],[{"node":"Telegram - Erro","type":"main","index":0}]]},"Capturar URL da Imagem":{"main":[[{"node":"Instagram - Criar Container","type":"main","index":0}]]},"Instagram - Criar Container":{"main":[[{"node":"Aguardar Processamento","type":"main","index":0}],[{"node":"Telegram - Erro","type":"main","index":0}]]},"Aguardar Processamento":{"main":[[{"node":"Instagram - Publicar","type":"main","index":0}]]},"Instagram - Publicar":{"main":[[{"node":"Montar HTML Story","type":"main","index":0}],[{"node":"Telegram - Erro","type":"main","index":0}]]},"Repassar URL":{"main":[[{"node":"Buscar Matéria","type":"main","index":0}]]},"Webhook Dispatcher":{"main":[[{"node":"Extrair URL do Telegram","type":"main","index":0}]]},"Montar HTML Story":{"main":[[{"node":"HCTI - Story PNG","type":"main","index":0}]]},"HCTI - Story PNG":{"main":[[{"node":"Capturar URL Story","type":"main","index":0}],[{"node":"Telegram - Erro","type":"main","index":0}]]},"Capturar URL Story":{"main":[[{"node":"Story - Criar Container","type":"main","index":0}]]},"Story - Criar Container":{"main":[[{"node":"Story - Aguardar","type":"main","index":0}],[{"node":"Telegram - Erro","type":"main","index":0}]]},"Story - Aguardar":{"main":[[{"node":"Story - Publicar","type":"main","index":0}]]},"Story - Publicar":{"main":[[{"node":"Telegram - Confirmar Publicação","type":"main","index":0}],[{"node":"Telegram - Erro","type":"main","index":0}]]}},"authors":"Ultimo Campos","name":null,"description":null,"autosaved":false,"workflowPublishHistory":[{"createdAt":"2026-08-21T18:13:02.243Z","id":602,"workflowId":"R1zn1l8zDaVpFSkm","versionId":"00bb73a4-6125-44e3-ac38-02f1d647406f","event":"activated","userId":"7fdfc85d-b5cb-411b-92ad-50cd2ccbad11"},{"createdAt":"2026-08-21T18:13:02.219Z","id":601,"workflowId":"R1zn1l8zDaVpFSkm","versionId":"00bb73a4-6125-44e3-ac38-02f1d647406f","event":"deactivated","userId":"7fdfc85d-b5cb-411b-92ad-50cd2ccbad11"}]}}