Python Telegram Bot can't get multiple image at a time from user

54 views Asked by At

I was writing a Python script to create a telegram bot so one of the function of the bot is collecting images from user, the problem comes here when a user selects multiple image and send them at the same time the bot is not getting there proper file id here is the code :

# Function to handle picture collection
def collect_pictures(message):
    user_id = message.chat.id
    if message.photo:
        # Iterate through each photo in the array
        for photo_data in message.photo:
            file_id = photo_data.file_id
            user_data[user_id]['pictures'].append(file_id)

            # Print information about the received picture
            print(f"User {message.from_user.username} sent a picture with file_id: {file_id}")

        # Total number of pictures received
        total_pictures = len(user_data[user_id]['pictures'])
        print(f"User {message.from_user.username} has sent {total_pictures} pictures in total.")

        # You can proceed with further processing or confirmation here
        markup = create_confirm_keyboard()
        bot.send_message(message.chat.id, "Do you want to submit the collected information and pictures?", reply_markup=markup)
        bot.register_next_step_handler(message, handle_additional_pictures)
    else:
        bot.send_message(message.chat.id, "Invalid input. Please send pictures.")
        bot.register_next_step_handler(message, collect_pictures)

  1. I tried to get the file_id accordingly and i used for loop but it's not functioning as expected it get the number of uploaded pictures but after iteration and getting the id it stores the first image file_id in all other images file_id
1

There are 1 answers

0
say8hi On

So basically in telegram - combined media is a separate messages that visually grouped. What you can do is use middleware to capture them in one handler.

import asyncio
from abc import ABC
from typing import Callable, Dict, Any, Awaitable
from aiogram.types import Message

from aiogram import BaseMiddleware
from aiogram import types
from aiogram.dispatcher.event.bases import CancelHandler


class AlbumMiddleware(BaseMiddleware, ABC):
    """This middleware is for capturing media groups."""

    album_data: dict = {}

    def __init__(self, latency: int | float = 0.01):
        """
        You can provide custom latency to make sure
        albums are handled properly in highload.
        """
        self.latency = latency
        super().__init__()

    async def __call__(
        self,
        handler: Callable[[Message, Dict[str, Any]], Awaitable[Any]],
        event: Message,
        data: Dict[str, Any],
    ) -> Any:
        if not event.media_group_id:
            return

        try:
            self.album_data[event.media_group_id].append(event)
            return  # Tell aiogram to cancel handler for this group element
        except KeyError:
            self.album_data[event.media_group_id] = [event]
            await asyncio.sleep(self.latency)

            event.model_config["is_last"] = True
            data["album"] = self.album_data[event.media_group_id]

            result = await handler(event, data)

            if event.media_group_id and event.model_config.get("is_last"):
                del self.album_data[event.media_group_id]

            return result

And then get data["album"] by adding album argument to the handler func:

@router.message(F.content_type.in_({'photo', 'document'}))
async def receive_album(message: Message, album: list[Message] = None):
    for file in album:
        print(file)

To register middleware before starting bot you can use:

middleware = AlbumMiddleware()

dp.message.outer_middleware(middleware)
dp.callback_query.outer_middleware(middleware)