ระบบ Event Flow

คู่มือตัวแก้ไข Event Flow

สร้างระบบอัตโนมัติที่เชื่อถือได้สำหรับ Social Stream Ninja คู่มือนี้อธิบายพื้นฐาน โหนดตรรกะ การไหลของสัญญาณ และเทคนิคใช้งานจริงที่ผู้สร้างถามบ่อยที่สุด เช่น การหลีกเลี่ยงข้อความแชตสะท้อนและการเลือกเวลาที่ควรต่อบล็อก AND/NOT

ไทย

0. ภาพรวมเริ่มต้น

Event Flow เป็นตัวแก้ไขแบบโหนด แต่ละเส้นส่งเพย์โหลดข้อความพร้อมสถานะบูลีน (true = ทำต่อ false = หยุด) ใช้ แหล่งข้อมูล เพื่อป้อนเหตุการณ์ โหนดตรรกะ เพื่อกรองการตัดสินใจ และ แอ็กชัน เพื่อดำเนินการต่าง ๆ (ส่งแชต ควบคุมโอเวอร์เลย์ ส่งต่อข้อความ ฯลฯ)
ต้องการจดจำผู้เข้าร่วม ตรวจสิทธิ์ภายหลัง สุ่มจากผู้ใช้ไม่ซ้ำ หรือล้างรายการที่มีชื่อเพียงรายการเดียวหรือไม่? เปิด คู่มือ User Memory สำหรับรูปแบบสถานะร่วม ภาพหน้าจอ และตัวอย่างที่นำเข้าได้

ตัวแก้ไขนี้คืออะไร?

ตัวแก้ไข Event Flow เป็นส่วน “ระบบอัตโนมัติขั้นสูง” ของ Social Stream Ninja อยู่เหนือสวิตช์ป๊อปอัปแบบง่าย และให้คุณกำหนดตรรกะการส่งต่อเอง ใช้เมื่อต้องการ:

  • ส่งต่อแชตระหว่างบริการพร้อมตัวกรอง (เช่น ส่ง Twitch ไป Discord แต่บล็อกคำสั่ง)
  • สร้างคำสั่งตามความภักดี เกมคีย์เวิร์ด หรือเงื่อนไขเข้าร่วมจับรางวัลด้วยตรรกะ AND/OR/NOT
  • กระตุ้นโอเวอร์เลย์กำหนดเอง เสียง ฉาก OBS หรือเว็บฮุกตามข้อมูลที่คุณเพิ่มในโฟลว์
  • รวมหลายแพลตฟอร์มในระบบอัตโนมัติเดียว (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, regex, เหตุการณ์บริจาค ฯลฯ) ที่เริ่มสายงาน จากนั้นแอ็กชันทั้งสองทำงานสำหรับทุกข้อความที่ตรงเงื่อนไข

โอเวอร์เลย์ Flow Actions (เอาต์พุตแอ็กชัน)

เริ่มจากเทมเพลตแจ้งเตือน:

เลือก บริจาค: ฉลอง + เสียงพูด เพื่อใช้แอนิเมชันสำเร็จรูปและคลิปเสียงขอบคุณสังเคราะห์ หรือเทมเพลตขั้นสูง บริจาค: แอนิเมชัน + เสียง + ฟิลเตอร์ OBS เทมเพลตแจ้งเตือนใหม่เริ่มในสถานะปิด เพื่อให้คุณตั้งค่าและทดสอบก่อน สำหรับเทมเพลต OBS ให้เลือกแหล่งข้อมูลและฟิลเตอร์เดียวกันที่ปกติปิดอยู่ในแอ็กชันฟิลเตอร์ทั้งสอง

เล่นคลิปเสียง (Play Audio Clip) และ Multi-Alerts ใช้คลังเสียง 17 เสียงร่วมกันแล้ว ได้แก่ ปรบมือ รัวกลอง เสียงวูบ เครื่องคิดเงิน และเอฟเฟกต์อื่น วลีภาษาอังกฤษสังเคราะห์สี่วลีที่ติดป้ายไว้ และเสียงง่าย ๆ ฟัง / หยุด แสดงตัวอย่างในเครื่องพร้อมสถานะการเล่นที่มองเห็นได้ คุณยังอัปโหลดเสียงบันทึกหรือเลือกไฟล์ในเครื่องของแอปได้ หากชื่อหรือข้อความเปลี่ยนไป ให้ใช้ อ่านข้อความ (Speak Text) แอ็กชัน

