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 장면, 웹훅을 실행하세요.
  • 여러 플랫폼을 하나의 자동화에 결합하세요(Kick + Twitch + YouTube를 하나의 흐름으로 처리).

팝업은 빠른 프리셋, Event Flow는 맞춤 워크플로를 위한 도구 모음으로 생각하세요.

시작과 기본 개념

  • 메인 대시보드 메뉴에서 Event Flow 편집기를 여세요(데스크톱 또는 확장 프로그램).
  • 내보내기 전까지 각 프로젝트는 로컬에 저장됩니다. 사용할 기능: Export 로 백업하거나 공유하세요.
  • 다음 이름의 캔버스에서 작업합니다: 흐름 (flows). 각 흐름은 여러 플랫폼을 동시에 구독할 수 있습니다.

노드 한눈에 보기

  • 입력 (왼쪽 포트)는 메시지 컨텍스트를 받습니다.
  • 출력 (오른쪽 포트)는 수정 사항을 포함한 같은 컨텍스트를 출력합니다.
  • 논리 노드는 다음 두 가지를 모두 출력할 수 있습니다: true 채널과 선택적인 false 채널입니다.

페이로드 구조

모든 메시지는 JSON 객체를 전달합니다. 필수 키는 다음을 따릅니다: docs/event-reference.html (platform, type, chatname, chatmessage 등). 사용자 지정 데이터는 다음 아래에 추가하세요: meta.

모든 흐름은 트리거로 시작합니다

작업 노드(초록)는 스스로 실행되지 않습니다. 앞 단계 트리거 노드(파랑)가 다음으로 평가될 때만 실행됩니다: true. 작업만 연결한 흐름은 유효해 보이지만 시작할 계기가 없어 항상 대기 상태입니다. 노드 이름은 해당 노드가 무엇을 하는지를 설명하며 발생 시점을 뜻하지 않습니다: 메시지 강조 (Feature Message) 는 흐름이 도달했을 때 메시지를 강조합니다. 다른 곳에서 메시지를 강조했을 때 실행되는 것은 아닙니다.

트리거 없이 작업 노드 두 개만 연결된 상태
❌ 실행되지 않습니다. Feature Message와 Speak Text는 모두 작업입니다. 앞에 트리거가 없으면 흐름이 시작되지 않습니다.
Feature Message 및 Speak Text 작업에 연결된 Any Message 트리거
✅ 작동합니다. 다음의 모든 메시지 (Any Message) 트리거(또는 Message Contains, 정규식, 후원 이벤트 등)가 흐름을 시작하며, 이후 두 작업이 일치하는 메시지마다 실행됩니다.

Flow Actions 오버레이 (작업 출력)

알림 템플릿으로 시작하세요:

선택: 후원: 축하 효과 + 음성 을 사용하면 미리 만들어진 애니메이션과 합성 감사 음성을 재생할 수 있습니다. 고급 템플릿: 후원: 애니메이션 + 소리 + OBS 필터 템플릿도 사용할 수 있습니다. 새 알림 템플릿은 먼저 설정하고 테스트하도록 비활성화 상태로 시작합니다. OBS 템플릿에서는 소스를 고르고, 두 필터 작업 모두에 평소 꺼져 있는 동일한 필터를 지정하세요.

