Телеграм бот на Aiogram — как совместить работу entities и parse_mode?

Хотел создать, и даже создал почти универсальный редактор постов на Aiogram, который добавляет подпись-ссылку к посту в телеграм-канале, при этом удаляя текстовые ссылки из поста и сохраняя свойства текста (жирный, курсив и т.д.). Но столкнулся с банальной проблемой: по-моему, невозможно совместить работу "entities" и "parse_mode".

То есть, с помощью примерно такого кода (возьмём только текстовые посты для упрощения):
@dp.channel_post_handler(content_type=['text'])
async def redactor(message: types.Message):
    ent = message.entities
    new_ent = [e for e in ent if e.type != "text_link"]
    mylink = '<a href="http://t.me/some_link">text for link</a>'
    await message.edit_text(f'{message.text} \n {mylink}', entities=new_ent, parse_mode="html")

И сообщения:
сообщение с жирным текстом

Результатом будет отредактированное сообщение со ссылкой, но без жирного текста. Если же убрать параметр parse_mode, то жирный текст останется жирным, но, естественно, ссылка не будет отображаться корректно. С Markdown разметкой работает аналогично.

Как выйти из ситуации, почему так работает? Получается, нужна только рукописная функция, которая будет обрабатывать текст, полученный с помощью parse_entities() или есть более простые варианты?
  • Вопрос задан
  • 2634 просмотра
Решения вопроса 1
drygdryg
@drygdryg
Python-разработчик
В официальной документации сказано, что parse_mode и entities взаимоисключаемые, т.е. возможно использовать только одно из них. Можно отказаться от parse_mode и использовать entities для вставки своей ссылки в конец сообщения как MessageEntity с типом "text_link", например, так:
@dp.channel_post()
async def redactor(message: types.Message):
    ent = message.entities
    new_ent = [e for e in ent if e.type != "text_link"]
    new_text = f'{message.text}\n'
    link_text = "text for link"
    link_address = "http://t.me/some_link"
    new_ent.append(types.MessageEntity(
        type="text_link", offset=len(new_text),
        length=len(link_text), url=link_address
    ))
    new_text = f'{new_text}{link_text}'
    await message.edit_text(new_text, entities=new_ent)

Результат работы:
636a70de08509412107858.png
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@fork995
Информация о форматировании также содержится в массиве entities.
Так например выглядит текстовое сообщение, написанное курсивом, одно слово в середине bold.

"entities": [
   {
    "offset": 0,
    "length": 7,
    "type": "italic"
   },
   {
    "offset": 7,
    "length": 9,
    "type": "italic"
   },
   {
    "offset": 7,
    "length": 4,
    "type": "bold"
   }
  ]
 }
}

Поэтому если в посте изначально было форматирование, то его можно сохранить.
Посмотрите дебаггером или просто принтом, что в entities до правки и что после, именно редактирование причина косяка. Надо дописать ссылку в массив, при этом не испортив то, что было. и parse_mode тут не нужен, в таком случае
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы