U
    hƱ                     @   s   d dl mZmZmZ d dlmZ ddlmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZ d	d
lmZmZmZmZ ddlmZmZ G dd deeeZdS )    )OptionalListTYPE_CHECKING)datetime   )
ChatGetter)SenderGetter)MessageButton)Forward)File   )TLObjecttypes	functionsalltlobjects   )utilserrorsc                -   @   s  e Zd ZdZdoeejee ee	 ee
 ee
 ee
 ee
 ee
 ee
 ee
 ee
 ee
 ee
 ee
 ee
 ee
 eej ee eej eej ee ee eej eej eej eeej  ee ee eej ee ee	 ee eej eeej  ee ee ee eej ee ee eej ee
 d+ddZdd Zedd	 Zed
d Zejdd Zedd Zejdd Zedd Zedd Zedd Zedd Z edd Z!dd Z"edd Z#edd Z$ed d! Z%ed"d# Z&ed$d% Z'ed&d' Z(ed(d) Z)ed*d+ Z*ed,d- Z+ed.d/ Z,ed0d1 Z-ed2d3 Z.ed4d5 Z/ed6d7 Z0ed8d9 Z1ed:d; Z2ed<d= Z3ed>d? Z4ed@dA Z5edBdC Z6edDdE Z7edFdG Z8edHdI Z9dpdJdKZ:dLdM Z;dNdO Z<dPdQ Z=dRdS Z>dTdU Z?dVdW Z@dXdY ZAdqdddddddZd[d\ZBd]d^ ZCd_d_d`dadbZDdcdd ZEdedf ZFdgdh ZGdidj ZHdkdl ZIdrdmdnZJdS )sMessagea  
    This custom class aggregates both :tl:`Message` and
    :tl:`MessageService` to ease accessing their members.

    Remember that this class implements `ChatGetter
    <telethon.tl.custom.chatgetter.ChatGetter>` and `SenderGetter
    <telethon.tl.custom.sendergetter.SenderGetter>` which means you
    have access to all their sender and chat properties and methods.

    Members:
        out (`bool`):
            Whether the message is outgoing (i.e. you sent it from
            another session) or incoming (i.e. someone else sent it).

            Note that messages in your own chat are always incoming,
            but this member will be `True` if you send a message
            to your own chat. Messages you forward to your chat are
            *not* considered outgoing, just like official clients
            display them.

        mentioned (`bool`):
            Whether you were mentioned in this message or not.
            Note that replies to your own messages also count
            as mentions.

        media_unread (`bool`):
            Whether you have read the media in this message
            or not, e.g. listened to the voice note media.

        silent (`bool`):
            Whether the message should notify people with sound or not.
            Previously used in channels, but since 9 August 2019, it can
            also be `used in private chats
            <https://telegram.org/blog/silent-messages-slow-mode>`_.

        post (`bool`):
            Whether this message is a post in a broadcast
            channel or not.

        from_scheduled (`bool`):
            Whether this message was originated from a previously-scheduled
            message or not.

        legacy (`bool`):
            Whether this is a legacy message or not.

        edit_hide (`bool`):
            Whether the edited mark of this message is edited
            should be hidden (e.g. in GUI clients) or shown.

        pinned (`bool`):
            Whether this message is currently pinned or not.

        noforwards (`bool`):
            Whether this message can be forwarded or not.

        invert_media (`bool`):
            Whether the media in this message should be inverted.
            
        offline (`bool`):
            Whether the message was sent by an implicit action, for example, as an away or a greeting business message, or as a scheduled message.

        id (`int`):
            The ID of this message. This field is *always* present.
            Any other member is optional and may be `None`.

        from_id (:tl:`Peer`):
            The peer who sent this message, which is either
            :tl:`PeerUser`, :tl:`PeerChat` or :tl:`PeerChannel`.
            This value will be `None` for anonymous messages.

        peer_id (:tl:`Peer`):
            The peer to which this message was sent, which is either
            :tl:`PeerUser`, :tl:`PeerChat` or :tl:`PeerChannel`. This
            will always be present except for empty messages.

        fwd_from (:tl:`MessageFwdHeader`):
            The original forward header if this message is a forward.
            You should probably use the `forward` property instead.

        via_bot_id (`int`):
            The ID of the bot used to send this message
            through its inline mode (e.g. "via @like").

        reply_to (:tl:`MessageReplyHeader`):
            The original reply header if this message is replying to another.

        date (`datetime`):
            The UTC+0 `datetime` object indicating when this message
            was sent. This will always be present except for empty
            messages.

        message (`str`):
            The string text of the message for `Message
            <telethon.tl.custom.message.Message>` instances,
            which will be `None` for other types of messages.

        media (:tl:`MessageMedia`):
            The media sent with this message if any (such as
            photos, videos, documents, gifs, stickers, etc.).

            You may want to access the `photo`, `document`
            etc. properties instead.

            If the media was not present or it was :tl:`MessageMediaEmpty`,
            this member will instead be `None` for convenience.

        reply_markup (:tl:`ReplyMarkup`):
            The reply markup for this message (which was sent
            either via a bot or by a bot). You probably want
            to access `buttons` instead.

        entities (List[:tl:`MessageEntity`]):
            The list of markup entities in this message,
            such as bold, italics, code, hyperlinks, etc.

        views (`int`):
            The number of views this message from a broadcast
            channel has. This is also present in forwards.

        forwards (`int`):
            The number of times this message has been forwarded.

        replies (`int`):
            The number of times another message has replied to this message.

        edit_date (`datetime`):
            The date when this message was last edited.

        post_author (`str`):
            The display name of the message sender to
            show in messages sent to broadcast channels.

        grouped_id (`int`):
            If this message belongs to a group of messages
            (photo albums or video albums), all of them will
            have the same value here.

        reactions (:tl:`MessageReactions`)
            Reactions to this message.

        restriction_reason (List[:tl:`RestrictionReason`])
            An optional list of reasons why this message was restricted.
            If the list is `None`, this message has not been restricted.

        ttl_period (`int`):
            The Time To Live period configured for this message.
            The message should be erased from wherever it's stored (memory, a
            local database, etc.) when
            ``datetime.now() > message.date + timedelta(seconds=message.ttl_period)``.

        action (:tl:`MessageAction`):
            The message action object of the message for :tl:`MessageService`
            instances, which will be `None` for other types of messages.

        saved_peer_id (:tl:`Peer`)
    N)+idpeer_iddatemessageout	mentionedmedia_unreadsilentpostfrom_scheduledlegacy	edit_hidepinned
noforwardsinvert_mediaofflinevideo_processing_pendingfrom_idfrom_boosts_appliedsaved_peer_idfwd_from
via_bot_idvia_business_bot_idreply_tomediareply_markupentitiesviewsforwardsreplies	edit_datepost_author
grouped_id	reactionsrestriction_reason
ttl_periodquick_reply_shortcut_ideffect	factcheckreport_delivery_until_datepaid_message_starsactionreactions_are_possiblec,           -      C   s  || _ || _|| _|| _t|| _|| _|| _|| _|	| _	|
| _
|| _|| _|| _|| _|| _|| _|| _|| _|| _|| _|| _|| _|| _|| _t|tjrd n|| _|| _|| _|| _|| _ || _!|| _"| | _#|!| _$|"| _%|#| _&|$| _'|%| _(|&| _)|'| _*|(| _+|)| _,|*| _-|+| _.d | _/d | _0d | _1d | _2d | _3d | _4d | _5d | _6d | _7d | _8d | _9d },|d k	rrt:;|},n*|r|	s|st|tj<rt:;|},t=j>| ||	d t?>| |, d | _@d | _Ad | _Bd S )N)	broadcast)Cr   r   r   r   boolr   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   
isinstancer   ZMessageMediaEmptyr-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   r;   r<   r=   r>   r?   _client_text_file_reply_message_buttons_buttons_flat_buttons_count_via_bot_via_input_bot_action_entities_linked_chatr   get_peer_idPeerUserr   __init__r   _forward_reply_to_chat_reply_to_sender)-selfr   r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   r;   r<   r=   r>   r?   	sender_id rV   >/tmp/pip-unpacked-wheel-c81u5j2r/telethon/tl/custom/message.pyrP      s    



zMessage.__init__c                    s  || _ | jt|jkr$| js$d| _|j}t	| j
 |\| _| _t	| j |\| _| _|rd|| _| jrt	| j |\| _| _| jrt| j | j | _| jrtt| jtjtjfrЇ fdd| jjD | _nt| jtjr | jjg| _nt| jtjr | jjg| _n^t| jtj rF t!t"| jj#g| _n.t| jtj$rt t!t%| jjg| _| j&r| j&j#r t!t"| j&j#| _'t| j(tj)r | j(j*r҈ t!| j(j*| _+| j(j,r | j(j,j-r  t!| j(j,j-| _.dS )z
        Finishes the initialization of this message by setting
        the client that sent the message and making use of the
        known entities.
        Tc                    s   g | ]}  |qS rV   )get).0ir/   rV   rW   