Event Flow เล่นผ่าน Flow Actions แหล่งเบราว์เซอร์ ส่วน Multi-Alerts เล่นผ่านแหล่งเบราว์เซอร์ของตัวเอง เปิดเสียงเพียงแห่งเดียวสำหรับเหตุการณ์เดียวกันเพื่อไม่ให้เล่นซ้ำ ใช้ Tab ไปยังโหนดโฟลว์แล้วกด Enter หรือ Space เพื่อแก้คุณสมบัติ

โหนดอย่าง เล่นคลิปเสียง (Play Audio Clip), แสดงโอเวอร์เลย์สื่อ (Display Media Overlay) และตัวควบคุม 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 ให้คลิก เลือกไฟล์ภายในเครื่อง (Choose Local File).
  2. คลิก คัดลอก URL ของ Local Flow Actions สำหรับ OBS (Copy Local Flow Actions URL for OBS) และใช้ URL localhost ที่สร้างนั้นแทน URL Flow Actions บนเซิร์ฟเวอร์
  3. เปิด SSApp ให้ทำงานต่อ หากไฟล์ที่เลือกถูกย้าย ให้กลับไปที่แอ็กชันและคลิก เชื่อมไฟล์ใหม่ (Relink).

ส่วนขยาย Chrome ไม่สามารถให้บริการไฟล์จากดิสก์ได้เอง ใช้ Upload หรือ URL บนเซิร์ฟเวอร์หากไม่มีแอปเดสก์ท็อปร่วม ดู คู่มือไฟล์สื่อสำหรับ Event Flow สำหรับการตั้งค่าทั้งหมด

เมื่อโหลดแล้ว โอเวอร์เลย์นั้นทำสิ่งต่อไปนี้ได้:

  • แสดง GIPHY หรือ URL สื่อโดยตรง ข้อความ และคอนเฟตตีที่โฟลว์ของคุณกระตุ้น
  • เล่นเสียง (TTS คลิปเสียง) ในเครื่องเพื่อให้ผู้ชมได้ยิน
  • สื่อสารกับ OBS ผ่านการตั้งค่า WebSocket ในส่วน Flow Actions ของป๊อปอัป (เปลี่ยนฉาก สลับแหล่งข้อมูล อัปเดตข้อความ GDI+/FreeType รีเพลย์บัฟเฟอร์ ฯลฯ)
โหมดควบคุม OBS:
  • Browser Source API: ใช้ได้เฉพาะเมื่อ actions.html กำลังทำงานในแหล่งเบราว์เซอร์ OBS พร้อม ระดับสิทธิ์ขั้นสูง (Advanced Access Level) การเปลี่ยนฉากใช้ได้ที่นี่ และแอ็กชันบันทึก / สตรีม / รีเพลย์บัฟเฟอร์ใช้วิธีนี้สำรองได้
  • OBS WebSocket: แนะนำเพื่อให้ควบคุมได้สม่ำเสมอ Social Stream Ninja Flow Actions ใช้ OBS WebSocket v5 API จาก OBS 28 ขึ้นไป และต้องใช้ชุดคำขอรุ่นใหม่ที่พอร์ต 4455.
  • รหัสผ่าน: เป็นตัวเลือกเสริม เพิ่มเฉพาะ &obspw=... ใน URL ของ Flow Actions หากเซิร์ฟเวอร์ OBS ของคุณกำหนดให้ยืนยันตัวตน
  • การวินิจฉัยโอเวอร์เลย์: เพิ่มต่อท้าย &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 จะหยุดแอ็กชันโอเวอร์เลย์/เสียง/OBS ทั้งหมดใน Event Flow ชั่วคราว ให้ซ่อนหรือย้ายไปจออื่นแทนการปิด

1. สิ่งที่ผ่านแต่ละโหนดคืออะไร?

ระบบรัน Event Flow ส่งสองสิ่งผ่านทุกเส้น:

  1. เพย์โหลด – ออบเจ็กต์ข้อมูลเหตุการณ์หรือข้อความ
  2. สัญญาณเกต – หนึ่ง true/false บิตที่บอกโหนดถัดไปว่าควรทำงานหรือไม่
