2091 lines
82 KiB
JSON
2091 lines
82 KiB
JSON
{
|
|
"name": "pruefen-und-importieren",
|
|
"nodes": [
|
|
{
|
|
"parameters": {},
|
|
"type": "n8n-nodes-base.manualTrigger",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
-460,
|
|
100
|
|
],
|
|
"id": "265263b1-e44a-4457-9478-eab95f7e5a84",
|
|
"name": "Manuell starten"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"httpMethod": "POST",
|
|
"path": "pruefen-und-importieren",
|
|
"responseMode": "onReceived",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.webhook",
|
|
"typeVersion": 2.1,
|
|
"position": [
|
|
-460,
|
|
280
|
|
],
|
|
"id": "94759c20-c550-4bbf-8139-aa61ca8d49e6",
|
|
"name": "Webhook Start",
|
|
"webhookId": "f14cad07-6ef2-4eda-b35c-cd42e5182987"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "manual",
|
|
"assignments": {
|
|
"assignments": [
|
|
{
|
|
"id": "093a0548-c164-4341-8728-d4e268ed4c91",
|
|
"name": "nw_base",
|
|
"value": "https://app.neuronwriter.com/neuron-api/0.5/writer",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "4bef6ac1-2c7a-4c03-b2e3-0d71953ef88b",
|
|
"name": "gitea_base",
|
|
"value": "http://gitea:3000",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "6d54a36c-0259-4ebb-a92b-c247ea98c7ea",
|
|
"name": "gitea_owner",
|
|
"value": "lucas.orth",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "f26c6607-7a45-4f1f-b29f-71a4da8bf754",
|
|
"name": "gitea_repo",
|
|
"value": "Skrift-Auto-Article",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "922c32f4-0897-4834-9640-c96b9af398af",
|
|
"name": "branch",
|
|
"value": "main",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "03f6d42d-170e-469e-88cd-986c1b4e11c8",
|
|
"name": "artikel_ordner",
|
|
"value": "artikel",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "555e09dc-ac0e-47ce-a939-e12f790d6e0d",
|
|
"name": "brief_ordner",
|
|
"value": "briefe",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "99916e7b-ef56-48dc-bda1-83a1e4cc0c13",
|
|
"name": "nachbessern_ordner",
|
|
"value": "nachbessern",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "e6259d17-c43d-42e4-8710-be43daaad6ff",
|
|
"name": "status_pfad",
|
|
"value": "status-importe.json",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "5cbe77f0-5ef3-4082-bdc6-2e7d1bf0427a",
|
|
"name": "wp_base",
|
|
"value": "https://skrift.de",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "5195f907-2616-4f97-9579-891001d25d23",
|
|
"name": "score_ziel",
|
|
"value": "={{ $json.body && $json.body.score_ziel ? Number($json.body.score_ziel) : 65 }}",
|
|
"type": "number"
|
|
},
|
|
{
|
|
"id": "c015b3d5-97b5-4c3c-a61e-33fce56c1a32",
|
|
"name": "pause_zwischen_artikeln",
|
|
"value": 5,
|
|
"type": "number"
|
|
},
|
|
{
|
|
"id": "fa40fab3-f5d1-4b11-9d8c-6c9660e783e9",
|
|
"name": "elementor_ausgabe",
|
|
"value": false,
|
|
"type": "boolean"
|
|
},
|
|
{
|
|
"id": "a929c610-3968-4fb3-8522-798575e1e273",
|
|
"name": "bild_aktiv",
|
|
"value": true,
|
|
"type": "boolean"
|
|
},
|
|
{
|
|
"id": "31d925cf-a15c-4edb-9fcb-9f017f63e7f6",
|
|
"name": "bild_modell",
|
|
"value": "gpt-image-2",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "9ccb1885-18e6-4094-8b3f-ca603d9dfb16",
|
|
"name": "bild_groesse",
|
|
"value": "1200x1200",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "f0730564-27da-4443-821c-606c3e12d174",
|
|
"name": "bild_qualitaet",
|
|
"value": "medium",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "92e2bdbf-47d8-4073-9a18-bdf8828c761b",
|
|
"name": "faq_ueberschrift",
|
|
"value": "Häufige Fragen",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "037987f1-5636-4544-a3da-734e00269da8",
|
|
"name": "benachrichtigung_an",
|
|
"value": "privat@lucas-orth.de",
|
|
"type": "string"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.set",
|
|
"typeVersion": 3.4,
|
|
"position": [
|
|
-240,
|
|
190
|
|
],
|
|
"id": "e619d11b-46f8-41d3-abb5-9f170ca5ac69",
|
|
"name": "Konfiguration"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "={{ $json.gitea_base }}/api/v1/repos/{{ $json.gitea_owner }}/{{ $json.gitea_repo }}/contents/{{ $json.artikel_ordner }}?ref={{ $json.branch }}",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": true,
|
|
"fullResponse": true
|
|
}
|
|
},
|
|
"timeout": 60000
|
|
}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
-20,
|
|
190
|
|
],
|
|
"id": "3f1a8c4e-4928-4e64-abe7-f8e67a322bd1",
|
|
"name": "Artikelordner lesen",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "VOD4JM5zwpSC8wAr",
|
|
"name": "Gitea Skrift Auto Article"
|
|
}
|
|
},
|
|
"retryOnFail": true,
|
|
"maxTries": 3,
|
|
"waitBetweenTries": 3000
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst antwort = $input.first().json;\n// n8n liefert den Koerper bei fullResponse je nach Version als body oder data.\nconst K = (r) => (r && r.body !== undefined) ? r.body : ((r || {}).data);\nconst ka = K(antwort);\nif (antwort.statusCode === 404) {\n return [{ json: { leer: true, grund: 'Ordner \"artikel\" existiert noch nicht im Repo.' } }];\n}\nif (antwort.statusCode !== 200) {\n throw new Error('Artikelordner konnte nicht gelesen werden (HTTP ' + antwort.statusCode\n + '). Antwort: ' + JSON.stringify(ka).slice(0, 400));\n}\nconst dateien = (ka || []).filter(e =>\n e.type === 'file' && /^artikel-.+\\.json$/.test(e.name));\n\nif (!dateien.length) {\n return [{ json: { leer: true, grund: 'Keine Dateien nach Muster artikel-<slug>.json gefunden.' } }];\n}\nreturn dateien.map(d => ({ json: {\n name: d.name, pfad: d.path, sha: d.sha,\n slug: d.name.replace(/^artikel-/, '').replace(/\\.json$/, ''),\n}}));\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
200,
|
|
190
|
|
],
|
|
"id": "8611694a-ff31-4964-b185-0c8a8abd9b5d",
|
|
"name": "Artikeldateien filtern"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "loose",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "fb30d9cc-c4d4-4323-a1e1-b5cb144d6597",
|
|
"leftValue": "={{ $json.leer === true }}",
|
|
"rightValue": "",
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "true",
|
|
"singleValue": true
|
|
}
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"looseTypeValidation": true,
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.2,
|
|
"position": [
|
|
420,
|
|
190
|
|
],
|
|
"id": "5e83eb61-eb78-437c-a57d-7358ccd84312",
|
|
"name": "Artikel vorhanden?"
|
|
},
|
|
{
|
|
"parameters": {},
|
|
"type": "n8n-nodes-base.noOp",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
640,
|
|
40
|
|
],
|
|
"id": "2d130159-cf3c-4932-aca1-bfc5e59ebe84",
|
|
"name": "Nichts zu tun"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"batchSize": 1,
|
|
"options": {
|
|
"reset": false
|
|
}
|
|
},
|
|
"type": "n8n-nodes-base.splitInBatches",
|
|
"typeVersion": 3,
|
|
"position": [
|
|
640,
|
|
320
|
|
],
|
|
"id": "abdbec06-3537-4dc5-8dd6-019e7aa2b24e",
|
|
"name": "Artikel nacheinander"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "={{ $('Konfiguration').first().json.gitea_base }}/api/v1/repos/{{ $('Konfiguration').first().json.gitea_owner }}/{{ $('Konfiguration').first().json.gitea_repo }}/contents/{{ $json.pfad }}?ref={{ $('Konfiguration').first().json.branch }}",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": false
|
|
}
|
|
},
|
|
"timeout": 60000
|
|
}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
900,
|
|
420
|
|
],
|
|
"id": "906172c7-45ac-4348-aee7-197d23d4304d",
|
|
"name": "Artikeldatei laden",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "VOD4JM5zwpSC8wAr",
|
|
"name": "Gitea Skrift Auto Article"
|
|
}
|
|
},
|
|
"onError": "continueErrorOutput",
|
|
"retryOnFail": true,
|
|
"maxTries": 3,
|
|
"waitBetweenTries": 3000
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst a = $('Artikel nacheinander').first().json;\nreturn [{ json: { slug: a.slug, ergebnis: 'fehler', stufe: 'artikel-laden',\n meldung: 'Artikeldatei ' + a.pfad + ' konnte nicht geladen werden: '\n + JSON.stringify($input.first().json).slice(0, 400) }}];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
900,
|
|
640
|
|
],
|
|
"id": "25977511-3ca4-4467-9014-ae013bbc839c",
|
|
"name": "Fehler Artikeldatei",
|
|
"onError": "continueRegularOutput"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "={{ $('Konfiguration').first().json.gitea_base }}/api/v1/repos/{{ $('Konfiguration').first().json.gitea_owner }}/{{ $('Konfiguration').first().json.gitea_repo }}/contents/{{ $('Konfiguration').first().json.brief_ordner }}/brief-{{ $('Artikel nacheinander').first().json.slug }}.json?ref={{ $('Konfiguration').first().json.branch }}",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": true,
|
|
"fullResponse": true
|
|
}
|
|
},
|
|
"timeout": 60000
|
|
}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
1120,
|
|
420
|
|
],
|
|
"id": "df42b00e-6e07-4ffd-83ff-65c061b160af",
|
|
"name": "Brief laden",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "VOD4JM5zwpSC8wAr",
|
|
"name": "Gitea Skrift Auto Article"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "// Stilpruefung: findet typische Muster maschinell wirkender Texte im Deutschen.\n// Wird von gen_wf2.py in den Code-Node \"Artikel pruefen\" eingebettet und ist\n// lokal mit node testbar. Liefert Hinweise, blockiert nichts.\nfunction stilpruefung(artikel) {\n const hinweise = [];\n const add = (art, stelle) => hinweise.push({ art, stelle: String(stelle).slice(0, 140) });\n const ohneTags = (h) => String(h || '').replace(/<[^>]+>/g, ' ').replace(/ /g, ' ').replace(/\\s+/g, ' ').trim();\n\n const html = String(artikel.content_html || '');\n const absaetze = [...html.matchAll(/<p>([\\s\\S]*?)<\\/p>/g)].map(m => ohneTags(m[1])).filter(Boolean);\n const volltext = [ohneTags(artikel.kurzantwort), ohneTags(html),\n ...(Array.isArray(artikel.faq) ? artikel.faq.map(f => ohneTags(f.antwort)) : [])].join(' ');\n\n // 1) Floskeln und Formeln, die in generierten Texten gehaeuft auftreten\n const formeln = [\n ['genau das', 'Formel'], ['genau diese', 'Formel'], ['genau daran', 'Formel'], ['genau so', 'Formel'],\n ['der grund ist', 'Formel'], ['nicht nur', 'Formel \"nicht nur, sondern auch\"'],\n ['entscheidend ist', 'Formel'], ['entscheidend für', 'Formel'], ['größten hebel', 'Formel'],\n ['den unterschied', 'Formel'], ['am ende des tages', 'Floskel'], ['unterm strich', 'Floskel'],\n ['kurz gesagt', 'Floskel'], ['mit anderen worten', 'Floskel'], ['die gute nachricht', 'Floskel'],\n ['spielt eine rolle', 'Floskel'], ['es lohnt sich', 'Floskel'], ['egal ob', 'Formel'],\n ['in diesem artikel', 'Meta-Satz'], ['wir zeigen ihnen', 'Meta-Satz'], ['fazit', 'Zusammenfassung'],\n ['tatsächlich', 'Fuellwort'], ['letztlich', 'Fuellwort'], ['schlicht', 'Fuellwort'], ['simpel', 'Fuellwort'],\n ['erfahrungsgemäß', 'unbelegte Behauptung'], ['in aller regel', 'unbelegte Behauptung'],\n ['studien zeigen', 'unbelegte Behauptung'], ['nachweislich', 'unbelegte Behauptung'],\n ['bekanntlich', 'Floskel'],\n ];\n const klein = volltext.toLowerCase();\n formeln.forEach(([f, art]) => {\n let i = klein.indexOf(f);\n while (i >= 0) {\n add(art + ': \"' + f + '\"', '…' + volltext.slice(Math.max(0, i - 40), i + f.length + 50) + '…');\n i = klein.indexOf(f, i + f.length);\n }\n });\n\n // 2) Aufzaehlungen im Fliesstext\n if (/\\berstens\\b[\\s\\S]*\\bzweitens\\b/i.test(volltext)) add('Aufzaehlung \"Erstens, zweitens\"', 'Im Fliesstext lieber eine echte Liste oder zwei Saetze');\n const dreier = volltext.match(/\\b\\w+(?:ig|lich|ell|bar|iv|sam)\\b, \\w+(?:ig|lich|ell|bar|iv|sam)\\b und \\w+(?:ig|lich|ell|bar|iv|sam)\\b/gi) || [];\n dreier.forEach(d => add('Dreierreihe aus Adjektiven', d));\n\n // 3) Rhetorische Frage im Absatz, direkt beantwortet\n absaetze.forEach(a => {\n const m = a.match(/[^.!?]{8,}\\?\\s+[A-ZÄÖÜ][^.!?]{3,}[.!]/);\n if (m) add('Rhetorische Frage mit Sofortantwort', m[0]);\n });\n\n // 4) Satzlaengen: gleichfoermiger Rhythmus\n const saetze = ohneTags(html).split(/(?<=[.!?])\\s+/).map(s => s.trim())\n .filter(s => s.split(' ').length >= 3);\n const laengen = saetze.map(s => s.split(' ').length);\n if (laengen.length >= 8) {\n const mittel = laengen.reduce((x, y) => x + y, 0) / laengen.length;\n const sd = Math.sqrt(laengen.reduce((x, y) => x + (y - mittel) ** 2, 0) / laengen.length);\n if (sd < 4.5) add('Gleichfoermige Satzlaengen', `Durchschnitt ${mittel.toFixed(1)} Woerter, Streuung nur ${sd.toFixed(1)}. Kurze und lange Saetze mischen.`);\n for (let i = 0; i + 4 <= laengen.length; i++) {\n const fenster = laengen.slice(i, i + 4);\n if (Math.max(...fenster) - Math.min(...fenster) <= 3) {\n add('Vier Saetze gleicher Laenge hintereinander', saetze[i]);\n i += 3;\n }\n }\n }\n\n // 5) Gleiche Satzanfaenge\n for (let i = 0; i + 3 <= saetze.length; i++) {\n const w = saetze.slice(i, i + 3).map(s => s.split(' ')[0].toLowerCase());\n if (w[0] === w[1] && w[1] === w[2] && w[0].length > 2) { add('Drei Saetze mit gleichem Anfang', saetze[i]); i += 2; }\n }\n const anfaenge = {};\n absaetze.forEach(a => { const k = a.split(' ').slice(0, 2).join(' ').toLowerCase(); anfaenge[k] = (anfaenge[k] || 0) + 1; });\n Object.entries(anfaenge).filter(([, n]) => n >= 3).forEach(([k, n]) => add('Absatzanfaenge wiederholen sich', `${n} Absaetze beginnen mit \"${k}\"`));\n\n // 6) Gleich lange Absaetze\n const al = absaetze.map(a => a.split(' ').length).filter(n => n >= 12);\n if (al.length >= 5) {\n const m = al.reduce((x, y) => x + y, 0) / al.length;\n const sd = Math.sqrt(al.reduce((x, y) => x + (y - m) ** 2, 0) / al.length);\n if (sd / m < 0.25) add('Absaetze fast gleich lang', `Durchschnitt ${m.toFixed(0)} Woerter, kaum Abweichung. Einen Absatz bewusst kurz halten.`);\n }\n\n // 7) Praxiswissen: ohne eigene Stichpunkte bleibt der Text generisch\n if (!Array.isArray(artikel.praxis) || artikel.praxis.length === 0) {\n add('Kein Praxiswissen hinterlegt', 'Feld \"praxis\" in artikel-index.json fuellen, dann den Artikel darauf aufbauen');\n }\n\n // 8) Interne Links: primaer auf Business-Leistungsseiten\n const B = 'https://skrift.de/';\n const BUSINESS = ['handgeschriebene-businessbriefe', 'handgeschriebene-postkarten',\n 'unterschriftenservice', 'automatisierte-follow-ups'];\n const NEUTRAL = ['papier-schriftmuster', 'kontakt'];\n const PRIVAT = ['handschrift-fuer-privatpersonen', 'handgeschriebene-private-briefe',\n 'handgeschriebene-private-postkarten'];\n const slugVon = (u) => String(u || '').replace(/^https?:\\/\\/(www\\.)?skrift\\.de\\/?/, '').replace(/\\/.*$/, '');\n const links = [...html.matchAll(/<a\\s[^>]*href=\"([^\"]+)\"/g)].map(m => m[1]);\n const intern = links.filter(u => /^https?:\\/\\/(www\\.)?skrift\\.de/.test(u) || u.startsWith('/'));\n const slugs = intern.map(u => u.startsWith('/') ? u.replace(/^\\/|\\/.*$/g, '') : slugVon(u));\n\n const cta = slugVon(artikel.cta_ziel);\n if (!BUSINESS.includes(cta)) add('Links: CTA-Ziel ist keine Business-Leistungsseite', `cta_ziel \"${artikel.cta_ziel || 'leer'}\", erlaubt: ${BUSINESS.join(', ')}`);\n const ctaAnzahl = slugs.filter(s => s === cta).length;\n if (ctaAnzahl < 1) add('Links: CTA-Ziel nicht verlinkt', 'cta_ziel mindestens einmal im Fliesstext verlinken');\n const bus = slugs.filter(s => BUSINESS.includes(s));\n const priv = slugs.filter(s => PRIVAT.includes(s));\n if (bus.length < 2) add('Links: zu wenige Business-Links', `${bus.length} Link(s) auf Business-Seiten, mindestens 2`);\n if (priv.length) add('Links: Privatkunden-Link im Text', 'Privatkunden-Seiten nicht aus dem Artikeltext verlinken, das uebernimmt das Seitenlayout');\n // Bausteine, die das Seitenlayout bereits liefert\n if (/Auch für Privatpersonen/i.test(html)) add('Baustein doppelt: \"Auch für Privatpersonen.\"', 'Block aus dem Artikeltext entfernen, er steht im Seitenlayout');\n if (/<h[23][^>]*>[^<]*(Muster anfordern|Handschriftmuster)/i.test(html)) add('Baustein doppelt: Muster-CTA', 'Abschnitt \"Kostenloses Handschriftmuster anfordern.\" entfernen, er steht im Seitenlayout');\n const unbekannt = [...new Set(slugs.filter(s => s && !BUSINESS.includes(s) && !NEUTRAL.includes(s) && !PRIVAT.includes(s)))];\n unbekannt.forEach(s => add('Links: kein Linkziel fuer Ratgeber', `/${s}/ (z. B. Dankeseite, Rechtstexte)`));\n\n return hinweise;\n}\n\n\nconst meta = $('Artikel nacheinander').first().json;\nconst artRoh = $('Artikeldatei laden').first().json;\nconst briefAntwort = $input.first().json;\n// n8n liefert den Koerper bei fullResponse je nach Version als body oder data.\nconst K = (r) => (r && r.body !== undefined) ? r.body : ((r || {}).data);\nconst kb = K(briefAntwort);\n\nlet artikel;\ntry { artikel = JSON.parse(Buffer.from(artRoh.content, 'base64').toString('utf8')); }\ncatch (e) { throw new Error('artikel-' + meta.slug + '.json ist kein gueltiges JSON: ' + e.message); }\n\nconst pflicht = ['slug', 'titel', 'query_id', 'kategorie', 'content_html'];\nconst fehlt = pflicht.filter(f => !artikel[f]);\nif (fehlt.length) {\n throw new Error('artikel-' + meta.slug + '.json fehlen Pflichtfelder: ' + fehlt.join(', ')\n + '. Erwartetes Format siehe README Abschnitt \"Vertrag Cowork -> Workflow 2\".');\n}\nif (artikel.slug !== meta.slug) {\n throw new Error('Slug im Dateinamen (' + meta.slug + ') und im JSON (' + artikel.slug + ') stimmen nicht ueberein.');\n}\n\nlet brief = null;\nif (briefAntwort.statusCode === 200 && kb && kb.content) {\n try { brief = JSON.parse(Buffer.from(kb.content, 'base64').toString('utf8')); }\n catch (e) { brief = null; }\n}\n\n// Preise muessen als Shortcode stehen, nie ausgeschrieben.\nconst preisTreffer = [];\nconst re = /(\\d{1,3}(?:[.,]\\d{1,2})?)\\s*(?:€|EUR|Euro)/gi;\nlet m;\nwhile ((m = re.exec(String(artikel.content_html || ''))) !== null) {\n preisTreffer.push(m[0].trim());\n}\nconst shortcodes = (String(artikel.content_html || '').match(/\\[skrift_preis[^\\]]*\\]/g) || []);\n\n// NeuronWriter bewertet nur den uebergebenen Text. Kurzantwort und FAQ stehen\n// aber auf der fertigen Seite, also gehoeren sie in die Bewertung. Der gespeicherte\n// Artikel bleibt unveraendert, das hier ist nur der Pruefkoerper.\nconst faqText = (Array.isArray(artikel.faq) ? artikel.faq : [])\n .map(f => `<h3>${f.frage || ''}</h3><p>${f.antwort || ''}</p>`).join('\\n');\nconst bewertungs_html = [\n artikel.kurzantwort ? `<p>${artikel.kurzantwort}</p>` : '',\n artikel.content_html || '',\n faqText ? `<h2>${artikel.faq_ueberschrift || 'Häufige Fragen'}</h2>\\n${faqText}` : '',\n].filter(Boolean).join('\\n');\n\nconst praxis = Array.isArray(artikel.praxis) && artikel.praxis.length ? artikel.praxis\n : ((brief && brief.artikel && brief.artikel.praxis) || []);\n\nreturn [{ json: { slug: meta.slug, artikel, brief, brief_vorhanden: !!brief,\n bewertungs_html,\n stil_hinweise: stilpruefung({ ...artikel, praxis }),\n preis_warnung: preisTreffer.length\n ? `${preisTreffer.length} ausgeschriebene(r) Preis(e) im Text: ${[...new Set(preisTreffer)].slice(0,5).join(', ')}. `\n + 'Bitte durch [skrift_preis key=\"...\"] ersetzen.'\n : null,\n preis_shortcodes: shortcodes.length } }];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
1340,
|
|
420
|
|
],
|
|
"id": "2432e9d4-90fb-4953-8521-f192cf502473",
|
|
"name": "Artikel pruefen"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "={{ $('Konfiguration').first().json.nw_base }}/evaluate-content",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": false
|
|
}
|
|
},
|
|
"timeout": 60000
|
|
},
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ JSON.stringify({ query: $json.artikel.query_id, html: $json.bewertungs_html || $json.artikel.content_html, title: $json.artikel.seo_titel || $json.artikel.titel, description: $json.artikel.seo_beschreibung || '' }) }}",
|
|
"sendHeaders": true,
|
|
"specifyHeaders": "json",
|
|
"jsonHeaders": "={\"Content-Type\":\"application/json\"}"
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
1560,
|
|
420
|
|
],
|
|
"id": "c775a775-a975-418f-81b2-c23d44ca310c",
|
|
"name": "Score ermitteln",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "U23n2O980GKWocWq",
|
|
"name": "NeuronWriter API"
|
|
}
|
|
},
|
|
"onError": "continueErrorOutput",
|
|
"retryOnFail": true,
|
|
"maxTries": 3,
|
|
"waitBetweenTries": 3000
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst p = $('Artikel pruefen').first().json;\nreturn [{ json: { slug: p.slug, ergebnis: 'fehler', stufe: 'evaluate-content',\n meldung: 'NeuronWriter /evaluate-content fehlgeschlagen. Haeufigste Ursache: query_id \"'\n + p.artikel.query_id + '\" existiert nicht oder gehoert zu einem anderen Projekt. Antwort: '\n + JSON.stringify($input.first().json).slice(0, 400) }}];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
1560,
|
|
640
|
|
],
|
|
"id": "03075c45-9d02-48f5-b176-94cdb509d866",
|
|
"name": "Fehler Score",
|
|
"onError": "continueRegularOutput"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst p = $('Artikel pruefen').first().json;\nconst e = $input.first().json;\nconst ziel = $('Konfiguration').first().json.score_ziel;\n\nif (typeof e.content_score !== 'number') {\n throw new Error('NeuronWriter lieferte kein numerisches content_score. Antwort: '\n + JSON.stringify(e).slice(0, 300));\n}\nreturn [{ json: { ...p, score: e.content_score, score_ziel: ziel, bestanden: e.content_score >= ziel } }];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
1780,
|
|
420
|
|
],
|
|
"id": "3e90f007-8d26-494c-ade0-ee58db39ad39",
|
|
"name": "Score auswerten"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "loose",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "009ffbe7-01c0-461c-b28d-b745c4d60afa",
|
|
"leftValue": "={{ $json.bestanden }}",
|
|
"rightValue": "",
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "true",
|
|
"singleValue": true
|
|
}
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"looseTypeValidation": true,
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.2,
|
|
"position": [
|
|
2000,
|
|
420
|
|
],
|
|
"id": "19ff7716-5710-41d6-bfd7-4fe08bd16cb7",
|
|
"name": "Score erreicht?"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\n// /evaluate-content liefert nur {status, content_score}, keine Begriffsliste.\n// Die Luecken werden deshalb gegen den Brief aus Workflow 1 selbst berechnet.\nconst s = $input.first().json;\nconst brief = s.brief;\n\nconst text = String(s.bewertungs_html || s.artikel.content_html || '')\n .replace(/<script[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, ' ')\n .replace(/<[^>]+>/g, ' ')\n .replace(/ /g, ' ')\n .replace(/\\s+/g, ' ')\n .toLowerCase();\n\nconst zaehle = (begriff) => {\n const b = String(begriff).toLowerCase().trim();\n if (!b) return 0;\n return text.split(b).length - 1;\n};\n\nconst pruefe = (liste) => (liste || []).map(e => {\n const ist = zaehle(e.begriff);\n const min = e.min ?? 1;\n return { begriff: e.begriff, soll_min: min, soll_max: e.max ?? null, ist,\n fehlt: ist < min, luecke: Math.max(0, min - ist) };\n});\n\nlet pflicht = [], erweitert = [], fragen_offen = [];\nif (brief) {\n pflicht = pruefe(brief.begriffe_pflicht).filter(x => x.fehlt);\n erweitert = pruefe(brief.begriffe_erweitert).filter(x => x.fehlt);\n fragen_offen = (brief.fragen || [])\n .filter(f => f.gewicht && f.gewicht >= 6)\n .filter(f => {\n const kern = String(f.frage).toLowerCase()\n .replace(/[?.,!]/g, '').split(' ').filter(w => w.length > 5).slice(0, 3);\n return kern.length ? !kern.every(w => text.includes(w)) : false;\n })\n .map(f => ({ frage: f.frage, gewicht: f.gewicht }));\n}\n\nconst woerter = text.split(' ').filter(Boolean).length;\n\nconst bericht = {\n slug: s.slug,\n titel: s.artikel.titel,\n query_id: s.artikel.query_id,\n score: s.score,\n score_ziel: s.score_ziel,\n geprueft_am: new Date().toISOString(),\n brief_vorhanden: s.brief_vorhanden,\n wortzahl: { ist: woerter, ziel: brief ? brief.wortzahl_ziel : null,\n differenz: brief && brief.wortzahl_ziel ? woerter - brief.wortzahl_ziel : null },\n fehlende_pflichtbegriffe: pflicht,\n fehlende_zusatzbegriffe: erweitert,\n unbeantwortete_fragen: fragen_offen,\n stil_hinweise: s.stil_hinweise || [],\n hinweis: s.brief_vorhanden\n ? 'Begriffe gegen briefe/brief-' + s.slug + '.json abgeglichen. Zaehlung als Teilstring, Komposita zaehlen mit.'\n : 'Kein Brief gefunden, daher nur der Score. Workflow 1 fuer diesen Slug erneut laufen lassen.',\n regel: 'Pflichtbegriffe sind verbindlich. Zusatzbegriffe nur einbauen, wenn der Satz dadurch nicht schlechter wird. Keine Saetze nur fuer den Score.',\n};\n\nconst konf = $('Konfiguration').first().json;\nreturn [{ json: { slug: s.slug, score: s.score, bericht,\n pfad: konf.nachbessern_ordner + '/nachbessern-' + s.slug + '.json',\n anzahl_pflicht: pflicht.length, anzahl_erweitert: erweitert.length }}];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
2220,
|
|
640
|
|
],
|
|
"id": "702f39bc-8886-42e5-a8dd-affd032569dd",
|
|
"name": "Fehlende Begriffe ermitteln"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "={{ $('Konfiguration').first().json.gitea_base }}/api/v1/repos/{{ $('Konfiguration').first().json.gitea_owner }}/{{ $('Konfiguration').first().json.gitea_repo }}/contents/{{ $json.pfad }}?ref={{ $('Konfiguration').first().json.branch }}",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": true,
|
|
"fullResponse": true
|
|
}
|
|
},
|
|
"timeout": 60000
|
|
}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
2440,
|
|
640
|
|
],
|
|
"id": "174bc5e0-168e-40ce-9486-d91f4e5cf91b",
|
|
"name": "Nachbesserung vorhanden?",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "VOD4JM5zwpSC8wAr",
|
|
"name": "Gitea Skrift Auto Article"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst n = $('Fehlende Begriffe ermitteln').first().json;\nconst p = $input.first().json;\n// n8n liefert den Koerper bei fullResponse je nach Version als body oder data.\nconst K = (r) => (r && r.body !== undefined) ? r.body : ((r || {}).data);\nconst kp = K(p);\nconst da = p.statusCode === 200 && kp && kp.sha;\nconst konf = $('Konfiguration').first().json;\nreturn [{ json: { ...n, methode: da ? 'PUT' : 'POST', commit_body: JSON.stringify({\n content: Buffer.from(JSON.stringify(n.bericht, null, 2), 'utf8').toString('base64'),\n message: `Nachbesserung ${n.slug}: Score ${n.score} unter Ziel`,\n branch: konf.branch, ...(da ? { sha: kp.sha } : {}),\n})}}];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
2660,
|
|
640
|
|
],
|
|
"id": "eaab366d-7814-47c6-9aa9-04f4637918a1",
|
|
"name": "Nachbesserung vorbereiten"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "={{ $json.methode }}",
|
|
"url": "={{ $('Konfiguration').first().json.gitea_base }}/api/v1/repos/{{ $('Konfiguration').first().json.gitea_owner }}/{{ $('Konfiguration').first().json.gitea_repo }}/contents/{{ $json.pfad }}",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": false
|
|
}
|
|
},
|
|
"timeout": 60000
|
|
},
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ $json.commit_body }}",
|
|
"sendHeaders": true,
|
|
"specifyHeaders": "json",
|
|
"jsonHeaders": "={\"Content-Type\":\"application/json\"}"
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
2880,
|
|
640
|
|
],
|
|
"id": "7d2e670b-6bcd-4240-90b2-27ef59f54dcc",
|
|
"name": "Nachbesserung committen",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "VOD4JM5zwpSC8wAr",
|
|
"name": "Gitea Skrift Auto Article"
|
|
}
|
|
},
|
|
"onError": "continueErrorOutput",
|
|
"retryOnFail": true,
|
|
"maxTries": 3,
|
|
"waitBetweenTries": 3000
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst n = $('Fehlende Begriffe ermitteln').first().json;\nreturn [{ json: { slug: n.slug, ergebnis: 'fehler', stufe: 'nachbessern-commit', score: n.score,\n meldung: 'Nachbesserungsdatei konnte nicht geschrieben werden: '\n + JSON.stringify($input.first().json).slice(0, 400) }}];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
2880,
|
|
860
|
|
],
|
|
"id": "c903692e-805d-4034-9555-651a6b0f2779",
|
|
"name": "Fehler Nachbesserung",
|
|
"onError": "continueRegularOutput"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst n = $('Fehlende Begriffe ermitteln').first().json;\nconst p = $('Artikel pruefen').first().json;\nreturn [{ json: { slug: n.slug, ergebnis: 'nachbessern', score: n.score,\n preis_warnung: p.preis_warnung || null,\n stil_hinweise: p.stil_hinweise || [],\n score_ziel: n.bericht.score_ziel, pfad: n.pfad,\n anzahl_pflicht: n.anzahl_pflicht, anzahl_erweitert: n.anzahl_erweitert,\n wortzahl: n.bericht.wortzahl,\n meldung: `Score ${n.score} unter Ziel ${n.bericht.score_ziel}. `\n + `${n.anzahl_pflicht} Pflichtbegriffe fehlen, ${n.anzahl_erweitert} Zusatzbegriffe.` }}];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
3100,
|
|
640
|
|
],
|
|
"id": "971c9f49-930f-4876-913c-d5bfb060826e",
|
|
"name": "Nachbesserung gemerkt"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "={{ $('Konfiguration').first().json.nw_base }}/import-content",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": false
|
|
}
|
|
},
|
|
"timeout": 60000
|
|
},
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ JSON.stringify({ query: $json.artikel.query_id, html: $json.bewertungs_html || $json.artikel.content_html, title: $json.artikel.seo_titel || $json.artikel.titel, description: $json.artikel.seo_beschreibung || '' }) }}",
|
|
"sendHeaders": true,
|
|
"specifyHeaders": "json",
|
|
"jsonHeaders": "={\"Content-Type\":\"application/json\"}"
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
2220,
|
|
240
|
|
],
|
|
"id": "ad73443d-79ec-418f-b9cb-422d73d71b40",
|
|
"name": "Revision zu NeuronWriter",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "U23n2O980GKWocWq",
|
|
"name": "NeuronWriter API"
|
|
}
|
|
},
|
|
"onError": "continueErrorOutput",
|
|
"retryOnFail": true,
|
|
"maxTries": 3,
|
|
"waitBetweenTries": 3000
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst s = $('Score auswerten').first().json;\nreturn [{ json: { ...s, import_warnung: 'Revision konnte nicht zu NeuronWriter gespeichert werden: '\n + JSON.stringify($input.first().json).slice(0, 300) }}];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
2220,
|
|
60
|
|
],
|
|
"id": "90c1cd8b-44f7-40e9-80cc-407e6d4ccb9e",
|
|
"name": "Fehler Revision",
|
|
"onError": "continueRegularOutput"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "={{ $('Konfiguration').first().json.wp_base }}/wp-json/wp/v2/posts?slug={{ $('Score auswerten').first().json.slug }}&status=publish,draft,pending,future,private&context=edit",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpBasicAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": true,
|
|
"fullResponse": true
|
|
}
|
|
},
|
|
"timeout": 60000
|
|
}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
2440,
|
|
240
|
|
],
|
|
"id": "9a6eaa50-09b1-4e68-a06f-74471a6e075c",
|
|
"name": "Beitrag vorhanden?",
|
|
"credentials": {
|
|
"httpBasicAuth": {
|
|
"id": "WIN05TZgM0K5VOGy",
|
|
"name": "WP skrift.de Redakteur"
|
|
}
|
|
},
|
|
"retryOnFail": true,
|
|
"maxTries": 3,
|
|
"waitBetweenTries": 3000
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "={{ $('Konfiguration').first().json.wp_base }}/wp-json/wp/v2/categories?search={{ encodeURIComponent($('Score auswerten').first().json.artikel.kategorie) }}&per_page=100",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpBasicAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": true,
|
|
"fullResponse": true
|
|
}
|
|
},
|
|
"timeout": 60000
|
|
}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
2660,
|
|
240
|
|
],
|
|
"id": "9d7d2fca-b517-43c5-a031-c123e52985da",
|
|
"name": "Kategorie suchen",
|
|
"credentials": {
|
|
"httpBasicAuth": {
|
|
"id": "WIN05TZgM0K5VOGy",
|
|
"name": "WP skrift.de Redakteur"
|
|
}
|
|
},
|
|
"retryOnFail": true,
|
|
"maxTries": 3,
|
|
"waitBetweenTries": 3000
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst s = $('Score auswerten').first().json;\nconst gesucht = String(s.artikel.kategorie).trim();\nconst antwort = $input.first().json;\n// n8n liefert den Koerper bei fullResponse je nach Version als body oder data.\nconst K = (r) => (r && r.body !== undefined) ? r.body : ((r || {}).data);\nconst ka = K(antwort);\nconst treffer = (antwort.statusCode === 200 && Array.isArray(ka))\n ? ka.find(c => c.name.toLowerCase() === gesucht.toLowerCase()) : null;\nreturn [{ json: { ...s, kategorie_id: treffer ? treffer.id : null,\n kategorie_name: gesucht, kategorie_fehlt: !treffer } }];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
2880,
|
|
240
|
|
],
|
|
"id": "f175da94-e137-4fac-b2e6-f38ef4d3e9b8",
|
|
"name": "Kategorie pruefen"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "loose",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "c553d779-7e48-4b1b-8808-1c2ff31737f0",
|
|
"leftValue": "={{ $json.kategorie_fehlt }}",
|
|
"rightValue": "",
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "true",
|
|
"singleValue": true
|
|
}
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"looseTypeValidation": true,
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.2,
|
|
"position": [
|
|
3100,
|
|
240
|
|
],
|
|
"id": "a9b527e8-a341-4a47-a6a3-261e54d3efac",
|
|
"name": "Kategorie anlegen?"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "={{ $('Konfiguration').first().json.wp_base }}/wp-json/wp/v2/categories",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpBasicAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": false
|
|
}
|
|
},
|
|
"timeout": 60000
|
|
},
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ JSON.stringify({ name: $json.kategorie_name }) }}",
|
|
"sendHeaders": true,
|
|
"specifyHeaders": "json",
|
|
"jsonHeaders": "={\"Content-Type\":\"application/json\"}"
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
3320,
|
|
140
|
|
],
|
|
"id": "1f2a04e4-0625-4ce5-a6d9-49737ccb7c85",
|
|
"name": "Kategorie anlegen",
|
|
"credentials": {
|
|
"httpBasicAuth": {
|
|
"id": "WIN05TZgM0K5VOGy",
|
|
"name": "WP skrift.de Redakteur"
|
|
}
|
|
},
|
|
"retryOnFail": true,
|
|
"maxTries": 3,
|
|
"waitBetweenTries": 3000
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst s = $('Kategorie pruefen').first().json;\nconst e = $input.first().json;\nconst id = s.kategorie_id || e.id || null;\nif (!id) {\n throw new Error('Kategorie \"' + s.kategorie_name + '\" konnte weder gefunden noch angelegt werden. '\n + 'Antwort: ' + JSON.stringify(e).slice(0, 300));\n}\nreturn [{ json: { ...s, kategorie_id: id } }];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
3540,
|
|
240
|
|
],
|
|
"id": "7eb5e79b-817e-4e7a-bc4b-6d8dfc32fc61",
|
|
"name": "Kategorie festlegen"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst s = $input.first().json;\nconst dup = $('Beitrag vorhanden?').first().json;\nconst a = s.artikel;\n\n// Duplikatspruefung: exakter Slug-Treffer entscheidet ueber anlegen oder aktualisieren.\n// n8n liefert den Koerper bei fullResponse je nach Version als body oder data.\nconst K = (r) => (r && r.body !== undefined) ? r.body : ((r || {}).data);\nconst kd = K(dup);\nconst treffer = (dup.statusCode === 200 && Array.isArray(kd))\n ? kd.find(p => p.slug === s.slug) : null;\n\nconst heute = new Date().toISOString().slice(0, 10);\n\nconst meta = {\n kurzantwort: a.kurzantwort || '',\n faq_ueberschrift: a.faq_ueberschrift || '',\n cta_ziel: a.cta_ziel || '',\n stand_datum: a.stand_datum || heute,\n faq: Array.isArray(a.faq)\n ? a.faq.filter(f => f && f.frage).map(f => ({ frage: String(f.frage), antwort: String(f.antwort || '') }))\n : [],\n _seopress_titles_title: a.seo_titel || a.titel,\n _seopress_titles_desc: a.seo_beschreibung || '',\n _seopress_analysis_target_kw: a.keyword || '',\n};\n\n// --- Elementor-Struktur aus Artikel und FAQ ---\n// Zerlegt den Text an den H2-Grenzen in Text-Editor-Widgets und haengt das FAQ\n// als nested-accordion an, dasselbe Widget wie auf den Leistungsseiten.\nconst konf = $('Konfiguration').first().json;\nconst eid = () => Math.random().toString(16).slice(2, 9);\nconst textWidget = (h) => ({ id: eid(), elType: 'widget', settings: { editor: h },\n elements: [], widgetType: 'text-editor' });\nconst behaelter = (kinder, innen) => {\n const s = { content_width: 'full' };\n if (innen) Object.assign(s, {\n _title: 'Element',\n padding: { unit: 'px', top: '8', right: '8', bottom: '8', left: '8', isLinked: true },\n flex_gap: { column: '20', row: '20', isLinked: true, unit: 'px', size: 20 },\n });\n const c = { id: eid(), elType: 'container', settings: s, elements: kinder };\n if (innen) { c.isInner = true; c.isLocked = true; }\n return c;\n};\n\nfunction elementorBauen() {\n const wurzel = [];\n if (a.kurzantwort) {\n wurzel.push(behaelter([textWidget(\n `<div class=\"skrift-kurzantwort\"><p>${a.kurzantwort}</p></div>`)]));\n }\n const html = String(a.content_html || '');\n const stellen = [];\n const re2 = /<h2[ >]/g;\n let mm;\n while ((mm = re2.exec(html)) !== null) stellen.push(mm.index);\n const bloecke = [];\n if (!stellen.length) {\n if (html.trim()) bloecke.push(html.trim());\n } else {\n if (stellen[0] > 0 && html.slice(0, stellen[0]).trim()) bloecke.push(html.slice(0, stellen[0]).trim());\n stellen.forEach((s, i) => {\n const ende = i + 1 < stellen.length ? stellen[i + 1] : html.length;\n const b = html.slice(s, ende).trim();\n if (b) bloecke.push(b);\n });\n }\n bloecke.forEach(b => wurzel.push(behaelter([textWidget(b)])));\n\n if (meta.faq.length) {\n const items = [], kinder = [];\n meta.faq.forEach(f => {\n items.push({ item_title: f.frage, _id: eid() });\n kinder.push(behaelter([textWidget(`<p>${f.antwort || ''}</p>`)], true));\n });\n wurzel.push(behaelter([\n textWidget(`<h2>${konf.faq_ueberschrift || 'Häufige Fragen'}</h2>`),\n { id: eid(), elType: 'widget', widgetType: 'nested-accordion',\n settings: { items, faq_schema: 'yes', default_state: 'all_collapsed' },\n elements: kinder },\n ]));\n }\n return wurzel;\n}\n\nif (konf.elementor_ausgabe) {\n meta._elementor_data = JSON.stringify(elementorBauen());\n meta._elementor_edit_mode = 'builder';\n meta._elementor_template_type = 'wp-post';\n}\n\nconst body = {\n title: a.titel,\n slug: s.slug,\n content: a.content_html,\n status: 'draft', // harte Vorgabe: nie automatisch veroeffentlichen\n categories: [s.kategorie_id],\n meta,\n};\nif (a.auszug) body.excerpt = a.auszug;\n\nreturn [{ json: {\n ...s,\n vorhanden: !!treffer,\n post_id: treffer ? treffer.id : null,\n alter_status: treffer ? treffer.status : null,\n wp_url: treffer\n ? `${$('Konfiguration').first().json.wp_base}/wp-json/wp/v2/posts/${treffer.id}`\n : `${$('Konfiguration').first().json.wp_base}/wp-json/wp/v2/posts`,\n wp_body: JSON.stringify(body),\n}}];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
3760,
|
|
240
|
|
],
|
|
"id": "3e24c6b8-d0b0-4983-a06c-1183918148bb",
|
|
"name": "WordPress-Body bauen"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "={{ $json.wp_url }}",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpBasicAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": false
|
|
}
|
|
},
|
|
"timeout": 60000
|
|
},
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ $json.wp_body }}",
|
|
"sendHeaders": true,
|
|
"specifyHeaders": "json",
|
|
"jsonHeaders": "={\"Content-Type\":\"application/json\"}"
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
3980,
|
|
240
|
|
],
|
|
"id": "e05040a1-66fe-467f-87d7-f8985acb2191",
|
|
"name": "Beitrag anlegen oder aktualisieren",
|
|
"credentials": {
|
|
"httpBasicAuth": {
|
|
"id": "WIN05TZgM0K5VOGy",
|
|
"name": "WP skrift.de Redakteur"
|
|
}
|
|
},
|
|
"retryOnFail": true,
|
|
"maxTries": 3,
|
|
"waitBetweenTries": 3000
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst v = $('WordPress-Body bauen').first().json;\nconst p = $input.first().json;\n\nif (!p.id) {\n throw new Error('WordPress lieferte keine Beitrags-ID zurueck. Antwort: '\n + JSON.stringify(p).slice(0, 400));\n}\nif (p.status !== 'draft') {\n throw new Error('Beitrag ' + p.id + ' hat Status \"' + p.status\n + '\" statt \"draft\". Der Workflow darf nie veroeffentlichen. Bitte pruefen.');\n}\n\n// Gegenprobe: sind die Meta-Felder wirklich angekommen?\nconst m = p.meta || {};\nconst fehlend = ['kurzantwort', 'cta_ziel', 'stand_datum', 'faq']\n .filter(k => m[k] === undefined);\nconst faq_ok = Array.isArray(m.faq) ? m.faq.length : -1;\n\nconst konf = $('Konfiguration').first().json;\nreturn [{ json: {\n slug: v.slug, ergebnis: 'importiert', score: v.score, score_ziel: v.score_ziel,\n post_id: p.id, featured_media: p.featured_media || 0, aktion: v.vorhanden ? 'aktualisiert' : 'neu angelegt',\n alter_status: v.alter_status, status: p.status,\n kategorie: v.kategorie_name, kategorie_id: v.kategorie_id,\n vorschau_url: `${konf.wp_base}/?p=${p.id}&preview=true`,\n bearbeiten_url: `${konf.wp_base}/wp-admin/post.php?post=${p.id}&action=edit`,\n meta_warnung: fehlend.length\n ? 'Diese Meta-Felder kamen nicht zurueck: ' + fehlend.join(', ')\n + '. Mu-Plugin skrift-ratgeber-felder.php installiert?'\n : null,\n faq_eintraege: faq_ok,\n elementor: (p.meta || {})._elementor_edit_mode === 'builder'\n ? (() => { try { return JSON.parse((p.meta || {})._elementor_data || '[]').length + ' Container'; }\n catch (e) { return 'ungueltig'; } })()\n : 'klassischer Inhalt',\n seo_titel: (p.meta || {})._seopress_titles_title || null,\n preis_warnung: v.preis_warnung || null,\n stil_hinweise: v.stil_hinweise || [],\n preis_shortcodes: v.preis_shortcodes || 0,\n}}];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
4200,
|
|
240
|
|
],
|
|
"id": "e6ff477c-cd6e-4d7d-8737-5cc4f69f6fb8",
|
|
"name": "Ergebnis pruefen"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "={{ $('Konfiguration').first().json.wp_base }}/wp-json/seopress/v1/commands/clear-cache",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpBasicAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": true,
|
|
"fullResponse": true
|
|
}
|
|
},
|
|
"timeout": 30000
|
|
},
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ JSON.stringify({}) }}",
|
|
"sendHeaders": true,
|
|
"specifyHeaders": "json",
|
|
"jsonHeaders": "={\"Content-Type\":\"application/json\"}"
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
4420,
|
|
240
|
|
],
|
|
"id": "293acc6c-2693-4cd7-a21a-3edc80a803f2",
|
|
"name": "Cache leeren",
|
|
"credentials": {
|
|
"httpBasicAuth": {
|
|
"id": "WIN05TZgM0K5VOGy",
|
|
"name": "WP skrift.de Redakteur"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst r = $('Ergebnis pruefen').first().json;\nconst c = $input.first().json;\nreturn [{ json: { ...r,\n cache_geleert: c.statusCode === 200,\n cache_hinweis: c.statusCode === 200 ? null\n : 'Cache-Endpunkt antwortete mit HTTP ' + c.statusCode + '. Kein Abbruchgrund.' }}];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
4640,
|
|
240
|
|
],
|
|
"id": "4d8c093e-e322-4a87-a79d-77db2724bc1a",
|
|
"name": "Importergebnis merken"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"amount": "={{ $('Konfiguration').first().json.pause_zwischen_artikeln }}",
|
|
"unit": "seconds"
|
|
},
|
|
"type": "n8n-nodes-base.wait",
|
|
"typeVersion": 1.1,
|
|
"position": [
|
|
4860,
|
|
420
|
|
],
|
|
"id": "56000936-7d58-4ab7-892e-60520c4bc20e",
|
|
"name": "Pause Rate Limit",
|
|
"webhookId": "4782cf6a-9326-4b0f-9b35-4754fa88908f"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "loose",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "1ae82a45-edd8-44f4-8946-47adc6800d41",
|
|
"leftValue": "={{ $('Konfiguration').first().json.bild_aktiv === true && !Number($json.featured_media) }}",
|
|
"rightValue": "",
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "true",
|
|
"singleValue": true
|
|
}
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"looseTypeValidation": true,
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.2,
|
|
"position": [
|
|
4860,
|
|
240
|
|
],
|
|
"id": "ff9b0ab2-1a97-44dc-a97d-d33688cb2501",
|
|
"name": "Beitragsbild fehlt?"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "={{ $('Konfiguration').first().json.gitea_base }}/api/v1/repos/{{ $('Konfiguration').first().json.gitea_owner }}/{{ $('Konfiguration').first().json.gitea_repo }}/contents/artikel-index.json?ref={{ $('Konfiguration').first().json.branch }}",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": true,
|
|
"fullResponse": true
|
|
}
|
|
},
|
|
"timeout": 60000
|
|
}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
5080,
|
|
120
|
|
],
|
|
"id": "d7a48424-743c-464d-8290-efdcb05d48d1",
|
|
"name": "Bilddaten laden",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "VOD4JM5zwpSC8wAr",
|
|
"name": "Gitea Skrift Auto Article"
|
|
}
|
|
},
|
|
"retryOnFail": true,
|
|
"maxTries": 3,
|
|
"waitBetweenTries": 3000
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\n// Prompt nach ratgeber/bildstil.md, Farbe und Motiv aus artikel-index.json.\nconst r = $('Importergebnis merken').first().json;\nconst antwort = $input.first().json;\nconst K = (x) => (x && x.body !== undefined) ? x.body : ((x || {}).data);\nconst konf = $('Konfiguration').first().json;\n\nlet zeile = null;\nconst kb = K(antwort);\nif (antwort.statusCode === 200 && kb && kb.content) {\n try {\n const tab = JSON.parse(Buffer.from(kb.content, 'base64').toString('utf8'));\n zeile = (Array.isArray(tab) ? tab : []).find(z => z.slug === r.slug) || null;\n } catch (e) { zeile = null; }\n}\nif (!zeile || !zeile.bild_farbe || !zeile.bildmotiv) {\n return [{ json: { ...r, bild_prompt: null,\n bild_hinweis: 'Kein bild_farbe oder bildmotiv in artikel-index.json, Bild uebersprungen.' } }];\n}\n\nconst FARBNAME = { '#7B96C2': 'muted light ink blue', '#B6997F': 'muted sepia brown',\n '#8C9A82': 'muted sage green', '#C47B5E': 'muted terracotta red' };\nconst farbe = String(zeile.bild_farbe).toUpperCase();\nconst name = FARBNAME[farbe] ? ` (${FARBNAME[farbe]}, not more saturated)` : '';\nconst leer = /price tag/i.test(zeile.bildmotiv) ? ', the price tag is completely empty' : '';\n\nconst prompt = [\n 'Hand-drawn doodle spot illustration, flat editorial icon style.',\n `Solid flat background color ${farbe}${name}, completely uniform, no texture, no gradient, no shadow, no vignette.`,\n 'In the center one simple object, drawn with thick uneven black marker outlines (#1A1A1A), slightly wobbly hand-drawn lines like a felt-tip pen, rounded line ends.',\n 'Clean closed outlines, no stray marks, no hatching and no small dashes inside the shapes.',\n 'Object fills are flat off-white cream (#F9F7F5), no shading, no highlights.',\n `Motif: ${zeile.bildmotiv}${leer}. Shown straight from the front, not tilted.`,\n 'The whole motif sits in the exact center and stays inside the middle band of the image: it takes about 28 percent of the image height and at most 60 percent of the image width, with wide empty background above and below.',\n 'No text, no letters, no numbers, no currency symbols, no logo, no border, no frame, no rounded corners, no people.',\n].join(' ');\n\nreturn [{ json: { ...r, bild_prompt: prompt, bild_titel: zeile.titel || r.slug,\n openai_body: JSON.stringify({ model: konf.bild_modell, prompt, size: konf.bild_groesse,\n n: 1, output_format: 'webp', quality: konf.bild_qualitaet }) } }];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
5300,
|
|
120
|
|
],
|
|
"id": "dd13bf7d-798d-43a4-af99-fd0ee8bffcab",
|
|
"name": "Bildprompt bauen"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "loose",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "98fcfee0-224f-422a-b567-ec68f40b465f",
|
|
"leftValue": "={{ !!$json.bild_prompt }}",
|
|
"rightValue": "",
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "true",
|
|
"singleValue": true
|
|
}
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"looseTypeValidation": true,
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.2,
|
|
"position": [
|
|
5520,
|
|
120
|
|
],
|
|
"id": "620a3df5-f36b-4192-b215-4c73b5e123d9",
|
|
"name": "Bildprompt vorhanden?"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "https://api.openai.com/v1/images/generations",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": false
|
|
}
|
|
},
|
|
"timeout": 180000
|
|
},
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ $json.openai_body }}",
|
|
"sendHeaders": true,
|
|
"specifyHeaders": "json",
|
|
"jsonHeaders": "={\"Content-Type\":\"application/json\"}"
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
5740,
|
|
40
|
|
],
|
|
"id": "6c1873c5-117c-4fb9-9109-e9b2cee026d2",
|
|
"name": "Bild erzeugen",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "03NmFB2C9IFRXIu8",
|
|
"name": "OpenAI Bilder"
|
|
}
|
|
},
|
|
"onError": "continueErrorOutput",
|
|
"retryOnFail": true,
|
|
"maxTries": 3,
|
|
"waitBetweenTries": 3000
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst r = $('Bildprompt bauen').first().json;\nconst e = $input.first().json;\nreturn [{ json: { ...r, openai_body: undefined,\n bild_hinweis: 'Bild nicht erzeugt, Artikel ist trotzdem importiert. Haeufige Ursachen: '\n + 'Guthaben leer, Organisation fuer Bildmodelle nicht verifiziert, Prompt abgelehnt. Antwort: '\n + JSON.stringify(e).slice(0, 300) } }];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
5740,
|
|
260
|
|
],
|
|
"id": "1f440c70-8596-4c40-963b-f8643698bbd4",
|
|
"name": "Fehler Bild",
|
|
"onError": "continueRegularOutput"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst r = $('Bildprompt bauen').first().json;\nconst a = $input.first().json;\nconst b64 = a && a.data && a.data[0] && a.data[0].b64_json;\nif (!b64) throw new Error('OpenAI lieferte kein data[0].b64_json. Antwort: ' + JSON.stringify(a).slice(0, 300));\nconst puffer = Buffer.from(b64, 'base64');\nconst datei = await this.helpers.prepareBinaryData(puffer, `${r.slug}.webp`, 'image/webp');\nconst { openai_body, ...rest } = r;\nreturn [{ json: { ...rest, bild_bytes: puffer.length }, binary: { bild: datei } }];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
5960,
|
|
40
|
|
],
|
|
"id": "d883b5e0-6185-42ff-a6e2-921bfb467ed5",
|
|
"name": "Bild als Datei"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "={{ $('Konfiguration').first().json.wp_base }}/wp-json/wp/v2/media?alt_text={{ encodeURIComponent('Illustration zum Artikel: ' + $json.bild_titel) }}&title={{ encodeURIComponent($json.bild_titel) }}",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpBasicAuth",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Content-Disposition",
|
|
"value": "=attachment; filename=\"{{ $json.slug }}.webp\""
|
|
},
|
|
{
|
|
"name": "Content-Type",
|
|
"value": "image/webp"
|
|
}
|
|
]
|
|
},
|
|
"sendBody": true,
|
|
"contentType": "binaryData",
|
|
"inputDataFieldName": "bild",
|
|
"options": {
|
|
"timeout": 120000
|
|
}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
6180,
|
|
40
|
|
],
|
|
"id": "f8891b55-37e7-459b-969a-6f9f33c51c33",
|
|
"name": "Bild in Mediathek",
|
|
"credentials": {
|
|
"httpBasicAuth": {
|
|
"id": "WIN05TZgM0K5VOGy",
|
|
"name": "WP skrift.de Redakteur"
|
|
}
|
|
},
|
|
"retryOnFail": true,
|
|
"maxTries": 3,
|
|
"waitBetweenTries": 3000
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "={{ $('Konfiguration').first().json.wp_base }}/wp-json/wp/v2/posts/{{ $('Bildprompt bauen').first().json.post_id }}",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpBasicAuth",
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ JSON.stringify({ featured_media: $json.id }) }}",
|
|
"sendHeaders": true,
|
|
"specifyHeaders": "json",
|
|
"jsonHeaders": "={\"Content-Type\":\"application/json\"}",
|
|
"options": {
|
|
"timeout": 60000
|
|
}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
6400,
|
|
40
|
|
],
|
|
"id": "3d497e77-7911-4ed0-9f22-f20504712ef9",
|
|
"name": "Beitragsbild setzen",
|
|
"credentials": {
|
|
"httpBasicAuth": {
|
|
"id": "WIN05TZgM0K5VOGy",
|
|
"name": "WP skrift.de Redakteur"
|
|
}
|
|
},
|
|
"retryOnFail": true,
|
|
"maxTries": 3,
|
|
"waitBetweenTries": 3000
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst r = $('Bild als Datei').first().json;\nconst m = $('Bild in Mediathek').first().json;\nconst p = $input.first().json;\nif (Number(p.featured_media) !== Number(m.id)) {\n throw new Error('Beitragsbild wurde nicht gesetzt. Erwartet ' + m.id + ', WordPress meldet ' + p.featured_media);\n}\nreturn [{ json: { ...r, bild: 'neu erzeugt', media_id: m.id, bild_url: m.source_url,\n featured_media: m.id, bild_kb: Math.round(r.bild_bytes / 1024) } }];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
6620,
|
|
40
|
|
],
|
|
"id": "453a90a0-5243-4d1a-9224-3e3fc3541599",
|
|
"name": "Bild gemerkt"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst alle = $input.all().map(i => i.json);\nconst importiert = alle.filter(r => r.ergebnis === 'importiert');\nconst nachbessern = alle.filter(r => r.ergebnis === 'nachbessern');\nconst fehler = alle.filter(r => r.ergebnis === 'fehler');\n\nconst zeilen = importiert.map(r => ({\n slug: r.slug, score: r.score, datum: new Date().toISOString(),\n post_id: r.post_id, vorschau_url: r.vorschau_url,\n aktion: r.aktion, kategorie: r.kategorie,\n}));\n\nreturn [{ json: { alle, importiert, nachbessern, fehler,\n neue_zeilen: zeilen,\n anzahl_importiert: importiert.length,\n anzahl_nachbessern: nachbessern.length,\n anzahl_fehler: fehler.length }}];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
900,
|
|
80
|
|
],
|
|
"id": "3e4abd4e-4a6f-4e54-9924-c2cfa154cf82",
|
|
"name": "Ergebnisse sammeln"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "={{ $('Konfiguration').first().json.gitea_base }}/api/v1/repos/{{ $('Konfiguration').first().json.gitea_owner }}/{{ $('Konfiguration').first().json.gitea_repo }}/contents/{{ $('Konfiguration').first().json.status_pfad }}?ref={{ $('Konfiguration').first().json.branch }}",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": true,
|
|
"fullResponse": true
|
|
}
|
|
},
|
|
"timeout": 60000
|
|
}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
1120,
|
|
80
|
|
],
|
|
"id": "ca0cb16c-0af2-4b3c-aaa2-5725972703be",
|
|
"name": "Statustabelle lesen",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "VOD4JM5zwpSC8wAr",
|
|
"name": "Gitea Skrift Auto Article"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst s = $('Ergebnisse sammeln').first().json;\nconst p = $input.first().json;\nconst konf = $('Konfiguration').first().json;\n\nlet bestand = [];\nlet sha = null;\n// n8n liefert den Koerper bei fullResponse je nach Version als body oder data.\nconst K = (r) => (r && r.body !== undefined) ? r.body : ((r || {}).data);\nconst kp = K(p);\nif (p.statusCode === 200 && kp && kp.content) {\n sha = kp.sha;\n try { bestand = JSON.parse(Buffer.from(kp.content, 'base64').toString('utf8')); }\n catch (e) { bestand = []; }\n if (!Array.isArray(bestand)) bestand = [];\n}\n\n// Je Slug nur die juengste Zeile behalten.\nconst neu = [...bestand];\ns.neue_zeilen.forEach(z => {\n const i = neu.findIndex(x => x.slug === z.slug);\n if (i >= 0) neu[i] = z; else neu.push(z);\n});\n\nreturn [{ json: { ueberspringen: s.neue_zeilen.length === 0, commit_body: JSON.stringify({\n content: Buffer.from(JSON.stringify(neu, null, 2), 'utf8').toString('base64'),\n message: `Import: ${s.anzahl_importiert} Beitrag/Beitraege als Entwurf`,\n branch: konf.branch, ...(sha ? { sha } : {}),\n}), methode: sha ? 'PUT' : 'POST' }}];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
1340,
|
|
80
|
|
],
|
|
"id": "78f81aa7-0ca1-4f29-815c-a5328ea514b9",
|
|
"name": "Statustabelle fortschreiben"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "loose",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "d2c17929-ba0a-4080-ae1a-e9a6aad3e118",
|
|
"leftValue": "={{ $json.ueberspringen }}",
|
|
"rightValue": "",
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "true",
|
|
"singleValue": true
|
|
}
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"looseTypeValidation": true,
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.2,
|
|
"position": [
|
|
1560,
|
|
80
|
|
],
|
|
"id": "7ce09846-988b-490b-a1d3-1b986eb17713",
|
|
"name": "Gab es Importe?"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "={{ $json.methode }}",
|
|
"url": "={{ $('Konfiguration').first().json.gitea_base }}/api/v1/repos/{{ $('Konfiguration').first().json.gitea_owner }}/{{ $('Konfiguration').first().json.gitea_repo }}/contents/{{ $('Konfiguration').first().json.status_pfad }}",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"neverError": false
|
|
}
|
|
},
|
|
"timeout": 60000
|
|
},
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ $json.commit_body }}",
|
|
"sendHeaders": true,
|
|
"specifyHeaders": "json",
|
|
"jsonHeaders": "={\"Content-Type\":\"application/json\"}"
|
|
},
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.3,
|
|
"position": [
|
|
1780,
|
|
160
|
|
],
|
|
"id": "0a900f70-93be-4997-b04a-c74061ea39e9",
|
|
"name": "Statustabelle schreiben",
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "VOD4JM5zwpSC8wAr",
|
|
"name": "Gitea Skrift Auto Article"
|
|
}
|
|
},
|
|
"onError": "continueErrorOutput",
|
|
"retryOnFail": true,
|
|
"maxTries": 3,
|
|
"waitBetweenTries": 3000
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nreturn [{ json: { statustabelle_warnung: 'Statustabelle konnte nicht geschrieben werden: '\n + JSON.stringify($input.first().json).slice(0, 300) }}];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
1780,
|
|
340
|
|
],
|
|
"id": "96e36221-b847-4b03-95cb-e1a103a27df7",
|
|
"name": "Fehler Statustabelle",
|
|
"onError": "continueRegularOutput"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForAllItems",
|
|
"jsCode": "\nconst s = $('Ergebnisse sammeln').first().json;\nconst z = [];\nz.push(`Importiert: ${s.anzahl_importiert} | Nachbessern: ${s.anzahl_nachbessern} | Fehler: ${s.anzahl_fehler}`);\nz.push('');\n\nif (s.importiert.length) {\n z.push('Als Entwurf in WordPress:');\n s.importiert.forEach(r => {\n z.push(` ${r.slug} (Score ${r.score}, ${r.aktion})`);\n z.push(` Vorschau: ${r.vorschau_url}`);\n z.push(` Bearbeiten: ${r.bearbeiten_url}`);\n if (r.elementor) z.push(` Layout: ${r.elementor}`);\n if (r.bild === 'neu erzeugt') z.push(` Bild: neu erzeugt (${r.bild_kb} KB), ${r.bild_url}`);\n else if (r.featured_media) z.push(` Bild: bereits vorhanden, nicht neu erzeugt`);\n if (r.bild_hinweis) z.push(` Bild: ${r.bild_hinweis}`);\n if (r.meta_warnung) z.push(` ACHTUNG: ${r.meta_warnung}`);\n if (r.preis_warnung) z.push(` PREISE: ${r.preis_warnung}`);\n if (r.stil_hinweise && r.stil_hinweise.length) {\n z.push(` STIL: ${r.stil_hinweise.length} Hinweis(e)`);\n r.stil_hinweise.slice(0, 6).forEach(h => z.push(` - ${h.art}: ${h.stelle}`));\n if (r.stil_hinweise.length > 6) z.push(` ... weitere im Nachbesserungsbericht bzw. in der Execution`);\n }\n if (r.cache_hinweis) z.push(` Hinweis: ${r.cache_hinweis}`);\n });\n z.push('');\n}\nif (s.nachbessern.length) {\n z.push('Score zu niedrig, Nachbesserung liegt im Repo:');\n s.nachbessern.forEach(r => {\n z.push(` ${r.slug}: Score ${r.score} von ${r.score_ziel}`);\n z.push(` ${r.anzahl_pflicht} Pflichtbegriffe fehlen, ${r.anzahl_erweitert} Zusatzbegriffe`);\n if (r.wortzahl && r.wortzahl.differenz !== null) {\n z.push(` Wortzahl ${r.wortzahl.ist} von ${r.wortzahl.ziel} (${r.wortzahl.differenz > 0 ? '+' : ''}${r.wortzahl.differenz})`);\n }\n z.push(` Datei: ${r.pfad}`);\n if (r.preis_warnung) z.push(` PREISE: ${r.preis_warnung}`);\n if (r.stil_hinweise && r.stil_hinweise.length) {\n z.push(` STIL: ${r.stil_hinweise.length} Hinweis(e)`);\n r.stil_hinweise.slice(0, 6).forEach(h => z.push(` - ${h.art}: ${h.stelle}`));\n if (r.stil_hinweise.length > 6) z.push(` ... weitere im Nachbesserungsbericht bzw. in der Execution`);\n }\n });\n z.push('');\n}\nif (s.fehler.length) {\n z.push('Fehler:');\n s.fehler.forEach(r => z.push(` ${r.slug || '?'} [${r.stufe}]: ${r.meldung}`));\n z.push('');\n}\nz.push('Kein Beitrag wurde veroeffentlicht. Alle Importe stehen auf Entwurf.');\n\nreturn [{ json: {\n betreff: `Skrift Ratgeber: ${s.anzahl_importiert} Entwurf/Entwuerfe`\n + (s.anzahl_nachbessern ? `, ${s.anzahl_nachbessern} zum Nachbessern` : '')\n + (s.anzahl_fehler ? `, ${s.anzahl_fehler} Fehler` : ''),\n text: z.join('\\n') }}];\n"
|
|
},
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
2000,
|
|
80
|
|
],
|
|
"id": "2899cba3-36f3-4fb1-b1cf-c99fe19b9020",
|
|
"name": "Meldung formulieren"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"fromEmail": "",
|
|
"toEmail": "={{ $('Konfiguration').first().json.benachrichtigung_an }}",
|
|
"subject": "={{ $json.betreff }}",
|
|
"emailFormat": "text",
|
|
"text": "={{ $json.text }}",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.emailSend",
|
|
"typeVersion": 2.1,
|
|
"position": [
|
|
2220,
|
|
80
|
|
],
|
|
"id": "12bdb6c6-d9d0-4271-ace8-e3e07c863819",
|
|
"name": "Benachrichtigung",
|
|
"disabled": true,
|
|
"notes": "SMTP-Credential zuweisen, Absender eintragen, dann aktivieren."
|
|
}
|
|
],
|
|
"connections": {
|
|
"Manuell starten": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Konfiguration",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Webhook Start": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Konfiguration",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Konfiguration": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Artikelordner lesen",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Artikelordner lesen": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Artikeldateien filtern",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Artikeldateien filtern": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Artikel vorhanden?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Artikel vorhanden?": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Nichts zu tun",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Artikel nacheinander",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Artikel nacheinander": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Ergebnisse sammeln",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Artikeldatei laden",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Artikeldatei laden": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Brief laden",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Fehler Artikeldatei",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Brief laden": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Artikel pruefen",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Artikel pruefen": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Score ermitteln",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Score ermitteln": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Score auswerten",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Fehler Score",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Score auswerten": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Score erreicht?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Score erreicht?": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Revision zu NeuronWriter",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Fehlende Begriffe ermitteln",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Fehlende Begriffe ermitteln": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Nachbesserung vorhanden?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Nachbesserung vorhanden?": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Nachbesserung vorbereiten",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Nachbesserung vorbereiten": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Nachbesserung committen",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Nachbesserung committen": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Nachbesserung gemerkt",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Fehler Nachbesserung",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Revision zu NeuronWriter": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Beitrag vorhanden?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Fehler Revision",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Fehler Revision": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Beitrag vorhanden?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Beitrag vorhanden?": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Kategorie suchen",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Kategorie suchen": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Kategorie pruefen",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Kategorie pruefen": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Kategorie anlegen?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Kategorie anlegen?": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Kategorie anlegen",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Kategorie festlegen",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Kategorie anlegen": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Kategorie festlegen",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Kategorie festlegen": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "WordPress-Body bauen",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"WordPress-Body bauen": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Beitrag anlegen oder aktualisieren",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Beitrag anlegen oder aktualisieren": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Ergebnis pruefen",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Ergebnis pruefen": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Cache leeren",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Cache leeren": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Importergebnis merken",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Nachbesserung gemerkt": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Pause Rate Limit",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Fehler Nachbesserung": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Pause Rate Limit",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Fehler Artikeldatei": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Pause Rate Limit",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Fehler Score": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Pause Rate Limit",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Pause Rate Limit": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Artikel nacheinander",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Importergebnis merken": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Beitragsbild fehlt?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Beitragsbild fehlt?": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Bilddaten laden",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Pause Rate Limit",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Bilddaten laden": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Bildprompt bauen",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Bildprompt bauen": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Bildprompt vorhanden?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Bildprompt vorhanden?": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Bild erzeugen",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Pause Rate Limit",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Bild erzeugen": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Bild als Datei",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Fehler Bild",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Fehler Bild": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Pause Rate Limit",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Bild als Datei": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Bild in Mediathek",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Bild in Mediathek": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Beitragsbild setzen",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Beitragsbild setzen": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Bild gemerkt",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Bild gemerkt": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Pause Rate Limit",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Ergebnisse sammeln": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Statustabelle lesen",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Statustabelle lesen": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Statustabelle fortschreiben",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Statustabelle fortschreiben": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Gab es Importe?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Gab es Importe?": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Meldung formulieren",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Statustabelle schreiben",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Statustabelle schreiben": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Meldung formulieren",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Fehler Statustabelle",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Fehler Statustabelle": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Meldung formulieren",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Meldung formulieren": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Benachrichtigung",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
}
|
|
},
|
|
"settings": {
|
|
"executionOrder": "v1",
|
|
"saveManualExecutions": true,
|
|
"callerPolicy": "workflowsFromSameOwner"
|
|
}
|
|
} |