Система Event Flow

Посібник із редактора потоків подій

Створюйте надійні автоматизації для Social Stream Ninja. Цей посібник пояснює основи, логічні вузли, проходження сигналів і практичні прийоми, про які автори найчастіше запитують: наприклад, як уникати відлуння чату та коли поєднувати блоки AND/NOT.

Українська

0. Короткий огляд

Потоки подій — редактор на основі вузлів. Кожна лінія передає дані повідомлення та логічний стан (true = продовжити, false = зупинити). Використовуйте джерела для додавання подій, логічні вузли для фільтрування рішень, а дії для виконання дій (надсилання чату, керування оверлеями, пересилання повідомлень тощо).
Потрібно запам’ятовувати учасників, перевіряти подальший допуск, проводити розіграш серед унікальних користувачів або очищувати один іменований список? Відкрийте Посібник із пам’яті користувачів щоб ознайомитися з моделлю спільного стану, знімками екрана та прикладом для імпорту.

Що це за редактор?

Редактор 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, регулярний вираз, подія донату тощо) запускає ланцюжок; потім обидві дії виконуються для кожного відповідного повідомлення.

Оверлей Flow Actions (вивід дій)

Почніть із шаблону сповіщення:

Виберіть Донат: святкування + голос для готової анімації та синтетичного кліпу подяки або розширений Донат: анімація + звук + фільтр OBS шаблон. Нові шаблони сповіщень спочатку вимкнені, щоб ви могли налаштувати й перевірити їх. Для шаблону OBS виберіть джерело та той самий зазвичай вимкнений фільтр в обох діях фільтра.

Відтворити аудіокліп (Play Audio Clip) і Multi-Alerts тепер мають спільну бібліотеку з 17 звуків: оплески, барабанний дріб, свист, касовий апарат та інші ефекти, чотири позначені синтетичні фрази англійською та прості звуки. Слухати / зупинити відтворює локальний попередній перегляд із видимим станом відтворення. Ви також можете завантажити запис або вибрати локальний файл застосунку. Для змінних імен або повідомлень використовуйте наявну Озвучити текст (Speak Text) дію.

Event Flow відтворює звук через джерело браузера Flow Actions ; Multi-Alerts відтворює через власне джерело браузера. Для тієї самої події залишайте звук увімкненим лише в одному з них, щоб уникати подвійного відтворення. Перейдіть клавішею Tab до вузла сценарію та натисніть Enter або пробіл, щоб редагувати його властивості.

Таким вузлам, як Відтворити аудіокліп (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 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: рекомендовано для узгодженого керування. Flow Actions Social Stream Ninja використовує API OBS WebSocket v5 з 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, таймери, ручний тригер тощо) ігнорують вхід згори — вони генерують власні дані й завжди видають 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 ──▶ Збіг Regex «^!» ─┐ │ ├─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/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 (TikTok Team Member) у вузлі User Role. Він розпізнає рівні й значки TikTok Fan Club/команди у вхідному повідомленні та не залежить від налаштувань головного оверлею чату.
  • Чи може кожен вузол Speak Text використовувати інший голос? Так. Введіть підтримувану постачальником назву або ID голосу в Перевизначення голосу (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}ID користувача на платформі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 вимкнені в розширенні браузера, оскільки політика безпеки вмісту Chrome Manifest V3 блокує new Function() / eval(). Відкрийте редактор через Настільний застосунок SSApp щоб увімкнути їх. У режимі розширення вузли відображаються сірими з позначкою «Лише настільний застосунок».
Редагування коду: виберіть вузол Custom Code і натисніть Відкрити редактор коду (Open Code Editor) для великого вікна редагування. Зберегти й закрити (Save & Close) перевіряє синтаксис JavaScript і зберігає весь сценарій; Ctrl+S або Cmd+S робить те саме. Скасування залишає вузол без змін.
Редактор Event Flow — порожній стан
Редактор Event Flow. Ліва панель перелічує доступні вузли; на крапковому полотні ви створюєте сценарії; права панель показує властивості вибраного вузла.

Custom Code — вузол тригера

Перетягніть Власний код (Custom Code) із групи Розширено на панелі Тригери на полотно. Він працює як перемикач пропуску: сценарій продовжується, лише коли ваш код повертає true.

Панель тригерів із вузлом Custom Code у групі Advanced
Custom Code розміщений у групі Розширено на панелі тригерів.
Панель властивостей тригера Custom Code з редактором JavaScript
Панель властивостей після розміщення тригера. Напишіть будь-який вираз, що повертає true або false.
Сигнатура: ваш код виконується як function(message) { ... }
Має повертати: логічне значення — true щоб дати сценарію продовжитися, false щоб його зупинити.
Доступно: об’єкт message (дивіться API повідомлення нижче), а також convertCurrency(value, targetCurrency, source) і convertToUSD(value, source).

Execute Custom Code — вузол дії

Перетягніть Виконати власний код (Execute Custom Code) із групи Інтеграції на панелі Дії . Він може змінювати повідомлення, блокувати його або додавати метадані, доступні наступним вузлам.

Панель дій з Execute Custom Code у групі Integrations
Execute Custom Code у групі Інтеграції на панелі дій.
Панель властивостей дії 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рядокID користувача платформи"12345678"
message.typeрядокПлатформа джерела (малими літерами)"twitch", "youtube", "kick"
message.hasDonationрядокФорматований рядок донату, якщо є"$5.00", "500 bits"
message.donoValueчисло / рядокЕквівалент донату в USD, якщо його надає джерело; дійсні нульові значення враховуються. 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');
Виявлення команд регулярним виразом
Знаходьте повідомлення, які починаються з команди із заданого списку (наприклад, !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 };
Видалити @згадки
Видаліть із повідомлення всі згадки @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/sub/mod │ │ Переформатувати текст │ │ │ │ + починається з │ │ → «📋 Запит на функцію │ │ │ │ !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, які надає скрипт попереднього завантаження (наприклад, window.ninjafy). Ставтеся до імпортованих файлів сценаріїв як до виконуваного коду — імпортуйте лише з джерел, яким довіряєте.
  • Немає мережевої пісочниці. Код дії може викликати fetch(). Якщо приймаєте сценарії від інших, перевіряйте JS перед їх активацією.
  • Помилки перехоплюються. Помилка виконання у вашому коді повертає false (тригер) або нічого не виконує (дія) і записує повідомлення в консоль DevTools — сценарій не завершується аварійно.
  • Синтаксичні помилки також. Помилка типу SyntaxError на етапі компіляції перехоплюється так само. Перевірте DevTools (F12), якщо вузол начебто нічого не робить.