Sistema Event Flow

Guida all'editor Event Flow

Crea automazioni affidabili per Social Stream Ninja. Questa guida illustra le basi, i nodi logici, il flusso dei segnali e gli accorgimenti pratici più richiesti dai creator, come evitare echi nella chat e capire quando combinare blocchi AND/NOT.

Italiano

0. Orientamento rapido

Event Flow è un editor basato su nodi. Ogni linea trasporta un payload del messaggio più uno stato booleano (true = continua, false = ferma). Usa sorgenti per inserire eventi, nodi logici per filtrare le decisioni e azioni per eseguire operazioni (inviare chat, controllare overlay, inoltrare messaggi ecc.).
Devi ricordare i partecipanti, verificare l'idoneità in seguito, estrarre un utente unico o svuotare un elenco con nome? Apri la Guida a User Memory per il modello di stato condiviso, gli screenshot e un esempio importabile.

Cos'è questo editor?

L'editor Event Flow è il livello di “automazione avanzata” di Social Stream Ninja. Si colloca sopra i semplici interruttori del popup e consente di programmare una propria logica di instradamento. Usalo quando devi:

  • Inoltra la chat tra servizi con filtri (ad esempio replica Twitch su Discord ma blocca i comandi).
  • Crea comandi basati sulla fedeltà, giochi con parole chiave o condizioni di accesso alle estrazioni con logica AND/OR/NOT.
  • Attiva overlay personalizzati, audio, scene OBS o webhook in base ai dati che arricchisci nel flusso.
  • Combina più piattaforme in una singola automazione (Kick + Twitch + YouTube instradati attraverso un solo flusso).

Considera il popup come una raccolta di preset rapidi ed Event Flow come l'insieme di strumenti per flussi personalizzati.

Avvio e basi

  • Apri l'editor Event Flow dal menu della dashboard principale (desktop o estensione).
  • Ogni progetto viene salvato localmente fino all'esportazione. Usa Export per eseguire un backup o condividere.
  • Lavora in aree chiamate flussi. Ogni flusso può sottoscrivere più piattaforme contemporaneamente.

Panoramica dei nodi

  • Ingressi (porte a sinistra) si aspettano il contesto del messaggio.
  • Uscite (porte a destra) emettono lo stesso contesto con le eventuali modifiche.
  • I nodi logici possono emettere il canale true e un canale facoltativo false .

Struttura del payload

Ogni messaggio trasporta un oggetto JSON. Le chiavi obbligatorie seguono docs/event-reference.html (platform, type, chatname, chatmessage ecc.). Inserisci i dati personalizzati sotto meta.

Ogni flusso inizia con un trigger

I nodi azione (verdi) non vengono mai eseguiti da soli: si attivano solo quando un nodo trigger (blu) sopra di loro restituisce true. Un flusso composto solo da azioni concatenate sembra valido, ma resta sempre inattivo perché nulla avvia la catena. I nomi dei nodi descrivono cosa il nodo fa, non quando avviene: Metti messaggio in evidenza (Feature Message) mette in evidenza un messaggio quando il flusso lo raggiunge; non si attiva quando metti un messaggio in evidenza altrove.

Due nodi azione concatenati senza un nodo trigger
❌ Non viene mai eseguito. Feature Message e Speak Text sono entrambe azioni; senza un trigger all'inizio, nulla avvia la catena.
Trigger Any Message collegato alle azioni Feature Message e Speak Text
✅ Funziona. Un trigger Qualsiasi messaggio (Any Message) (oppure Message Contains, una regex, un evento di donazione ecc.) avvia la catena; entrambe le azioni vengono poi eseguite per ogni messaggio corrispondente.

Overlay Flow Actions (uscita delle azioni)

Inizia con un modello di avviso:

Scegli Donazione: festeggiamento + voce per un'animazione pronta e una clip sintetica di ringraziamento, oppure il modello avanzato Donazione: animazione + suono + filtro OBS . I nuovi modelli di avviso partono disattivati, così puoi configurarli e provarli prima. Per il modello OBS, scegli una sorgente e lo stesso filtro normalmente disattivato in entrambe le azioni di filtro.

Riproduci clip audio e Multi-Alerts ora condividono una libreria di 17 suoni: applausi, rullo di tamburi, sibilo, registratore di cassa e altri effetti, quattro frasi sintetiche inglesi etichettate e suoni semplici. Ascolta / Ferma riproduce un'anteprima locale con stato di riproduzione visibile. Puoi comunque caricare una registrazione o scegliere un file locale dell'app. Per nomi o messaggi variabili, usa l'azione esistente Leggi testo (Speak Text) .

Event Flow riproduce tramite la sorgente browser Flow Actions ; Multi-Alerts riproduce tramite la propria sorgente browser. Mantieni il suono attivo in una sola delle due per lo stesso evento, per evitare riproduzioni duplicate. Raggiungi un nodo del flusso con Tab e premi Invio o Spazio per modificarne le proprietà.

