crash
crash

Reputation: 23

How can I send an image with a caption using Telethon in python?

I'm aware I can use this

client.send_file(receiver, '/path/to/photo.jpg')

to send an image, but how can I attach a caption to the image?

Upvotes: 2

Views: 4397

Answers (2)

Liquidgenius
Liquidgenius

Reputation: 708

While this question on how to send an image with caption to Telegram using Telethon was already answered concisely by @matthew-barlowe, (which I used to come to my own solution, thank you), I felt that it would be helpful to include a more comprehensive example using Telethon v3's new async API.

The code is documented and type hinted so it should provide it's own explanation. In the interest of keeping the example brief, capturing of exceptions is excluded.


    import logging
    from random import uniform
    from time import sleep
    from typing import Dict, List, Union
    
    from telethon.sync import TelegramClient
    
    
    logging.basicConfig(
        format="[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s", level=logging.WARNING
    )
    
    # you should use dotenv module to extract credentials from the environment or .env file; 'pip install python-dotenv'
    # do not store credentials in the file in production or git commit, this is only included for example purposes
    SESSION_NAME = "sqlite-session"
    TG_API_ID = 1234567890
    TG_API_HASH = "*****"
    CHANNEL_NAME = "yourchannelname"
    CHANNEL_DISPLAY_NAME = "Your Channel Name"
    CHANNEL_URL = "https://t.me/your-channel-name"
    
    # define client
    client = TelegramClient(SESSION_NAME, TG_API_ID, TG_API_HASH)
    
    
    def create_message(data: Dict) -> str:
        """Formats a dictionary as a Telegram message.
        :param data: Dict: A dictionary containing 'title', 'subtitle', 'text', 'url' and
            'image_path' keys to be formatted as a message.
        :return: str: A string including Markup to be sent as a message to a Telegram channel.
        """
    
        # generate message
        message = ""
        if data.get("title", None):
            message += f'**{data["title"]}**\n'
        message += f'{data["subtitle"]}\n' if data.get("subtitle", None) else ""
        if data.get("url", None):
            message += data["url"]
        message += "\n\n"
        message += f"[{CHANNEL_DISPLAY_NAME}]({CHANNEL_URL})"
        return message
    
    
    async def channel_broadcast(
        messages: Union[Dict, List[Dict]],
        channel: str,
        min_wait: float = 25.0,
        max_wait: float = 120.0
    ) -> None:
        """ Broadcasts a message to the specified Telegram channel. There will be a humanized wait in between postings.
        :param messages: Union[Dict, List[Dict, ...]]: A dictionary or list of dicts containing 'title', 'subtitle',
            'text', 'url' and 'image_path' keys to be formatted as a message.
        :param channel: str: The name of the channel messages are to be broadcast to. You must have permission to
            broadcast to this channel. See setup in telethon docs.
        :param min_wait: float: Minimum wait between messages.
        :param max_wait: float: Maximum wait between messages.
        :return: None
        """
    
        # ensure list
        messages = [messages] if isinstance(messages, dict) else messages
    
        for item in messages:
    
            # generate a properly formatted message using markup and available fields
            message = create_message(item)
    
            # connect previously defined client
            async with client:
                await client.connect()
    
                # send message if image is included
                if item.get("image_path", None):
                    await client.send_file(
                        channel, item["image_path"], caption=message, link_preview=True
                    )
    
                # send message without image
                else:
                    await client.send_message(channel, message, link_preview=True)
    
            # short blocking wait for multiple messages
            # non-blocking waits are not in scope of this example
            if len(messages) > 1:
                sleep(uniform(min_wait, max_wait))
    
    
    # you can provide a single dict or list of dicts
    messages = [
        {
            "title": "First Message",
            "subtitle": "This is the first message.",
            "text": "This is a paragraph of text. The main idea of the message will be included here.",
            "url": "https://test.com",
            "image_path": "/path/to/a/local/image.png",
        },
        {
            "title": "Second Message",
            "subtitle": None,
            "text": "This is a paragraph of text. The main idea of the message will be included here.",
            "url": None,
        },
    ]
    
    # send all messages with a humanized wait between messages
    with client:
        client.loop.run_until_complete(
            channel_broadcast(
                messages, CHANNEL_NAME
            )
        )

'''

Upvotes: 1

Matthew Barlowe
Matthew Barlowe

Reputation: 2328

According to the documentation just pass the value of the caption with a keyword argument like so client.send_file(chat, '/my/photos/me.jpg', caption="It's me!"). You can read the documentation here

Upvotes: 6

Related Questions