หากโหนดส่งค่า false: โหนดถัดไปหยุดทำงาน เว้นแต่จะรับอินพุตจากสาขาอื่น (เช่น false ของโหนด Condition) จึงสร้างตรรกะสำรองได้ง่ายโดยไม่ต้องทำโฟลว์ทั้งหมดซ้ำ

สิ่งที่อินพุตคาดหวัง

  • แหล่งเหตุการณ์ (Twitch Message, Timers, Manual Trigger ฯลฯ) ไม่สนใจอินพุตจากโหนดก่อนหน้า โดยสร้างเพย์โหลดเองและส่งค่าเสมอเป็น true เว้นแต่ตัวโหนดเองเกิดข้อผิดพลาด
  • โหนดแปลงข้อมูลและตรรกะ อ่านเพย์โหลดและอาจเขียนฟิลด์ใหม่ ตั้งสถานะ หรือเปลี่ยนสัญญาณเกตเป็น false.
  • โหนดแอ็กชัน ทำงานเฉพาะเมื่อเกตยังเป็น true โหนดยังส่งเพย์โหลดที่อัปเดตแล้วได้ หากคุณต้องการต่อแอ็กชันถัดไป

รูปแบบเอาต์พุต

เอาต์พุตเดียว

โหนดส่วนใหญ่มีเอาต์พุตเดียว สิ่งที่เข้า (เพย์โหลด + เกต) จะออกไปโดยไม่เปลี่ยน เว้นแต่โหนดจะแก้ไข

เอาต์พุต True/False

โหนด Condition, Compare, Regex และ Logic มีเอาต์พุตสองพอร์ต จริง จะผ่านพอร์ตสีเขียวต่อไป 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 ──▶ Regex Match "^!" ─┐ │ ├─false──▶ ตอบกลับอัตโนมัติ ("ขอบคุณที่แชต!") │ └─true──▶ ไม่ทำอะไร

ในที่นี้ โหนด Regex ส่งค่า true เมื่อข้อความเป็นคำสั่ง เราเชื่อมซ็อกเก็ต false ไปยังการตอบกลับ เพื่อให้ผู้แชตทั่วไปได้รับคำตอบรับ ขณะที่คำสั่งเพียงผ่านไป

B. กำหนดให้ผ่านหลายเงื่อนไขด้วย AND

ข้อความ YouTube ──▶ Contains "!queue" ─▶ AND ─▶ ส่งต่อไป Discord สมาชิกที่ได้รับเป็นของขวัญ ─▶ User Role = Member ──▲

โหนด AND ทำให้ส่งต่อไป Discord เฉพาะสมาชิกที่ใช้คีย์เวิร์ดถูกต้อง ทั้งสองสาขาส่งผลบูลีนไปยัง AND โดยเพย์โหลดจาก สาขาแรก จะส่งต่อไปยังโหนดถัดไป

C. ใช้โหนด NOT บล็อกการแจ้งเตือนซ้ำ

เพย์โหลดเหตุการณ์ ─▶ ตรวจสอบสถานะ (isAlertMuted) └─false─▶ NOT ─▶ เล่นการฉลอง

State Check ส่งค่าเป็น true เมื่อปิดเสียงการแจ้งเตือน การกลับผลลัพธ์นั้นด้วย NOT ทำให้แน่ใจว่าเล่นการฉลองเฉพาะเมื่อค่าสถานะเป็น false.

D. สุ่มเล่นเสียงหนึ่งในสองเสียง

โฟลว์ที่ใช้เกต RANDOM, NOT และ AND เพื่อสุ่มเล่นหนึ่งในสองคลิปเสียง
สุ่มแบบ 50/50 ระหว่างคลิปเสียงสองคลิป เกต RANDOM สุ่มหนึ่งครั้งต่อข้อความที่ตรงเงื่อนไข เมื่อผ่านจะเล่นเสียง A เมื่อไม่ผ่าน เกต NOT กลับผลลัพธ์และเกต AND ให้เล่นเสียง B แทน
ทริกเกอร์ ──▶ RANDOM (50%) ──▶ เล่นเสียง A │ └──▶ NOT ──▶ AND ──▶ เล่นเสียง B ทริกเกอร์ ──────────────────▲