Nodi come Riproduci clip audio, Mostra overlay multimediale, e i controlli OBS hanno bisogno di una superficie di visualizzazione. Questa superficie è la pagina overlay Flow Actions servita da actions.html. Mantienila in esecuzione nel software di trasmissione (dock browser OBS/Streamer.bot/ecc.) affinché le azioni Event Flow abbiano un posto dove apparire.

Trigger Any Message collegato a un'azione Play Audio Clip
Questo flusso è completo e si attiva a ogni messaggio, ma il suono viene riprodotto sulla pagina overlay Flow Actions, non nell’editor. Il pulsante Anteprima dell’editor riproduce localmente; la riproduzione in diretta richiede che l’overlay sia aperto. Se il browser blocca la riproduzione automatica, fai clic su Attiva audio nella pagina Flow Actions per riprovare l'ultima clip bloccata. Anche un clic altrove sulla pagina abilita la riproduzione. Una sorgente browser OBS normalmente consente la riproduzione automatica.
Come aprirlo (dal popup/dashboard):
  1. Apri il popup principale Social Stream Ninja (la finestra caricata da popup.html o dall'icona dell'estensione).
  2. Scorri fino alla scheda “Flow Actions”. Usa il pulsante [copia link] oppure fai clic sull'URL nella scheda.
  3. Il link ha questo aspetto: https://socialstream.ninja/actions.html?session=YOURSESSION. Incollalo in una sorgente browser OBS (consigliati 1920×1080) oppure aprilo in un qualsiasi browser per overlay.
Usare contenuti multimediali locali nell'app autonoma:
  1. In un'azione Play Audio Clip o Display Media Overlay, fai clic su Scegli file locale.
  2. Fai clic su Copia URL Flow Actions locale per OBS e usa quell'URL localhost generato al posto dell'URL Flow Actions ospitato.
  3. Mantieni SSApp in esecuzione. Se un file selezionato viene spostato, torna all'azione e fai clic su Ricollega.

L'estensione Chrome non può servire da sola i file su disco. Usa Upload o un URL ospitato quando non è disponibile un'app desktop di supporto. Consulta la guida ai file multimediali per Event Flow per la configurazione completa.

Una volta caricato, quell'overlay può:

  • Mostrare URL GIPHY o multimediali diretti, testo e coriandoli attivati dai flussi.
  • Riprodurre suoni (TTS, clip audio) localmente affinché gli spettatori li sentano.
  • Comunica con OBS tramite le impostazioni WebSocket nella sezione Flow Actions del popup (cambio di scena, visibilità delle sorgenti, aggiornamenti di testo GDI+/FreeType, buffer replay ecc.).
Modalità di controllo OBS:
  • API Browser Source: disponibile solo quando actions.html è in esecuzione nella sorgente browser OBS con Livello di accesso avanzato (Advanced Access Level). Qui funziona il cambio di scena e le azioni di registrazione / diretta / buffer replay possono usarla come ripiego.
  • OBS WebSocket: consigliato per un controllo uniforme. Social Stream Ninja Flow Actions usa l'API OBS WebSocket v5 di OBS 28+ e si aspetta il set moderno di richieste sulla porta 4455.
  • Password: facoltativa. Aggiungi &obspw=... all'URL Flow Actions se il server OBS è configurato per richiedere autenticazione.
  • Diagnostica overlay: aggiungi &obsdebug=1 all’URL di actions.html se vuoi un piccolo badge live della connessione OBS sull'overlay durante la risoluzione dei problemi.
  • Set Text Source: aggiorna direttamente gli ingressi OBS Testo (GDI+) e Testo (FreeType 2) e supporta variabili di modello Event Flow come {counterValue} e {counterTarget}.
  • Vecchie installazioni 4.x: se usi ancora obs-websocket 4.x / porta 4444, le azioni di sorgente / filtro / muto / testo non funzioneranno finché OBS / obs-websocket non saranno aggiornati.

Consulta la guida dedicata Guida al controllo OBS per ogni trigger, azione, passaggio di configurazione e ricetta verificata.

Percorso diagnostico consigliato:
  1. Apri obs-websocket-test.html.
  2. Verifica che GetVersion, GetCurrentProgramScene, e GetSceneList hanno esito positivo.
  3. Esegui lì il controllo dell'azione corrispondente prima di provare l'intera automazione Event Flow.
Mantieni aperto l'overlay. Chiudere la pagina Flow Actions sospende ogni azione overlay/audio/OBS in Event Flow. Nascondila o spostala su un monitor separato anziché chiuderla.

1. Cosa passa attraverso un nodo?

Il runtime Event Flow passa due elementi attraverso ogni filo:

  1. Payload – l'oggetto dati dell'evento o del messaggio.
  2. Segnale della porta – un bit true/false che indica al nodo successivo se deve essere eseguito.
Se un nodo emette false: i nodi a valle smettono di essere eseguiti, a meno che non ricevano un ingresso da un ramo separato (ad esempio la porta false su un nodo Condition). Questo rende semplice creare una logica alternativa senza duplicare interi flussi.

