Begin unification of event builders and events

This commit is contained in:
Lonami Exo
2022-01-28 11:34:16 +01:00
parent f2ef0bfceb
commit 9726169a8c
15 changed files with 1142 additions and 1719 deletions

View File

@@ -2,7 +2,7 @@ import asyncio
import time
import weakref
from .common import EventBuilder, EventCommon, name_inner_event
from .base import EventBuilder
from .._misc import utils
from .. import _tl
from ..types import _custom
@@ -64,13 +64,16 @@ class AlbumHack:
await asyncio.sleep(diff)
@name_inner_event
class Album(EventBuilder):
class Album(EventBuilder, _custom.chatgetter.ChatGetter, _custom.sendergetter.SenderGetter):
"""
Occurs whenever you receive an album. This event only exists
to ease dealing with an unknown amount of messages that belong
to the same album.
Members:
messages (Sequence[`Message <telethon.tl._custom.message.Message>`]):
The list of messages belonging to the same album.
Example
.. code-block:: python
@@ -91,12 +94,20 @@ class Album(EventBuilder):
await event.messages[4].reply('Cool!')
"""
def __init__(
self, chats=None, *, blacklist_chats=False, func=None):
super().__init__(chats, blacklist_chats=blacklist_chats, func=func)
def __init__(self, messages):
message = messages[0]
if not message.out and isinstance(message.peer_id, _tl.PeerUser):
# Incoming message (e.g. from a bot) has peer_id=us, and
# from_id=bot (the actual "chat" from a user's perspective).
chat_peer = message.from_id
else:
chat_peer = message.peer_id
@classmethod
def build(cls, update, others=None, self_id=None, *todo, **todo2):
_custom.chatgetter.ChatGetter.__init__(self, chat_peer=chat_peer, broadcast=bool(message.post))
_custom.sendergetter.SenderGetter.__init__(self, message.sender_id)
self.messages = messages
def _build(cls, update, others=None, self_id=None, *todo, **todo2):
if not others:
return # We only care about albums which come inside the same Updates
@@ -135,216 +146,188 @@ class Album(EventBuilder):
and u.message.grouped_id == group)
])
def filter(self, event):
# Albums with less than two messages require a few hacks to work.
if len(event.messages) > 1:
return super().filter(event)
def _set_client(self, client):
super()._set_client(client)
self._sender, self._input_sender = utils._get_entity_pair(self.sender_id, self._entities)
class Event(EventCommon, _custom.sendergetter.SenderGetter):
"""
Represents the event of a new album.
self.messages = [
_custom.Message._new(client, m, self._entities, None)
for m in self.messages
]
Members:
messages (Sequence[`Message <telethon.tl._custom.message.Message>`]):
The list of messages belonging to the same album.
"""
def __init__(self, messages):
message = messages[0]
if not message.out and isinstance(message.peer_id, _tl.PeerUser):
# Incoming message (e.g. from a bot) has peer_id=us, and
# from_id=bot (the actual "chat" from a user's perspective).
chat_peer = message.from_id
if len(self.messages) == 1:
# This will require hacks to be a proper album event
hack = client._albums.get(self.grouped_id)
if hack is None:
client._albums[self.grouped_id] = AlbumHack(client, self)
else:
chat_peer = message.peer_id
hack.extend(self.messages)
super().__init__(chat_peer=chat_peer,
msg_id=message.id, broadcast=bool(message.post))
@property
def grouped_id(self):
"""
The shared ``grouped_id`` between all the messages.
"""
return self.messages[0].grouped_id
_custom.sendergetter.SenderGetter.__init__(self, message.sender_id)
self.messages = messages
@property
def text(self):
"""
The message text of the first photo with a caption,
formatted using the client's default parse mode.
"""
return next((m.text for m in self.messages if m.text), '')
def _set_client(self, client):
super()._set_client(client)
self._sender, self._input_sender = utils._get_entity_pair(self.sender_id, self._entities)
@property
def raw_text(self):
"""
The raw message text of the first photo
with a caption, ignoring any formatting.
"""
return next((m.raw_text for m in self.messages if m.raw_text), '')
self.messages = [
_custom.Message._new(client, m, self._entities, None)
for m in self.messages
]
@property
def is_reply(self):
"""
`True` if the album is a reply to some other message.
if len(self.messages) == 1:
# This will require hacks to be a proper album event
hack = client._albums.get(self.grouped_id)
if hack is None:
client._albums[self.grouped_id] = AlbumHack(client, self)
else:
hack.extend(self.messages)
Remember that you can access the ID of the message
this one is replying to through `reply_to_msg_id`,
and the `Message` object with `get_reply_message()`.
"""
# Each individual message in an album all reply to the same message
return self.messages[0].is_reply
@property
def grouped_id(self):
"""
The shared ``grouped_id`` between all the messages.
"""
return self.messages[0].grouped_id
@property
def forward(self):
"""
The `Forward <telethon.tl._custom.forward.Forward>`
information for the first message in the album if it was forwarded.
"""
# Each individual message in an album all reply to the same message
return self.messages[0].forward
@property
def text(self):
"""
The message text of the first photo with a caption,
formatted using the client's default parse mode.
"""
return next((m.text for m in self.messages if m.text), '')
# endregion Public Properties
@property
def raw_text(self):
"""
The raw message text of the first photo
with a caption, ignoring any formatting.
"""
return next((m.raw_text for m in self.messages if m.raw_text), '')
# region Public Methods
@property
def is_reply(self):
"""
`True` if the album is a reply to some other message.
async def get_reply_message(self):
"""
The `Message <telethon.tl._custom.message.Message>`
that this album is replying to, or `None`.
Remember that you can access the ID of the message
this one is replying to through `reply_to_msg_id`,
and the `Message` object with `get_reply_message()`.
"""
# Each individual message in an album all reply to the same message
return self.messages[0].is_reply
The result will be cached after its first use.
"""
return await self.messages[0].get_reply_message()
@property
def forward(self):
"""
The `Forward <telethon.tl._custom.forward.Forward>`
information for the first message in the album if it was forwarded.
"""
# Each individual message in an album all reply to the same message
return self.messages[0].forward
async def respond(self, *args, **kwargs):
"""
Responds to the album (not as a reply). Shorthand for
`telethon.client.messages.MessageMethods.send_message`
with ``entity`` already set.
"""
return await self.messages[0].respond(*args, **kwargs)
# endregion Public Properties
async def reply(self, *args, **kwargs):
"""
Replies to the first photo in the album (as a reply). Shorthand
for `telethon.client.messages.MessageMethods.send_message`
with both ``entity`` and ``reply_to`` already set.
"""
return await self.messages[0].reply(*args, **kwargs)
# region Public Methods
async def forward_to(self, *args, **kwargs):
"""
Forwards the entire album. Shorthand for
`telethon.client.messages.MessageMethods.forward_messages`
with both ``messages`` and ``from_peer`` already set.
"""
if self._client:
kwargs['messages'] = self.messages
kwargs['from_peer'] = await self.get_input_chat()
return await self._client.forward_messages(*args, **kwargs)
async def get_reply_message(self):
"""
The `Message <telethon.tl._custom.message.Message>`
that this album is replying to, or `None`.
async def edit(self, *args, **kwargs):
"""
Edits the first caption or the message, or the first messages'
caption if no caption is set, iff it's outgoing. Shorthand for
`telethon.client.messages.MessageMethods.edit_message`
with both ``entity`` and ``message`` already set.
The result will be cached after its first use.
"""
return await self.messages[0].get_reply_message()
Returns `None` if the message was incoming,
or the edited `Message` otherwise.
async def respond(self, *args, **kwargs):
"""
Responds to the album (not as a reply). Shorthand for
`telethon.client.messages.MessageMethods.send_message`
with ``entity`` already set.
"""
return await self.messages[0].respond(*args, **kwargs)
.. note::
async def reply(self, *args, **kwargs):
"""
Replies to the first photo in the album (as a reply). Shorthand
for `telethon.client.messages.MessageMethods.send_message`
with both ``entity`` and ``reply_to`` already set.
"""
return await self.messages[0].reply(*args, **kwargs)
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.
async def forward_to(self, *args, **kwargs):
"""
Forwards the entire album. Shorthand for
`telethon.client.messages.MessageMethods.forward_messages`
with both ``messages`` and ``from_peer`` already set.
"""
if self._client:
kwargs['messages'] = self.messages
kwargs['from_peer'] = await self.get_input_chat()
return await self._client.forward_messages(*args, **kwargs)
This is generally the most desired and convenient behaviour,
and will work for link previews and message buttons.
"""
for msg in self.messages:
if msg.raw_text:
return await msg.edit(*args, **kwargs)
async def edit(self, *args, **kwargs):
"""
Edits the first caption or the message, or the first messages'
caption if no caption is set, iff it's outgoing. Shorthand for
`telethon.client.messages.MessageMethods.edit_message`
with both ``entity`` and ``message`` already set.
return await self.messages[0].edit(*args, **kwargs)
Returns `None` if the message was incoming,
or the edited `Message` otherwise.
async def delete(self, *args, **kwargs):
"""
Deletes the entire album. 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 self._client:
return await self._client.delete_messages(
await self.get_input_chat(), self.messages,
*args, **kwargs
)
.. note::
async def mark_read(self):
"""
Marks the entire album as read. Shorthand for
`client.mark_read()
<telethon.client.messages.MessageMethods.mark_read>`
with both ``entity`` and ``message`` already set.
"""
if self._client:
await self._client.mark_read(
await self.get_input_chat(), max_id=self.messages[-1].id)
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.
async def pin(self, *, notify=False):
"""
Pins the first photo in the album. Shorthand for
`telethon.client.messages.MessageMethods.pin_message`
with both ``entity`` and ``message`` already set.
"""
return await self.messages[0].pin(notify=notify)
This is generally the most desired and convenient behaviour,
and will work for link previews and message buttons.
"""
for msg in self.messages:
if msg.raw_text:
return await msg.edit(*args, **kwargs)
def __len__(self):
"""
Return the amount of messages in the album.
return await self.messages[0].edit(*args, **kwargs)
Equivalent to ``len(self.messages)``.
"""
return len(self.messages)
async def delete(self, *args, **kwargs):
"""
Deletes the entire album. 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 self._client:
return await self._client.delete_messages(
await self.get_input_chat(), self.messages,
*args, **kwargs
)
def __iter__(self):
"""
Iterate over the messages in the album.
async def mark_read(self):
"""
Marks the entire album as read. Shorthand for
`client.mark_read()
<telethon.client.messages.MessageMethods.mark_read>`
with both ``entity`` and ``message`` already set.
"""
if self._client:
await self._client.mark_read(
await self.get_input_chat(), max_id=self.messages[-1].id)
Equivalent to ``iter(self.messages)``.
"""
return iter(self.messages)
async def pin(self, *, notify=False):
"""
Pins the first photo in the album. Shorthand for
`telethon.client.messages.MessageMethods.pin_message`
with both ``entity`` and ``message`` already set.
"""
return await self.messages[0].pin(notify=notify)
def __getitem__(self, n):
"""
Access the n'th message in the album.
def __len__(self):
"""
Return the amount of messages in the album.
Equivalent to ``len(self.messages)``.
"""
return len(self.messages)
def __iter__(self):
"""
Iterate over the messages in the album.
Equivalent to ``iter(self.messages)``.
"""
return iter(self.messages)
def __getitem__(self, n):
"""
Access the n'th message in the album.
Equivalent to ``event.messages[n]``.
"""
return self.messages[n]
Equivalent to ``event.messages[n]``.
"""
return self.messages[n]