เกต 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) แอ็กชันที่มี บล็อกทั้งหมด (Block All), อนุญาตรายการแรก (Allow First), หรือ อนุญาตทั้งหมด (Allow All) ค่านี้ควบคุมการแสดงผลเมื่อรับกลับเข้ามา ไม่ใช่การส่ง ทำตาม ขั้นตอนส่งต่อ Twitch และ YouTube สำหรับการตั้งค่าครบถ้วน
  • หลีกเลี่ยงระบบส่งต่อซ้ำซ้อน ปิด Relay all ส่วนกลางเมื่อใช้เส้นทาง Event Flow ที่ทำงานเทียบเท่ากัน และตรวจสอบบริการอื่นที่เชื่อมแชตเดียวกัน เมทาดาทากำหนดเองไม่รับประกันว่าจะคงอยู่หลังส่งผ่านแชตของแพลตฟอร์ม
  • ใช้โหนด 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 ในโหนด User Role โดยตรวจจับระดับและป้าย TikTok Fan Club/ทีมจากข้อความขาเข้า ไม่ขึ้นกับการตั้งค่า Main Chat Overlay
  • แต่ละโหนด Speak Text ใช้เสียงต่างกันได้หรือไม่? ได้ ป้อนชื่อหรือรหัสเสียงที่ผู้ให้บริการรองรับใน กำหนดเสียงแทน (Voice Override) หรือเว้นว่างเพื่อใช้ค่า TTS เริ่มต้นของ Flow Actions

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}มูลค่าบริจาคเทียบเท่า USD ที่ให้มาหรือประมาณไว้ Event Flow คำนวณค่าเกณฑ์จากค่าที่ปรับรูปแบบแล้วใน hasDonation ป้าย เช่น ค่า $ค่า ค่า + หน่วย หรือรูปย่อหน่วย/ค่า หน่วยเสมือนที่มีชื่อแต่ไม่รู้จักใช้ 100 หน่วย = $0.01 USD ส่วนของขวัญ TikTok ที่ไม่มีราคาใช้หนึ่งเหรียญต่อของขวัญ ($0.01 ต่อชิ้น) {donationAmount} เป็นนามแฝงแบบเดิม5.00
{event}ตัวระบุประเภทเหตุการณ์cheer, raid, new_follower
{membership}สถานะสมาชิกMEMBERSHIP, new_sponsor
{subtitle}บริบทเพิ่มเติมเป็นสมาชิกมา 3 เดือน
{userid}รหัสผู้ใช้บนแพลตฟอร์ม12345678
{chatimg}URL อวาตาร์ผู้ใช้https://...
{contentimg}URL รูปภาพที่แนบhttps://...
{rewardTitle}ชื่อรางวัลเมื่อแหล่งข้อมูลมีฟิลด์ชื่อรางวัลระดับบนสุดไฮไลต์ข้อความของฉัน
{meta}ข้อมูลเหตุการณ์แบบมีโครงสร้าง (JSON){"viewers":100}
{counterValue}ค่าตัวนับปัจจุบันหลังขั้นตอน Counter หรือ Check Counter12
{counterTarget}ค่าเป้าหมายตัวนับ30
{counterRemaining}ค่าเป้าหมายตัวนับลบค่าปัจจุบัน โดยค่าต่ำสุดคือ 018
การจับคู่ตัวแปรไม่แยกตัวพิมพ์เล็กใหญ่ {USERNAME}, {Username}, และ {username} ทั้งหมดทำงานแบบเดียวกัน
ฟิลด์ที่โฟลว์เพิ่มก็ใช้ได้ หากแอ็กชันก่อนหน้าเพิ่มค่าระดับบนสุดให้ข้อความ เทมเพลตภายหลังจะอ่านค่านั้นได้โดยตรง นี่คือวิธีที่ Check Counter มีให้ใช้ {counterValue}, {counterTarget}, และ {counterRemaining}.
JSON สำหรับ Call Webhook: ตัวแปรเทมเพลตใช้ได้ในค่าข้อความ JSON ไม่ว่าออบเจ็กต์หรืออาร์เรย์จะซ้อนลึกเท่าใด คีย์ออบเจ็กต์ไม่ผ่านการแทนค่า และเนื้อหากำหนดเองที่ไม่มีตัวแทนค่าจะส่งโดยไม่เปลี่ยน