Requisiti degli ingressi

  • Sorgenti degli eventi (messaggio Twitch, timer, trigger manuale ecc.) ignorano l'ingresso a monte: generano il proprio payload ed emettono sempre true a meno che il nodo stesso non produca un errore.
  • Nodi di trasformazione e logica leggono il payload e possono riscrivere campi, impostare lo stato o cambiare il segnale della porta in false.
  • Nodi azione si attivano solo quando la porta resta true. Possono comunque emettere un payload aggiornato se vuoi continuare a concatenare azioni.

Schemi di uscita

Uscita singola

La maggior parte dei nodi espone una sola uscita. Ciò che entra (payload + porta) esce invariato, a meno che il nodo non lo modifichi.

Uscite True/False

I nodi Condition, Compare, Regex e Logic hanno due porte di uscita. True prosegue dalla porta verde; false diventa disponibile sulla porta grigia/rossa.

Passaggio invariato e sostituzione

Alcuni nodi (Set Variable, Math, Text Replace) modificano il payload, ma inoltrano comunque lo stato true/false del loro ingresso. Altri (NOT, AND, OR) ricalcolano il booleano autonomamente.

2. Riepilogo dei nodi logici

Questi blocchi rispondono alle domande più comuni su cosa significhino true/false.

NOT

  • Ingressi: 1 booleano (true/false) derivato dal nodo precedente.
  • Uscite: il booleano invertito più il payload intatto.
  • Comportamento predefinito: Se all'ingresso di NOT non è collegato nulla, il risultato è false, quindi l'uscita è true.
Esempio: Inserisci NOT dopo “Contains Keyword” per attivare un avviso quando uno spettatore non usa la parola chiave.

AND

  • Ingressi: due o più segnali booleani (A, B, ...). Puoi lasciare vuote le porte extra.
  • Uscite: true solo se tutti gli ingressi collegati sono uguali a true.
  • Usa AND quando devono essere soddisfatte più condizioni contemporaneamente ("è abbonato" e "il messaggio chat contiene !raffle").

OR

  • Emette true se qualunque ingresso collegato è true.
  • Ideale per trigger multipiattaforma: collega i nodi dei messaggi Twitch + YouTube a un solo OR, poi unifica l'azione a valle.
Mi serve sempre un nodo AND?
No. Molti nodi offrono già filtri completi (ad esempio "Filter User Level" + "Contains Text"). Usa AND solo quando le opzioni integrate non coprono la tua combinazione oppure quando vuoi una giunzione logica riutilizzabile e condivisibile con altri rami.
NOT e ingressi vuoti: Un nodo NOT scollegato emetterà comunque true. Mantienilo collegato a qualcosa di significativo oppure disattiva il nodo affinché non sblocchi accidentalmente un flusso.

3. Esempi di microflussi

A. Rispondi automaticamente, salvo quando il messaggio è un comando

Messaggio Twitch ──▶ Corrispondenza regex "^!" ─┐ │ ├─false──▶ Risposta automatica ("Grazie per aver scritto in chat!") │ └─true──▶ Non fare nulla

Qui il nodo Regex emette true quando il messaggio è un comando. Instradiamo l’uscita false alla nostra risposta, così chi scrive normalmente riceve un riscontro mentre i comandi passano semplicemente oltre.

B. Richiedi più verifiche con AND

Messaggio YouTube ──▶ Contiene "!queue" ─▶ AND ─▶ Inoltra a Discord Abbonamento regalo ─▶ Ruolo utente = Membro ──▲

Il nodo AND assicura che solo i membri che usano la parola chiave corretta vengano inoltrati a Discord. Entrambi i rami inviano il risultato booleano al nodo AND; il payload del primo ramo prosegue a valle.

C. Nodo NOT per bloccare avvisi ripetuti

Payload evento ─▶ Controllo stato (isAlertMuted) └─false─▶ NOT ─▶ Riproduci festeggiamento

State Check restituisce il valore true quando l'avviso è silenziato. Invertendo quel risultato, il nodo NOT assicura che il festeggiamento venga riprodotto solo quando il flag è false.

D. Riproduci casualmente uno di due suoni

Flusso con porta RANDOM, porta NOT e porta AND per riprodurre casualmente una di due clip audio
Un lancio di moneta 50/50 tra due clip audio. La porta RANDOM decide una volta per ogni messaggio corrispondente: se passa, viene riprodotto il suono A; se fallisce, la porta NOT inverte il risultato e la porta AND lascia riprodurre il suono B.
Trigger ──▶ RANDOM (50%) ──▶ Riproduci suono A │ └──▶ NOT ──▶ AND ──▶ Riproduci suono B Trigger ──────────────────▲

La porta AND non è facoltativa. Un NOT isolato emetterebbe true ogni volta che la porta RANDOM è inattiva, quindi il suono B verrebbe riprodotto per ogni messaggio chat che non corrisponde al trigger. Collegare il trigger ad AND come secondo ingresso limita il suono B ai soli messaggi corrispondenti. Lo stesso schema funziona con qualsiasi coppia alternativa di azioni, non solo con l’audio.

