Event Flow 系統

Event Flow 編輯器指南

為 Social Stream Ninja 建立可靠的自動化。本指南介紹基礎知識、邏輯節點、訊號流,以及創作者最常詢問的實用技巧,例如避免聊天回傳以及何時組合 AND/NOT 區塊。

繁體中文

0. 快速入門

Event Flow 是以節點為基礎的編輯器。每條連線帶有訊息承載資料和布林狀態(true = 繼續, false = 停止)。使用 來源 以插入事件, 邏輯節點 以篩選決策,以及 動作 以執行實際動作(傳送聊天、控制疊加畫面、轉送訊息等)。
需要記住參加者、檢查後續資格、進行不重複使用者抽獎,或清除一個具名清單?開啟 使用者記憶指南 了解共用狀態模型、螢幕擷取畫面和可匯入範例。

這個編輯器是什麼?

Event Flow 編輯器是 Social Stream Ninja 的「進階自動化」層。它位於簡單彈出視窗開關之上,讓您撰寫自己的路由邏輯。在需要以下功能時使用它:

  • 在服務之間篩選並轉送聊天(例如將 Twitch 鏡像至 Discord,但封鎖命令)。
  • 透過 AND/OR/NOT 邏輯建立以忠誠度為依據的命令、關鍵字遊戲或抽獎資格限制。
  • 根據在流程中補充的資料,觸發自訂疊加畫面、音訊、OBS 場景或 webhook。
  • 在單一自動化中混合多個平台(Kick + Twitch + YouTube 透過一個流程路由)。

可以將彈出視窗視為「快速預設」,將 Event Flow 視為自訂工作流程的工具集。

啟動和基礎知識

  • 從主儀表板選單(桌面應用程式或擴充功能)開啟 Event Flow 編輯器。
  • 每個專案在匯出前都儲存在本機。使用 Export 以備份或分享。
  • 在稱為以下名稱的畫布中工作: 流程。每個流程都可以同時訂閱多個平台。

節點速覽

  • 輸入 (左側連接埠)接收訊息脈絡。
  • 輸出 (右側連接埠)發出相同脈絡以及所有編輯。
  • 邏輯節點可能同時發出 true 頻道和可選的 false 頻道。

承載資料結構

每則訊息都帶有 JSON 物件。必要鍵遵循 docs/event-reference.html (platform、type、chatname、chatmessage 等)。將自訂資料附加至 meta.

每個流程都從觸發條件開始

動作節點(綠色)從不自行執行,只有上方的觸發條件節點(藍色)求值為以下結果時才觸發: true。僅將動作串聯起來的流程看似有效,但會一直閒置,因為沒有任何東西啟動該鏈。節點名稱描述的是節點 做什麼,而不是它何時發生: 精選訊息(Feature Message) 在流程抵達它時精選訊息,而不會在您於其他位置精選訊息時觸發。

兩個串聯的動作節點,沒有觸發條件節點
❌ 從不執行。Feature Message 和 Speak Text 都是 動作;如果上方沒有觸發條件,就沒有任何東西啟動該鏈。
Any Message 觸發條件連接至 Feature Message 和 Speak Text 動作
✅ 可執行。一個 任意訊息(Any Message) 觸發條件(或 Message Contains、規則運算式、贊助事件等)啟動該鏈;之後,每則相符訊息都會執行這兩個動作。

Flow Actions 疊加畫面(動作輸出)

從提醒範本開始:

選擇 贊助:慶祝 + 語音 以使用現成的動畫和合成感謝語音片段,或使用進階的 贊助:動畫 + 聲音 + OBS 濾鏡 範本。新提醒範本初始為停用狀態,讓您可以先設定並測試。對於 OBS 範本,在兩個濾鏡動作中選擇同一個來源和同一個通常關閉的濾鏡。

播放音訊片段 和 Multi-Alerts 現在共用一個包含 17 種聲音的音效庫:掌聲、擊鼓、呼嘯、收銀機及其他效果,四個帶標籤的合成英語片語,以及簡單聲音。 聆聽 / 停止(Listen / Stop) 在本機預覽並顯示播放狀態。您仍可以上傳錄音或選擇應用程式本機檔案。對於變化的姓名或訊息,使用現有的 朗讀文字(Speak Text) 動作。

