Объект MessageEntity - приятный бонус от Телеграм

Объект с полезной информацией, который помогает боту модерировать сообщения пользователей в группе.

В Телеграм есть хороший инструмент, он позволяет без дополнительных манипуляций модерировать сообщения на предмет наличия нежелательного содержимого, такого как ссылки или email. Можно создать логику, где ссылки запрещено постить пользователям, которые только добавились в группу и не имеют нужного доверия.

Если текстовая часть имеет форматирование, то Телеграм вместе с текстом направить в бот массив объектов MessageEntity, при этом если посмотреть на сам текст, то он без тегов форматирования, то есть все лежит в объекте entities

Содержание объекта:

  1. type - mention - ссылка на пользователя, hashtag - хештег, cashtag - валюта, bot_command - команда для бота, url - ссылка, email - электронная почта, phone_number - номер телефона, [bold, italic, underline, strikethrough] - форматирование текста, spoiler - скрытый текст, code - часть строки как код, pre - блок кода, text_link - текстовая сслыка, text_mention - ссылка на пользователя без username
  2. offset - старт форматированного фрагмента от начала текста
  3. length - длинна форматированного фрагмента
  4. url - ссылка для text_link
  5. user - объект User для text_mention
  6. language - язык блока pre

Нам останется только получить фрагмент по указанным координатам [offset, length], и что-то с ним сделать - например закрыть каждый символ знаком звездочки (*).

Пример приведу в окружении Google App Script на JavaScript, как работать в этом окружении можете ознакомиться в статье про бота обратной связи  

Сделаем бота, который будет отслеживать содержание сообщений участников группы на предмет наличия определенного форматирования: текстовые ссылки (text_link), просто ссылки (url) и email.

После получения содержимого сообщения, это может быть как просто текстовое сообщение так и описание медиа-файла. И там и там возможно форматирование. Направим текст и объект с настройками форматирования в функцию checkText().

В этой функции разделим объекты форматирования на две группы [запрещенные и остальные], если запрещенные обнаружены, то передадим в функцию преобразования prepareText()

/**
 * Проверяем необходимость проверки
 * @param text
 * @param entities
 */
function checkText(text, entities) {
  // массив запрещенного форматирования
  const off = ['text_link', 'url', 'email'];
  // если есть форматирование
  if (entities !== null) {
    // получаем массив запрещенного
    let prohibited = entities.filter(item => off.includes(item.type));
    // получаем массив допустимого
    let admissible = entities.filter(item => !off.includes(item.type));
    // если есть что заменить
    if (prohibited.length) {
      // отправляем на обработку
      prepareText(text, prohibited, admissible);
    }
  }
}

В функции prepareText() переберем массив с запрещенным форматированием и преобразуем через функцию replaceText(), после через функцию sendFormattedText() удалим сообщение пользователя и выведем преобразованное.

/**
 * Заменяем запрещенное
 * @param text
 * @param prohibited
 * @param admissible
 */
function prepareText(text, prohibited, admissible) {
  // перебираем запрещенное и заменяем текст звездочкой
  prohibited.forEach(function (item) {
    // обрабатываем
    text = replaceText(text, item);
  });
  // отправим отформатированный текст
  sendFormattedText(text, admissible);
}

Функция replaceText() получаем исходный текст и объект с форматированием, по координатам offset и length заменим все символы кроме пробелов на знак звездочки (*)

/**
 * Заменяем
 * @param text
 * @param formate
 * @returns {string}
 */
function replaceText(text, formate) {
  // Заменим фрагмент *
  let formatting = text.substring(formate.offset, formate.offset + formate.length)
       .replace(/[^\s]/g, "*");
  // вернем склейку текст до фрагмента + фрагмент + текст после фрагмента
  return text.substring(0, formate.offset) + formatting + text.substring(formate.offset + formate.length);
}

Перед отправкой отредактированного сообщения текст пропустим через функцию prepareMessageWithEntities(), которая применит допущенное форматирование если оно есть.

/**
 * Форматирование текста
 * @param text
 * @param entities
 * @returns {*}
 */
function prepareMessageWithEntities(text, entities) {
  // проверяем наличие форматирования
  if (entities !== null && entities.length > 0) {
    // готовим переменную в нее будем добавлять
    let prepareText = "";
    // перебираем форматирование
    entities.forEach(function (entity, idx, arr) {
      // добавляем все что между форматированием
      if (entity.offset > 0) {
        /*
          * старт = если начало больше 0 и это первый элемент то берем сначала с нуля
          * если не первый то берем сразу после предыдущего элемента
          *
          * длина = это разница между стартом и текущим началом
          */
        // определяем начало
        let start = (idx === 0)
          ? 0
          : (arr[idx - 1].offset + arr[idx - 1].length);
        // определяем длину
        let length = entity.offset - start;
        // добавляем
        prepareText = prepareText + text.substr(start, length);
      }
      // выбираем текущий элемент форматирования
      let charts = text.substr(entity.offset, entity.length);
      // обрамляем в необходимый формат
      if (entity.type === "bold") {
        // полужирный
        charts = "<b>" + charts + "</b>";
      } else if (entity.type === "italic") {
        // курсив
        charts = "<i>" + charts + "</i>";
      } else if (entity.type === "code") {
        // код
        charts = "<code>" + charts + "</code>";
      } else if (entity.type === "pre") {
        // inline код
        charts = "<pre>" + charts + "</pre>";
      } else if (entity.type === "strikethrough") {
        // зачеркнутый
        charts = "<s>" + charts + "</s>";
      } else if (entity.type === "underline") {
        // подчеркнутый
        charts = "<u>" + charts + "</u>";
      } else if (entity.type === "spoiler") {
        // скрытый
        charts = "<tg-spoiler>" + charts + "</tg-spoiler>";
      } else if (entity.type === "text_link") {
        // ссылка текстовая
        charts = "<a href='" + entity.url + "'>" + charts + "</a>";
      }
      // добавляем в переменную
      prepareText = prepareText + charts;
    });
    // добавляем остатки текста если такие есть
    prepareText = prepareText + text.substr((entities[entities.length - 1].offset + entities[entities.length - 1].length));
    // возвращаем результат
    return prepareText;
  }
  // по умолчанию вернем не форматированный текст
  return text;
}

Результат работы бота


Весь код бота вы можете скачать и использовать его как пример

Исходный код бота.gs
2.6
0 комментариев
Авторизуйтесь через Telegram, чтобы оставить комментарий.
Откройте бот @iMakeBot, нажмите кнопку Старт/Start. Следуйте инструкциям бота.