4. Prevenire echi, cicli e ritorni nell'inoltro

Inoltrare la chat tra interfacce è potente, ma può generare echi infiniti se ascolti il tuo stesso output. Segui queste precauzioni:

Nota sulla destinazione YouTube Shorts:
Sia i trigger in ingresso sia le destinazioni in uscita di Relay Chat distinguono tra youtube e youtubeshorts. Usa due azioni di inoltro quando un messaggio deve raggiungere entrambe le varianti. Consulta YouTube Shorts ed Event Flow.
Relay Chat ignora automaticamente le riflessioni riconosciute.
Una riflessione è un messaggio in uscita acquisito di nuovo da una chat di destinazione. Le attuali azioni Relay Chat ignorano queste riflessioni riconosciute; non c'è una casella No Reflections separata. Per nasconderne o limitarne la visualizzazione nel dock e negli overlay, usa un Filtro dei messaggi di ritorno (Reflection Filter) con Blocca tutti (Block All), Consenti il primo (Allow First), oppure Consenti tutti (Allow All). Controlla la visualizzazione alla riacquisizione, non l'invio. Segui la Guida passo passo all'inoltro Twitch e YouTube per una configurazione completa.
  • Evita sistemi di inoltro duplicati. Disattiva Relay all globale quando usi percorsi Event Flow equivalenti e controlla se altri servizi collegano le stesse chat. Non è garantito che i metadati personalizzati sopravvivano al passaggio attraverso la chat di una piattaforma.
  • Usa nodi Debounce o Cooldown per avvisi che devono attivarsi solo una volta ogni X secondi.
  • Interrompi i cicli intenzionalmente. Se due rami si alimentano a vicenda, aggiungi un nodo logico che controlli una variabile di stato ("currentlyRelaying"), così il flusso esce subito quando il flag è impostato.

5. Ingressi, uscite e domande pratiche

Cosa entra in un nodo?

  • Il payload completo del messaggio.
  • Il bit della porta (true/false).
  • Contesto facoltativo (variabili di stato, timer) richiesto esplicitamente dal nodo.

Cosa esce da un nodo?

  • Lo stesso payload, a meno che il nodo non lo modifichi.
  • Un bit di porta ricalcolato (nodi logici) oppure un bit passato invariato (azioni).
  • La maggior parte degli effetti (come inviare chat) non altera il payload, ma le azioni sui punti possono aggiungere campi di stato come pointsTotal oppure pointsSpendError per la logica a valle.

Quando creare un ramo?

Ogni volta che vuoi reagire diversamente a true rispetto a false. Trascina un filo dall'uscita colorata necessaria (verde = true, grigio/rosso = false) al nodo successivo.

Ricorda: Se non fai nulla con un risultato false in uscita, il flusso termina semplicemente lì. È perfetto per i filtri ("blocca tutto ciò che non supera il controllo"), ma non dimenticare di collegare il percorso false se ti servono alternative.

Domande e risposte comuni

  • Devo usare AND per ogni coppia di filtri? No. Molti nodi includono più controlli (ad esempio il filtro messaggi di base supporta parola chiave + ruolo). Usa AND solo per combinazioni avanzate o quando unisci segnali da nodi diversi.
  • Come arrivano i valori true/false al nodo NOT? Ogni nodo con un'uscita verde emette true per impostazione predefinita. Quando una condizione fallisce, emette false. Collega quel filo a NOT per invertire il risultato.
  • Un nodo può emettere un payload anche se restituisce false? Sì. Il payload passa comunque attraverso l'uscita false; spetta a te decidere dove deve andare quel ramo.
  • Come riconosco i membri del team TikTok? Scegli Membro del team TikTok (TikTok Team Member) nel nodo User Role. Riconosce livelli e badge TikTok Fan Club/team nel messaggio in arrivo e non dipende dalle impostazioni del Main Chat Overlay.
  • Ogni nodo Speak Text può usare una voce diversa? Sì. Inserisci un nome o ID voce supportato dal provider in Sostituzione voce (Voice Override), oppure lascialo vuoto per usare la voce TTS predefinita di Flow Actions.

6. Riferimento delle variabili di modello

Diversi nodi azione (Show Text, Set Text Source, Send Message, Relay Chat, TTS Speak, Call Webhook, Print Thermal Label) supportano variabili di modello che vengono sostituite con i dati dell'evento durante l'esecuzione. Racchiudi i nomi delle variabili tra parentesi graffe, come {username}.

Variabili di base (compatibili con le versioni precedenti)

VariabileAliasDescrizioneEsempio
{username}{chatname}Nome visualizzato dell'utenteCoolViewer123
{message}{chatmessage}Testo del messaggio chatCiao a tutti!
{source}-Nome della piattaforma (con iniziale maiuscola)Twitch, YouTube
{type}-Nome della piattaforma (grezzo)twitch, youtube
{donation}{hasDonation}Etichetta visualizzata di donazione/mancia$5.00, 500 bits