Event Flow 透過以下頁面播放: Flow Actions 瀏覽器來源;Multi-Alerts 透過自己的瀏覽器來源播放。對於同一事件,只在其中一個來源啟用聲音,以免重複播放。使用 Tab 移動至流程節點,按 Enter 或空白鍵編輯其屬性。

例如以下節點: 播放音訊片段, 顯示媒體疊加畫面,以及 OBS 控制項都需要一個繪製介面。該介面就是由以下位址提供的 Flow Actions 疊加畫面頁面: actions.html。讓它在直播軟體(OBS/Streamer.bot 瀏覽器停駐面板等)中保持執行,讓 Event Flow 動作有地方顯示。

Any Message 觸發條件連接至 Play Audio Clip 動作
該流程完整,並在每則訊息時觸發,但聲音會在 Flow Actions 疊加畫面頁面上播放, 而不是在編輯器中。 編輯器的 Preview 按鈕會在本機播放;即時播放需要開啟疊加畫面。如果瀏覽器封鎖自動播放,請點擊 啟用音訊 在 Flow Actions 頁面上,以重試最近遭封鎖的片段。點擊該頁面其他位置也會啟用播放。OBS 瀏覽器來源通常允許自動播放。
如何開啟(從彈出視窗/儀表板):
  1. 開啟 Social Stream Ninja 主彈出視窗(從以下位置載入的視窗: popup.html 或擴充功能圖示)。
  2. 捲動至「Flow Actions」卡片。使用 [複製連結] 按鈕,或點擊卡片內的 URL。
  3. 連結類似於 https://socialstream.ninja/actions.html?session=YOURSESSION。將其貼到 OBS 瀏覽器來源(建議 1920×1080),或在任意疊加畫面瀏覽器中開啟。
在獨立應用程式中使用本機媒體:
  1. 在 Play Audio Clip 或 Display Media Overlay 動作中,點擊 選擇本機檔案.
  2. 點選 複製用於 OBS 的本機 Flow Actions URL 並使用產生的 localhost URL 代替代管的 Flow Actions URL。
  3. 保持 SSApp 執行。如果所選檔案移動了,請回到動作並點擊 重新連結.

Chrome 擴充功能本身無法提供磁碟檔案。沒有桌面輔助應用程式時,請使用 Upload 或代管 URL。請參閱 Event Flow 媒體檔案指南 了解完整設定。

載入後,該疊加畫面可以:

  • 顯示由流程觸發的 GIPHY 或直接媒體 URL、文字和彩紙。
  • 在本機播放聲音(TTS、音訊片段),讓觀眾聽到。
  • 透過彈出視窗 Flow Actions 區段中的 WebSocket 設定與 OBS 通訊(場景切換、來源開關、GDI+/FreeType 文字更新、重播緩衝區等)。
OBS 控制模式:
  • 瀏覽器來源 API: 僅在以下情況下可用: actions.html 在 OBS 瀏覽器來源內執行,帶有 進階存取層級(Advanced Access Level)。此處支援場景切換,錄製 / 直播 / 重播緩衝區動作也可以將它用作備援方式。
  • OBS WebSocket: 建議使用,以實現一致的控制。Social Stream Ninja Flow Actions 使用 OBS 28+ 的 OBS WebSocket v5 API,並要求連接埠上提供現代請求集: 4455.
  • 密碼: 選用。僅在 OBS 伺服器要求驗證時,才將 &obspw=... 加入 Flow Actions URL。
  • 疊加畫面診斷: 附加 &obsdebug=1 至以下頁面的 URL: actions.html 如果希望在排查問題時,在疊加畫面上顯示一個小型即時 OBS 連接徽章。
  • 設定文字來源(Set Text Source): 直接更新 OBS Text (GDI+) 和 Text (FreeType 2) 輸入,並支援 Event Flow 範本變數,例如 {counterValue} 和 {counterTarget}.
  • 舊版 4.x 安裝: 如果仍使用 obs-websocket 4.x / 連接埠 4444,在升級 OBS / obs-websocket 之前,來源 / 濾鏡 / 靜音 / 文字動作將無法運作。

請參閱專門的 OBS 控制指南 了解每個觸發條件、動作、設定步驟和經過測試的方案。

