Работая в одном из проектов в PyCharm понадобилась возможность ловить одним хендлером альбом из фотографий, отправленных одним сообщением. Как оказалось, в aiogram 3 нет встроенных инструментов, для того, чтобы это делать, но получилось найти обходной путь, а именно создать мидлварь для альбомов
middleware.py
import asyncio
from typing import Callable, Any, Awaitable, Union
from aiogram import BaseMiddleware
from aiogram.types import Message
class AlbumMiddleware(BaseMiddleware):
album_data: dict = {}
def __init__(self, latency: Union[int, float] = 0.01):
self.latency = latency
async def __call__(
self,
handler: Callable[[Message, dict[str, Any]], Awaitable[Any]],
message: Message,
data: dict[str, Any]
) -> Any:
if not message.media_group_id:
await handler(message, data)
return
try:
self.album_data[message.media_group_id].append(message)
except KeyError:
self.album_data[message.media_group_id] = [message]
await asyncio.sleep(self.latency)
data['_is_last'] = True
data["album"] = self.album_data[message.media_group_id]
await handler(message, data)
if message.media_group_id and data.get("_is_last"):
del self.album_data[message.media_group_id]
del data['_is_last']
Объявив мидлварь перед хендлерами мы получаем вот такую связку:
anyPythonScript.py
from aiogram import Router, F
from aiogram.types import Message, InputMediaPhoto, ContentType as CT
router = Router()
router.message.middleware(AlbumMiddleware())
@router.message(F.content_type.in_([CT.PHOTO]))
async def handle_photo(message: Message, state: FSMContext, album: list[Message] = []):
answer_text = 'Фотографии прикреплены.'
media_group = []
for msg in album:
if msg.photo:
file_id = msg.photo[-1].file_id
media_group.append(InputMediaPhoto(media=file_id))
try:
media_group[0].caption = answer_text
except IndexError:
if message.content_type == 'photo':
photo = message.photo[-1].file_id
chat_id = message.from_user.id
answer_text = answer_text
from main import bot
await bot.send_photo(chat_id, photo=photo,
caption=answer_text)
await state.update_data(media_group=photo,
isAlbum=False)
await message.answer('Подтвердить?')
return
await state.update_data(media_group=media_group,
isAlbum=True)
await message.answer_media_group(media_group)
await message.answer('Подтвердить?')
Казалось бы, всё должно работать правильно, каждая фотография в альбоме обработается как отдельное событие и код пройдёт по необходимому сценарию. Когда фотография одна - обработает одну, когда фотографий несколько, в ход идёт мидлварь. Так я и сделал в своём проекте и все сработало отлично и правильно:
Код сначала схавал все три фотографии, а уже потом, предварительно зафиксировав их своём "альбоме", обработал и вывел ответ один раз, а не три, сколько было фотографий
Экран юзера выглядит следующим образом:
Но когда я перешёл к другому проекту и вставил туда абсолютно тот же самый код, меня ждала неудача. Фотографии ловятся совершенно по другому:
Текст из консоли:
Итак, вопрос: Как исправить проблему того, что при отправке медиа-группы хендлер ловит только первую фотографию? И как в будущем избежать этой проблемы при загрузке на сервер? Пользуюсь Пайчармом, python 3.10 во всех проектах одинаковый
upd:
Бот работает некорректно только по отношению к иностранным тг-аккаунтам
russian sim-card tg account
Правильная работа бота с тг аккаунтом, зарегистрированным на русскую симку +7(ХХХ)
Non-russian sim-card tg account
Неправильная работа бота с тг аккаунтом, зарегистрированным на иностранную симку, не на +7(ХХХ)