<listcomp>)  s   z(Message._finish_init.<locals>.<listcomp>N)/rC   r   r   rO   _self_idr)   r   _mb_entity_cacher   Z_get_entity_pairrU   _sender_input_senderZchat_id_chat_input_chatr*   rJ   rK   r
   rQ   r>   rB   ZMessageActionChatAddUserZMessageActionChatCreateZusersrL   ZMessageActionChatDeleteUserrX   Zuser_idZMessageActionChatJoinedByLinkZ
inviter_idZMessageActionChatMigrateTorN   ZPeerChannelZ
channel_idZMessageActionChannelMigrateFromZPeerChatr2   rM   r,   ZMessageReplyHeaderZreply_to_peer_idrR   Z
reply_fromr&   rS   )rT   clientr/   
input_chatcacherV   r[   rW   _finish_init  sp          


 


zMessage._finish_initc                 C   s   | j S )aR  
        Returns the `TelegramClient <telethon.client.telegramclient.TelegramClient>`
        that *patched* this message. This will only be present if you
        **use the friendly methods**, it won't be there if you invoke
        raw API methods manually, in which case you should only access
        members, not properties.
        )rC   rT   rV   rV   rW   rc   H  s    	zMessage.clientc                 C   s>   | j dkr8| jr8| jjs"| j| _ n| jj| j| j| _ | j S )z
        The message text, formatted using the client's default
        parse mode. Will be `None` for :tl:`MessageService`.
        N)rD   rC   
parse_moder   Zunparser/   rg   rV   rV   rW   textS  s    
 zMessage.textc                 C   s>   || _ | jr,| jjr,| jj|\| _| _n|g  | _| _d S N)rD   rC   rh   parser   r/   rT   valuerV   rV   rW   ri   b  s    c                 C   s   | j S )z
        The raw message text, ignoring any formatting.
        Will be `None` for :tl:`MessageService`.

        Setting a value to this field will erase the
        `entities`, unlike changing the `message` member.
        )r   rg   rV   rV   rW   raw_textj  s    	zMessage.raw_textc                 C   s   || _ g | _d | _d S rj   )r   r/   rD   rl   rV   rV   rW   rn   u  s    c                 C   s
   | j dk	S )a  
        `True` if the message is a reply to some other message.

        Remember that you can access the ID of the message
        this one is replying to through `reply_to.reply_to_msg_id`,
        and the `Message` object with `get_reply_message()`.
        N)r,   rg   rV   rV   rW   is_reply{  s    	zMessage.is_replyc                 C   s   | j S )z
        The `Forward <telethon.tl.custom.forward.Forward>`
        information if this message is a forwarded message.
        )rQ   rg   rV   rV   rW   forward  s    zMessage.forwardc                 C   s   | j S )z
        The :tl:`Channel` in which the replied-to message was sent,
        if this message is a reply in another chat
        )rR   rg   rV   rV   rW   reply_to_chat  s    zMessage.reply_to_chatc                 C   s   | j S )z
        The :tl:`User`, :tl:`Channel`, or whatever other entity that
        sent the replied-to message, if this message is a reply in another chat.
        )rS   rg   rV   rV   rW   reply_to_sender  s    zMessage.reply_to_senderc                 C   sR   | j dkrL| jrL| jsdS z|  }W n tk
r<   Y dS X | | j| | j S )z
        Returns a list of lists of `MessageButton
        <telethon.tl.custom.messagebutton.MessageButton>`,
        if any.

        Otherwise, it returns `None`.
        N)rG   r.   rd   _needed_markup_bot