建議診斷路徑:
  1. 開啟 obs-websocket-test.html.
  2. 確認 GetVersion, GetCurrentProgramScene,以及 GetSceneList 成功。
  3. 在測試完整 Event Flow 自動化之前,先在那裡執行相應的動作檢查。
保持疊加畫面開啟。 關閉 Flow Actions 頁面會暫停 Event Flow 中的所有疊加畫面/音訊/OBS 動作。請將其隱藏或放在另一台螢幕上,而不要完全關閉。

1. 什麼內容流經節點?

Event Flow 執行階段透過每條連線傳遞兩種內容:

  1. 承載資料 — 事件或訊息資料物件。
  2. 閘控訊號 — 一個 true/false 位元,告知下一個節點是否執行。
如果節點輸出 false: 下游節點停止執行,除非它們從其他分支收到輸入(例如 false 連接埠,位於 Condition 節點上)。這樣就能輕鬆建立備援邏輯,無需複製整個流程。

輸入需求

  • 事件來源 (Twitch Message、Timers、Manual Trigger 等)忽略上游輸入,它們產生自己的承載資料,並始終發出 true 除非節點本身出錯。
  • 轉換和邏輯節點 讀取承載資料,並可重寫欄位、設定狀態,或將閘控訊號翻轉為 false.
  • 動作節點 僅在閘控保持以下值時觸發: true。如果您希望繼續串聯動作,它們仍可輸出更新後的承載資料。

輸出模式

單一輸出

大多數節點提供一個輸出。進入的內容(承載資料 + 閘控)會原樣輸出,除非節點對其進行編輯。

True/False 輸出

Condition、Compare、Regex 和 Logic 節點提供兩個輸出連接埠。 真(True) 透過綠色連接埠繼續; false 會在灰色/紅色連接埠提供。

直通與覆寫

部分節點(Set Variable、Math、Text Replace)會修改承載資料,但仍轉送 true/false 來自輸入的狀態。其他節點(NOT、AND、OR)自行重新計算布林值。

2. 邏輯節點速查

這些區塊解答最常見的「true/false 是什麼意思?」問題。

非(NOT)

  • 輸入:來自前一節點的 1 個布林值(true/false)。
  • 輸出:反轉後的布林值,以及未改動的承載資料。
  • 預設行為: 如果 NOT 輸入沒有連接任何內容,它會求值為 false,因此輸出為 true.
範例: 將 NOT 放在「Contains Keyword」後,即可在下列情況觸發提醒:觀眾 未使用該關鍵字。

且(AND)

  • 輸入:兩個或更多布林訊號(A、B 等)。可讓額外連接埠留空。
  • 輸出: true 僅當所有連接輸入都等於 true.
  • 當多個條件必須同時滿足時使用 AND(「是訂閱者」 和 「聊天訊息包含 !raffle」)。

OR

  • 發出 true 如果 任意 連接的輸入為 true。
  • 適合多平台觸發條件:將 Twitch 和 YouTube 訊息節點接入單一 OR,然後統一下游動作。
始終需要 AND 節點嗎?
不需要。許多節點已經提供整合式篩選器(例如「Filter User Level」 + 「Contains Text」)。僅當內建選項無法涵蓋您的組合,或需要供其他分支共用的可重用邏輯連接點時,才使用 AND。
NOT 和空輸入: 懸空的 NOT 節點仍會輸出 true。保持它連接至有意義的節點,或停用該節點,以免意外放行流程。

3. 微型流程範例

A. 除命令訊息外自動回覆

Twitch Message ──▶ Regex Match "^!" ─┐ │ ├─false──▶ Auto Reply ("Thanks for chatting!") │ └─true──▶ Do nothing

此處 Regex 節點發出 true ,條件是訊息為指令。我們將 false 連接埠接到回覆,因此一般聊天者會收到確認,而命令直接通過。

B. 使用 AND 要求多項檢查

YouTube Message ──▶ Contains "!queue" ─▶ AND ─▶ Relay to Discord Gifted Membership ─▶ User Role = Member ──▲

AND 節點確保只有使用正確關鍵字的會員才會轉送至 Discord。兩個分支都將布林結果傳送至 AND 節點;承載資料來自 第一個分支 ,並繼續向下游傳遞。

