Уведомления через вебхук
Рецепт на Node.js — небольшой сервер принимает вебхуки Slicer, проверяет подпись и присылает в Telegram сообщение, когда ролик готов или опубликован.
На этой странице
Монтаж идёт несколько минут, и ждать его в терминале не нужно. Этот рецепт поднимает маленький сервер, который получает вебхуки Slicer и пишет в Telegram: «Ролик готов» со ссылкой на проект, «Опубликовано» со ссылкой на ролик в соцсети. Так же легко отправлять сообщения в Slack, почту или свою систему задач.
Что понадобится: Node.js 20+, сервер с публичным https-адресом (или туннель для проверки), токен с областью
webhooks, бот Telegram (его токен выдаёт @BotFather (откроется в новой вкладке)) и id чата, куда писать.
Сервер
// npm install express
// SLICER_WEBHOOK_SECRET=whsec_… TELEGRAM_BOT_TOKEN=… TELEGRAM_CHAT_ID=… node notify.mjs
import { createHmac, timingSafeEqual } from 'node:crypto';
import express from 'express';
const TOLERANCE_SEC = 5 * 60;
function verifySlicerSignature(rawBody, header, secret) {
if (typeof header !== 'string') return false;
const pairs = header.split(',').map((part) => part.trim().split('='));
const timestamp = pairs.find(([key]) => key === 't')?.[1];
const signatures = pairs.filter(([key]) => key === 'v1').map(([, value]) => value);
if (!timestamp || !/^\d+$/.test(timestamp) || signatures.length === 0) return false;
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > TOLERANCE_SEC) return false;
const expected = createHmac('sha256', secret).update(`${timestamp}.`).update(rawBody).digest();
return signatures.some((value) => {
const received = Buffer.from(value, 'hex');
return received.length === expected.length && timingSafeEqual(received, expected);
});
}
async function telegram(text) {
const response = await fetch(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ chat_id: process.env.TELEGRAM_CHAT_ID, text, disable_web_page_preview: true }),
});
if (!response.ok) console.error('Telegram ответил', response.status);
}
function message(event) {
const item = event.data ?? {};
switch (event.type) {
case 'project.succeeded':
return `🎬 Ролик «${item.title}» готов — ${Math.round(item.durationSec ?? 0)} с.\n${item.appUrl}`;
case 'export.succeeded':
return `📦 Экспорт «${item.title}» готов.\n${item.appUrl}`;
case 'publication.published':
return `🚀 Опубликовано в ${item.platform}: ${item.url}`;
case 'ping':
return '✅ Вебхук Slicer подключён';
default:
return null; // остальные события этому боту не нужны
}
}
const app = express();
const seen = new Set(); // id событий: повторная доставка не пришлёт второе сообщение
app.post('/slicer/webhook', express.raw({ type: 'application/json' }), (req, res) => {
if (!verifySlicerSignature(req.body, req.get('Slicer-Signature'), process.env.SLICER_WEBHOOK_SECRET)) {
return res.status(400).send('invalid signature');
}
const event = JSON.parse(req.body.toString('utf8'));
res.sendStatus(204); // Slicer ждёт ответа не дольше 10 секунд — отвечаем сразу
if (seen.has(event.id)) return;
seen.add(event.id);
const text = message(event);
if (text) telegram(text).catch((error) => console.error(error));
});
app.listen(Number(process.env.PORT ?? 3000), () => console.log('Жду вебхуки Slicer'));Подключение
Запустите сервер по https
Разместите
notify.mjsна сервере с публичнымhttps-адресом. Для проверки на своём компьютере подойдёт туннель:Терминал node notify.mjs & cloudflared tunnel --url http://localhost:3000Туннель напечатает адрес вида
https://….trycloudflare.com.Зарегистрируйте вебхук
Терминал curl https://api.slicer.media/v1/webhooks \ -H "Authorization: Bearer $SLICER_TOKEN" \ -H "Content-Type: application/json" \ -d '{"url":"https://notify.example.com/slicer/webhook","events":["project.succeeded","export.succeeded","publication.published"],"description":"Telegram"}' \ | jq -r '.data.secret, .data.webhook.id'Первая строка ответа — секрет
whsec_…: передайте его серверу вSLICER_WEBHOOK_SECRETи перезапустите его. Вторая — id вебхука.Проверьте
Терминал curl -X POST https://api.slicer.media/v1/webhooks/$WEBHOOK_ID/test -H "Authorization: Bearer $SLICER_TOKEN"В чат придёт «✅ Вебхук Slicer подключён». Если нет — посмотрите журнал доставок:
GET /v1/webhooks/{id}/deliveriesпокажет код ответа вашего сервера.
Тонкости
- Сырое тело.
express.rawотдаёт тело как есть — подпись считается именно по нему. Если в приложении уже стоитexpress.json()глобально, подключите маршрут вебхука до него. - Повторы. Если сервер не ответил за 10 секунд или ответил ошибкой, Slicer повторит доставку позже. Множество
seenне даёт отправить сообщение дважды; в продакшене храните id событий в Redis или базе. - Безопасность. Не логируйте секрет и не отвечайте подробностями на неверную подпись. Ссылка
appUrlоткрывает проект только после входа в аккаунт Slicer, поэтому её можно отправлять в рабочий чат.