เทมเพลตตัวอย่าง

  • Show Text: {username} just cheered {hasDonation}!
  • ตั้งแหล่งข้อความ OBS: {username}: now {counterValue}, need {counterTarget}
  • Relay Chat: [{source}] {username}: {message}
  • TTS: {username} says {message}
  • การแจ้งเตือนบริจาค: {username} donated {donation} - {subtitle}
  • ฉลากความร้อน: {username} ขึ้นบรรทัดใหม่ แล้วตามด้วย {donation} ดู คู่มือเครื่องพิมพ์ความร้อน สำหรับการตั้งค่าเครื่องพิมพ์ ฉลากขนาดคงที่ และโฟลว์ครบชุด
  • Discord Call 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 กำหนดเองถูกปิดในส่วนขยายเบราว์เซอร์ เพราะ Content Security Policy ของ 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.

แผงทริกเกอร์ที่แสดงโหนด Custom Code ในกลุ่ม Advanced
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 ในกลุ่ม Integrations
Execute Custom Code อยู่ภายใต้ การเชื่อมต่อ (Integrations) กลุ่มในแผง 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 เข้าคิวงานแบบเงียบผ่าน API เครื่องพิมพ์ของ Windows และใช้การตั้งค่าที่บันทึกไว้ โฟลว์แทนที่ค่าเหล่านั้นได้ด้วยตัวเลือก เช่น { 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สตริงรหัสผู้ใช้บนแพลตฟอร์ม"12345678"
message.typeสตริงแพลตฟอร์มต้นทาง (ตัวพิมพ์เล็ก)"twitch", "youtube", "kick"
message.hasDonationสตริงข้อความบริจาคที่จัดรูปแบบแล้ว หากมี"$5.00", "500 bits"
message.donoValueตัวเลข / ข้อความมูลค่าบริจาคเทียบเท่า USD เมื่อแหล่งข้อมูลให้มา โดยยอมรับค่า 0 ที่ถูกต้อง Event Flow ใช้ค่าทดแทนจาก currency.js การแปลงค่าที่ปรับรูปแบบแล้วใน hasDonation เพื่อเปรียบเทียบเกณฑ์ รวมถึงหน่วยเสมือนที่มีชื่อแต่ไม่รู้จัก 100 หน่วย = $0.01 USD โดยไม่แยกวิเคราะห์ 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บูลีนผู้ส่งมีสถานะ VIPtrue
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');
ตรวจจับคำสั่งด้วย Regex
จับคู่ข้อความที่เริ่มด้วยคำสั่งจากรายการที่กำหนด (เช่น !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;
YouTube Super Chat หรือ Super Sticker ในช่วง EUR ที่กำหนด
แปลงป้ายบริจาค 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 };
ลบ @mentions
ลบการกล่าวถึง @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 │────▶│ แอ็กชัน Execute Custom Code │────▶│ Relay Chat │ │ │ │ │ │ (ไป Discord) │ │ เกต: VIP/สมาชิก/ผู้ดูแลแชต │ │ จัดรูปแบบข้อความใหม่ │ │ │ │ + เริ่มด้วย │ │ → "📋 คำขอเพิ่มฟีเจอร์ │ │ │ │ !feature │ │ จาก {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 ออบเจ็กต์และ API ที่สคริปต์ preload เปิดให้ใช้ (เช่น window.ninjafy) ปฏิบัติต่อไฟล์โฟลว์ที่นำเข้าเหมือนโค้ดที่รันได้ นำเข้าเฉพาะโฟลว์จากแหล่งที่เชื่อถือ
  • ไม่มีแซนด์บ็อกซ์เครือข่าย โค้ดแอ็กชันเรียกใช้ fetch() หากรับโฟลว์ที่ผู้อื่นแชร์มา ให้ตรวจสอบ JS ก่อนเปิดใช้
  • มีการดักจับข้อผิดพลาด ข้อผิดพลาดขณะรันในโค้ดของคุณจะคืนค่า false (ทริกเกอร์) หรือไม่ทำอะไร (แอ็กชัน) และบันทึกลงคอนโซล DevTools โดยโฟลว์ไม่ล่ม
  • รวมถึงข้อผิดพลาดทางไวยากรณ์ด้วย ข้อผิดพลาดชนิด SyntaxError ในขั้นคอมไพล์ก็ถูกดักจับแบบเดียวกัน ตรวจ DevTools (F12) หากโหนดดูเหมือนไม่ทำอะไร