Скрипт и HTTP API для отправки Markdown-сообщения в канал MAX и, при наличии Telegram-настроек, в Telegram.
- Создайте бота в MAX и получите токен.
- Добавьте бота в нужный канал/чат MAX и дайте ему права на публикацию.
- Скопируйте
.env.exampleв.envи заполните значения:
BOT_TOKEN=your_bot_token_here
TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here
API_PORT=3000
HOST_PORT=3000
API_TOKEN=change_me
ROUTES_FILE=routes.jsonЕсли API_TOKEN задан, API требует заголовок Authorization: Bearer API_TOKEN.
Маршруты настраиваются в routes.json:
{
"defaultRoute": "main",
"routes": {
"main": {
"title": "Основной раздел",
"max": { "chatId": 123456789 },
"telegram": {
"chatId": -1001234567890,
"messageThreadId": null
}
},
"roundtable": {
"title": "Круглые столы",
"max": { "chatId": 123456789 },
"telegram": {
"chatId": -1001234567890,
"messageThreadId": 2
}
}
}
}messageThreadId нужен для Telegram-темы в forum-группе. Для обычного канала/чата укажите null.
Если маршрут должен отправлять только в MAX или только в Telegram, удалите ненужный блок max или telegram.
Для API текст сообщения передаётся прямо в запросе. Первая строка с # используется как заголовок, остальной Markdown отправляется как тело сообщения.
# Заголовок сообщения
Текст сообщения.
Можно использовать **Markdown**.Запуск:
npm run apiСборка образа:
docker build -t radioekat-message-broadcaster .Запуск контейнера:
docker run --rm \
--env-file .env \
-e API_PORT=3000 \
-p 3000:3000 \
-v "$(pwd)/routes.json:/app/routes.json:ro" \
radioekat-message-broadcasterЗапуск через Docker Compose:
docker compose up -d --buildВ Docker Compose контейнер всегда слушает API_PORT=3000, а наружный порт задаётся через HOST_PORT.
После запуска Swagger-документация открывается по умолчанию:
http://localhost:3000/
OpenAPI JSON доступен по адресу:
http://localhost:3000/openapi.json
Страница со всеми маршрутами доступна по адресу:
http://localhost:3000/routes
Публичный JSON со списком маршрутов доступен по адресу:
http://localhost:3000/routes.json
Формат ответа:
{
"defaultRoute": "general",
"routes": [
{ "title": "УКВ раздел", "route": "vhf_section" },
{ "title": "Общее радиолюбительское", "route": "general" }
]
}В Swagger ссылка на список маршрутов указана в описании параметра route.
Отправка сообщения:
curl -X POST "http://localhost:3000/send?route=roundtable" \
-H "Content-Type: text/markdown" \
-H "Authorization: Bearer change_me" \
--data-binary $'# [Заголовок](https://example.com)\n\nТекст сообщения\n\n1. **Первый пункт**\n2. [Ссылка](https://example.com)'Если параметр route не передан, используется defaultRoute из routes.json.
Отправка с картинкой и встроенной URL-кнопкой:
curl -X POST "http://localhost:3000/send?route=roundtable&imageUrl=https%3A%2F%2Fexample.com%2Fimage.jpg&buttonUrl=https%3A%2F%2Fexample.com%2Fpost&buttonText=Открыть%20запись" \
-H "Content-Type: text/markdown" \
-H "Authorization: Bearer change_me" \
--data-binary $'# Заголовок\n\nТекст сообщения'Если imageUrl не передан, сообщение уйдёт без картинки. Если buttonUrl не передан, кнопка не добавится.
Минимальный body запроса:
# Заголовок
Текст сообщенияMAX использует bot.api.sendMessageToChat(chatId, text, { format: 'markdown' }).
В Telegram используется sendMessage или sendPhoto с parse_mode: 'HTML'; поддерживаются заголовок, **bold**, *italic*, code, ссылки вида [text](https://example.com), опциональная картинка и URL-кнопка.