mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2024-11-10 19:46:36 +03:00
Reuse code to get chat and sender
This commit is contained in:
parent
531a02a2a1
commit
8eecd9c226
|
@ -53,3 +53,19 @@ telethon\.tl\.custom\.button module
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
telethon\.tl\.custom\.chatgetter module
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: telethon.tl.custom.chatgetter
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
telethon\.tl\.custom\.sendergetter module
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: telethon.tl.custom.sendergetter
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
|
@ -3,6 +3,7 @@ import warnings
|
||||||
|
|
||||||
from .. import utils
|
from .. import utils
|
||||||
from ..tl import TLObject, types
|
from ..tl import TLObject, types
|
||||||
|
from ..tl.custom.chatgetter import ChatGetter
|
||||||
|
|
||||||
|
|
||||||
async def _into_id_set(client, chats):
|
async def _into_id_set(client, chats):
|
||||||
|
@ -79,13 +80,16 @@ class EventBuilder(abc.ABC):
|
||||||
return event
|
return event
|
||||||
|
|
||||||
|
|
||||||
class EventCommon(abc.ABC):
|
class EventCommon(ChatGetter, abc.ABC):
|
||||||
"""
|
"""
|
||||||
Intermediate class with common things to all events.
|
Intermediate class with common things to all events.
|
||||||
|
|
||||||
All events (except `Raw`) have ``is_private``, ``is_group``
|
Remember that this class implements `ChatGetter
|
||||||
and ``is_channel`` boolean properties, as well as an
|
<telethon.tl.custom.chatgetter.ChatGetter>` which
|
||||||
``original_update`` field containing the original :tl:`Update`.
|
means you have access to all chat properties and methods.
|
||||||
|
|
||||||
|
In addition, you can access the `original_update`
|
||||||
|
field which contains the original :tl:`Update`.
|
||||||
"""
|
"""
|
||||||
_event_name = 'Event'
|
_event_name = 'Event'
|
||||||
|
|
||||||
|
@ -96,64 +100,27 @@ class EventCommon(abc.ABC):
|
||||||
self._message_id = msg_id
|
self._message_id = msg_id
|
||||||
self._input_chat = None
|
self._input_chat = None
|
||||||
self._chat = None
|
self._chat = None
|
||||||
|
self._broadcast = broadcast
|
||||||
self.original_update = None
|
self.original_update = None
|
||||||
|
|
||||||
self.is_private = isinstance(chat_peer, types.PeerUser)
|
|
||||||
self.is_group = (
|
|
||||||
isinstance(chat_peer, (types.PeerChat, types.PeerChannel))
|
|
||||||
and not broadcast
|
|
||||||
)
|
|
||||||
self.is_channel = isinstance(chat_peer, types.PeerChannel)
|
|
||||||
|
|
||||||
def _set_client(self, client):
|
def _set_client(self, client):
|
||||||
"""
|
"""
|
||||||
Setter so subclasses can act accordingly when the client is set.
|
Setter so subclasses can act accordingly when the client is set.
|
||||||
"""
|
"""
|
||||||
self._client = client
|
self._client = client
|
||||||
|
self._chat = self._entities.get(self.chat_id)
|
||||||
|
if not self._chat:
|
||||||
|
return
|
||||||
|
|
||||||
@property
|
self._input_chat = utils.get_input_peer(self._chat)
|
||||||
def input_chat(self):
|
if not getattr(self._input_chat, 'access_hash', True):
|
||||||
"""
|
# getattr with True to handle the InputPeerSelf() case
|
||||||
This (:tl:`InputPeer`) is the input version of the chat where the
|
|
||||||
event occurred. This doesn't have things like username or similar,
|
|
||||||
but is still useful in some cases.
|
|
||||||
|
|
||||||
Note that this might not be available if the library doesn't have
|
|
||||||
enough information available.
|
|
||||||
"""
|
|
||||||
if self._input_chat is None and self._chat_peer is not None:
|
|
||||||
try:
|
try:
|
||||||
self._input_chat =\
|
self._input_chat = self._client.session.get_input_entity(
|
||||||
self._client.session.get_input_entity(self._chat_peer)
|
self._chat_peer
|
||||||
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
self._input_chat = None
|
||||||
|
|
||||||
return self._input_chat
|
|
||||||
|
|
||||||
async def get_input_chat(self):
|
|
||||||
"""
|
|
||||||
Returns `input_chat`, but will make an API call to find the
|
|
||||||
input chat unless it's already cached.
|
|
||||||
"""
|
|
||||||
if self.input_chat is None and self._chat_peer is not None:
|
|
||||||
ch = isinstance(self._chat_peer, types.PeerChannel)
|
|
||||||
if not ch and self._message_id is not None:
|
|
||||||
msg = await self._client.get_messages(
|
|
||||||
None, ids=self._message_id)
|
|
||||||
self._chat = msg._chat
|
|
||||||
self._input_chat = msg._input_chat
|
|
||||||
else:
|
|
||||||
target = utils.get_peer_id(self._chat_peer)
|
|
||||||
async for d in self._client.iter_dialogs(100):
|
|
||||||
if d.id == target:
|
|
||||||
self._chat = d.entity
|
|
||||||
self._input_chat = d.input_entity
|
|
||||||
# TODO Don't break, exhaust the iterator, otherwise
|
|
||||||
# async_generator raises RuntimeError: partially-
|
|
||||||
# exhausted async_generator 'xyz' garbage collected
|
|
||||||
# break
|
|
||||||
|
|
||||||
return self._input_chat
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def client(self):
|
def client(self):
|
||||||
|
@ -162,44 +129,6 @@ class EventCommon(abc.ABC):
|
||||||
"""
|
"""
|
||||||
return self._client
|
return self._client
|
||||||
|
|
||||||
@property
|
|
||||||
def chat(self):
|
|
||||||
"""
|
|
||||||
The :tl:`User`, :tl:`Chat` or :tl:`Channel` on which
|
|
||||||
the event occurred. This property may make an API call the first time
|
|
||||||
to get the most up to date version of the chat (mostly when the event
|
|
||||||
doesn't belong to a channel), so keep that in mind. You should use
|
|
||||||
`get_chat` instead, unless you want to avoid an API call.
|
|
||||||
"""
|
|
||||||
if not self.input_chat:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if self._chat is None:
|
|
||||||
self._chat = self._entities.get(utils.get_peer_id(self._chat_peer))
|
|
||||||
|
|
||||||
return self._chat
|
|
||||||
|
|
||||||
async def get_chat(self):
|
|
||||||
"""
|
|
||||||
Returns `chat`, but will make an API call to find the
|
|
||||||
chat unless it's already cached.
|
|
||||||
"""
|
|
||||||
if self.chat is None and await self.get_input_chat():
|
|
||||||
try:
|
|
||||||
self._chat =\
|
|
||||||
await self._client.get_entity(self._input_chat)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
return self._chat
|
|
||||||
|
|
||||||
@property
|
|
||||||
def chat_id(self):
|
|
||||||
"""
|
|
||||||
Returns the marked integer ID of the chat, if any.
|
|
||||||
"""
|
|
||||||
if self._chat_peer:
|
|
||||||
return utils.get_peer_id(self._chat_peer)
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return TLObject.pretty_format(self.to_dict())
|
return TLObject.pretty_format(self.to_dict())
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ from async_generator import isasyncgenfunction
|
||||||
|
|
||||||
from .client.telegramclient import TelegramClient
|
from .client.telegramclient import TelegramClient
|
||||||
from .tl.custom import Draft, Dialog, MessageButton, Forward, Message
|
from .tl.custom import Draft, Dialog, MessageButton, Forward, Message
|
||||||
|
from .tl.custom.chatgetter import ChatGetter
|
||||||
|
from .tl.custom.sendergetter import SenderGetter
|
||||||
|
|
||||||
|
|
||||||
def _syncify_coro(t, method_name):
|
def _syncify_coro(t, method_name):
|
||||||
|
@ -78,4 +80,5 @@ def syncify(*types):
|
||||||
_syncify_gen(t, method_name)
|
_syncify_gen(t, method_name)
|
||||||
|
|
||||||
|
|
||||||
syncify(TelegramClient, Draft, Dialog, MessageButton, Forward, Message)
|
syncify(TelegramClient, Draft, Dialog, MessageButton,
|
||||||
|
ChatGetter, SenderGetter, Forward, Message)
|
||||||
|
|
114
telethon/tl/custom/chatgetter.py
Normal file
114
telethon/tl/custom/chatgetter.py
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
import abc
|
||||||
|
|
||||||
|
from ... import errors, utils
|
||||||
|
from ...tl import types
|
||||||
|
|
||||||
|
|
||||||
|
class ChatGetter(abc.ABC):
|
||||||
|
"""
|
||||||
|
Helper base class that introduces the `chat`, `input_chat`
|
||||||
|
and `chat_id` properties and `get_chat` and `get_input_chat`
|
||||||
|
methods.
|
||||||
|
|
||||||
|
Subclasses **must** have the following private members: `_chat`,
|
||||||
|
`_input_chat`, `_chat_peer`, `_broadcast` and `_client`. As an end
|
||||||
|
user, you should not worry about this.
|
||||||
|
"""
|
||||||
|
@property
|
||||||
|
def chat(self):
|
||||||
|
"""
|
||||||
|
Returns the :tl:`User`, :tl:`Chat` or :tl:`Channel` where this object
|
||||||
|
belongs to. It may be ``None`` if Telegram didn't send the chat.
|
||||||
|
|
||||||
|
If you're using `telethon.events`, use `get_chat` instead.
|
||||||
|
"""
|
||||||
|
return self._chat
|
||||||
|
|
||||||
|
async def get_chat(self):
|
||||||
|
"""
|
||||||
|
Returns `chat`, but will make an API call to find the
|
||||||
|
chat unless it's already cached.
|
||||||
|
"""
|
||||||
|
if self._chat is None and await self.get_input_chat():
|
||||||
|
try:
|
||||||
|
self._chat =\
|
||||||
|
await self._client.get_entity(self._input_chat)
|
||||||
|
except ValueError:
|
||||||
|
await self._refetch_chat()
|
||||||
|
return self._chat
|
||||||
|
|
||||||
|
@property
|
||||||
|
def input_chat(self):
|
||||||
|
"""
|
||||||
|
This :tl:`InputPeer` is the input version of the chat where the
|
||||||
|
message was sent. Similarly to `input_sender`, this doesn't have
|
||||||
|
things like username or similar, but still useful in some cases.
|
||||||
|
|
||||||
|
Note that this might not be available if the library doesn't
|
||||||
|
have enough information available.
|
||||||
|
"""
|
||||||
|
if self._input_chat is None and self._chat_peer:
|
||||||
|
try:
|
||||||
|
self._input_chat =\
|
||||||
|
self._client.session.get_input_entity(self._chat_peer)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return self._input_chat
|
||||||
|
|
||||||
|
async def get_input_chat(self):
|
||||||
|
"""
|
||||||
|
Returns `input_chat`, but will make an API call to find the
|
||||||
|
input chat unless it's already cached.
|
||||||
|
"""
|
||||||
|
if self.input_chat is None and self.chat_id:
|
||||||
|
try:
|
||||||
|
# The chat may be recent, look in dialogs
|
||||||
|
target = self.chat_id
|
||||||
|
async for d in self._client.iter_dialogs(100):
|
||||||
|
if d.id == target:
|
||||||
|
self._chat = d.entity
|
||||||
|
self._input_chat = d.input_entity
|
||||||
|
break
|
||||||
|
except errors.RPCError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return self._input_chat
|
||||||
|
|
||||||
|
@property
|
||||||
|
def chat_id(self):
|
||||||
|
"""
|
||||||
|
Returns the marked chat integer ID. Note that this value **will
|
||||||
|
be different** from `to_id` for incoming private messages, since
|
||||||
|
the chat *to* which the messages go is to your own person, but
|
||||||
|
the *chat* itself is with the one who sent the message.
|
||||||
|
|
||||||
|
TL;DR; this gets the ID that you expect.
|
||||||
|
"""
|
||||||
|
return utils.get_peer_id(self._chat_peer) if self._chat_peer else None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_private(self):
|
||||||
|
"""True if the message was sent as a private message."""
|
||||||
|
return isinstance(self._chat_peer, types.PeerUser)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_group(self):
|
||||||
|
"""True if the message was sent on a group or megagroup."""
|
||||||
|
if self._broadcast is None and self.chat:
|
||||||
|
self._broadcast = getattr(self.chat, 'broadcast', None)
|
||||||
|
|
||||||
|
return (
|
||||||
|
isinstance(self._chat_peer, (types.PeerChat, types.PeerChannel))
|
||||||
|
and not self._broadcast
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_channel(self):
|
||||||
|
"""True if the message was sent on a megagroup or channel."""
|
||||||
|
return isinstance(self._chat_peer, types.PeerChannel)
|
||||||
|
|
||||||
|
async def _refetch_chat(self):
|
||||||
|
"""
|
||||||
|
Re-fetches chat information through other means.
|
||||||
|
"""
|
|
@ -1,11 +1,19 @@
|
||||||
from ...utils import get_input_peer
|
from .chatgetter import ChatGetter
|
||||||
|
from .sendergetter import SenderGetter
|
||||||
|
from ... import utils
|
||||||
|
from ...tl import types
|
||||||
|
|
||||||
|
|
||||||
class Forward:
|
class Forward(ChatGetter, SenderGetter):
|
||||||
"""
|
"""
|
||||||
Custom class that encapsulates a :tl:`MessageFwdHeader` providing an
|
Custom class that encapsulates a :tl:`MessageFwdHeader` providing an
|
||||||
abstraction to easily access information like the original sender.
|
abstraction to easily access information like the original sender.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
|
|
||||||
original_fwd (:tl:`MessageFwdHeader`):
|
original_fwd (:tl:`MessageFwdHeader`):
|
||||||
|
@ -19,105 +27,21 @@ class Forward:
|
||||||
self.__dict__ = original.__dict__
|
self.__dict__ = original.__dict__
|
||||||
self._client = client
|
self._client = client
|
||||||
self.original_fwd = original
|
self.original_fwd = original
|
||||||
|
|
||||||
|
self._sender_id = original.from_id
|
||||||
self._sender = entities.get(original.from_id)
|
self._sender = entities.get(original.from_id)
|
||||||
self._chat = entities.get(original.channel_id)
|
|
||||||
|
|
||||||
self._input_sender =\
|
self._input_sender =\
|
||||||
get_input_peer(self._sender) if self._sender else None
|
utils.get_input_peer(self._sender) if self._sender else None
|
||||||
self._input_chat =\
|
|
||||||
get_input_peer(self._chat) if self._chat else None
|
|
||||||
|
|
||||||
# TODO The pattern to get sender and chat is very similar
|
self._broadcast = None
|
||||||
# and copy pasted in/to several places. Reuse the code.
|
if original.channel_id:
|
||||||
#
|
self._chat_peer = types.PeerChannel(original.channel_id)
|
||||||
# It could be an ABC with some ``resolve_sender`` abstract,
|
self._chat = entities.get(utils.get_peer_id(self._chat_peer))
|
||||||
# so every subclass knew what tricks it can make to get
|
else:
|
||||||
# the sender.
|
self._chat_peer = None
|
||||||
|
self._chat = None
|
||||||
|
|
||||||
@property
|
self._input_chat = \
|
||||||
def sender(self):
|
utils.get_input_peer(self._chat) if self._chat else None
|
||||||
"""
|
|
||||||
The :tl:`User` that sent the original message. This may be ``None``
|
|
||||||
if it couldn't be found or the message wasn't forwarded from an user
|
|
||||||
but instead was forwarded from e.g. a channel.
|
|
||||||
"""
|
|
||||||
return self._sender
|
|
||||||
|
|
||||||
async def get_sender(self):
|
|
||||||
"""
|
|
||||||
Returns `sender` but will make an API if necessary.
|
|
||||||
"""
|
|
||||||
if not self.sender and self.original_fwd.from_id:
|
|
||||||
try:
|
|
||||||
self._sender = await self._client.get_entity(
|
|
||||||
await self.get_input_sender())
|
|
||||||
except ValueError:
|
|
||||||
# TODO We could reload the message
|
# TODO We could reload the message
|
||||||
pass
|
|
||||||
|
|
||||||
return self._sender
|
|
||||||
|
|
||||||
@property
|
|
||||||
def input_sender(self):
|
|
||||||
"""
|
|
||||||
Returns the input version of `user`.
|
|
||||||
"""
|
|
||||||
if not self._input_sender and self.original_fwd.from_id:
|
|
||||||
try:
|
|
||||||
self._input_sender = self._client.session.get_input_entity(
|
|
||||||
self.original_fwd.from_id)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return self._input_sender
|
|
||||||
|
|
||||||
async def get_input_sender(self):
|
|
||||||
"""
|
|
||||||
Returns `input_sender` but will make an API call if necessary.
|
|
||||||
"""
|
|
||||||
# TODO We could reload the message
|
|
||||||
return self.input_sender
|
|
||||||
|
|
||||||
@property
|
|
||||||
def chat(self):
|
|
||||||
"""
|
|
||||||
The :tl:`Channel` where the original message was sent. This may be
|
|
||||||
``None`` if it couldn't be found or the message wasn't forwarded
|
|
||||||
from a channel but instead was forwarded from e.g. an user.
|
|
||||||
"""
|
|
||||||
return self._chat
|
|
||||||
|
|
||||||
async def get_chat(self):
|
|
||||||
"""
|
|
||||||
Returns `chat` but will make an API if necessary.
|
|
||||||
"""
|
|
||||||
if not self.chat and self.original_fwd.channel_id:
|
|
||||||
try:
|
|
||||||
self._chat = await self._client.get_entity(
|
|
||||||
await self.get_input_chat())
|
|
||||||
except ValueError:
|
|
||||||
# TODO We could reload the message
|
|
||||||
pass
|
|
||||||
|
|
||||||
return self._chat
|
|
||||||
|
|
||||||
@property
|
|
||||||
def input_chat(self):
|
|
||||||
"""
|
|
||||||
Returns the input version of `chat`.
|
|
||||||
"""
|
|
||||||
if not self._input_chat and self.original_fwd.channel_id:
|
|
||||||
try:
|
|
||||||
self._input_chat = self._client.session.get_input_entity(
|
|
||||||
self.original_fwd.channel_id)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return self._input_chat
|
|
||||||
|
|
||||||
async def get_input_chat(self):
|
|
||||||
"""
|
|
||||||
Returns `input_chat` but will make an API call if necessary.
|
|
||||||
"""
|
|
||||||
# TODO We could reload the message
|
|
||||||
return self.input_chat
|
|
||||||
|
|
|
@ -1,15 +1,22 @@
|
||||||
from .. import types
|
from .. import types
|
||||||
from ...utils import get_input_peer, get_peer_id, get_inner_text
|
from ...utils import get_input_peer, get_inner_text
|
||||||
|
from .chatgetter import ChatGetter
|
||||||
|
from .sendergetter import SenderGetter
|
||||||
from .messagebutton import MessageButton
|
from .messagebutton import MessageButton
|
||||||
from .forward import Forward
|
from .forward import Forward
|
||||||
|
|
||||||
|
|
||||||
class Message:
|
class Message(ChatGetter, SenderGetter):
|
||||||
"""
|
"""
|
||||||
Custom class that encapsulates a message providing an abstraction to
|
Custom class that encapsulates a message providing an abstraction to
|
||||||
easily access some commonly needed features (such as the markdown text
|
easily access some commonly needed features (such as the markdown text
|
||||||
or the text for a given message entity).
|
or the text for a given message entity).
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
|
|
||||||
original_message (:tl:`Message`):
|
original_message (:tl:`Message`):
|
||||||
|
@ -34,7 +41,8 @@ class Message:
|
||||||
self._buttons_flat = None
|
self._buttons_flat = None
|
||||||
self._buttons_count = None
|
self._buttons_count = None
|
||||||
|
|
||||||
self._sender = entities.get(self.original_message.from_id)
|
self._sender_id = self.original_message.from_id
|
||||||
|
self._sender = entities.get(self._sender_id)
|
||||||
if self._sender:
|
if self._sender:
|
||||||
self._input_sender = get_input_peer(self._sender)
|
self._input_sender = get_input_peer(self._sender)
|
||||||
if not getattr(self._input_sender, 'access_hash', None):
|
if not getattr(self._input_sender, 'access_hash', None):
|
||||||
|
@ -46,10 +54,11 @@ class Message:
|
||||||
# was sent, not *to which ID* it was sent.
|
# was sent, not *to which ID* it was sent.
|
||||||
if not self.original_message.out \
|
if not self.original_message.out \
|
||||||
and isinstance(self.original_message.to_id, types.PeerUser):
|
and isinstance(self.original_message.to_id, types.PeerUser):
|
||||||
self._chat_peer = types.PeerUser(self.original_message.from_id)
|
self._chat_peer = types.PeerUser(self._sender_id)
|
||||||
else:
|
else:
|
||||||
self._chat_peer = self.original_message.to_id
|
self._chat_peer = self.original_message.to_id
|
||||||
|
|
||||||
|
self._broadcast = bool(self.original_message.post)
|
||||||
self._chat = entities.get(self.chat_id)
|
self._chat = entities.get(self.chat_id)
|
||||||
self._input_chat = input_chat
|
self._input_chat = input_chat
|
||||||
if not self._input_chat and self._chat:
|
if not self._input_chat and self._chat:
|
||||||
|
@ -171,158 +180,8 @@ class Message:
|
||||||
self._chat = msg._chat
|
self._chat = msg._chat
|
||||||
self._input_chat = msg._input_chat
|
self._input_chat = msg._input_chat
|
||||||
|
|
||||||
@property
|
async def _refetch_sender(self):
|
||||||
def sender(self):
|
|
||||||
"""
|
|
||||||
Returns the :tl:`User` that sent this message. It may be ``None``
|
|
||||||
if the message has no sender or if Telegram didn't send the sender
|
|
||||||
inside message events.
|
|
||||||
|
|
||||||
If you're using `telethon.events`, use `get_sender` instead.
|
|
||||||
"""
|
|
||||||
return self._sender
|
|
||||||
|
|
||||||
async def get_sender(self):
|
|
||||||
"""
|
|
||||||
Returns `sender`, but will make an API call to find the
|
|
||||||
sender unless it's already cached.
|
|
||||||
"""
|
|
||||||
if self._sender is None and await self.get_input_sender():
|
|
||||||
try:
|
|
||||||
self._sender =\
|
|
||||||
await self._client.get_entity(self._input_sender)
|
|
||||||
except ValueError:
|
|
||||||
await self._reload_message()
|
await self._reload_message()
|
||||||
return self._sender
|
|
||||||
|
|
||||||
@property
|
|
||||||
def chat(self):
|
|
||||||
"""
|
|
||||||
Returns the :tl:`User`, :tl:`Chat` or :tl:`Channel` where this message
|
|
||||||
was sent. It may be ``None`` if Telegram didn't send the chat inside
|
|
||||||
message events.
|
|
||||||
|
|
||||||
If you're using `telethon.events`, use `get_chat` instead.
|
|
||||||
"""
|
|
||||||
return self._chat
|
|
||||||
|
|
||||||
async def get_chat(self):
|
|
||||||
"""
|
|
||||||
Returns `chat`, but will make an API call to find the
|
|
||||||
chat unless it's already cached.
|
|
||||||
"""
|
|
||||||
if self._chat is None and await self.get_input_chat():
|
|
||||||
try:
|
|
||||||
self._chat =\
|
|
||||||
await self._client.get_entity(self._input_chat)
|
|
||||||
except ValueError:
|
|
||||||
await self._reload_message()
|
|
||||||
return self._chat
|
|
||||||
|
|
||||||
@property
|
|
||||||
def input_sender(self):
|
|
||||||
"""
|
|
||||||
This (:tl:`InputPeer`) is the input version of the user who
|
|
||||||
sent the message. Similarly to `input_chat`, this doesn't have
|
|
||||||
things like username or similar, but still useful in some cases.
|
|
||||||
|
|
||||||
Note that this might not be available if the library can't
|
|
||||||
find the input chat, or if the message a broadcast on a channel.
|
|
||||||
"""
|
|
||||||
if self._input_sender is None:
|
|
||||||
if self.is_channel and not self.is_group:
|
|
||||||
return None
|
|
||||||
try:
|
|
||||||
self._input_sender = self._client.session\
|
|
||||||
.get_input_entity(self.original_message.from_id)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
return self._input_sender
|
|
||||||
|
|
||||||
async def get_input_sender(self):
|
|
||||||
"""
|
|
||||||
Returns `input_sender`, but will make an API call to find the
|
|
||||||
input sender unless it's already cached.
|
|
||||||
"""
|
|
||||||
if self.input_sender is None\
|
|
||||||
and not self.is_channel and not self.is_group:
|
|
||||||
await self._reload_message()
|
|
||||||
return self._input_sender
|
|
||||||
|
|
||||||
@property
|
|
||||||
def input_chat(self):
|
|
||||||
"""
|
|
||||||
This (:tl:`InputPeer`) is the input version of the chat where the
|
|
||||||
message was sent. Similarly to `input_sender`, this doesn't have
|
|
||||||
things like username or similar, but still useful in some cases.
|
|
||||||
|
|
||||||
Note that this might not be available if the library doesn't know
|
|
||||||
where the message came from.
|
|
||||||
"""
|
|
||||||
if self._input_chat is None:
|
|
||||||
try:
|
|
||||||
self._input_chat =\
|
|
||||||
self._client.session.get_input_entity(self._chat_peer)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return self._input_chat
|
|
||||||
|
|
||||||
async def get_input_chat(self):
|
|
||||||
"""
|
|
||||||
Returns `input_chat`, but will make an API call to find the
|
|
||||||
input chat unless it's already cached.
|
|
||||||
"""
|
|
||||||
if self.input_chat is None:
|
|
||||||
# There's a chance that the chat is a recent new dialog.
|
|
||||||
# The input chat cannot rely on ._reload_message() because
|
|
||||||
# said method may need the input chat.
|
|
||||||
target = self.chat_id
|
|
||||||
async for d in self._client.iter_dialogs(100):
|
|
||||||
if d.id == target:
|
|
||||||
self._chat = d.entity
|
|
||||||
self._input_chat = d.input_entity
|
|
||||||
break
|
|
||||||
|
|
||||||
return self._input_chat
|
|
||||||
|
|
||||||
@property
|
|
||||||
def sender_id(self):
|
|
||||||
"""
|
|
||||||
Returns the marked sender integer ID, if present.
|
|
||||||
"""
|
|
||||||
return self.original_message.from_id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def chat_id(self):
|
|
||||||
"""
|
|
||||||
Returns the marked chat integer ID. Note that this value **will
|
|
||||||
be different** from `to_id` for incoming private messages, since
|
|
||||||
the chat *to* which the messages go is to your own person, but
|
|
||||||
the *chat* itself is with the one who sent the message.
|
|
||||||
|
|
||||||
TL;DR; this gets the ID that you expect.
|
|
||||||
"""
|
|
||||||
return get_peer_id(self._chat_peer)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_private(self):
|
|
||||||
"""True if the message was sent as a private message."""
|
|
||||||
return isinstance(self.original_message.to_id, types.PeerUser)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_group(self):
|
|
||||||
"""True if the message was sent on a group or megagroup."""
|
|
||||||
return (
|
|
||||||
isinstance(self.original_message.to_id, (types.PeerChat,
|
|
||||||
types.PeerChannel))
|
|
||||||
and not self.original_message.post
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_channel(self):
|
|
||||||
"""True if the message was sent on a megagroup or channel."""
|
|
||||||
return isinstance(self.original_message.to_id, types.PeerChannel)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_reply(self):
|
def is_reply(self):
|
||||||
|
@ -602,10 +461,10 @@ class Message:
|
||||||
if self.original_message.fwd_from:
|
if self.original_message.fwd_from:
|
||||||
return None
|
return None
|
||||||
if not self.original_message.out:
|
if not self.original_message.out:
|
||||||
if not isinstance(self.original_message.to_id, types.PeerUser):
|
if not isinstance(self._chat_peer, types.PeerUser):
|
||||||
return None
|
return None
|
||||||
me = await self._client.get_me(input_peer=True)
|
me = await self._client.get_me(input_peer=True)
|
||||||
if self.original_message.to_id.user_id != me.user_id:
|
if self._chat_peer.user_id != me.user_id:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return await self._client.edit_message(
|
return await self._client.edit_message(
|
||||||
|
|
74
telethon/tl/custom/sendergetter.py
Normal file
74
telethon/tl/custom/sendergetter.py
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
import abc
|
||||||
|
|
||||||
|
|
||||||
|
class SenderGetter(abc.ABC):
|
||||||
|
"""
|
||||||
|
Helper base class that introduces the `sender`, `input_sender`
|
||||||
|
and `sender_id` properties and `get_sender` and `get_input_sender`
|
||||||
|
methods.
|
||||||
|
|
||||||
|
Subclasses **must** have the following private members: `_sender`,
|
||||||
|
`_input_sender`, `_sender_id` and `_client`. As an end user, you
|
||||||
|
should not worry about this.
|
||||||
|
"""
|
||||||
|
@property
|
||||||
|
def sender(self):
|
||||||
|
"""
|
||||||
|
Returns the :tl:`User` that created this object. It may be ``None``
|
||||||
|
if the object has no sender or if Telegram didn't send the sender.
|
||||||
|
|
||||||
|
If you're using `telethon.events`, use `get_sender` instead.
|
||||||
|
"""
|
||||||
|
return self._sender
|
||||||
|
|
||||||
|
async def get_sender(self):
|
||||||
|
"""
|
||||||
|
Returns `sender`, but will make an API call to find the
|
||||||
|
sender unless it's already cached.
|
||||||
|
"""
|
||||||
|
if self._sender is None and await self.get_input_sender():
|
||||||
|
try:
|
||||||
|
self._sender =\
|
||||||
|
await self._client.get_entity(self._input_sender)
|
||||||
|
except ValueError:
|
||||||
|
await self._reload_message()
|
||||||
|
return self._sender
|
||||||
|
|
||||||
|
@property
|
||||||
|
def input_sender(self):
|
||||||
|
"""
|
||||||
|
This :tl:`InputPeer` is the input version of the user who
|
||||||
|
sent the message. Similarly to `input_chat`, this doesn't have
|
||||||
|
things like username or similar, but still useful in some cases.
|
||||||
|
|
||||||
|
Note that this might not be available if the library can't
|
||||||
|
find the input chat, or if the message a broadcast on a channel.
|
||||||
|
"""
|
||||||
|
if self._input_sender is None and self._sender_id:
|
||||||
|
try:
|
||||||
|
self._input_sender = self._client.session\
|
||||||
|
.get_input_entity(self._sender_id)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
return self._input_sender
|
||||||
|
|
||||||
|
async def get_input_sender(self):
|
||||||
|
"""
|
||||||
|
Returns `input_sender`, but will make an API call to find the
|
||||||
|
input sender unless it's already cached.
|
||||||
|
"""
|
||||||
|
if self.input_sender is None and self._sender_id:
|
||||||
|
await self._refetch_sender()
|
||||||
|
return self._input_sender
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sender_id(self):
|
||||||
|
"""
|
||||||
|
Returns the marked sender integer ID, if present.
|
||||||
|
"""
|
||||||
|
return self._sender_id
|
||||||
|
|
||||||
|
async def _refetch_sender(self):
|
||||||
|
"""
|
||||||
|
Re-fetches sender information through other means.
|
||||||
|
"""
|
Loading…
Reference in New Issue
Block a user