오디오 클립 재생 (Play Audio Clip) 와 Multi-Alerts는 이제 17개 소리 라이브러리를 공유합니다. 박수, 드럼롤, 휙 지나가는 소리, 금전등록기 등 효과음과 이름이 표시된 합성 영어 문구 4개, 간단한 소리가 포함됩니다. 듣기 / 중지 는 재생 상태를 표시하며 로컬에서 미리 재생합니다. 녹음 파일을 업로드하거나 앱 로컬 파일을 선택할 수도 있습니다. 이름이나 메시지가 바뀌는 경우에는 기존 기능을 사용하세요: 텍스트 읽기 (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 작업을 표시할 화면을 유지하세요.

Play Audio Clip 작업에 연결된 Any Message 트리거
이 흐름은 완성되어 모든 메시지에 실행됩니다. 소리가 재생되는 곳은 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. 클릭: OBS용 로컬 흐름 동작 URL 복사 (Copy Local Flow Actions URL for OBS) 를 실행하고 호스팅된 Flow Actions URL 대신 생성된 localhost URL을 사용하세요.
  3. SSApp을 계속 실행하세요. 선택한 파일이 이동했다면 작업으로 돌아가 다음을 클릭하세요: 다시 연결 (Relink).

Chrome 확장 프로그램은 단독으로 디스크 파일을 제공할 수 없습니다. 데스크톱 도우미를 사용할 수 없으면 Upload 또는 호스팅된 URL을 사용하세요. 참고: Event Flow용 미디어 파일 가이드 에서 전체 설정을 확인하세요.

로드된 오버레이에서 가능한 작업:

  • 흐름에서 트리거한 GIPHY 또는 직접 미디어 URL, 텍스트, 색종이 효과를 표시합니다.
  • 시청자가 들을 수 있도록 소리(TTS, 오디오 클립)를 로컬에서 재생합니다.
  • 팝업의 Flow Actions 섹션에 있는 WebSocket 설정으로 OBS를 제어합니다(장면 전환, 소스 켜기/끄기, GDI+/FreeType 텍스트 업데이트, 리플레이 버퍼 등).
OBS 제어 모드:
  • 브라우저 소스 API: 사용 가능 조건: actions.html 가 OBS 브라우저 소스 안에서 다음과 함께 실행되어야 합니다: 고급 접근 권한입니다. 장면 전환이 작동하며 녹화/방송/리플레이 버퍼 작업은 이 방식으로 대체할 수 있습니다.
  • OBS WebSocket: 는 일관된 제어를 위해 권장됩니다. Social Stream Ninja Flow Actions는 OBS 28+의 OBS WebSocket v5 API를 사용하며 다음 포트의 최신 요청 집합을 기대합니다: 4455.
  • 비밀번호: 선택 사항입니다. 다음은 필요한 경우에만 추가하세요: &obspw=... 를 OBS 서버에 인증이 필요한 경우 Flow Actions URL에 추가하세요.
  • 오버레이 진단: 추가할 값: &obsdebug=1 를 다음 페이지의 URL에 추가하세요: actions.html . 문제 해결 중 오버레이에 작은 실시간 OBS 연결 배지를 표시하고 싶을 때 사용하세요.
  • 텍스트 소스 설정: 는 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를 출력하면: 다른 분기에서 입력을 받지 않는 한 후속 노드의 실행이 멈춥니다(예: Condition 노드의 false 포트). 전체 흐름을 복제하지 않고 대체 논리를 쉽게 만들 수 있습니다.

입력 조건

  • 이벤트 소스 (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

  • 입력: 이전 노드에서 나온 불리언(true/false) 하나.
  • 출력: 반전된 불리언과 변경되지 않은 페이로드.
  • 기본 동작: NOT 입력에 아무것도 연결하지 않으면 결과는 false이므로 출력은 true.
예시: "Contains Keyword" 뒤에 NOT을 배치하면 다음 조건에서 알림이 실행됩니다: 시청자가 키워드를 사용하지 않는 경우.

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 메시지 ──▶ 정규식 일치 "^!" ─┐ │ ├─false──▶ 자동 답변 ("채팅 감사합니다!") │ └─true──▶ 아무 작업 없음

여기서 Regex 노드의 출력: true 는 메시지가 명령일 때의 값입니다. false 출력을 답변에 연결하므로 일반 채팅 참여자는 응답을 받고 명령은 그대로 통과합니다.

B. AND로 여러 조건 요구

YouTube 메시지 ──▶ "!queue" 포함 ─▶ AND ─▶ Discord로 전달 선물 회원권 ─▶ 사용자 역할 = 멤버 ──▲

AND 노드는 올바른 키워드를 사용하는 멤버만 Discord로 전달되도록 합니다. 두 분기가 불리언 결과를 AND 노드로 보냅니다. 다음으로 전달되는 것은 첫 번째 분기 의 페이로드입니다.

C. NOT 노드로 반복 알림 차단

이벤트 페이로드 ─▶ 상태 확인 (isAlertMuted) └─false─▶ NOT ─▶ 축하 효과 재생

State Check 는 알림이 음소거되었을 때 true 를 출력합니다. NOT 노드가 결과를 반전시켜 플래그가 다음일 때만 축하 효과를 재생합니다: false.

D. 두 소리 중 하나를 무작위 재생

RANDOM, NOT, AND 게이트로 두 오디오 클립 중 하나를 무작위로 재생하는 흐름
두 오디오 클립 중 하나를 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 및 이벤트 흐름.
Relay Chat은 인식된 반사 메시지를 자동으로 건너뜁니다.
반사 메시지는 대상 채팅으로 보낸 메시지를 다시 캡처한 것입니다. 현재 Relay Chat 작업은 인식된 반사 메시지를 건너뛰며 별도의 No Reflections 체크박스는 없습니다. 도크와 오버레이에서 표시를 숨기거나 제한하려면 다음을 사용하세요: 반향 필터(Reflection Filter) 작업의 설정: 모두 차단(Block All), 첫 번째 허용(Allow First), 또는 모두 허용(Allow All)입니다. 이는 전송이 아니라 다시 수신될 때의 표시를 제어합니다. 참고할 가이드: 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 팀 멤버를 어떻게 일치시키나요? 선택: TikTok 팀 멤버 을 User Role 노드에서 선택하세요. 수신 메시지의 TikTok 팬클럽/팀 레벨과 배지를 인식하며 메인 채팅 오버레이 설정과는 무관합니다.
  • 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}제공되거나 추정된 USD 환산 후원 값. Event Flow는 정규화된 다음 값에서 기준값을 계산합니다: hasDonation 표시 형식은 값, $값, 값 + 단위 또는 축약된 단위/값을 지원합니다. 알 수 없는 이름의 가상 단위는 100단위 = $0.01 USD로 계산하며, 가격이 없는 TikTok 선물은 선물 하나당 1코인($0.01)으로 계산합니다. {donationAmount} 는 이전 버전의 별칭입니다5.00
{event}이벤트 유형 식별자cheer, raid, new_follower
{membership}멤버십 상태MEMBERSHIP, new_sponsor
{subtitle}추가 컨텍스트멤버십 3개월
{userid}사용자의 플랫폼 ID12345678
{chatimg}사용자 아바타 URLhttps://...
{contentimg}첨부 이미지 URLhttps://...
{rewardTitle}소스가 최상위 보상 제목 필드를 제공하는 경우 보상 이름내 메시지 강조
{meta}구조화된 이벤트 데이터 (JSON){"viewers":100}
{counterValue}Counter 또는 Check Counter 단계 이후의 현재 카운터 값12
{counterTarget}카운터 목표값30
{counterRemaining}카운터 목표에서 현재 값을 뺀 값, 최소 018
변수 일치는 대소문자를 구분하지 않습니다. {USERNAME}, {Username}, 그리고 {username} 모두 같은 방식으로 작동합니다.
흐름에서 추가한 필드도 사용할 수 있습니다. 앞선 작업이 메시지에 최상위 값을 추가하면 이후 템플릿에서 직접 읽을 수 있습니다. 다음 항목도 이 방식으로 작동합니다: Check Counter 는 다음을 제공합니다: {counterValue}, {counterTarget}, 그리고 {counterRemaining}.
Call Webhook JSON: 템플릿 변수는 중첩 깊이와 관계없이 객체나 배열의 JSON 문자열 값에서 작동합니다. 객체 키에는 템플릿을 적용하지 않으며 자리표시자가 없는 사용자 지정 본문은 그대로 전송됩니다.

예시 템플릿

  • 텍스트 표시: {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 데스크톱 앱을 사용하나요? 잠금 해제 (Unlock) 사용자 지정 JavaScript 노드 를 사용하면 내장 노드로 처리할 수 없는 논리를 구현할 수 있습니다.
  • 확인할 항목: 이벤트 참고 문서 에서 모든 플랫폼의 상세 페이로드 문서를 확인하세요.

이 가이드는 독립적으로 사용할 수 있도록 작성되었습니다. 로컬에 복사하거나 팀에 맞게 수정하고 편집기에서 계속 실험해 보세요.

9. 사용자 지정 JavaScript SSApp / 데스크톱 전용

Event Flow 편집기의 두 노드로 흐름 처리 과정 안에서 실행되는 임의의 JavaScript를 작성할 수 있습니다: 사용자 지정 코드 (Custom Code) (트리거) 및 사용자 지정 코드 실행 (Execute Custom Code) (작업)입니다. 내장 노드로 표현할 수 없는 동작을 구현할 때 사용합니다.

데스크톱 앱이 필요합니다. Chrome Manifest V3의 콘텐츠 보안 정책이 다음을 차단하므로 브라우저 확장 프로그램에서는 사용자 지정 JavaScript 노드가 비활성화됩니다: 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 패널에 있습니다.
JavaScript 코드 편집기가 표시된 Custom Code 트리거 속성 패널
트리거 배치 후의 속성 패널. 다음을 반환하는 표현식을 작성하세요: true 또는 false.
함수 형식: 코드는 다음 형식으로 실행됩니다: function(message) { ... }
필수 반환값: 불리언 — true 이면 흐름을 계속하고 false 이면 중지합니다.
사용 가능: 객체 message (참고: message API 참고)와 convertCurrency(value, targetCurrency, source) 그리고 convertToUSD(value, source).

Execute Custom Code — 작업 노드

드래그할 항목: 사용자 지정 코드 실행 (Execute Custom Code) 가 있는 위치: 통합(Integrations) 그룹, 패널: 동작 패널에 있습니다. 메시지를 수정하거나 차단하거나 후속 노드가 읽을 수 있는 메타데이터를 추가할 수 있습니다.

Integrations 그룹의 Execute Custom Code가 표시된 작업 패널
Execute Custom Code의 위치: 통합(Integrations) 그룹은 Actions 패널에 있습니다.
코드 편집기가 표시된 Execute Custom Code 작업 속성 패널
작업 속성. 객체를 반환하면 변경 사항이 흐름 결과에 병합됩니다.
함수 형식: 코드는 다음 형식으로 실행됩니다: function(message, result) { ... }
권장 반환값: 다음에 병합할 객체 또는 Promise: result— 참고: result API.
사용 가능: message (이벤트 페이로드), result (현재 흐름 결과 상태), printThermal(html, options), 그리고 convertCurrency(value, targetCurrency, source) 그리고 convertToUSD(value, source).
SSApp의 감열 인쇄: 프린터 선택과 용지 폭/안전 여백 보정은 다음에서 하세요: 프린터 제어, 이어서 반환할 값: 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숫자 / 문자열소스가 제공하는 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불리언발신자가 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)를 확인하세요.