ValueError_set_buttonsrb   )rT   botrV   rV   rW   buttons  s    	zMessage.buttonsc                    sl   | j sf| jrf|  I dH }|s"dS z|  }W n* tk
rX   |  I dH  |  }Y nX | || | jS )zU
        Returns `buttons` when that property fails (this is rarely needed).
        N)rw   r.   get_input_chatrs   rt   _reload_messageru   rG   rT   chatrv   rV   rV   rW   get_buttons  s    zMessage.get_buttonsc                 C   sD   | j dkr>t| jtjtjfr8tdd | jjD | _ nd| _ | j S )zM
        Returns the total button count (sum of all `buttons` rows).
        Nc                 s   s   | ]}t |jV  qd S rj   )lenrw   rY   rowrV   rV   rW   	<genexpr>  s    z'Message.button_count.<locals>.<genexpr>r   )rI   rB   r.   r   ReplyInlineMarkupReplyKeyboardMarkupsumrowsrg   rV   rV   rW   button_count  s    
 zMessage.button_countc                 C   s&   | j s | jp| j}|r t|| _ | j S )a  
        Returns a `File <telethon.tl.custom.file.File>` wrapping the
        `photo` or `document` in this message. If the media type is different
        (polls, games, none, etc.), this property will be `None`.

        This instance lets you easily access other properties, such as
        `file.id <telethon.tl.custom.file.File.id>`,
        `file.name <telethon.tl.custom.file.File.name>`,
        etc., without having to manually inspect the ``document.attributes``.
        )rE   photodocumentr   )rT   r-   rV   rV   rW   file  s
    