C. 使用 NOT 節點封鎖重複提醒

Event Payload ─▶ State Check (isAlertMuted) └─false─▶ NOT ─▶ Play Celebration

State Check 在提醒遭靜音時輸出 true 。透過反轉該結果,NOT 節點確保僅在旗標為以下值時播放慶祝效果: false.

D. 隨機播放兩種聲音之一

流程使用 RANDOM 閘、NOT 閘和 AND 閘,隨機播放兩個音訊片段之一
以各 50% 機率在兩個音訊片段中選擇。RANDOM 閘對每則相符訊息隨機判斷一次:通過時播放聲音 A;失敗時,NOT 閘反轉結果,AND 閘讓聲音 B 播放。
Trigger ──▶ RANDOM (50%) ──▶ Play Sound A │ └──▶ NOT ──▶ AND ──▶ Play Sound B Trigger ──────────────────▲

AND 閘不可省略。 獨立的 NOT 會輸出 true 每當 RANDOM 閘閒置時,因此聲音 B 會在每則以下聊天訊息時播放: 不符合觸發條件的訊息。 將觸發器連接至 AND 的第二個輸入,可將聲音 B 限制為僅在訊息符合條件時播放。同一模式適用於任何二選一的動作組合,不限於音訊。

4. 防止回傳、循環和轉送回授

跨介面轉送聊天很有用,但如果監聽自己的輸出,就可能產生無限回傳。請遵循以下防護措施:

YouTube Shorts 目標說明:
傳入觸發條件和傳出 Relay Chat 的目標都會區分 youtube 和 youtubeshorts。當訊息應抵達兩個變體時,使用兩個轉送動作。請參閱 YouTube Shorts 與 Event Flow.
Relay Chat 自動略過已識別的回流。
回流是指傳送至目標聊天後又被擷取的訊息。目前 Relay Chat 動作會略過這些已識別的回流;沒有單獨的 No Reflections 核取方塊。如需隱藏或限制它們在停駐面板和疊加畫面中的顯示,請使用 回流篩選器(Reflection Filter) 動作,帶有 全部封鎖, 允許第一則,或 全部允許。這控制重新接收時的顯示,而不是傳送。請遵循 Twitch 和 YouTube 轉送教學 了解完整設定。
  • 避免重複轉送系統。 使用等效的 Event Flow 路由時,請停用全域 Relay all,並檢查是否有其他服務橋接相同聊天。自訂中繼資料不能保證在經過平台聊天後仍保留。
  • 使用 Debounce 或 Cooldown 節點 用於每 X 秒只應觸發一次的提醒。
  • 有意識地中斷循環。 如果兩個分支相互輸入,請新增邏輯節點檢查狀態變數(「currentlyRelaying」),以便在旗標已設定時提前退出流程。

5. 輸入、輸出和實用問題

節點接收什麼?

  • 完整訊息承載資料。
  • 閘控位元(true/false).
  • 節點明確請求的可選脈絡(狀態變數、計時器)。

什麼內容離開節點?

  • 相同承載資料,除非節點對其進行編輯。
  • 重新計算的閘控位元(邏輯節點)或直通位元(動作)。
  • 大多數副作用(如傳送聊天)不會改變承載資料,但點數動作可以附加狀態欄位,例如 pointsTotal 或 pointsSpendError 用於下游邏輯。

何時分支?

每當希望針對以下內容作出不同反應時: true 與 false。從所需的彩色輸出(綠色 = true,灰色/紅色 = false)拖曳連線至下一個節點。

請記住: 如果不處理 false 輸出,流程就會在此結束。這非常適合篩選器(「封鎖所有未通過檢查的內容」),但別忘了連接 false 路徑,如果需要備援處理。