Variabili estese

VariabileDescrizioneEsempio
{displayname}Nome visualizzato (campo alternativo)CoolViewer123
{donoValue}Equivalente in USD della donazione, fornito o stimato; Event Flow ricava i valori di soglia dal campo normalizzato hasDonation come valore, $valore, valore + unità oppure unità/valore compatti. Le unità virtuali con nome sconosciuto usano 100 unità = $0.01 USD; i regali TikTok senza prezzo usano una moneta per regalo ($0.01 ciascuno). {donationAmount} è un alias precedente5.00
{event}Identificatore del tipo di eventocheer, raid, new_follower
{membership}Stato dell'abbonamentoMEMBERSHIP, new_sponsor
{subtitle}Contesto aggiuntivoMembro da 3 mesi
{userid}ID dell'utente sulla piattaforma12345678
{chatimg}URL avatar dell'utentehttps://...
{contentimg}URL dell'immagine allegatahttps://...
{rewardTitle}Nome della ricompensa quando la sorgente espone un campo del titolo della ricompensa al primo livelloMetti in evidenza il mio messaggio
{meta}Dati strutturati dell'evento (JSON){"viewers":100}
{counterValue}Valore corrente del contatore dopo un passaggio Counter o Check Counter12
{counterTarget}Valore obiettivo del contatore30
{counterRemaining}Obiettivo del contatore meno valore corrente, limitato a un minimo di 018
La corrispondenza delle variabili non distingue maiuscole e minuscole. {USERNAME}, {Username}, e {username} funzionano tutti allo stesso modo.
Funzionano anche i campi aggiunti dal flusso. Se un'azione precedente aggiunge un valore al primo livello del messaggio, i modelli successivi possono leggerlo direttamente. È così che Check Counter espone {counterValue}, {counterTarget}, e {counterRemaining}.
JSON di Call Webhook: Le variabili di modello funzionano nei valori stringa JSON a qualsiasi profondità di oggetti o array annidati. Le chiavi degli oggetti non vengono elaborate come modelli e un corpo personalizzato senza segnaposto viene inviato invariato.

Modelli di esempio

  • Show Text: {username} just cheered {hasDonation}!
  • Imposta sorgente di testo OBS: {username}: now {counterValue}, need {counterTarget}
  • Relay Chat: [{source}] {username}: {message}
  • TTS: {username} says {message}
  • Avviso di donazione: {username} donated {donation} - {subtitle}
  • Etichetta termica: {username}, una nuova riga, poi {donation}. Vedi la Guida alle stampanti termiche per configurare la stampante, le etichette di dimensioni fisse e un flusso completo.
  • Call Webhook Discord: {"content":"{message}","username":"{username}","avatar_url":"{chatimg}"}
Le variabili mancanti diventano stringhe vuote. Se un evento non ha un determinato campo (ad esempio {donation} in un normale messaggio chat), il segnaposto viene sostituito con una stringa vuota anziché mostrare il testo letterale {donation} .

7. Elenco delle buone pratiche

  • Dai un nome e un colore ai nodi, così in futuro saprai riconoscere ogni ramo.
  • Prova con il simulatore integrato (Send Test Event) prima di usare un flusso in diretta.
  • Raggruppa la logica vicino alla sorgente. Filtra il prima possibile per evitare elaborazioni aggiuntive più avanti.
  • Memorizza le ripetizioni nei nodi di stato. Usa contatori, interruttori e timestamp per evitare avvisi duplicati.
  • Documenta i campi meta. Quando aggiungi chiavi meta personalizzate, documentale affinché overlay e client remoti restino coerenti.
Salva le versioni. Esporta il flusso a ogni traguardo raggiunto. Le importazioni sono il modo più semplice per tornare indietro se un esperimento va storto.

8. Ulteriori approfondimenti

Esegui flussi personalizzati da Stream Deck o dall'API: trigger con nome, modello iniziale, rilevamento dei flussi, dati aggiuntivi, esempi HTTP/WebSocket/P2P e gesti delle manopole.

Vuoi approfondire?

  • Usa Nodi di stato (contatori, interruttori, timer) per tenere traccia del contesto tra gli eventi.
  • Combina Variabili e logica per creare sistemi di coda, estrazioni o motori di punteggio.
  • Collegati al sistema Punti e ricompense affinché gli spettatori possano attivare intenzionalmente i flussi.
  • Usi l’app desktop SSApp? Sblocca Nodi JavaScript personalizzati per logiche arbitrarie non coperte da nodi integrati.
  • Controlla il Riferimento degli eventi per una documentazione dettagliata dei payload di tutte le piattaforme.

Questa guida è volutamente autonoma: copiala in locale, adattala al tuo team e continua a sperimentare nell'editor.

9. JavaScript personalizzato Solo SSApp / desktop