zMessage.filec                 C   s`   t | jtjr(t | jjtjr\| jjS n4t | jtjr>| jjS | j}|r\t |jtjr\|jS dS )z
        The :tl:`Photo` media in this message, if any.

        This will also return the photo for :tl:`MessageService` if its
        action is :tl:`MessageActionChatEditPhoto`, or if the message has
        a web preview with a photo.
        N)	rB   r-   r   ZMessageMediaPhotor   ZPhotor>   ZMessageActionChatEditPhotoweb_previewrT   ZwebrV   rV   rW   r     s    	
zMessage.photoc                 C   sJ   t | jtjr(t | jjtjrF| jjS n| j}|rFt |jtjrF|jS dS )zC
        The :tl:`Document` media in this message, if any.
        N)rB   r-   r   ZMessageMediaDocumentr   Documentr   r   rV   rV   rW   r     s    
zMessage.documentc                 C   s*   t | jtjr&t | jjtjr&| jjS dS )zB
        The :tl:`WebPage` media in this message, if any.
        N)rB   r-   r   ZMessageMediaWebPageZwebpageZWebPagerg   rV   rV   rW   r     s    zMessage.web_previewc                 C   s   |  tjdd S )zR
        The :tl:`Document` media in this message, if it's an audio file.
        c                 S   s   | j  S rj   voiceattrrV   rV   rW   <lambda>      zMessage.audio.<locals>.<lambda>_document_by_attributer   ZDocumentAttributeAudiorg   rV   rV   rW   audio  s    zMessage.audioc                 C   s   |  tjdd S )zQ
        The :tl:`Document` media in this message, if it's a voice note.
        c                 S   s   | j S rj   r   r   rV   rV   rW   r     r   zMessage.voice.<locals>.<lambda>r   rg   rV   rV   rW   r     s    zMessage.voicec                 C   s   |  tjS )zL
        The :tl:`Document` media in this message, if it's a video.
        r   r   ZDocumentAttributeVideorg   rV   rV   rW   video   s    zMessage.videoc                 C   s   |  tjdd S )zQ
        The :tl:`Document` media in this message, if it's a video note.
        c                 S   s   | j S rj   )Zround_messager   rV   rV   rW   r   -  r   z$Message.video_note.<locals>.<lambda>r   rg   rV   rV   rW   
video_note'  s    zMessage.video_notec                 C   s   |  tjS )a  
        The :tl:`Document` media in this message, if it's a "gif".

        "Gif" files by Telegram are normally ``.mp4`` video files without
        sound, the so called "animated" media. However, it may be the actual
        gif format if the file is too large.
        )r   r   ZDocumentAttributeAnimatedrg   rV   rV   rW   gif/  s    	zMessage.gifc                 C   s   |  tjS )zN
        The :tl:`Document` media in this message, if it's a sticker.
        )r   r   ZDocumentAttributeStickerrg   rV   rV   rW   sticker:  s    zMessage.stickerc                 C   s   t | jtjr| jS dS )zS
        The :tl:`MessageMediaContact` in this message, if it's a contact.
        N)rB   r-   r   ZMessageMediaContactrg   rV   rV   rW   contactA  s    zMessage.contactc                 C   s   t | jtjr| jjS dS )zG
        The :tl:`Game` media in this message, if it's a game.
        N)rB   r-   r   ZMessageMediaGamegamerg   rV   rV   rW   r   I  s    zMessage.gamec                 C   s$   t | jtjtjtjfr | jjS dS )zQ
        The :tl:`GeoPoint` media in this message, if it has a location.
        N)rB   r-   r   ZMessageMediaGeoZMessageMediaGeoLiveMessageMediaVenuegeorg   rV   rV   rW   r   Q  s
    
zMessage.geoc                 C   s   t | jtjr| jS dS )zT
        The :tl:`MessageMediaInvoice` in this message, if it's an invoice.
        N)rB   r-   r   ZMessageMediaInvoicerg   rV   rV   rW   invoice[  s    zMessage.invoicec                 C   s   t | jtjr| jS dS )zM
        The :tl:`MessageMediaPoll` in this message, if it's a poll.
        N)rB   r-   r   ZMessageMediaPollrg   rV   rV   rW   pollc  s    zMessage.pollc                 C   s   t | jtjr| jS dS )zO
        The :tl:`MessageMediaVenue` in this message, if it's a venue.
        N)rB   r-   r   r   rg   rV   rV   rW   venuek  s    zMessage.venuec                 C   s   t | jtjr| jS dS )zR
        The :tl:`MessageMediaDice` in this message, if it's a dice roll.
        N)rB   r-   r   ZMessageMediaDicerg   rV   rV   rW   dices  s    zMessage.dicec                 C   s   | j S )a  
        Returns a list of entities that took part in this action.

        Possible cases for this are :tl:`MessageActionChatAddUser`,
        :tl:`types.MessageActionChatCreate`, :tl:`MessageActionChatDeleteUser`,
        :tl:`MessageActionChatJoinedByLink` :tl:`MessageActionChatMigrateTo`
        and :tl:`MessageActionChannelMigrateFrom`.

        If the action is neither of those, the result will be `None`.
        If some entities could not be retrieved, the list may contain
        some `None` items in it.
        )rL   rg   rV   rV   rW   action_entities{  s    zMessage.action_entitiesc                 C   s   | j S )z
        The bot :tl:`User` if the message was sent via said bot.

        This will only be present if `via_bot_id` is not `None` and
        the entity is known.
        )rJ   rg   rV   rV   rW   via_bot  s    zMessage.via_botc                 C   s   | j S )z9
        Returns the input variant of `via_bot`.
        )rK   rg   rV   rV   rW   via_input_bot  s    zMessage.via_input_botc                 C   s   | j r| j jS dS )z
        Returns the message ID this message is replying to, if any.
        This is equivalent to accessing ``.reply_to.reply_to_msg_id``.
        N)r,   reply_to_msg_idrg   rV   rV   rW   r     s    zMessage.reply_to_msg_idc                 C   s&   | j r | js | jr t| j jS | jS )z{
        Returns the peer to which this message was sent to. This used to exist
        to infer the ``.peer_id``.
        )rC   r   
is_privater   rO   r]   r   rg   rV   rV   rW   to_id  s    zMessage.to_idc                    s@   | j }|sg S  r$ fdd|D }t| j|}tt||S )a  
        Returns a list of ``(markup entity, inner text)``
        (like bold or italics).

        The markup entity is a :tl:`MessageEntity` that represents bold,
        italics, etc., and the inner text is the `str` inside that markup
        entity.

        For example:

        .. code-block:: python

            print(repr(message.text))  # shows: 'Hello **world**!'

            for ent, txt in message.get_entities_text():
                print(ent)  # shows: MessageEntityBold(offset=6, length=5)
                print(txt)  # shows: world

        Args:
            cls (`type`):
                Returns entities matching this type only. For example,
                the following will print the text for all ``code`` entities:

                >>> from telethon.tl.types import MessageEntityCode
                >>>
                >>> m = ...  # get the message
                >>> for _, inner_text in m.get_entities_text(MessageEntityCode):
                >>>     print(inner_text)
        c                    s   g | ]}t | r|qS rV   )rB   )rY   cclsrV   rW   r\     s     
 z-Message.get_entities_text.<locals>.<listcomp>)r/   r   Zget_inner_textr   listzip)rT   r   entZtextsrV   r   rW   get_entities_text  s    zMessage.get_entities_textc                    s   | j dkr|| jr|| jsdS | jj| jr4|  I dH ndt| jdI dH | _ | j s|| jj| jrf| j	nd| jj
dI dH | _ | j S )z
        The `Message` that this message is replying to, or `None`.

        The result will be cached after its first use.
        Nids)rF   rC   r,   get_messages
is_channelrx   r   ZInputMessageReplyTor   rb   r   rg   rV   rV   rW   get_reply_message  s    
zMessage.get_reply_messagec                    s.   | j r*| j j|  I dH f||I dH S dS )z
        Responds to the message (not as a reply). Shorthand for
        `telethon.client.messages.MessageMethods.send_message`
        with ``entity`` already set.
        N)rC   send_messagerx   rT   argskwargsrV   rV   rW   respond  s    zMessage.respondc                    s8   | j r4| j|d< | j j|  I dH f||I dH S dS )z
        Replies to the message (as a reply). Shorthand for
        `telethon.client.messages.MessageMethods.send_message`
        with both ``entity`` and ``reply_to`` already set.
        r,   N)rC   r   r   rx   r   rV   rV   rW   reply  s    
zMessage.replyc                    s:   | j r6| j|d< |  I dH |d< | j j||I dH S dS )ar  
        Forwards the message. Shorthand for
        `telethon.client.messages.MessageMethods.forward_messages`
        with both ``messages`` and ``from_peer`` already set.

        If you need to forward more than one message at once, don't use
        this `forward_to` method. Use a
        `telethon.client.telegramclient.TelegramClient` instance directly.
        messagesNZ	from_peer)rC   r   rx   Zforward_messagesr   rV   rV   rW   
forward_to  s    

zMessage.forward_toc                    sP   d|krt | j|d< d|kr(| j|d< | jj|  I dH | jf||I dH S )a  
        Edits the message if it's outgoing. Shorthand for
        `telethon.client.messages.MessageMethods.edit_message`
        with both ``entity`` and ``message`` already set.

        Returns
            The edited `Message <telethon.tl.custom.message.Message>`,
            unless `entity` was a :tl:`InputBotInlineMessageID` or :tl:`InputBotInlineMessageID64` in which
            case this method returns a boolean.

        Raises
            ``MessageAuthorRequiredError`` if you're not the author of the
            message but tried editing it anyway.

            ``MessageNotModifiedError`` if the contents of the message were
            not modified at all.

            ``MessageIdInvalidError`` if the ID of the message is invalid
            (the ID itself may be correct, but the message with that ID
            cannot be edited). For example, when trying to edit messages
            with a reply markup (or clear markup) this error will be raised.

        .. note::

            This is different from `client.edit_message
            <telethon.client.messages.MessageMethods.edit_message>`
            and **will respect** the previous state of the message.
            For example, if the message didn't have a link preview,
            the edit won't add one by default, and you should force
            it by setting it to `True` if you want it.

            This is generally the most desired and convenient behaviour,
            and will work for link previews and message buttons.
        Zlink_previewrw   N)rA   r   r.   rC   Zedit_messagerx   r   r   rV   rV   rW   edit  s    #
 zMessage.editc                    s4   | j r0| j j|  I dH | jgf||I dH S dS )a  
        Deletes the message. You're responsible for checking whether you
        have the permission to do so, or to except the error otherwise.
        Shorthand for
        `telethon.client.messages.MessageMethods.delete_messages` with
        ``entity`` and ``message_ids`` already set.

        If you need to delete more than one message at once, don't use
        this `delete` method. Use a
        `telethon.client.telegramclient.TelegramClient` instance directly.
        N)rC   Zdelete_messagesrx   r   r   rV   rV   rW   deleteK  s     zMessage.deletec                    s$   | j r | j j| f||I dH S dS )z
        Downloads the media contained in the message, if any. Shorthand
        for `telethon.client.downloads.DownloadMethods.download_media`
        with the ``message`` already set.
        N)rC   download_mediar   rV   rV   rW   r   ]  s    zMessage.download_media)ri   filterdatashare_phone	share_geopasswordc                   s  j s
dS |rV I dH }	|	s$dS td|}
tj |
|	djj|||dI dH S tdd  fD dkrztdj	dk	rʇ fdd	}| }|dkrg } t
jjjj|d
I dH S  I dH sdS  fdd}| }|r|j|||dI dH S dS )u  
        Calls :tl:`SendVote` with the specified poll option
        or `button.click <telethon.tl.custom.messagebutton.MessageButton.click>`
        on the specified button.

        Does nothing if the message is not a poll or has no buttons.

        Args:
            i (`int` | `list`):
                Clicks the i'th button or poll option (starting from the index 0).
                For multiple-choice polls, a list with the indices should be used.
                Will ``raise IndexError`` if out of bounds. Example:

                >>> message = ...  # get the message somehow
                >>> # Clicking the 3rd button
                >>> # [button1] [button2]
                >>> # [     button3     ]
                >>> # [button4] [button5]
                >>> await message.click(2)  # index

            j (`int`):
                Clicks the button at position (i, j), these being the
                indices for the (row, column) respectively. Example:

                >>> # Clicking the 2nd button on the 1st row.
                >>> # [button1] [button2]
                >>> # [     button3     ]
                >>> # [button4] [button5]
                >>> await message.click(0, 1)  # (row, column)

                This is equivalent to ``message.buttons[0][1].click()``.

            text (`str` | `callable`):
                Clicks the first button or poll option with the text "text". This may
                also be a callable, like a ``re.compile(...).match``,
                and the text will be passed to it.

                If you need to select multiple options in a poll,
                pass a list of indices to the ``i`` parameter.

            filter (`callable`):
                Clicks the first button or poll option for which the callable
                returns `True`. The callable should accept a single
                `MessageButton <telethon.tl.custom.messagebutton.MessageButton>`
                or `PollAnswer <telethon.tl.types.PollAnswer>` argument.

                If you need to select multiple options in a poll,
                pass a list of indices to the ``i`` parameter.

            data (`bytes`):
                This argument overrides the rest and will not search any
                buttons. Instead, it will directly send the request to
                behave as if it clicked a button with said data. Note
                that if the message does not have this data, it will
                ``raise DataInvalidError``.

            share_phone (`bool` | `str` | tl:`InputMediaContact`):
                When clicking on a keyboard button requesting a phone number
                (:tl:`KeyboardButtonRequestPhone`), this argument must be
                explicitly set to avoid accidentally sharing the number.

                It can be `True` to automatically share the current user's
                phone, a string to share a specific phone number, or a contact
                media to specify all details.

                If the button is pressed without this, `ValueError` is raised.

            share_geo (`tuple` | `list` | tl:`InputMediaGeoPoint`):
                When clicking on a keyboard button requesting a geo location
                (:tl:`KeyboardButtonRequestGeoLocation`), this argument must
                be explicitly set to avoid accidentally sharing the location.

                It must be a `tuple` of `float` as ``(longitude, latitude)``,
                or a :tl:`InputGeoPoint` instance to avoid accidentally using
                the wrong roder.

                If the button is pressed without this, `ValueError` is raised.

            password (`str`):
                When clicking certain buttons (such as BotFather's confirmation
                button to transfer ownership), if your account has 2FA enabled,
                you need to provide your account's password. Otherwise,
                `teltehon.errors.PasswordHashInvalidError` is raised.

            Example:

                .. code-block:: python

                    # Click the first button
                    await message.click(0)

                    # Click some row/column
                    await message.click(row, column)

                    # Click by text
                    await message.click(text='👍')

                    # Click by data
                    await message.click(data=b'payload')

                    # Click on a button requesting a phone
                    await message.click(0, share_phone=True)
        N )r   r   r   c                 s   s   | ]}t |d k	V  qd S rj   )int)rY   xrV   rV   rW   r     s     z Message.click.<locals>.<genexpr>r   z,You can only set either of i, text or filterc                     s   j j j d k	r:tr. fddD S   jgS d k	rtrl D ]} | jrN| jg  S qNn  D ]} | jkrp| jg  S qpd S d k	r D ]} | r| jg  S qd S d S )Nc                    s   g | ]} | j qS rV   )option)rY   idxanswersrV   rW   r\     s     z7Message.click.<locals>.find_options.<locals>.<listcomp>)r   r   r   Zis_list_liker   callableri   )Zanswer)r   rZ   rT   ri   r   rW   find_options  s&    



z#Message.click.<locals>.find_options)ZpeerZmsg_idoptionsc                     s   d k	rRt r0jD ]} | jr|   S qnjD ]} | jkr6|   S q6d S  d k	rzjD ]}  | r`|   S q`d S d krdd krj S j  S d S )Nr   )r   rH   ri   rG   )buttonr   rZ   jrT   ri   rV   rW   find_button  s&    







z"Message.click.<locals>.find_button)rC   rx   r   ZKeyboardButtonCallbackr	   r   clickr   rt   r   r   r   ZSendVoteRequestrb   r|   )rT   rZ   r   ri   r   r   r   r   r   r{   Zbutr   r   r   r   rV   r   rW   r   h  sH    j  

  zMessage.clickc                    s,   | j r(| j j|  I dH | jdI dH  dS )z
        Marks the message as read. Shorthand for
        `client.send_read_acknowledge()
        <telethon.client.messages.MessageMethods.send_read_acknowledge>`
        with both ``entity`` and ``message`` already set.
        N)Zmax_id)rC   Zsend_read_acknowledgerx   r   rg   rV   rV   rW   	mark_read'  s
     zMessage.mark_readFnotify
pm_onesidec                   s0   | j r,| j j|  I dH | j||dI dH S dS )z
        Pins the message. Shorthand for
        `telethon.client.messages.MessageMethods.pin_message`
        with both ``entity`` and ``message`` already set.
        Nr   )rC   Zpin_messagerx   r   )rT   r   r   rV   rV   rW   pin2  s    	   zMessage.pinc                    s*   | j r&| j |  I dH | jI dH S dS )z
        Unpins the message. Shorthand for
        `telethon.client.messages.MessageMethods.unpin_message`
        with both ``entity`` and ``message`` already set.
        N)rC   Zunpin_messagerx   r   rg   rV   rV   rW   unpin?  s
     zMessage.unpinc                    s   | j s
dS z4| jr |  I dH nd}| j j|| jdI dH }W n tk
rT   Y dS X |s^dS |j| _|j| _|j| _|j	| _	|j
| _
|j| _|j| _|j| _dS )zz
        Re-fetches this message to reload the sender and chat entities,
        along with their input versions.
        Nr   )rC   r   rx   r   r   rt   r_   r`   ra   rb   rJ   rK   rQ   rL   )rT   r{   msgrV   rV   rW   ry   M  s"    zMessage._reload_messagec                    s   |   I d H  d S rj   )ry   rg   rV   rV   rW   _refetch_senderf  s    zMessage._refetch_senderc                    sL   j rHtjtjtjfrH fddjjD _dd jD _dS )zT
        Helper methods to set the buttons given the input sender and chat.
        c                    s$   g | ]} fd d|j D qS )c                    s    g | ]}t j| jqS rV   )r	   rC   r   )rY   r   rv   r{   rT   rV   rW   r\   o  s   z3Message._set_buttons.<locals>.<listcomp>.<listcomp>)rw   r~   r   rV   rW   r\   o  s   z(Message._set_buttons.<locals>.<listcomp>c                 S   s   g | ]}|D ]}|qqS rV   rV   )rY   r   r   rV   rV   rW   r\   s  s       N)	rC   rB   r.   r   r   r   r   rG   rH   rz   rV   r   rW   ru   i  s     zMessage._set_buttonsc              
   C   s   | j rt| jtjtjfsdS | jjD ]}|jD ]}t|tjr0|j	sL| j