常見問答

  • 每一對篩選器都必須使用 AND 嗎? 不需要。許多節點包含多項檢查(例如,基本 Message Filter 支援關鍵字 + 角色)。僅對進階組合,或合併來自不同節點的訊號時使用 AND。
  • true/false 值如何抵達 NOT 節點? 任何具有綠色輸出的節點都會發出 true 作為預設值。條件失敗時,它發出 false。將該連線接入 NOT 以反轉結果。
  • 節點傳回 false 時,仍能發出承載資料嗎? 可以。承載資料仍會透過 false 輸出傳遞;由您決定該分支應通向何處。
  • 如何比對 TikTok Team 成員? 選擇 TikTok Team 成員(TikTok Team Member) 在 User Role 節點中。它識別傳入訊息中的 TikTok Fan Club/team 等級和徽章,不依賴 Main Chat Overlay 設定。
  • 每個 Speak Text 節點可以使用不同的語音嗎? 可以。在以下欄位中輸入提供者支援的語音名稱或 ID: 語音覆寫(Voice Override),或留空以使用 Flow Actions TTS 預設值。

6. 範本變數參考

多個動作節點(Show Text、Set Text Source、Send Message、Relay Chat、TTS Speak、Call Webhook、Print Thermal Label)支援 範本變數 在執行階段會被事件資料替換。用大括號包住變數名稱,例如 {username}.

核心變數(回溯相容)

變數別名說明範例
{username}{chatname}使用者的顯示名稱CoolViewer123
{message}{chatmessage}聊天訊息文字大家好!
{source}-平台名稱(首字母大寫)Twitch, YouTube
{type}-平台名稱(原始值)twitch, youtube
{donation}{hasDonation}贊助顯示標籤$5.00, 500 bits

延伸變數

變數說明範例
{displayname}顯示名稱(備用欄位)CoolViewer123
{donoValue}提供或估算的等值美元贊助金額;Event Flow 從標準化的以下欄位推導門檻: hasDonation 標籤,例如數值, $數值、數值 + 單位,或精簡的單位/數值格式。未知具名虛擬單位依 100 單位 = 0.01 美元換算;未定價的 TikTok 禮物依每份禮物一個金幣(每個 0.01 美元)計算。 {donationAmount} 是舊版別名5.00
{event}事件類型識別碼cheer, raid, new_follower
{membership}會員狀態MEMBERSHIP, new_sponsor
{subtitle}補充脈絡已加入會員 3 個月
{userid}使用者的平台 ID12345678
{chatimg}使用者頭像 URLhttps://...
{contentimg}附加的影像 URLhttps://...
{rewardTitle}來源提供頂層獎勵標題欄位時的獎勵名稱醒目顯示我的訊息(Highlight My Message)
{meta}結構化事件資料(JSON){"viewers":100}
{counterValue}經過 Counter 或 Check Counter 步驟後的目前計數器值12
{counterTarget}計數器目標值30
{counterRemaining}計數器目標減去目前值,最小為 018
變數比對不區分大小寫。 {USERNAME}, {Username},以及 {username} 都以相同方式運作。
流程加入的欄位也適用。 如果較早的動作向訊息加入了頂層值,後續範本可以直接讀取它。這就是 Check Counter 提供 {counterValue}, {counterTarget},以及 {counterRemaining}.
呼叫 Webhook JSON: 範本變數適用於任意巢狀物件或陣列深度的 JSON 字串值。物件鍵不進行範本替換,不含預留位置的自訂本文會原樣傳送。

範例範本

  • 顯示文字(Show Text): {username} just cheered {hasDonation}!
  • 設定 OBS 文字來源(Set OBS Text Source): {username}: now {counterValue}, need {counterTarget}
  • 轉送聊天(Relay Chat): [{source}] {username}: {message}
  • TTS: {username} says {message}
  • 贊助提醒: {username} donated {donation} - {subtitle}
  • 熱感標籤: {username},換行,然後 {donation}。請參閱 熱感印表機指南 了解印表機設定、固定尺寸標籤和完整流程。
  • Discord 呼叫 Webhook: {"content":"{message}","username":"{username}","avatar_url":"{chatimg}"}
缺失的變數變成空字串。 如果事件沒有某個欄位(例如 {donation} 在一般聊天訊息中),預留位置會替換為空字串,而不是顯示字面的 {donation} 文字。

7. 最佳做法檢查表

  • 命名並設定色彩: 為節點設定名稱和色彩,以便日後辨認各個分支。
  • 使用內建模擬器測試 (Send Test Event),然後再將流程投入直播。
  • 在來源附近集中邏輯。 儘早篩選,避免後續額外處理。
  • 將重複記錄存入狀態節點。 使用計數器、開關和時間戳記避免重複提醒。
  • 記載 meta 欄位。 當您新增自訂的 meta 鍵時,請記載它們,讓疊加畫面和遠端用戶端保持一致。
