Kapitel 10/Free Rhohtext.md aktualisiert

This commit is contained in:
2025-10-09 19:42:33 +00:00
parent a0b33cec67
commit 996722e066

View File

@@ -421,6 +421,44 @@ Ein händisches Nachtragen würde bedeuten, dass der Workflow regelmäßig ausf
Wir werden deshalb im **Verlauf des Workflows** einen eigenen Node hinzufügen, der den Access Token automatisch anfordert und bei Bedarf erneuert. Wir werden deshalb im **Verlauf des Workflows** einen eigenen Node hinzufügen, der den Access Token automatisch anfordert und bei Bedarf erneuert.
So bleibt der Workflow stabil und benötigt keine manuelle Pflege. So bleibt der Workflow stabil und benötigt keine manuelle Pflege.
### 5.9 Nextcloud-Credentials anlegen
**Zweck:**
Damit n8n automatisch auf Dateien in deiner Nextcloud zugreifen kann (z. B. für vorbereitete Posts oder temporäre Daten), benötigen wir ein eigenes App-Passwort und ein passendes Credential in n8n.
#### In Nextcloud: App-Passwort erstellen
1) Melde dich in deiner **Nextcloud** an.
2) Öffne oben rechts das **Benutzermenü → Einstellungen**.
3) Wähle im linken Menü den Punkt **Sicherheit** (engl. „Security“).
4) Scrolle nach unten bis zum Bereich **App-Passwörter**.
5) Vergib unter „Neues App-Passwort“ einen Namen, z. B. `n8n`.
6) Klicke auf **App-Passwort erstellen**.
7) Kopiere den angezeigten Schlüssel sofort er wird nur einmal angezeigt.
👉 Screenshot geeignet: Nextcloud Bereich *Sicherheit / App-Passwörter*
[!IMPORTANT]
Nur dieses **App-Passwort** wird in n8n verwendet, **nicht** dein normales Login-Passwort.
Das App-Passwort kann bei Bedarf jederzeit widerrufen oder neu erstellt werden.
#### In n8n: Credential hinzufügen
1) Öffne in n8n oben links **+ → Credentials → Nextcloud**.
2) Trage folgende Werte ein:
| Feld | Wert / Beschreibung |
|------|---------------------|
| **Name** | `Nextcloud` |
| **Base URL** | `https://deine-domain.tld` *(ohne `/remote.php/...`)* |
| **Username** | dein Nextcloud-Benutzername |
| **Password** | das zuvor erstellte App-Passwort |
3) Klicke auf **Save**.
👉 Screenshot geeignet: n8n Nextcloud-Credential mit Base URL und App-Passwort
[!NOTE]
Das Credential „Nextcloud“ wird später in Schritt **6.13** verwendet, um Dateien wie `posts.txt` automatisiert aus der Cloud zu laden und lokal zu verarbeiten.
## Schritt 6 Workflow in n8n aufbauen ## Schritt 6 Workflow in n8n aufbauen
In diesem Schritt erstellen wir den eigentlichen Workflow in **n8n**. In diesem Schritt erstellen wir den eigentlichen Workflow in **n8n**.
@@ -809,4 +847,180 @@ return out;
[!NOTE] [!NOTE]
- `tz` ist fest auf `Europe/Berlin` gesetzt, kann aber bei Bedarf angepasst werden. - `tz` ist fest auf `Europe/Berlin` gesetzt, kann aber bei Bedarf angepasst werden.
- Das Feld `cancelled` wird genutzt, um abgesagte Streams zu kennzeichnen. - Das Feld `cancelled` wird genutzt, um abgesagte Streams zu kennzeichnen.
- Jeder Stream-Eintrag erhält einen Hash, der später als eindeutiger Schlüssel dient. - Jeder Stream-Eintrag erhält einen Hash, der später als eindeutiger Schlüssel dient.
### 6.10 Code-Node: „Nächstes Event finden“
**Zweck:**
Dieser Node wählt aus allen vom **„Parse ICS“**-Node gelieferten Terminen den **nächsten bevorstehenden Stream** aus.
Er liefert das Start-Datum und die relevanten Infos des nächsten Events als einzelnes Item.
**Node-Typ:** `Code`
**Name:** `Nächstes Event finden`
👉 Screenshot geeignet: n8n geöffneter Code-Node mit dem folgenden Script
#### Node-Einstellungen
- **Programming Language:** `JavaScript`
- Alle weiteren Optionen bleiben auf Standard.
#### Eingabe
Dieser Node erwartet als Input die komplette Liste der Stream-Segmente aus dem Node **„Parse ICS“**.
#### Code-Inhalt
Kopiere den folgenden Code vollständig in das Code-Feld:
```
/**
* INPUT: Array von Items aus "Parse ICS"
* OUTPUT: nur das nächste bevorstehende Event
*/
const now = Date.now();
const upcoming = items
.map(i => i.json)
.filter(e => !e.cancelled && new Date(e.startIso).getTime() > now)
.sort((a, b) => new Date(a.startIso) - new Date(b.startIso));
if (upcoming.length === 0) {
return [{ json: { message: 'Kein bevorstehender Stream gefunden' } }];
}
const next = upcoming[0];
return [{
json: {
uid: next.uid,
title: next.title,
description: next.description,
startIso: next.startIso,
endIso: next.endIso,
tz: next.tz,
hash: next.hash
}
}];
```
[!TIP]
Dieser Node gibt **genau ein Item** mit dem nächsten Stream zurück.
Fehlt ein Termin, wird eine kurze Meldung im Feld `message` ausgegeben.
### 6.11 Code-Node: „Stream prüfen“
**Zweck:**
Dieser Node überprüft, ob der nächste geplante Stream in den kommenden **30 Minuten** beginnt und ob für diesen Stream bereits ein Post veröffentlicht wurde.
Nur wenn beide Bedingungen erfüllt sind, wird der Workflow fortgesetzt.
**Node-Typ:** `Code`
**Name:** `Stream prüfen`
👉 Screenshot geeignet: n8n geöffneter Code-Node mit folgendem Script
#### Node-Einstellungen
- **Programmiersprache:** `JavaScript`
- Keine weiteren Optionen ändern
#### Eingabe
Der Node erhält den Output aus **„Nächstes Event finden“** also einen einzelnen Stream-Eintrag mit `uid`, `title`, `startIso` und weiteren Feldern.
#### Code-Inhalt
Kopiere den folgenden Code:
```
/**
* Prüft:
* 1. Startet der Stream in ≤ 30 Minuten?
* 2. Wurde bereits ein Post erstellt?
*
* Zeitumwandlung: Twitch liefert UTC ("2025-10-15T16:00:00Z").
* Wir rechnen in lokale Zeit (Europe/Berlin), um MEZ/MESZ korrekt zu berücksichtigen.
*/
const event = items[0]?.json ?? {};
if (!event.startIso) {
return [{
json: {
postAllowed: false,
reason: 'Kein Termin gefunden'
}
}];
}
// Aktuelle Zeit + Startzeit in lokale Zeitzone überführen
const tz = 'Europe/Berlin';
const now = new Date(); // lokale Zeit des n8n-Servers
const startUtc = new Date(event.startIso);
// Startzeit in lokales Format (inkl. Sommer-/Winterzeit)
const startLocal = new Date(startUtc.toLocaleString('en-US', { timeZone: tz }));
// Differenz in Minuten
const diffMin = (startLocal - now) / 60000;
const within30 = diffMin > 0 && diffMin <= 30;
// Zugriff auf global gespeicherte IDs
const sd = $getWorkflowStaticData('global');
sd.postedIds = sd.postedIds || [];
const alreadyPosted = sd.postedIds.includes(event.uid);
// Wenn innerhalb von 30 Minuten und noch kein Post → erlauben
if (within30 && !alreadyPosted) {
sd.postedIds.push(event.uid);
return [{
json: {
...event,
postAllowed: true,
reason: 'Stream startet bald, noch kein Post vorhanden',
localStart: startLocal.toISOString(),
diffMinutes: Math.round(diffMin)
}
}];
}
// Keine Aktion notwendig
return [{
json: {
...event,
postAllowed: false,
reason: alreadyPosted
? 'Für diesen Stream wurde bereits gepostet'
: 'Stream liegt außerhalb des 30-Minuten-Fensters',
localStart: startLocal.toISOString(),
diffMinutes: Math.round(diffMin)
}
}];
```
[!NOTE]
Dieser Node speichert die **UID jedes angekündigten Streams** im Workflow-Speicher (`global static data`).
So wird sichergestellt, dass kein Termin doppelt angekündigt wird auch nicht nach einem Neustart des Systems.
Der Zeitvergleich erfolgt in **MEZ/MESZ (Europe/Berlin)**, damit lokale Streamzeiten korrekt erkannt werden.
### 6.12 IF-Node: „Post ausführen?“
**Zweck:**
Der IF-Node entscheidet, ob tatsächlich ein Social-Post (z. B. auf X) ausgelöst werden soll.
Er prüft das Feld `postAllowed`, das aus dem vorherigen Code-Node stammt.
**Node-Typ:** `IF`
**Name:** `Post ausführen?`
👉 Screenshot geeignet: n8n geöffneter IF-Node mit konfigurierter Bedingung
#### Node-Einstellungen
**Conditions**
| Feld | Einstellung |
|------|--------------|
| **Left Value** | `{{$json.postAllowed}}` |
| **Operator** | `is true` |
| **Type** | `Boolean` |
[!NOTE]
- Der *True*-Pfad wird nur ausgeführt, wenn der Stream innerhalb der nächsten 30 Minuten startet **und** noch kein Post gesendet wurde.
- Der *False*-Pfad kann später genutzt werden, um Debug-Logs oder Benachrichtigungen zu schreiben (z. B. „Kein Post nötig“).
👉 Screenshot geeignet: n8n IF-Node mit `{{$json.postAllowed}} is true (Boolean)`