Search code examples
telegramtelegram-botpython-telegram-bottelegram-api

Getting multiple images to download from telegram bot


I have this code

file_name = f'photo_{update.message.message_id}_{photo.file_unique_id}.jpg'


full_download_url = f"https://api.telegram.org/file/bot{BOT_TOKEN}/{download_url}"
logger.info(f'Downloading photo from URL: {full_download_url}')   
response = requests.get(full_download_url)
response.raise_for_status()   
with open(file_name, 'wb') as f:
    f.write(response.content)

This code finds the telegram url

What Telegram does is send images in multiple messages or updates within the same context. I am having a hard time getting this part to work where it downloads the images. Currently, what this code does is download the same image 4 times instead of checking to see the actual number of images in the update. So even if I send 2 images, it still just downloads the first image and iterates over it by renaming and saving it 4 times. Could you please advise how to resolve this issue?

async def download_photo(update: Update, context: ContextTypes.DEFAULT_TYPE):
 
    photos = update.message.photo
    media_paths = []

    for photo in photos:
        file_id = photo.file_id
        logger.info(f'Processing photo with file_id: {file_id}')  
        try:
            file_info = await context.bot.get_file(file_id)
            download_url = file_info.file_path  # Use the file_path directly

            # Create a unique filename for each photo
            file_name = f'photo_{update.message.message_id}_{photo.file_unique_id}.jpg'

            # Log the full download URL
            full_download_url = f"https://api.telegram.org/file/bot{BOT_TOKEN}/{download_url}"
            logger.info(f'Downloading photo from URL: {full_download_url}')  

            # Download the photo using the full download URL
            response = requests.get(full_download_url)
            response.raise_for_status()  
            with open(file_name, 'wb') as f:
                f.write(response.content)
            media_paths.append(file_name)
            logger.info(f'Downloaded photo successfully with file_id: {file_id}')
        except Exception as e:
            logger.error(f'Error downloading photo with file_id {file_id}: {e}')

    logger.info(f'All downloaded media paths: {media_paths}')  

Solution

  • Multiple photos in one message are actually multiple messages grouped together with a unique media_group_id. Each message update you receive holds only one photo. The photos field in the message update is an array of PhotoSize objects (refer to the Message documentation). Telegram sends multiple sizes of the same image in this array, sorted from smallest to largest.

    To download all the photos in a message, you should handle all message updates, and for each one, download the last image in the array (the highest resolution).

    Here's how you can modify your loop with a condition:

    async def download_photo(update: Update, context: ContextTypes.DEFAULT_TYPE):
    
        photo = update.message.photo
        media_paths = []
    
        if photo:
            file_id = photo[-1].file_id
            ... # proceed with the rest of your logic
            
    

    And implement this logic in your bot to handle all relevant message updates.