sj| j}|s^td|    S z(| j jt| j
d  W     S  tk
r   tddY q0X q0q&dS )a;  
        Returns the input peer of the bot that's needed for the reply markup.

        This is necessary for :tl:`KeyboardButtonSwitchInline` since we need
        to know what bot we want to start. Raises ``ValueError`` if the bot
        cannot be found but is needed. Returns `None` if it's not needed.
        NzNo input senderr   )rC   rB   r.   r   r   r   r   rw   ZKeyboardButtonSwitchInlineZ	same_peerr*   Zinput_senderrt   r^   rX   r   Z
resolve_idZ_as_input_peerAttributeError)rT   r   r   rv   rV   rV   rW   rs   u  s&     
zMessage._needed_markup_botc                 C   s>   | j }|r:|jD ](}t||r|r*||r2|  S  dS qdS )z
        Helper method to return the document only if it has an attribute
        that's an instance of the given kind, and passes the condition.
        N)r   
attributesrB   )rT   kind	conditiondocr   rV   rV   rW   r     s    

zMessage._document_by_attribute))NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN)N)NN)N)K__name__
__module____qualname____doc__r   r   ZTypePeerr   r   strrA   ZTypeMessageFwdHeaderZTypeMessageReplyHeaderZTypeMessageMediaZTypeReplyMarkupr   ZTypeMessageEntityZTypeMessageRepliesZTypeMessageReactionsZTypeRestrictionReasonZTypeFactCheckZTypeMessageActionrP   rf   propertyrc   ri   setterrn   ro   rp   rq   rr   rw   r|   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   ry   r   ru   rs   r   rV   rV   rV   rW   r      sj   $                                                                                                                      XA



























	





	



(
.     @r   N)typingr   r   r   r   Z
chatgetterr   Zsendergetterr   Zmessagebuttonr	   rp   r
   r   r   r   r   r   r   r   r   r   r   rV   rV   rV   rW   <module>   s   