File: messagebutton.py

package info (click to toggle)
python-telethon 1.42.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,520 kB
  • sloc: python: 16,285; javascript: 200; makefile: 16; sh: 11
file content (154 lines) | stat: -rw-r--r-- 6,275 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
from .. import types, functions
from ... import password as pwd_mod
from ...errors import BotResponseTimeoutError
try:
    import webbrowser
except ModuleNotFoundError:
    pass
import sys
import os


class MessageButton:
    """
    .. note::

        `Message.buttons <telethon.tl.custom.message.Message.buttons>`
        are instances of this type. If you want to **define** a reply
        markup for e.g. sending messages, refer to `Button
        <telethon.tl.custom.button.Button>` instead.

    Custom class that encapsulates a message button providing
    an abstraction to easily access some commonly needed features
    (such as clicking the button itself).

    Attributes:

        button (:tl:`KeyboardButton`):
            The original :tl:`KeyboardButton` object.
    """
    def __init__(self, client, original, chat, bot, msg_id):
        self.button = original
        self._bot = bot
        self._chat = chat
        self._msg_id = msg_id
        self._client = client

    @property
    def client(self):
        """
        Returns the `telethon.client.telegramclient.TelegramClient`
        instance that created this instance.
        """
        return self._client

    @property
    def text(self):
        """The text string of the button."""
        return self.button.text

    @property
    def data(self):
        """The `bytes` data for :tl:`KeyboardButtonCallback` objects."""
        if isinstance(self.button, types.KeyboardButtonCallback):
            return self.button.data

    @property
    def inline_query(self):
        """The query `str` for :tl:`KeyboardButtonSwitchInline` objects."""
        if isinstance(self.button, types.KeyboardButtonSwitchInline):
            return self.button.query

    @property
    def url(self):
        """The url `str` for :tl:`KeyboardButtonUrl` objects."""
        if isinstance(self.button, types.KeyboardButtonUrl):
            return self.button.url

    async def click(self, share_phone=None, share_geo=None, *, password=None, open_url=None):
        """
        Emulates the behaviour of clicking this button.

        If it's a normal :tl:`KeyboardButton` with text, a message will be
        sent, and the sent `Message <telethon.tl.custom.message.Message>` returned.

        If it's an inline :tl:`KeyboardButtonCallback` with text and data,
        it will be "clicked" and the :tl:`BotCallbackAnswer` returned.

        If it's an inline :tl:`KeyboardButtonSwitchInline` button, the
        :tl:`StartBotRequest` will be invoked and the resulting updates
        returned.

        If it's a :tl:`KeyboardButtonUrl`, the ``URL`` of the button will
        be returned. If you pass ``open_url=True`` the URL of the button will
        be passed to ``webbrowser.open`` and return `True` on success.

        If it's a :tl:`KeyboardButtonRequestPhone`, you must indicate that you
        want to ``share_phone=True`` in order to share it. Sharing it is not a
        default because it is a privacy concern and could happen accidentally.

        You may also use ``share_phone=phone`` to share a specific number, in
        which case either `str` or :tl:`InputMediaContact` should be used.

        If it's a :tl:`KeyboardButtonRequestGeoLocation`, you must pass a
        tuple in ``share_geo=(longitude, latitude)``. Note that Telegram seems
        to have some heuristics to determine impossible locations, so changing
        this value a lot quickly may not work as expected. You may also pass a
        :tl:`InputGeoPoint` if you find the order confusing.
        """
        if isinstance(self.button, types.KeyboardButton):
            return await self._client.send_message(
                self._chat, self.button.text, parse_mode=None)
        elif isinstance(self.button, types.KeyboardButtonCallback):
            if password is not None:
                pwd = await self._client(functions.account.GetPasswordRequest())
                password = pwd_mod.compute_check(pwd, password)

            req = functions.messages.GetBotCallbackAnswerRequest(
                peer=self._chat, msg_id=self._msg_id, data=self.button.data,
                password=password
            )
            try:
                return await self._client(req)
            except BotResponseTimeoutError:
                return None
        elif isinstance(self.button, types.KeyboardButtonSwitchInline):
            return await self._client(functions.messages.StartBotRequest(
                bot=self._bot, peer=self._chat, start_param=self.button.query
            ))
        elif isinstance(self.button, types.KeyboardButtonUrl):
            if open_url:
                if "webbrowser" in sys.modules:
                    return webbrowser.open(self.button.url)
            return self.button.url
        elif isinstance(self.button, types.KeyboardButtonGame):
            req = functions.messages.GetBotCallbackAnswerRequest(
                peer=self._chat, msg_id=self._msg_id, game=True
            )
            try:
                return await self._client(req)
            except BotResponseTimeoutError:
                return None
        elif isinstance(self.button, types.KeyboardButtonRequestPhone):
            if not share_phone:
                raise ValueError('cannot click on phone buttons unless share_phone=True')

            if share_phone == True or isinstance(share_phone, str):
                me = await self._client.get_me()
                share_phone = types.InputMediaContact(
                    phone_number=me.phone if share_phone == True else share_phone,
                    first_name=me.first_name or '',
                    last_name=me.last_name or '',
                    vcard=''
                )

            return await self._client.send_file(self._chat, share_phone)
        elif isinstance(self.button, types.KeyboardButtonRequestGeoLocation):
            if not share_geo:
                raise ValueError('cannot click on geo buttons unless share_geo=(longitude, latitude)')

            if isinstance(share_geo, (tuple, list)):
                long, lat = share_geo
                share_geo = types.InputMediaGeoPoint(types.InputGeoPoint(lat=lat, long=long))

            return await self._client.send_file(self._chat, share_geo)