Due nodi nell'editor Event Flow consentono di scrivere JavaScript arbitrario eseguito nella sequenza del flusso: Codice personalizzato (Custom Code) (trigger) e Esegui codice personalizzato (Execute Custom Code) (azione). Sono la soluzione per tutto ciò che i nodi integrati non possono esprimere.

È richiesta l'app desktop. I nodi JavaScript personalizzati sono disattivati nell'estensione browser perché la Content Security Policy di Chrome Manifest V3 blocca new Function() / eval(). Apri l’editor tramite questa applicazione: App desktop SSApp per attivarli. In modalità estensione, i nodi appaiono in grigio con l'etichetta "Solo desktop".
Modifica del codice: seleziona un nodo Custom Code e fai clic su Apri editor del codice per una finestra di modifica più grande. Salva e chiudi verifica la sintassi JavaScript e salva l'intero flusso; Ctrl+S oppure Cmd+S fa lo stesso. Annulla lascia invariato il nodo.
Editor Event Flow — stato vuoto
L'editor Event Flow. Il pannello sinistro elenca tutti i nodi disponibili; l'area punteggiata serve a creare i flussi; il pannello destro mostra le proprietà del nodo selezionato.

Custom Code — Nodo trigger

Trascina Codice personalizzato (Custom Code) dal gruppo Avanzate nel pannello Trigger nell'area di lavoro. Funziona da porta: il flusso prosegue solo quando il codice restituisce true.

Pannello dei trigger con il nodo Custom Code nel gruppo Advanced
Custom Code si trova nel gruppo Avanzate nel pannello Triggers.
Pannello delle proprietà del trigger Custom Code con editor JavaScript
Pannello delle proprietà dopo il posizionamento del trigger. Scrivi un'espressione che restituisca true oppure false.
Firma: il codice viene eseguito come function(message) { ... }
Deve restituire: un booleano — true per lasciar proseguire il flusso, false per fermarlo.
Disponibile: l’oggetto message (vedi API dei messaggi sotto), più convertCurrency(value, targetCurrency, source) e convertToUSD(value, source).

Execute Custom Code — Nodo azione

Trascina Esegui codice personalizzato (Execute Custom Code) dal gruppo Integrazioni nel pannello Azioni . Può modificare il messaggio, bloccarlo o aggiungere metadati leggibili dai nodi successivi.

