Enhance message sending functionality to filter unsupported parameters

- Introduced a `SUPPORTED_PARAMS` dictionary to define valid parameters for each message type.
- Added a `filter_kwargs` utility function to filter out unsupported parameters based on the content type.
- Updated `send_message_by_type`, `send_message_via_queue`, and `send_direct_message` functions to utilize the new filtering logic, ensuring only valid parameters are passed during message sending.
- Improved handling for unknown content types by sending a default text message.
This commit is contained in:
machka-pasla
2025-08-25 13:49:31 +03:00
parent b42fae8772
commit 6e7eb6acfd
+66 -32
View File
@@ -1,7 +1,7 @@
# Bot utilities package # Bot utilities package
from dataclasses import dataclass from dataclasses import dataclass
from typing import Optional from typing import Optional, Dict, Any
from aiogram import types from aiogram import types
@@ -13,6 +13,26 @@ class MessageContent:
text: Optional[str] = None text: Optional[str] = None
# Словари поддерживаемых параметров для каждого типа сообщения
SUPPORTED_PARAMS = {
"text": {"parse_mode", "entities", "disable_web_page_preview", "disable_notification", "protect_content", "reply_markup", "reply_to_message_id", "allow_sending_without_reply", "message_thread_id"},
"photo": {"caption", "parse_mode", "caption_entities", "disable_notification", "protect_content", "reply_markup", "reply_to_message_id", "allow_sending_without_reply", "message_thread_id", "has_spoiler"},
"video": {"duration", "width", "height", "thumbnail", "caption", "parse_mode", "caption_entities", "supports_streaming", "disable_notification", "protect_content", "reply_markup", "reply_to_message_id", "allow_sending_without_reply", "message_thread_id", "has_spoiler"},
"animation": {"duration", "width", "height", "thumbnail", "caption", "parse_mode", "caption_entities", "disable_notification", "protect_content", "reply_markup", "reply_to_message_id", "allow_sending_without_reply", "message_thread_id", "has_spoiler"},
"document": {"thumbnail", "caption", "parse_mode", "caption_entities", "disable_content_type_detection", "disable_notification", "protect_content", "reply_markup", "reply_to_message_id", "allow_sending_without_reply", "message_thread_id"},
"audio": {"caption", "parse_mode", "caption_entities", "duration", "performer", "title", "thumbnail", "disable_notification", "protect_content", "reply_markup", "reply_to_message_id", "allow_sending_without_reply", "message_thread_id"},
"voice": {"caption", "parse_mode", "caption_entities", "duration", "disable_notification", "protect_content", "reply_markup", "reply_to_message_id", "allow_sending_without_reply", "message_thread_id"},
"sticker": {"disable_notification", "protect_content", "reply_markup", "reply_to_message_id", "allow_sending_without_reply", "message_thread_id"},
"video_note": {"duration", "length", "thumbnail", "disable_notification", "protect_content", "reply_markup", "reply_to_message_id", "allow_sending_without_reply", "message_thread_id"},
}
def filter_kwargs(content_type: str, kwargs: Dict[str, Any]) -> Dict[str, Any]:
"""Фильтрует kwargs, оставляя только поддерживаемые параметры для данного типа сообщения"""
supported = SUPPORTED_PARAMS.get(content_type, set())
return {k: v for k, v in kwargs.items() if k in supported}
def get_message_content(message: types.Message) -> MessageContent: def get_message_content(message: types.Message) -> MessageContent:
""" """
Определяет тип контента сообщения и возвращает его данные. Определяет тип контента сообщения и возвращает его данные.
@@ -53,76 +73,79 @@ async def send_message_by_type(bot, chat_id: int, content: MessageContent, **kwa
""" """
Отправляет сообщение указанного типа. Отправляет сообщение указанного типа.
Использует match/case вместо длинных if-elif цепочек. Использует match/case вместо длинных if-elif цепочек.
Автоматически фильтрует неподдерживаемые параметры.
""" """
# Фильтруем kwargs для данного типа сообщения
filtered_kwargs = filter_kwargs(content.content_type, kwargs)
match content.content_type: match content.content_type:
case "text": case "text":
await bot.send_message( await bot.send_message(
chat_id=chat_id, chat_id=chat_id,
text=content.text, text=content.text,
**kwargs **filtered_kwargs
) )
case "photo": case "photo":
await bot.send_photo( await bot.send_photo(
chat_id=chat_id, chat_id=chat_id,
photo=content.file_id, photo=content.file_id,
caption=content.text or None, caption=content.text or None,
**kwargs **filtered_kwargs
) )
case "video": case "video":
await bot.send_video( await bot.send_video(
chat_id=chat_id, chat_id=chat_id,
video=content.file_id, video=content.file_id,
caption=content.text or None, caption=content.text or None,
**kwargs **filtered_kwargs
) )
case "animation": case "animation":
await bot.send_animation( await bot.send_animation(
chat_id=chat_id, chat_id=chat_id,
animation=content.file_id, animation=content.file_id,
caption=content.text or None, caption=content.text or None,
**kwargs **filtered_kwargs
) )
case "document": case "document":
await bot.send_document( await bot.send_document(
chat_id=chat_id, chat_id=chat_id,
document=content.file_id, document=content.file_id,
caption=content.text or None, caption=content.text or None,
**kwargs **filtered_kwargs
) )
case "audio": case "audio":
await bot.send_audio( await bot.send_audio(
chat_id=chat_id, chat_id=chat_id,
audio=content.file_id, audio=content.file_id,
caption=content.text or None, caption=content.text or None,
**kwargs **filtered_kwargs
) )
case "voice": case "voice":
await bot.send_voice( await bot.send_voice(
chat_id=chat_id, chat_id=chat_id,
voice=content.file_id, voice=content.file_id,
caption=content.text or None, caption=content.text or None,
**kwargs **filtered_kwargs
) )
case "sticker": case "sticker":
await bot.send_sticker( await bot.send_sticker(
chat_id=chat_id, chat_id=chat_id,
sticker=content.file_id, sticker=content.file_id,
# stickers не поддерживают caption - удаляем его из kwargs **filtered_kwargs
**{k: v for k, v in kwargs.items() if k != 'caption'}
) )
case "video_note": case "video_note":
await bot.send_video_note( await bot.send_video_note(
chat_id=chat_id, chat_id=chat_id,
video_note=content.file_id, video_note=content.file_id,
# video_note не поддерживает caption - удаляем его из kwargs **filtered_kwargs
**{k: v for k, v in kwargs.items() if k != 'caption'}
) )
case _: case _:
# Fallback для неизвестных типов # Fallback для неизвестных типов - отправляем как текст
text_kwargs = filter_kwargs("text", kwargs)
await bot.send_message( await bot.send_message(
chat_id=chat_id, chat_id=chat_id,
text=content.text or "Unknown content type", text=content.text or "Unknown content type",
**{k: v for k, v in kwargs.items() if k != 'caption'} **text_kwargs
) )
@@ -130,48 +153,53 @@ async def send_message_via_queue(queue_manager, uid: int, content: MessageConten
""" """
Отправляет сообщение через очередь в зависимости от типа контента. Отправляет сообщение через очередь в зависимости от типа контента.
Использует match/case вместо длинных if-elif цепочек. Использует match/case вместо длинных if-elif цепочек.
Автоматически фильтрует неподдерживаемые параметры.
""" """
# Фильтруем kwargs для данного типа сообщения
filtered_kwargs = filter_kwargs(content.content_type, kwargs)
match content.content_type: match content.content_type:
case "text": case "text":
await queue_manager.send_message( await queue_manager.send_message(
chat_id=uid, text=content.text, **kwargs chat_id=uid, text=content.text, **filtered_kwargs
) )
case "photo": case "photo":
await queue_manager.send_photo( await queue_manager.send_photo(
chat_id=uid, photo=content.file_id, caption=content.text or None, **kwargs chat_id=uid, photo=content.file_id, caption=content.text or None, **filtered_kwargs
) )
case "video": case "video":
await queue_manager.send_video( await queue_manager.send_video(
chat_id=uid, video=content.file_id, caption=content.text or None, **kwargs chat_id=uid, video=content.file_id, caption=content.text or None, **filtered_kwargs
) )
case "animation": case "animation":
await queue_manager.send_animation( await queue_manager.send_animation(
chat_id=uid, animation=content.file_id, caption=content.text or None, **kwargs chat_id=uid, animation=content.file_id, caption=content.text or None, **filtered_kwargs
) )
case "document": case "document":
await queue_manager.send_document( await queue_manager.send_document(
chat_id=uid, document=content.file_id, caption=content.text or None, **kwargs chat_id=uid, document=content.file_id, caption=content.text or None, **filtered_kwargs
) )
case "audio": case "audio":
await queue_manager.send_audio( await queue_manager.send_audio(
chat_id=uid, audio=content.file_id, caption=content.text or None, **kwargs chat_id=uid, audio=content.file_id, caption=content.text or None, **filtered_kwargs
) )
case "voice": case "voice":
await queue_manager.send_voice( await queue_manager.send_voice(
chat_id=uid, voice=content.file_id, caption=content.text or None, **kwargs chat_id=uid, voice=content.file_id, caption=content.text or None, **filtered_kwargs
) )
case "sticker": case "sticker":
await queue_manager.send_sticker( await queue_manager.send_sticker(
chat_id=uid, sticker=content.file_id chat_id=uid, sticker=content.file_id, **filtered_kwargs
) )
case "video_note": case "video_note":
await queue_manager.send_video_note( await queue_manager.send_video_note(
chat_id=uid, video_note=content.file_id chat_id=uid, video_note=content.file_id, **filtered_kwargs
) )
case _: case _:
# Fallback для неизвестных типов # Fallback для неизвестных типов - отправляем как текст
text_kwargs = filter_kwargs("text", kwargs)
await queue_manager.send_message( await queue_manager.send_message(
chat_id=uid, text=content.text or "Unknown content type", **kwargs chat_id=uid, text=content.text or "Unknown content type", **text_kwargs
) )
@@ -179,45 +207,51 @@ async def send_direct_message(bot, chat_id: int, content: MessageContent, extra_
""" """
Отправляет прямое сообщение с дополнительной обработкой для sticker и video_note. Отправляет прямое сообщение с дополнительной обработкой для sticker и video_note.
Для этих типов медиа отправляется отдельное текстовое сообщение, т.к. они не поддерживают caption. Для этих типов медиа отправляется отдельное текстовое сообщение, т.к. они не поддерживают caption.
Автоматически фильтрует неподдерживаемые параметры.
""" """
match content.content_type: match content.content_type:
case "sticker": case "sticker":
# Отправляем стикер # Отправляем стикер с отфильтрованными параметрами
sticker_kwargs = filter_kwargs("sticker", kwargs)
await bot.send_sticker( await bot.send_sticker(
chat_id=chat_id, chat_id=chat_id,
sticker=content.file_id, sticker=content.file_id,
**{k: v for k, v in kwargs.items() if k != 'caption'} **sticker_kwargs
) )
# Если есть текст с подписью, отправляем отдельно # Если есть текст с подписью, отправляем отдельно
if content.text or extra_text: if content.text or extra_text:
text_to_send = (content.text + extra_text) if content.text else extra_text text_to_send = (content.text + extra_text) if content.text else extra_text
text_kwargs = filter_kwargs("text", kwargs)
await bot.send_message( await bot.send_message(
chat_id, chat_id,
text_to_send, text_to_send,
**{k: v for k, v in kwargs.items() if k not in ['caption']} **text_kwargs
) )
case "video_note": case "video_note":
# Отправляем видео-заметку # Отправляем видео-заметку с отфильтрованными параметрами
video_note_kwargs = filter_kwargs("video_note", kwargs)
await bot.send_video_note( await bot.send_video_note(
chat_id=chat_id, chat_id=chat_id,
video_note=content.file_id, video_note=content.file_id,
**{k: v for k, v in kwargs.items() if k != 'caption'} **video_note_kwargs
) )
# Если есть текст с подписью, отправляем отдельно # Если есть текст с подписью, отправляем отдельно
if content.text or extra_text: if content.text or extra_text:
text_to_send = (content.text + extra_text) if content.text else extra_text text_to_send = (content.text + extra_text) if content.text else extra_text
text_kwargs = filter_kwargs("text", kwargs)
await bot.send_message( await bot.send_message(
chat_id, chat_id,
text_to_send, text_to_send,
**{k: v for k, v in kwargs.items() if k not in ['caption']} **text_kwargs
) )
case "text": case "text":
# Для текста объединяем с extra_text # Для текста объединяем с extra_text
final_text = (content.text + extra_text) if content.text else extra_text final_text = (content.text + extra_text) if content.text else extra_text
text_kwargs = filter_kwargs("text", kwargs)
await bot.send_message( await bot.send_message(
chat_id=chat_id, chat_id=chat_id,
text=final_text, text=final_text,
**kwargs **text_kwargs
) )
case _: case _:
# Для остальных типов медиа используем caption # Для остальных типов медиа используем caption