儲存版本。 每當達到一個里程碑時就匯出流程。如果實驗出錯,匯入是最簡單的還原方式。

8. 進一步探索

從 Stream Deck 或 API 執行自訂工作流程:具名觸發條件、入門範本、工作流程探索、額外資料、HTTP/WebSocket/P2P 範例和旋鈕手勢。

準備深入了解?

  • 使用 狀態節點 (計數器、開關、計時器)來追蹤事件之間的脈絡。
  • 組合 變數和邏輯 以建立佇列系統、抽獎或評分引擎。
  • 接入 點數和獎勵 系統,讓觀眾可以主動觸發流程。
  • 執行 SSApp 桌面應用程式? 解鎖 自訂 JavaScript 節點 用於內建節點未涵蓋的任意邏輯。
  • 檢查 事件參考 了解所有平台的詳細承載資料文件。

本指南刻意設計為獨立文件,您可以複製到本機、為團隊調整,並繼續在編輯器中嘗試。

9. 自訂 JavaScript 僅限 SSApp / 桌面應用程式

Event Flow 編輯器中的兩個節點讓您撰寫在流程處理管線內執行的任意 JavaScript: 自訂程式碼(Custom Code) (觸發條件)和 執行自訂程式碼(Execute Custom Code) (動作)。當內建節點無法表達某種需求時,它們提供自訂途徑。

需要桌面應用程式。 瀏覽器擴充功能中停用了自訂 JavaScript 節點,因為 Chrome Manifest V3 內容安全性原則封鎖 new Function() / eval()。透過以下入口開啟編輯器: SSApp 桌面應用程式 以啟用它們。在擴充功能模式中,節點顯示為灰色,並帶有標籤 「僅限桌面應用程式」.
編輯程式碼: 選擇 Custom Code 節點並點擊 開啟程式碼編輯器(Open Code Editor) 開啟大型編輯視窗。 儲存並關閉(Save & Close) 檢查 JavaScript 語法並儲存整個流程; Ctrl+S 或 Cmd+S 執行相同動作。Cancel 不會變更節點。
Event Flow 編輯器 — 空白狀態
Event Flow 編輯器。左側面板列出所有可用節點;點陣畫布用於建立流程;右側面板顯示所選節點的屬性。

Custom Code — 觸發條件節點

拖曳 自訂程式碼(Custom Code) 來自 進階 群組,位於 觸發器 面板拖到畫布上。它充當閘控:僅當程式碼傳回以下值時流程才繼續: true.

觸發條件面板,顯示 Advanced 群組下的 Custom Code 節點
Custom Code 位於 進階 群組,位於 Triggers 面板。
Custom Code 觸發條件屬性面板,顯示 JavaScript 程式碼編輯器
放置觸發條件後的屬性面板。撰寫任意傳回以下值的運算式: true 或 false.
簽章: 您的程式碼以下列形式執行: function(message) { ... }
必須傳回: 布林值 — true 讓流程繼續, false 以停止它。
可用: 物件 message (參見 訊息 API 如下),加上 convertCurrency(value, targetCurrency, source) 和 convertToUSD(value, source).

Execute Custom Code — 動作節點

拖曳 執行自訂程式碼(Execute Custom Code) 來自 整合 群組,位於 操作 面板。它可以修改訊息、封鎖訊息或附加供下游節點讀取的中繼資料。