Pannello delle azioni con Execute Custom Code nel gruppo Integrations
Execute Custom Code nel gruppo Integrazioni nel pannello Actions.
Pannello delle proprietà dell'azione Execute Custom Code con editor del codice
Proprietà dell'azione. Restituisci un oggetto per unire le modifiche al risultato del flusso.
Firma: il codice viene eseguito come function(message, result) { ... }
Dovrebbe restituire: un oggetto o una Promise uniti a result— consulta API dei risultati.
Disponibile: message (il payload dell'evento), result (stato del risultato del flusso corrente), printThermal(html, options), più convertCurrency(value, targetCurrency, source) e convertToUSD(value, source).
Stampa termica in SSApp: scegli la stampante e calibra larghezza della carta e margini di sicurezza in Controllo stampante (Printer Control), poi restituisci printThermal('<strong>' + message.chatname + '</strong>'). SSApp accoda il lavoro senza finestre di dialogo tramite l'API di stampa nativa Windows e usa le impostazioni salvate. Un flusso può sostituirle con opzioni come { width: '58mm', marginLeft: '3mm', marginRight: '3mm', marginTop: '2mm', marginBottom: '2mm', feed: '3mm', marginType: 'printableArea' }. Restituire la Promise consente a Event Flow di attendere l'invio e segnalare errori.
Area di lavoro con un trigger Custom Code e un'azione Execute Custom Code affiancati
Un trigger Custom Code (blu) e un'azione Execute Custom Code (verde) nell'area di lavoro. Collega la porta di uscita del trigger alla porta di ingresso dell'azione.

L’oggetto message

Entrambi i nodi ricevono il payload completo dell'evento come message. I campi qui sotto sono sempre disponibili; gli eventi specifici delle piattaforme possono includerne altri.

CampoTipo di datiDescrizioneEsempio
message.chatmessagestringaIl testo del messaggio chat (può contenere HTML)"Hello stream!"
message.chatnamestringaNome visualizzato del mittente"CoolViewer"
message.useridstringaID utente della piattaforma"12345678"
message.typestringaPiattaforma sorgente (minuscolo)"twitch", "youtube", "kick"
message.hasDonationstringaStringa della donazione formattata, se presente"$5.00", "500 bits"
message.donoValuenumero / stringaEquivalente in USD della donazione quando fornito dalla sorgente; vengono rispettati i valori zero validi. In mancanza, Event Flow usa currency.js per convertire le etichette normalizzate di hasDonation per i confronti di soglia, incluso 100 unità con nome sconosciuto = $0.01 USD. Non analizza il testo discorsivo di chatmessage per i valori delle donazioni.5
message.eventstringaIdentificatore del tipo di evento"new_follower", "cheer", "raid"
message.membershipstringaStato dell'abbonamento, quando applicabile"MEMBERSHIP"
message.subtitlestringaRiga di contesto secondaria"Member for 3 months"
message.modbooleanoIl mittente è moderatoretrue
message.subscriberbooleanoIl mittente è abbonatotrue
message.vipbooleanoIl mittente ha lo stato VIPtrue
message.chatimgstringaURL avatar dell'utente"https://..."
message.metaoggettoDati strutturati arbitrari allegati all'evento{ viewers: 120 }
Conversione valuta: usa convertCurrency(message.hasDonation, 'EUR', message.type) per convertire in EUR l'etichetta formattata della donazione. Restituisce un numero, oppure null quando la valuta di destinazione richiesta non è supportata. Il convertitore usa i tassi interni approssimativi di Social Stream Ninja; non contatta un servizio di cambio esterno.

Cosa restituisce l'azione

Restituisci un oggetto semplice dal codice dell'azione. Tutti i campi inclusi vengono uniti all’oggetto result ; i campi omessi conservano i valori attuali.

Campo restituitoTipo di datiEffetto
modifiedbooleanoImposta true se hai modificato campi di message . Indica ai nodi successivi che il payload è stato modificato.
messageoggettoRestituisci il messaggio (eventualmente modificato) affinché i nodi successivi ricevano le tue modifiche.
blockedbooleanoImposta true per impedire che il messaggio venga mostrato o inoltrato.
Valore restituito minimo e sicuro: return { modified: false, message };
Anche se non hai modificato nulla, restituire message lo fa proseguire verso il nodo successivo.

Frammenti di esempio

Copia uno di questi esempi nel campo JavaScript Code del tipo di nodo corrispondente.

Frammenti di trigger — restituisci true per continuare il flusso

Corrispondenza di parole chiave (senza distinzione tra maiuscole e minuscole)
Continua il flusso solo quando il messaggio contiene una parola o frase specifica.
// Matches "!hello" anywhere in the message return (message.chatmessage || '').toLowerCase().includes('!hello');
Rilevamento dei comandi tramite regex
Riconosci i messaggi che iniziano con un comando di un elenco definito (ad esempio !queue, !raffle, !enter).
return /^!(queue|raffle|enter)\b/i.test(message.chatmessage || '');
Donazione sopra una soglia
Attiva solo quando una donazione raggiunge o supera un importo minimo.
const amount = message.donoValue !== undefined && message.donoValue !== null && message.donoValue !== '' ? Number(message.donoValue) : (typeof convertToUSD === 'function' ? convertToUSD(message.hasDonation || '', message.type || '') : Number(String(message.hasDonation || '').replace(/[^0-9.]/g, '') || 0)); return amount >= 5;
Super Chat o Super Sticker YouTube in un intervallo EUR
Converti in EUR l'etichetta standard delle donazioni YouTube, escludi Jewels/Gifts e seleziona un intervallo sonoro o visivo.
var eventName = String(message.event || '').toLowerCase(); if (eventName !== 'superchat' && eventName !== 'supersticker') return false; var eurValue = convertCurrency(message.hasDonation || '', 'EUR', message.type || ''); if (typeof eurValue !== 'number' || !isFinite(eurValue)) return false; message.eurValue = eurValue; return eurValue >= 10 && eurValue < 25;
Filtro piattaforma
Elabora solo eventi di piattaforme specifiche.
return ['twitch', 'youtube'].includes(message.type);
Controllo abbonato / VIP / moderatore
Lascia proseguire il flusso solo per gli utenti con privilegi.
return !!(message.subscriber || message.vip || message.mod);
Condizione multipla — VIP + parola chiave
Combina controllo del ruolo e contenuto del messaggio in una sola espressione non coperta da un trigger integrato.
const isPrivileged = !!(message.subscriber || message.vip || message.mod); const isCommand = /^!feature\b/i.test(message.chatmessage || ''); return isPrivileged && isCommand;
Controllo della lunghezza del messaggio
Elabora solo messaggi con abbastanza contenuto (utile per TTS o inoltro per evitare spam di singole emoji).
return (message.chatmessage || '').replace(/<[^>]+>/g, '').trim().length >= 20;

Frammenti di azione — restituisci { modified, message }

Aggiungi un badge o un'etichetta al messaggio
Aggiungi un indicatore visivo alla fine di ogni messaggio che passa attraverso questa azione.
message.chatmessage = (message.chatmessage || '').trimEnd() + ' ✅'; return { modified: true, message };
Blocca un messaggio in base a una condizione
Esamina il contenuto e scarta il messaggio senza avvisi se una regola corrisponde: utile per schemi di spam che il filtro per parole chiave non può esprimere.
const text = (message.chatmessage || '').toLowerCase(); const spamPatterns = ['buy followers', 'free nitro', 'click here']; if (spamPatterns.some(p => text.includes(p))) { return { blocked: true, message }; } return { modified: false, message };
Rimuovi @menzioni
Rimuovi tutte le menzioni @username da un messaggio prima di inoltrarlo a un'altra piattaforma.
message.chatmessage = (message.chatmessage || '').replace(/@\w+/g, '').trim(); return { modified: true, message };
Formatta un annuncio di donazione
Riscrivi chatmessage come stringa di annuncio uniforme quando è presente una donazione.
const amount = parseFloat(message.donoValue || 0); if (amount > 0) { const note = (message.chatmessage || '').trim(); message.chatmessage = `💰 ${message.chatname} donated $${amount.toFixed(2)}!` + (note ? ` "${note}"` : ''); return { modified: true, message }; } return { modified: false, message };
Aggiungi metadati di instradamento per i nodi successivi
Contrassegna il messaggio con un campo personalizzato che un successivo nodo Inoltra chat (Relay Chat) oppure Invia messaggio (Send Message) può leggere da una variabile di modello ({meta}).
message.meta = message.meta || {}; // Assign a donation tier so the next node can use {meta} to decide overlay colour const amount = parseFloat(message.donoValue || 0); message.meta.donationTier = amount >= 20 ? 'gold' : amount >= 5 ? 'silver' : 'bronze'; return { modified: true, message };
Prefisso del messaggio in base alla piattaforma
Aggiungi un'etichetta della piattaforma all'inizio del messaggio quando lo inoltri tra piattaforme, così gli spettatori ne conoscono l'origine.
const labels = { twitch: '[Twitch]', youtube: '[YouTube]', kick: '[Kick]', tiktok: '[TikTok]', }; const label = labels[message.type] || `[${message.type || 'Chat'}]`; message.chatmessage = `${label} ${message.chatname}: ${message.chatmessage || ''}`; return { modified: true, message };

Esempio completo — bot di richieste di funzionalità per VIP

Questo flusso ascolta !feature <text> da abbonati, VIP o moderatori, lo riformatta come richiesta di funzionalità e lo inoltra a una seconda destinazione (ad esempio Discord).

┌──────────────────────┐ ┌──────────────────────────┐ ┌──────────────────┐ │ Custom Code Trigger │────▶│ Execute Custom Code Action│────▶│ Relay Chat │ │ │ │ │ │ (a Discord) │ │ Condizione: VIP/abbonato/mod │ │ Riformatta il messaggio │ │ │ │ + inizia con │ │ → "📋 Richiesta di funzionalità │ │ │ │ !feature │ │ da {name}: {text}" │ │ │ └──────────────────────┘ └──────────────────────────┘ └──────────────────┘

Passaggio 1 — Trigger Custom Code (incolla nel campo JavaScript Code del trigger):

// Only let VIPs, subscribers, and mods through, and only for !feature commands const isPrivileged = !!(message.subscriber || message.vip || message.mod); const isCommand = /^!feature\b/i.test((message.chatmessage || '').trim()); return isPrivileged && isCommand;

Passaggio 2 — Azione Execute Custom Code (incolla nel campo JavaScript Code dell'azione):

// Strip the "!feature" command word and format a clean announcement const featureText = (message.chatmessage || '') .replace(/^!feature\s*/i, '') .trim(); if (!featureText) { // No text after the command: block rather than relay an empty request return { blocked: true, message }; } message.chatmessage = `📋 Feature request from ${message.chatname}: ${featureText}`; return { modified: true, message };

Passaggio 3 — Azione Relay Chat: aggiungi un normale nodo Relay Chat dopo l'azione e configuralo per la destinazione Discord (o un'altra). Qui non serve codice personalizzato: il campo riformattato message.chatmessage passa automaticamente.

Provare il flusso. Fai clic su questo pulsante: Prova flusso (Test Flow) (in alto a destra nell’editor) per inviare un messaggio sintetico attraverso la sequenza senza bisogno di una diretta. Imposta chatname su un abbonato, aggiungi un messaggio come !feature dark mode support, e verifica che la destinazione Relay Chat riceva la stringa riformattata.
Pannello Test Flow per inviare eventi sintetici di prova
Il pannello Test Flow. Compila i campi in modo che corrispondano alle condizioni del trigger e fai clic su Esegui test per verificare l'intera sequenza.

Considerazioni sulla sicurezza

Il codice personalizzato viene eseguito con i privilegi del processo renderer. Dentro SSApp, il codice dei nodi Custom JS ha accesso completo all’oggetto window e a tutte le API esposte dallo script preload (ad esempio window.ninjafy). Tratta i file dei flussi importati come codice eseguibile: importa solo flussi da fonti di cui ti fidi.
  • Nessuna sandbox di rete. Il codice di un'azione può chiamare fetch(). Se accetti flussi condivisi da altri, esamina il JavaScript prima di attivarli.
  • Gli errori vengono intercettati. Un errore di esecuzione nel codice restituisce false (trigger) oppure un'operazione nulla (azione) e scrive nella console DevTools: il flusso non si arresta in modo anomalo.
  • Anche gli errori di sintassi. Un errore di tipo SyntaxError in fase di compilazione viene intercettato allo stesso modo. Controlla DevTools (F12) se un nodo sembra non fare nulla.