Как в Telethon правильно обработать список сущностей при пересылке нескольких сообщений?

Как можно удалить ссылки при пересылке группы сообщений, учитывая, что метод <code>forward_messages()</code> не позволяет изменять список <code>entities</code> на уровне API Telegram? Я создал свой класс для группировки сообщений и использую метод <code>send_file()</code>, в который можно передать список файлов, подпись и <code>entities</code>. Есть ли другие подходы или рекомендации для решения этой проблемы?
  • 3 октября 2024 г. 20:34
Ответы на вопрос 2
Для обработки списка сущностей при пересылке нескольких сообщений с использованием Telethon, а также для удаления ссылок можно рассмотреть несколько подходов. Как вы правильно заметили, метод `forward_messages()` не позволяет изменять сущности, так как они формируются на стороне API Telegram.

1. **Использование `send_message()` вместо `forward_messages()`:**
   Как вы уже упомянули, вы можете использовать метод `send_file()` с вашими собственными изменениями. Вы можете пройтись по сообщениям, извлекать текст и сущности, и затем модифицировать их по своему усмотрению, например, удалять ссылки. После этого вы можете использовать `send_message()` для отправки модифицированного текста и новых сущностей.

2. **Создание собственного класса для обработки сообщений:**
   Если вы уже создали свой класс для группировки сообщений, добавьте в него метод для обработки текста и модификации сущностей. В этом методе можете реализовать логику удаления ссылок из текста сообщения.

   Пример кода для удаления ссылок из текста и работы с сущностями:

   ```python
   import re
   from telethon import TelegramClient
   from telethon.tl.types import MessageEntityUrl

   async def process_and_send_messages(client, messages, target):
       for message in messages:
           text = message.message
           entities = list(message.entities)  # Копируем сущности

           # Удаляем ссылки из текста
           urls_to_remove = {entity for entity in entities if isinstance(entity, MessageEntityUrl)}
           for url in urls_to_remove:
               start = url.offset
               end = start + url.length
               text = text[:start] + text[end:]  # Удаляем URL из текста
               # Освобождаем сущность URL от списка
               entities.remove(url)

           # Отправляем сообщение без ссылок
           await client.send_message(target, text, entities=entities)

   # Пример использования:
   async with TelegramClient('session_name', api_id, api_hash) as client:
       messages_to_send = await client.get_messages('source_chat', limit=10)
       await process_and_send_messages(client, messages_to_send, 'target_chat')
   ```

3. **Группировка сообщений:**
   Если вы хотите отправить сообщения группами, вы можете дополнительно сохранять сообщения в временном списке и отправлять их партиями, используя `await client.send_message()` для каждой группы.

4. **Дополнительные подходы:**
   - **Webhook-based solution:** Если это критично, вы можете настроить свой собственный прокси-сервер, который будет обрабатывать сообщения перед отправкой. Это более сложный путь, но полезный, если вам нужно выполнить больше манипуляций с сообщениями.
   - **Использование формата Markdown или HTML:** Если вы хотите просто убрать ссылки, а не тексты, можете использовать форматирование в Telethon. Например, можно послать текст с форматированием, где ссылки просто не будут отображаться.

Используя один из этих подходов, вы сможете управлять сущностями и контролировать содержимое сообщений при их пересылке.
Решил проблему под свои нужды изменением кода в библиотеке. Оказалось, если передаётся список медиа, то он обрабатывается в этом блоке  через цикл, с помощью вызова метода _send_album() , который даже не принимает переданные ранее formatting_entities . 

Поэтому, я дописал в аргументы метода _send_album() аргумент formatting_entities:
async def _send_album(self: 'TelegramClient', entity, files, caption='',
                          formatting_entities=None,
                          progress_callback=None, reply_to=None,
                          parse_mode=(), silent=None, schedule=None,
                          supports_streaming=None, clear_draft=None,
                          force_document=False, background=None, ttl=None):

И в сам вызов _send_album() тоже дописал передачу наших formatted_entities
result = []
            while file:
                result += await self._send_album(
                    entity, file[:10], caption=captions[:10], formatting_entities=formatting_entities,
                    progress_callback=used_callback, reply_to=reply_to,
                    parse_mode=parse_mode, silent=silent, schedule=schedule,
                    supports_streaming=supports_streaming, clear_draft=clear_draft,
                    force_document=force_document, background=background,
                )
                file = file[10:]
                captions = captions[10:]
                sent_count += 10

            return result

Затем, внутри метода _send_album() после обработки подписей вставил код, чтобы formatted_entities к первому сообщению, если оно содержит текст:
if captions and captions[0]:
            captions[0] = (captions[0][0], formatting_entities)

Ну и всё заработало. Теперь группа отправляется с форматированием. Но эти изменения тоже необходимо немного подкорректировать чтобы они универсально работали в разных случаях.
Похожие вопросы