動作面板,顯示 Integrations 群組下的 Execute Custom Code
Execute Custom Code 位於 整合 群組,位於 Actions 面板。
Execute Custom Code 動作屬性面板,顯示程式碼編輯器
動作屬性。傳回一個物件,將變更合併回流程結果。
簽章: 您的程式碼以下列形式執行: function(message, result) { ... }
應傳回: 物件或 Promise,合併至 result— 請參閱 結果 API.
可用: message (事件承載資料), result (目前流程結果狀態), printThermal(html, options),加上 convertCurrency(value, targetCurrency, source) 和 convertToUSD(value, source).
SSApp 中的熱感列印: 在以下位置選擇印表機並校準紙張寬度和安全邊界: 印表機控制(Printer Control),然後傳回 printThermal('<strong>' + message.chatname + '</strong>')。SSApp 透過原生 Windows 印表機 API 靜默將工作排入佇列,並使用這些已儲存設定。流程可以透過以下選項覆寫它們: { width: '58mm', marginLeft: '3mm', marginRight: '3mm', marginTop: '2mm', marginBottom: '2mm', feed: '3mm', marginType: 'printableArea' }。傳回 Promise 使 Event Flow 能夠等待提交並回報錯誤。
畫布並排顯示 Custom Code 觸發條件和 Execute Custom Code 動作
畫布上放置了 Custom Code 觸發條件(藍色)和 Execute Custom Code 動作(綠色)。將觸發條件的輸出連接埠連接至動作的輸入連接埠即可連接它們。

物件 message

兩個節點都以下列形式接收完整事件承載資料: message。以下欄位始終可用;平台專屬事件可能包含其他欄位。

欄位資料型別說明範例
message.chatmessage字串聊天訊息文字(可能包含 HTML)"Hello stream!"
message.chatname字串傳送者的顯示名稱"CoolViewer"
message.userid字串平台使用者 ID"12345678"
message.type字串來源平台(小寫)"twitch", "youtube", "kick"
message.hasDonation字串存在時的格式化贊助字串"$5.00", "500 bits"
message.donoValue數值 / 字串來源提供時的等值美元贊助金額;有效的零值會予以採用。Event Flow 改用以下內容作為備援: currency.js 轉換標準化的 hasDonation 標籤用於門檻比較,包括 100 個未知具名單位 = 0.01 美元。它不會解析 chatmessage 文字來擷取贊助值。5
message.event字串事件類型識別碼"new_follower", "cheer", "raid"
message.membership字串適用時的會員狀態"MEMBERSHIP"
message.subtitle字串次要脈絡列"Member for 3 months"
message.mod布林值傳送者是管理員true
message.subscriber布林值傳送者是訂閱者true
message.vip布林值傳送者具有 VIP 身分true
message.chatimg字串使用者頭像 URL"https://..."
message.meta物件附加至事件的任意結構化資料{ viewers: 120 }
貨幣換算: 使用 convertCurrency(message.hasDonation, 'EUR', message.type) 將格式化的贊助標籤轉換為 EUR。它傳回數字,或 null 當不支援請求的目標貨幣時。轉換器使用 Social Stream Ninja 的內部近似匯率,不會聯繫外部匯率服務。

動作傳回的內容

從動作程式碼傳回一般物件。您包含的任何欄位都會合併至流程的 result 物件;省略的欄位保持目前值。

傳回欄位資料型別效果
modified布林值設定 true 如果您變更了 message 欄位。告知下游節點承載資料已編輯。
message物件將訊息(可能已修改)傳回,讓下游節點收到您的變更。
blocked布林值設定 true 以防止訊息顯示或轉送。
最小安全傳回值: return { modified: false, message };
即使沒有變更任何內容,傳回 message 使它繼續流向下一個節點。

程式碼片段範例

將任一項複製到相應節點類型的 JavaScript Code 文字區域。

觸發條件程式碼片段 — 傳回 true 以繼續流程

關鍵字比對(不區分大小寫)
僅當訊息包含特定單字或片語時繼續流程。
// Matches "!hello" anywhere in the message return (message.chatmessage || '').toLowerCase().includes('!hello');
規則運算式命令偵測
比對以預先定義清單中某個命令開頭的訊息(例如 !queue, !raffle, !enter).
return /^!(queue|raffle|enter)\b/i.test(message.chatmessage || '');
超過門檻的贊助
僅當贊助達到或超過最低金額時觸發。
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;
EUR 區間內的 YouTube Super Chat 或 Super Sticker
將標準 YouTube 贊助標籤轉換為 EUR,排除 Jewels/Gifts,並選擇一個聲音或視覺效果區間。
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;
平台篩選器
僅處理來自特定平台的事件。
return ['twitch', 'youtube'].includes(message.type);
訂閱者 / VIP / 管理員閘控
僅允許具權限的使用者讓流程繼續。
return !!(message.subscriber || message.vip || message.mod);
多條件 — VIP + 關鍵字
將角色檢查和訊息內容組合為單一運算式,以實現內建觸發條件無法涵蓋的條件。
const isPrivileged = !!(message.subscriber || message.vip || message.mod); const isCommand = /^!feature\b/i.test(message.chatmessage || ''); return isPrivileged && isCommand;
訊息長度閘控
僅處理包含足夠內容的訊息(適用於 TTS 或轉送,以避免單一表情洗版)。
return (message.chatmessage || '').replace(/<[^>]+>/g, '').trim().length >= 20;

動作程式碼片段 — 傳回 { modified, message }

在訊息後附加徽章或標籤
在通過此動作的每則訊息結尾加入視覺標記。
message.chatmessage = (message.chatmessage || '').trimEnd() + ' ✅'; return { modified: true, message };
有條件地封鎖訊息
檢查內容,並在規則相符時靜默捨棄訊息,適用於關鍵字篩選器無法表達的垃圾訊息模式。
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 };
移除 @提及
轉送至另一個平台之前,移除訊息中的所有 @username 提及。
message.chatmessage = (message.chatmessage || '').replace(/@\w+/g, '').trim(); return { modified: true, message };
格式化贊助公告
存在贊助時,將 chatmessage 重寫為一致的公告字串。
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 };
附加路由中繼資料,供下游節點使用
為訊息加入自訂欄位標記,後續的 轉送聊天(Relay Chat) 或 傳送訊息(Send Message) 動作可從範本變數讀取({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 };
依平台區分的訊息前綴
跨平台轉送時加入平台標籤前綴,讓觀眾知道來源。
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 };

完整範例 — VIP 功能請求機器人

該流程監聽 !feature <text> 來自訂閱者、VIP 或管理員的內容,將其重新格式化為功能請求,並轉送至第二個目標(例如 Discord)。

┌──────────────────────┐ ┌──────────────────────────┐ ┌──────────────────┐ │ Custom Code Trigger │────▶│ Execute Custom Code Action│────▶│ Relay Chat │ │ │ │ │ │ (to Discord) │ │ Gate: VIP/sub/mod │ │ Reformat message text │ │ │ │ + starts with │ │ → "📋 Feature Request │ │ │ │ !feature │ │ from {name}: {text}" │ │ │ └──────────────────────┘ └──────────────────────────┘ └──────────────────┘

步驟 1 — Custom Code 觸發條件 (貼到觸發條件的 JavaScript Code 欄位):

// 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;

步驟 2 — Execute Custom Code 動作 (貼到動作的 JavaScript Code 欄位):

// 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 };

步驟 3 — Relay Chat 動作:在動作後新增標準 Relay Chat 節點,並設定為指向 Discord(或其他)目標。此處無需自訂程式碼,重新格式化的 message.chatmessage 會自動流經。

測試流程。 點擊此按鈕: 測試流程(Test Flow) (位於編輯器右上角),無需直播即可向處理流程傳送模擬訊息。將 chatname 設為訂閱者的名稱,新增類似下列內容的訊息: !feature dark mode support,並確認 Relay Chat 目標收到重新格式化的字串。
用於傳送模擬測試事件的 Test Flow 面板
Test Flow 面板。填寫與觸發條件相符的欄位,然後點擊 執行測試(Run Test) 以驗證完整處理管線。

安全注意事項

自訂程式碼以繪製程序權限執行。 在 SSApp 內,Custom JS 節點中的程式碼可以完整存取 window 物件,以及 preload 指令碼提供的任何 API(例如 window.ninjafy)。請將匯入的流程檔案視為可執行程式碼,只匯入可信來源的流程。
  • 沒有網路沙盒。 動作程式碼可以呼叫 fetch()。如果接受他人分享的流程,請在啟用前審核 JS。
  • 錯誤會遭攔截。 程式碼中的執行階段錯誤會傳回 false (觸發條件)或不執行動作(動作),並記錄至 DevTools 主控台,流程不會當機。
  • 語法錯誤也一樣。 類型為 SyntaxError 的編譯錯誤也會以相同方式攔截。如果節點似乎沒有反應,請檢查 DevTools(F12)。