mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2024-12-01 22:03:46 +03:00
Continue work on Message sending overhaul
This commit is contained in:
parent
3853f98e5f
commit
72fc8f6808
|
@ -650,3 +650,18 @@ CdnDecrypter has been removed
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
It was not really working and was more intended to be an implementation detail than anything else.
|
It was not really working and was more intended to be an implementation detail than anything else.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
you can no longer pass an attributes list because the constructor is now nice.
|
||||||
|
use raw api if you really need it.
|
||||||
|
goal is to hide raw api from high level api. sorry.
|
||||||
|
|
||||||
|
no parsemode. use the correct parameter. it's more convenient than setting two.
|
||||||
|
|
||||||
|
formatting_entities stays because otherwise it's the only feasible way to manually specify it.
|
||||||
|
|
||||||
|
todo update send_message and send_file docs (well review all functions)
|
||||||
|
|
||||||
|
album overhaul. use a list of Message instead.
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import inspect
|
import inspect
|
||||||
import itertools
|
import itertools
|
||||||
|
import time
|
||||||
import typing
|
import typing
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from .._misc import helpers, utils, requestiter, hints
|
from .._misc import helpers, utils, requestiter, hints
|
||||||
from ..types import _custom
|
from ..types import _custom
|
||||||
|
from ..types._custom.inputmessage import InputMessage
|
||||||
from .. import errors, _tl
|
from .. import errors, _tl
|
||||||
|
|
||||||
_MAX_CHUNK_SIZE = 100
|
_MAX_CHUNK_SIZE = 100
|
||||||
|
@ -395,82 +397,95 @@ async def send_message(
|
||||||
entity: 'hints.EntityLike',
|
entity: 'hints.EntityLike',
|
||||||
message: 'hints.MessageLike' = '',
|
message: 'hints.MessageLike' = '',
|
||||||
*,
|
*,
|
||||||
reply_to: 'typing.Union[int, _tl.Message]' = None,
|
# - Message contents
|
||||||
attributes: 'typing.Sequence[_tl.TypeDocumentAttribute]' = None,
|
# Formatting
|
||||||
parse_mode: typing.Optional[str] = (),
|
markdown: str = None,
|
||||||
formatting_entities: typing.Optional[typing.List[_tl.TypeMessageEntity]] = None,
|
html: str = None,
|
||||||
link_preview: bool = True,
|
formatting_entities: list = None,
|
||||||
file: 'typing.Union[hints.FileLike, typing.Sequence[hints.FileLike]]' = None,
|
link_preview: bool = (),
|
||||||
thumb: 'hints.FileLike' = None,
|
# Media
|
||||||
force_document: bool = False,
|
file: typing.Optional[hints.FileLike] = None,
|
||||||
clear_draft: bool = False,
|
file_name: str = None,
|
||||||
buttons: 'hints.MarkupLike' = None,
|
mime_type: str = None,
|
||||||
silent: bool = None,
|
thumb: str = False,
|
||||||
background: bool = None,
|
force_file: bool = False,
|
||||||
|
file_size: int = None,
|
||||||
|
# Media attributes
|
||||||
|
duration: int = None,
|
||||||
|
width: int = None,
|
||||||
|
height: int = None,
|
||||||
|
title: str = None,
|
||||||
|
performer: str = None,
|
||||||
supports_streaming: bool = False,
|
supports_streaming: bool = False,
|
||||||
|
video_note: bool = False,
|
||||||
|
voice_note: bool = False,
|
||||||
|
waveform: bytes = None,
|
||||||
|
# Additional parametrization
|
||||||
|
silent: bool = False,
|
||||||
|
buttons: list = None,
|
||||||
|
ttl: int = None,
|
||||||
|
# - Send options
|
||||||
|
reply_to: 'typing.Union[int, _tl.Message]' = None,
|
||||||
|
clear_draft: bool = False,
|
||||||
|
background: bool = None,
|
||||||
schedule: 'hints.DateLike' = None,
|
schedule: 'hints.DateLike' = None,
|
||||||
comment_to: 'typing.Union[int, _tl.Message]' = None
|
comment_to: 'typing.Union[int, _tl.Message]' = None,
|
||||||
) -> '_tl.Message':
|
) -> '_tl.Message':
|
||||||
if file is not None:
|
if isinstance(message, str):
|
||||||
return await self.send_file(
|
message = InputMessage(
|
||||||
entity, file, caption=message, reply_to=reply_to,
|
text=message,
|
||||||
attributes=attributes, parse_mode=parse_mode,
|
markdown=markdown,
|
||||||
force_document=force_document, thumb=thumb,
|
html=html,
|
||||||
buttons=buttons, clear_draft=clear_draft, silent=silent,
|
|
||||||
schedule=schedule, supports_streaming=supports_streaming,
|
|
||||||
formatting_entities=formatting_entities,
|
formatting_entities=formatting_entities,
|
||||||
comment_to=comment_to, background=background
|
link_preview=link_preview,
|
||||||
|
file=file,
|
||||||
|
file_name=file_name,
|
||||||
|
mime_type=mime_type,
|
||||||
|
thumb=thumb,
|
||||||
|
force_file=force_file,
|
||||||
|
file_size=file_size,
|
||||||
|
duration=duration,
|
||||||
|
width=width,
|
||||||
|
height=height,
|
||||||
|
title=title,
|
||||||
|
performer=performer,
|
||||||
|
supports_streaming=supports_streaming,
|
||||||
|
video_note=video_note,
|
||||||
|
voice_note=voice_note,
|
||||||
|
waveform=waveform,
|
||||||
|
silent=silent,
|
||||||
|
buttons=buttons,
|
||||||
|
ttl=ttl,
|
||||||
)
|
)
|
||||||
|
elif isinstance(message, _custom.Message):
|
||||||
|
message = message._as_input()
|
||||||
|
elif not isinstance(message, InputMessage):
|
||||||
|
raise TypeError(f'message must be either str, Message or InputMessage, but got: {message!r}')
|
||||||
|
|
||||||
entity = await self.get_input_entity(entity)
|
entity = await self.get_input_entity(entity)
|
||||||
if comment_to is not None:
|
if comment_to is not None:
|
||||||
entity, reply_to = await _get_comment_data(self, entity, comment_to)
|
entity, reply_to = await _get_comment_data(self, entity, comment_to)
|
||||||
|
elif reply_to:
|
||||||
|
reply_to = utils.get_message_id(reply_to)
|
||||||
|
|
||||||
if isinstance(message, _tl.Message):
|
if message._file:
|
||||||
if buttons is None:
|
# TODO Properly implement allow_cache to reuse the sha256 of the file
|
||||||
markup = message.reply_markup
|
# i.e. `None` was used
|
||||||
|
|
||||||
|
# TODO album
|
||||||
|
if message._file._should_upload_thumb():
|
||||||
|
message._file._set_uploaded_thumb(await self.upload_file(message._file._thumb))
|
||||||
|
|
||||||
|
if message._file._should_upload_file():
|
||||||
|
message._file._set_uploaded_file(await self.upload_file(message._file._file))
|
||||||
|
|
||||||
|
request = _tl.fn.messages.SendMedia(
|
||||||
|
entity, message._file._media, reply_to_msg_id=reply_to, message=message._text,
|
||||||
|
entities=message._fmt_entities, reply_markup=message._reply_markup, silent=message._silent,
|
||||||
|
schedule_date=schedule, clear_draft=clear_draft,
|
||||||
|
background=background
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
markup = _custom.button.build_reply_markup(buttons)
|
|
||||||
|
|
||||||
if silent is None:
|
|
||||||
silent = message.silent
|
|
||||||
|
|
||||||
if (message.media and not isinstance(
|
|
||||||
message.media, _tl.MessageMediaWebPage)):
|
|
||||||
return await self.send_file(
|
|
||||||
entity,
|
|
||||||
message.media,
|
|
||||||
caption=message.message,
|
|
||||||
silent=silent,
|
|
||||||
background=background,
|
|
||||||
reply_to=reply_to,
|
|
||||||
buttons=markup,
|
|
||||||
formatting_entities=message.entities,
|
|
||||||
schedule=schedule
|
|
||||||
)
|
|
||||||
|
|
||||||
request = _tl.fn.messages.SendMessage(
|
|
||||||
peer=entity,
|
|
||||||
message=message.message or '',
|
|
||||||
silent=silent,
|
|
||||||
background=background,
|
|
||||||
reply_to_msg_id=utils.get_message_id(reply_to),
|
|
||||||
reply_markup=markup,
|
|
||||||
entities=message.entities,
|
|
||||||
clear_draft=clear_draft,
|
|
||||||
no_webpage=not isinstance(
|
|
||||||
message.media, _tl.MessageMediaWebPage),
|
|
||||||
schedule_date=schedule
|
|
||||||
)
|
|
||||||
message = message.message
|
|
||||||
else:
|
|
||||||
if formatting_entities is None:
|
|
||||||
message, formatting_entities = await self._parse_message_text(message, parse_mode)
|
|
||||||
if not message:
|
|
||||||
raise ValueError(
|
|
||||||
'The message cannot be empty unless a file is provided'
|
|
||||||
)
|
|
||||||
|
|
||||||
request = _tl.fn.messages.SendMessage(
|
request = _tl.fn.messages.SendMessage(
|
||||||
peer=entity,
|
peer=entity,
|
||||||
message=message,
|
message=message,
|
||||||
|
@ -489,7 +504,7 @@ async def send_message(
|
||||||
return _custom.Message._new(self, _tl.Message(
|
return _custom.Message._new(self, _tl.Message(
|
||||||
id=result.id,
|
id=result.id,
|
||||||
peer_id=await _get_peer(self, entity),
|
peer_id=await _get_peer(self, entity),
|
||||||
message=message,
|
message=message._text,
|
||||||
date=result.date,
|
date=result.date,
|
||||||
out=result.out,
|
out=result.out,
|
||||||
media=result.media,
|
media=result.media,
|
||||||
|
|
|
@ -2075,31 +2075,46 @@ class TelegramClient:
|
||||||
entity: 'hints.EntityLike',
|
entity: 'hints.EntityLike',
|
||||||
message: 'hints.MessageLike' = '',
|
message: 'hints.MessageLike' = '',
|
||||||
*,
|
*,
|
||||||
reply_to: 'typing.Union[int, _tl.Message]' = None,
|
# - Message contents
|
||||||
attributes: 'typing.Sequence[_tl.TypeDocumentAttribute]' = None,
|
# Formatting
|
||||||
parse_mode: typing.Optional[str] = (),
|
markdown: str = None,
|
||||||
formatting_entities: typing.Optional[typing.List[_tl.TypeMessageEntity]] = None,
|
html: str = None,
|
||||||
link_preview: bool = True,
|
formatting_entities: list = None,
|
||||||
file: 'typing.Union[hints.FileLike, typing.Sequence[hints.FileLike]]' = None,
|
link_preview: bool = (),
|
||||||
thumb: 'hints.FileLike' = None,
|
# Media
|
||||||
force_document: bool = False,
|
file: 'typing.Optional[hints.FileLike]' = None,
|
||||||
clear_draft: bool = False,
|
file_name: str = None,
|
||||||
buttons: 'hints.MarkupLike' = None,
|
mime_type: str = None,
|
||||||
silent: bool = None,
|
thumb: str = False,
|
||||||
background: bool = None,
|
force_file: bool = False,
|
||||||
|
file_size: int = None,
|
||||||
|
# Media attributes
|
||||||
|
duration: int = None,
|
||||||
|
width: int = None,
|
||||||
|
height: int = None,
|
||||||
|
title: str = None,
|
||||||
|
performer: str = None,
|
||||||
supports_streaming: bool = False,
|
supports_streaming: bool = False,
|
||||||
|
video_note: bool = False,
|
||||||
|
voice_note: bool = False,
|
||||||
|
waveform: bytes = None,
|
||||||
|
# Additional parametrization
|
||||||
|
silent: bool = False,
|
||||||
|
buttons: list = None,
|
||||||
|
ttl: int = None,
|
||||||
|
# - Send options
|
||||||
|
reply_to: 'typing.Union[int, _tl.Message]' = None,
|
||||||
|
clear_draft: bool = False,
|
||||||
|
background: bool = None,
|
||||||
schedule: 'hints.DateLike' = None,
|
schedule: 'hints.DateLike' = None,
|
||||||
comment_to: 'typing.Union[int, _tl.Message]' = None
|
comment_to: 'typing.Union[int, _tl.Message]' = None,
|
||||||
) -> '_tl.Message':
|
) -> '_tl.Message':
|
||||||
"""
|
"""
|
||||||
Sends a message to the specified user, chat or channel.
|
Sends a Message to the specified user, chat or channel.
|
||||||
|
|
||||||
The default parse mode is the same as the official applications
|
The message can be either a string or a previous Message instance.
|
||||||
(a _custom flavour of markdown). ``**bold**, `code` or __italic__``
|
If it's a previous Message instance, the rest of parameters will be ignored.
|
||||||
are available. In addition you can send ``[links](https://example.com)``
|
If it's not, a Message instance will be constructed, and send_to used.
|
||||||
and ``[mentions](@username)`` (or using IDs like in the Bot API:
|
|
||||||
``[mention](tg://user?id=123456789)``) and ``pre`` blocks with three
|
|
||||||
backticks.
|
|
||||||
|
|
||||||
Sending a ``/start`` command with a parameter (like ``?start=data``)
|
Sending a ``/start`` command with a parameter (like ``?start=data``)
|
||||||
is also done through this method. Simply send ``'/start data'`` to
|
is also done through this method. Simply send ``'/start data'`` to
|
||||||
|
@ -3517,15 +3532,6 @@ class TelegramClient:
|
||||||
async def _parse_message_text(self: 'TelegramClient', message, parse_mode):
|
async def _parse_message_text(self: 'TelegramClient', message, parse_mode):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@forward_call(uploads._file_to_media)
|
|
||||||
async def _file_to_media(
|
|
||||||
self, file, force_document=False, file_size=None,
|
|
||||||
progress_callback=None, attributes=None, thumb=None,
|
|
||||||
allow_cache=True, voice_note=False, video_note=False,
|
|
||||||
supports_streaming=False, mime_type=None, as_image=None,
|
|
||||||
ttl=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@forward_call(messageparse._get_response_message)
|
@forward_call(messageparse._get_response_message)
|
||||||
def _get_response_message(self: 'TelegramClient', request, result, input_chat):
|
def _get_response_message(self: 'TelegramClient', request, result, input_chat):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -92,105 +92,74 @@ def _resize_photo_if_needed(
|
||||||
async def send_file(
|
async def send_file(
|
||||||
self: 'TelegramClient',
|
self: 'TelegramClient',
|
||||||
entity: 'hints.EntityLike',
|
entity: 'hints.EntityLike',
|
||||||
file: 'typing.Union[hints.FileLike, typing.Sequence[hints.FileLike]]',
|
file: typing.Optional[hints.FileLike] = None,
|
||||||
*,
|
*,
|
||||||
caption: typing.Union[str, typing.Sequence[str]] = None,
|
# - Message contents
|
||||||
force_document: bool = False,
|
# Formatting
|
||||||
|
caption: 'hints.MessageLike' = '',
|
||||||
|
markdown: str = None,
|
||||||
|
html: str = None,
|
||||||
|
formatting_entities: list = None,
|
||||||
|
link_preview: bool = (),
|
||||||
|
# Media
|
||||||
|
file_name: str = None,
|
||||||
|
mime_type: str = None,
|
||||||
|
thumb: str = False,
|
||||||
|
force_file: bool = False,
|
||||||
file_size: int = None,
|
file_size: int = None,
|
||||||
clear_draft: bool = False,
|
# Media attributes
|
||||||
progress_callback: 'hints.ProgressCallback' = None,
|
duration: int = None,
|
||||||
reply_to: 'hints.MessageIDLike' = None,
|
width: int = None,
|
||||||
attributes: 'typing.Sequence[_tl.TypeDocumentAttribute]' = None,
|
height: int = None,
|
||||||
thumb: 'hints.FileLike' = None,
|
title: str = None,
|
||||||
allow_cache: bool = True,
|
performer: str = None,
|
||||||
parse_mode: str = (),
|
|
||||||
formatting_entities: typing.Optional[typing.List[_tl.TypeMessageEntity]] = None,
|
|
||||||
voice_note: bool = False,
|
|
||||||
video_note: bool = False,
|
|
||||||
buttons: 'hints.MarkupLike' = None,
|
|
||||||
silent: bool = None,
|
|
||||||
background: bool = None,
|
|
||||||
supports_streaming: bool = False,
|
supports_streaming: bool = False,
|
||||||
|
video_note: bool = False,
|
||||||
|
voice_note: bool = False,
|
||||||
|
waveform: bytes = None,
|
||||||
|
# Additional parametrization
|
||||||
|
silent: bool = False,
|
||||||
|
buttons: list = None,
|
||||||
|
ttl: int = None,
|
||||||
|
# - Send options
|
||||||
|
reply_to: 'typing.Union[int, _tl.Message]' = None,
|
||||||
|
clear_draft: bool = False,
|
||||||
|
background: bool = None,
|
||||||
schedule: 'hints.DateLike' = None,
|
schedule: 'hints.DateLike' = None,
|
||||||
comment_to: 'typing.Union[int, _tl.Message]' = None,
|
comment_to: 'typing.Union[int, _tl.Message]' = None,
|
||||||
ttl: int = None,
|
) -> '_tl.Message':
|
||||||
**kwargs) -> '_tl.Message':
|
self.send_message(
|
||||||
# TODO Properly implement allow_cache to reuse the sha256 of the file
|
entity=entity,
|
||||||
# i.e. `None` was used
|
message=caption,
|
||||||
if not file:
|
markdown=markdown,
|
||||||
raise TypeError('Cannot use {!r} as file'.format(file))
|
html=html,
|
||||||
|
formatting_entities=formatting_entities,
|
||||||
if not caption:
|
link_preview=link_preview,
|
||||||
caption = ''
|
file=file,
|
||||||
|
file_name=file_name,
|
||||||
entity = await self.get_input_entity(entity)
|
mime_type=mime_type,
|
||||||
if comment_to is not None:
|
thumb=thumb,
|
||||||
entity, reply_to = await _get_comment_data(self, entity, comment_to)
|
force_file=force_file,
|
||||||
else:
|
|
||||||
reply_to = utils.get_message_id(reply_to)
|
|
||||||
|
|
||||||
# First check if the user passed an iterable, in which case
|
|
||||||
# we may want to send grouped.
|
|
||||||
if utils.is_list_like(file):
|
|
||||||
if utils.is_list_like(caption):
|
|
||||||
captions = caption
|
|
||||||
else:
|
|
||||||
captions = [caption]
|
|
||||||
|
|
||||||
result = []
|
|
||||||
while file:
|
|
||||||
result += await _send_album(
|
|
||||||
self, entity, file[:10], caption=captions[:10],
|
|
||||||
progress_callback=progress_callback, reply_to=reply_to,
|
|
||||||
parse_mode=parse_mode, silent=silent, schedule=schedule,
|
|
||||||
supports_streaming=supports_streaming, clear_draft=clear_draft,
|
|
||||||
force_document=force_document, background=background,
|
|
||||||
)
|
|
||||||
file = file[10:]
|
|
||||||
captions = captions[10:]
|
|
||||||
|
|
||||||
for doc, cap in zip(file, captions):
|
|
||||||
result.append(await self.send_file(
|
|
||||||
entity, doc, allow_cache=allow_cache,
|
|
||||||
caption=cap, force_document=force_document,
|
|
||||||
progress_callback=progress_callback, reply_to=reply_to,
|
|
||||||
attributes=attributes, thumb=thumb, voice_note=voice_note,
|
|
||||||
video_note=video_note, buttons=buttons, silent=silent,
|
|
||||||
supports_streaming=supports_streaming, schedule=schedule,
|
|
||||||
clear_draft=clear_draft, background=background,
|
|
||||||
**kwargs
|
|
||||||
))
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
if formatting_entities is not None:
|
|
||||||
msg_entities = formatting_entities
|
|
||||||
else:
|
|
||||||
caption, msg_entities =\
|
|
||||||
await self._parse_message_text(caption, parse_mode)
|
|
||||||
|
|
||||||
file_handle, media, image = await _file_to_media(
|
|
||||||
self, file, force_document=force_document,
|
|
||||||
file_size=file_size,
|
file_size=file_size,
|
||||||
progress_callback=progress_callback,
|
duration=duration,
|
||||||
attributes=attributes, allow_cache=allow_cache, thumb=thumb,
|
width=width,
|
||||||
voice_note=voice_note, video_note=video_note,
|
height=height,
|
||||||
supports_streaming=supports_streaming, ttl=ttl
|
title=title,
|
||||||
|
performer=performer,
|
||||||
|
supports_streaming=supports_streaming,
|
||||||
|
video_note=video_note,
|
||||||
|
voice_note=voice_note,
|
||||||
|
waveform=waveform,
|
||||||
|
silent=silent,
|
||||||
|
buttons=buttons,
|
||||||
|
ttl=ttl,
|
||||||
|
reply_to=reply_to,
|
||||||
|
clear_draft=clear_draft,
|
||||||
|
background=background,
|
||||||
|
schedule=schedule,
|
||||||
|
comment_to=comment_to,
|
||||||
)
|
)
|
||||||
|
|
||||||
# e.g. invalid cast from :tl:`MessageMediaWebPage`
|
|
||||||
if not media:
|
|
||||||
raise TypeError('Cannot use {!r} as file'.format(file))
|
|
||||||
|
|
||||||
markup = _custom.button.build_reply_markup(buttons)
|
|
||||||
request = _tl.fn.messages.SendMedia(
|
|
||||||
entity, media, reply_to_msg_id=reply_to, message=caption,
|
|
||||||
entities=msg_entities, reply_markup=markup, silent=silent,
|
|
||||||
schedule_date=schedule, clear_draft=clear_draft,
|
|
||||||
background=background
|
|
||||||
)
|
|
||||||
return self._get_response_message(request, await self(request), entity)
|
|
||||||
|
|
||||||
async def _send_album(self: 'TelegramClient', entity, files, caption='',
|
async def _send_album(self: 'TelegramClient', entity, files, caption='',
|
||||||
progress_callback=None, reply_to=None,
|
progress_callback=None, reply_to=None,
|
||||||
parse_mode=(), silent=None, schedule=None,
|
parse_mode=(), silent=None, schedule=None,
|
||||||
|
@ -368,98 +337,3 @@ async def upload_file(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def _file_to_media(
|
|
||||||
self, file, force_document=False, file_size=None,
|
|
||||||
progress_callback=None, attributes=None, thumb=None,
|
|
||||||
allow_cache=True, voice_note=False, video_note=False,
|
|
||||||
supports_streaming=False, mime_type=None, as_image=None,
|
|
||||||
ttl=None):
|
|
||||||
if not file:
|
|
||||||
return None, None, None
|
|
||||||
|
|
||||||
if isinstance(file, pathlib.Path):
|
|
||||||
file = str(file.absolute())
|
|
||||||
|
|
||||||
is_image = utils.is_image(file)
|
|
||||||
if as_image is None:
|
|
||||||
as_image = is_image and not force_document
|
|
||||||
|
|
||||||
# `aiofiles` do not base `io.IOBase` but do have `read`, so we
|
|
||||||
# just check for the read attribute to see if it's file-like.
|
|
||||||
if not isinstance(file, (str, bytes, _tl.InputFile, _tl.InputFileBig))\
|
|
||||||
and not hasattr(file, 'read'):
|
|
||||||
# The user may pass a Message containing media (or the media,
|
|
||||||
# or anything similar) that should be treated as a file. Try
|
|
||||||
# getting the input media for whatever they passed and send it.
|
|
||||||
#
|
|
||||||
# We pass all attributes since these will be used if the user
|
|
||||||
# passed :tl:`InputFile`, and all information may be relevant.
|
|
||||||
try:
|
|
||||||
return (None, utils.get_input_media(
|
|
||||||
file,
|
|
||||||
is_photo=as_image,
|
|
||||||
attributes=attributes,
|
|
||||||
force_document=force_document,
|
|
||||||
voice_note=voice_note,
|
|
||||||
video_note=video_note,
|
|
||||||
supports_streaming=supports_streaming,
|
|
||||||
ttl=ttl
|
|
||||||
), as_image)
|
|
||||||
except TypeError:
|
|
||||||
# Can't turn whatever was given into media
|
|
||||||
return None, None, as_image
|
|
||||||
|
|
||||||
media = None
|
|
||||||
file_handle = None
|
|
||||||
|
|
||||||
if isinstance(file, (_tl.InputFile, _tl.InputFileBig)):
|
|
||||||
file_handle = file
|
|
||||||
elif not isinstance(file, str) or os.path.isfile(file):
|
|
||||||
file_handle = await self.upload_file(
|
|
||||||
_resize_photo_if_needed(file, as_image),
|
|
||||||
file_size=file_size,
|
|
||||||
progress_callback=progress_callback
|
|
||||||
)
|
|
||||||
elif re.match('https?://', file):
|
|
||||||
if as_image:
|
|
||||||
media = _tl.InputMediaPhotoExternal(file, ttl_seconds=ttl)
|
|
||||||
else:
|
|
||||||
media = _tl.InputMediaDocumentExternal(file, ttl_seconds=ttl)
|
|
||||||
|
|
||||||
if media:
|
|
||||||
pass # Already have media, don't check the rest
|
|
||||||
elif not file_handle:
|
|
||||||
raise ValueError(
|
|
||||||
'Failed to convert {} to media. Not an existing file or '
|
|
||||||
'HTTP URL'.format(file)
|
|
||||||
)
|
|
||||||
elif as_image:
|
|
||||||
media = _tl.InputMediaUploadedPhoto(file_handle, ttl_seconds=ttl)
|
|
||||||
else:
|
|
||||||
attributes, mime_type = utils.get_attributes(
|
|
||||||
file,
|
|
||||||
mime_type=mime_type,
|
|
||||||
attributes=attributes,
|
|
||||||
force_document=force_document and not is_image,
|
|
||||||
voice_note=voice_note,
|
|
||||||
video_note=video_note,
|
|
||||||
supports_streaming=supports_streaming,
|
|
||||||
thumb=thumb
|
|
||||||
)
|
|
||||||
|
|
||||||
if not thumb:
|
|
||||||
thumb = None
|
|
||||||
else:
|
|
||||||
if isinstance(thumb, pathlib.Path):
|
|
||||||
thumb = str(thumb.absolute())
|
|
||||||
thumb = await self.upload_file(thumb, file_size=file_size)
|
|
||||||
|
|
||||||
media = _tl.InputMediaUploadedDocument(
|
|
||||||
file=file_handle,
|
|
||||||
mime_type=mime_type,
|
|
||||||
attributes=attributes,
|
|
||||||
thumb=thumb,
|
|
||||||
force_file=force_document and not is_image,
|
|
||||||
ttl_seconds=ttl
|
|
||||||
)
|
|
||||||
return file_handle, media, as_image
|
|
||||||
|
|
|
@ -1,11 +1,36 @@
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from ... import _tl
|
from ... import _tl
|
||||||
|
from ..._misc import utils
|
||||||
|
|
||||||
|
|
||||||
class InputFile:
|
class InputFile:
|
||||||
|
# Expected Time-To-Live for _uploaded_*.
|
||||||
|
# After this period they should be reuploaded.
|
||||||
|
# Telegram's limit are unknown, so this value is conservative.
|
||||||
|
UPLOAD_TTL = 8 * 60 * 60
|
||||||
|
|
||||||
|
__slots__ = (
|
||||||
|
# main media
|
||||||
|
'_file', # can reupload
|
||||||
|
'_media', # can only use as-is
|
||||||
|
'_uploaded_file', # (input file, timestamp)
|
||||||
|
# thumbnail
|
||||||
|
'_thumb', # can reupload
|
||||||
|
'_uploaded_thumb', # (input file, timestamp)
|
||||||
|
# document parameters
|
||||||
|
'_mime_type',
|
||||||
|
'_attributes',
|
||||||
|
'_video_note',
|
||||||
|
'_force_file',
|
||||||
|
'_ttl',
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
file = None,
|
file = None,
|
||||||
|
@ -26,7 +51,57 @@ class InputFile:
|
||||||
waveform: bytes = None,
|
waveform: bytes = None,
|
||||||
ttl: int = None,
|
ttl: int = None,
|
||||||
):
|
):
|
||||||
if isinstance(file, pathlib.Path):
|
# main media
|
||||||
|
self._file = None
|
||||||
|
self._media = None
|
||||||
|
self._uploaded_file = None
|
||||||
|
|
||||||
|
if isinstance(file, str) and re.match('https?://', file, flags=re.IGNORECASE):
|
||||||
|
if not force_file and mime_type.startswith('image'):
|
||||||
|
self._media = _tl.InputMediaPhotoExternal(file, ttl_seconds=ttl)
|
||||||
|
else:
|
||||||
|
self._media = _tl.InputMediaDocumentExternal(file, ttl_seconds=ttl)
|
||||||
|
|
||||||
|
elif isinstance(file, (str, bytes, Path)) or callable(getattr(file, 'read', None)):
|
||||||
|
self._file = file
|
||||||
|
|
||||||
|
elif isinstance(file, (_tl.InputFile, _tl.InputFileBig)):
|
||||||
|
self._uploaded_file = (file, time.time())
|
||||||
|
|
||||||
|
else:
|
||||||
|
self._media = utils.get_input_media(
|
||||||
|
file,
|
||||||
|
is_photo=not force_file and mime_type.startswith('image'),
|
||||||
|
attributes=[],
|
||||||
|
force_document=force_file,
|
||||||
|
voice_note=voice_note,
|
||||||
|
video_note=video_note,
|
||||||
|
supports_streaming=supports_streaming,
|
||||||
|
ttl=ttl
|
||||||
|
)
|
||||||
|
|
||||||
|
# thumbnail
|
||||||
|
self._thumb = None
|
||||||
|
self._uploaded_thumb = None
|
||||||
|
|
||||||
|
if isinstance(thumb, (str, bytes, Path)) or callable(getattr(thumb, 'read', None)):
|
||||||
|
self._thumb = thumb
|
||||||
|
|
||||||
|
elif isinstance(thumb, (_tl.InputFile, _tl.InputFileBig)):
|
||||||
|
self._uploaded_thumb = (thumb, time.time())
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise TypeError(f'thumb must be a file to upload, but got: {thumb!r}')
|
||||||
|
|
||||||
|
# document parameters (only if it's our file, i.e. there's no media ready yet)
|
||||||
|
if self._media:
|
||||||
|
self._mime_type = None
|
||||||
|
self._attributes = None
|
||||||
|
self._video_note = None
|
||||||
|
self._force_file = None
|
||||||
|
self._ttl = None
|
||||||
|
else:
|
||||||
|
if isinstance(file, Path):
|
||||||
if not file_name:
|
if not file_name:
|
||||||
file_name = file.name
|
file_name = file.name
|
||||||
file = str(file.absolute())
|
file = str(file.absolute())
|
||||||
|
@ -67,104 +142,34 @@ class InputFile:
|
||||||
supports_streaming=supports_streaming,
|
supports_streaming=supports_streaming,
|
||||||
))
|
))
|
||||||
|
|
||||||
# mime_type: str = None,
|
self._mime_type = mime_type
|
||||||
# thumb: str = False,
|
|
||||||
# force_file: bool = False,
|
|
||||||
# file_size: int = None,
|
|
||||||
# ttl: int = None,
|
|
||||||
|
|
||||||
self._file = file
|
|
||||||
self._attributes = attributes
|
self._attributes = attributes
|
||||||
|
self._video_note = video_note
|
||||||
|
self._force_file = force_file
|
||||||
|
self._ttl = ttl
|
||||||
|
|
||||||
|
def _should_upload_thumb(self):
|
||||||
|
return self._thumb and (
|
||||||
|
not self._uploaded_thumb
|
||||||
|
or time.time() > self._uploaded_thumb[1] + InputFile.UPLOAD_TTL)
|
||||||
|
|
||||||
# TODO rest
|
def _should_upload_file(self):
|
||||||
|
return self._file and (
|
||||||
|
not self._uploaded_file
|
||||||
|
or time.time() > self._uploaded_file[1] + InputFile.UPLOAD_TTL)
|
||||||
|
|
||||||
is_image = utils.is_image(file)
|
def _set_uploaded_thumb(self, input_file):
|
||||||
if as_image is None:
|
self._uploaded_thumb = (input_file, time.time())
|
||||||
as_image = is_image and not force_document
|
|
||||||
|
|
||||||
# `aiofiles` do not base `io.IOBase` but do have `read`, so we
|
def _set_uploaded_file(self, input_file):
|
||||||
# just check for the read attribute to see if it's file-like.
|
if not self._force_file and self._mime_type.startswith('image'):
|
||||||
if not isinstance(file, (str, bytes, _tl.InputFile, _tl.InputFileBig))\
|
self._media = _tl.InputMediaUploadedPhoto(input_file, ttl_seconds=self._ttl)
|
||||||
and not hasattr(file, 'read'):
|
|
||||||
# The user may pass a Message containing media (or the media,
|
|
||||||
# or anything similar) that should be treated as a file. Try
|
|
||||||
# getting the input media for whatever they passed and send it.
|
|
||||||
#
|
|
||||||
# We pass all attributes since these will be used if the user
|
|
||||||
# passed :tl:`InputFile`, and all information may be relevant.
|
|
||||||
try:
|
|
||||||
return (None, utils.get_input_media(
|
|
||||||
file,
|
|
||||||
is_photo=as_image,
|
|
||||||
attributes=attributes,
|
|
||||||
force_document=force_document,
|
|
||||||
voice_note=voice_note,
|
|
||||||
video_note=video_note,
|
|
||||||
supports_streaming=supports_streaming,
|
|
||||||
ttl=ttl
|
|
||||||
), as_image)
|
|
||||||
except TypeError:
|
|
||||||
# Can't turn whatever was given into media
|
|
||||||
return None, None, as_image
|
|
||||||
|
|
||||||
media = None
|
|
||||||
file_handle = None
|
|
||||||
|
|
||||||
if isinstance(file, (_tl.InputFile, _tl.InputFileBig)):
|
|
||||||
file_handle = file
|
|
||||||
elif not isinstance(file, str) or os.path.isfile(file):
|
|
||||||
file_handle = await self.upload_file(
|
|
||||||
_resize_photo_if_needed(file, as_image),
|
|
||||||
file_size=file_size,
|
|
||||||
progress_callback=progress_callback
|
|
||||||
)
|
|
||||||
elif re.match('https?://', file):
|
|
||||||
if as_image:
|
|
||||||
media = _tl.InputMediaPhotoExternal(file, ttl_seconds=ttl)
|
|
||||||
else:
|
else:
|
||||||
media = _tl.InputMediaDocumentExternal(file, ttl_seconds=ttl)
|
self._media = _tl.InputMediaUploadedDocument(
|
||||||
|
file=input_file,
|
||||||
if media:
|
mime_type=self._mime_type,
|
||||||
pass # Already have media, don't check the rest
|
attributes=self._attributes,
|
||||||
elif not file_handle:
|
thumb=self._uploaded_thumb[0] if self._uploaded_thumb else None,
|
||||||
raise ValueError(
|
force_file=self._force_file,
|
||||||
'Failed to convert {} to media. Not an existing file or '
|
ttl_seconds=self._ttl,
|
||||||
'HTTP URL'.format(file)
|
|
||||||
)
|
)
|
||||||
elif as_image:
|
|
||||||
media = _tl.InputMediaUploadedPhoto(file_handle, ttl_seconds=ttl)
|
|
||||||
else:
|
|
||||||
attributes, mime_type = utils.get_attributes(
|
|
||||||
file,
|
|
||||||
mime_type=mime_type,
|
|
||||||
attributes=attributes,
|
|
||||||
force_document=force_document and not is_image,
|
|
||||||
voice_note=voice_note,
|
|
||||||
video_note=video_note,
|
|
||||||
supports_streaming=supports_streaming,
|
|
||||||
thumb=thumb
|
|
||||||
)
|
|
||||||
|
|
||||||
if not thumb:
|
|
||||||
thumb = None
|
|
||||||
else:
|
|
||||||
if isinstance(thumb, pathlib.Path):
|
|
||||||
thumb = str(thumb.absolute())
|
|
||||||
thumb = await self.upload_file(thumb, file_size=file_size)
|
|
||||||
|
|
||||||
media = _tl.InputMediaUploadedDocument(
|
|
||||||
file=file_handle,
|
|
||||||
mime_type=mime_type,
|
|
||||||
attributes=attributes,
|
|
||||||
thumb=thumb,
|
|
||||||
force_file=force_document and not is_image,
|
|
||||||
ttl_seconds=ttl
|
|
||||||
)
|
|
||||||
return file_handle, media, as_image
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
from typing import Optional
|
||||||
|
from .inputfile import InputFile
|
||||||
|
from ... import _misc
|
||||||
|
from .button import build_reply_markup
|
||||||
|
|
||||||
|
|
||||||
class InputMessage:
|
class InputMessage:
|
||||||
__slots__ = (
|
__slots__ = (
|
||||||
|
@ -9,21 +14,83 @@ class InputMessage:
|
||||||
'_file',
|
'_file',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_default_parse_mode = (lambda t: (t, []), lambda t, e: t)
|
||||||
|
_default_link_preview = True
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
text,
|
text: str = None,
|
||||||
*,
|
*,
|
||||||
link_preview,
|
markdown: str = None,
|
||||||
silent,
|
html: str = None,
|
||||||
reply_markup,
|
formatting_entities: list = None,
|
||||||
fmt_entities,
|
link_preview: bool = (),
|
||||||
file,
|
file=None,
|
||||||
|
file_name: str = None,
|
||||||
|
mime_type: str = None,
|
||||||
|
thumb: str = False,
|
||||||
|
force_file: bool = False,
|
||||||
|
file_size: int = None,
|
||||||
|
duration: int = None,
|
||||||
|
width: int = None,
|
||||||
|
height: int = None,
|
||||||
|
title: str = None,
|
||||||
|
performer: str = None,
|
||||||
|
supports_streaming: bool = False,
|
||||||
|
video_note: bool = False,
|
||||||
|
voice_note: bool = False,
|
||||||
|
waveform: bytes = None,
|
||||||
|
silent: bool = False,
|
||||||
|
buttons: list = None,
|
||||||
|
ttl: int = None,
|
||||||
|
parse_fn = None,
|
||||||
):
|
):
|
||||||
|
if (text and markdown) or (text and html) or (markdown and html):
|
||||||
|
raise ValueError('can only set one of: text, markdown, html')
|
||||||
|
|
||||||
|
if formatting_entities:
|
||||||
|
text = text or markdown or html
|
||||||
|
elif text:
|
||||||
|
text, formatting_entities = self._default_parse_mode[0](text)
|
||||||
|
elif markdown:
|
||||||
|
text, formatting_entities = _misc.markdown.parse(markdown)
|
||||||
|
elif html:
|
||||||
|
text, formatting_entities = _misc.html.parse(html)
|
||||||
|
|
||||||
|
reply_markup = build_reply_markup(buttons) if buttons else None
|
||||||
|
|
||||||
|
if not text:
|
||||||
|
text = ''
|
||||||
|
if not formatting_entities:
|
||||||
|
formatting_entities = None
|
||||||
|
|
||||||
|
if link_preview == ():
|
||||||
|
link_preview = self._default_link_preview
|
||||||
|
|
||||||
|
if file and not isinstance(file, InputFile):
|
||||||
|
file = InputFile(
|
||||||
|
file=file,
|
||||||
|
file_name=file_name,
|
||||||
|
mime_type=mime_type,
|
||||||
|
thumb=thumb,
|
||||||
|
force_file=force_file,
|
||||||
|
file_size=file_size,
|
||||||
|
duration=duration,
|
||||||
|
width=width,
|
||||||
|
height=height,
|
||||||
|
title=title,
|
||||||
|
performer=performer,
|
||||||
|
supports_streaming=supports_streaming,
|
||||||
|
video_note=video_note,
|
||||||
|
voice_note=voice_note,
|
||||||
|
waveform=waveform,
|
||||||
|
)
|
||||||
|
|
||||||
self._text = text
|
self._text = text
|
||||||
self._link_preview = link_preview
|
self._link_preview = link_preview
|
||||||
self._silent = silent
|
self._silent = silent
|
||||||
self._reply_markup = reply_markup
|
self._reply_markup = reply_markup
|
||||||
self._fmt_entities = fmt_entities
|
self._fmt_entities = formatting_entities
|
||||||
self._file = file
|
self._file = file
|
||||||
|
|
||||||
# oh! when this message is used, the file can be cached in here! if not inputfile upload and set inputfile
|
# oh! when this message is used, the file can be cached in here! if not inputfile upload and set inputfile
|
||||||
|
|
|
@ -228,9 +228,6 @@ class Message(ChatGetter, SenderGetter):
|
||||||
|
|
||||||
# region Initialization
|
# region Initialization
|
||||||
|
|
||||||
_default_parse_mode = None
|
|
||||||
_default_link_preview = True
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
text: str = None,
|
text: str = None,
|
||||||
|
@ -241,7 +238,7 @@ class Message(ChatGetter, SenderGetter):
|
||||||
formatting_entities: list = None,
|
formatting_entities: list = None,
|
||||||
link_preview: bool = (),
|
link_preview: bool = (),
|
||||||
# Media
|
# Media
|
||||||
file: Optional[hints.FileLike] = None,
|
file: 'Optional[hints.FileLike]' = None,
|
||||||
file_name: str = None,
|
file_name: str = None,
|
||||||
mime_type: str = None,
|
mime_type: str = None,
|
||||||
thumb: str = False,
|
thumb: str = False,
|
||||||
|
@ -379,30 +376,12 @@ class Message(ChatGetter, SenderGetter):
|
||||||
Not all types of media can be used with this parameter, such as text documents, which
|
Not all types of media can be used with this parameter, such as text documents, which
|
||||||
will fail with ``TtlMediaInvalidError``.
|
will fail with ``TtlMediaInvalidError``.
|
||||||
"""
|
"""
|
||||||
if (text and markdown) or (text and html) or (markdown and html):
|
self._message = InputMessage(
|
||||||
raise ValueError('can only set one of: text, markdown, html')
|
text=text,
|
||||||
|
markdown=markdown,
|
||||||
if formatting_entities:
|
html=html,
|
||||||
text = text or markdown or html
|
formatting_entities=formatting_entities,
|
||||||
elif text:
|
link_preview=link_preview,
|
||||||
text, formatting_entities = self._default_parse_mode[0](text)
|
|
||||||
elif markdown:
|
|
||||||
text, formatting_entities = _misc.markdown.parse(markdown)
|
|
||||||
elif html:
|
|
||||||
text, formatting_entities = _misc.html.parse(html)
|
|
||||||
|
|
||||||
reply_markup = build_reply_markup(buttons) if buttons else None
|
|
||||||
|
|
||||||
if not text:
|
|
||||||
text = ''
|
|
||||||
if not formatting_entities:
|
|
||||||
formatting_entities = None
|
|
||||||
|
|
||||||
if link_preview == ():
|
|
||||||
link_preview = self._default_link_preview
|
|
||||||
|
|
||||||
if file:
|
|
||||||
file = InputFile(
|
|
||||||
file =file,
|
file =file,
|
||||||
file_name=file_name,
|
file_name=file_name,
|
||||||
mime_type=mime_type,
|
mime_type=mime_type,
|
||||||
|
@ -418,15 +397,9 @@ class Message(ChatGetter, SenderGetter):
|
||||||
video_note=video_note,
|
video_note=video_note,
|
||||||
voice_note=voice_note,
|
voice_note=voice_note,
|
||||||
waveform=waveform,
|
waveform=waveform,
|
||||||
)
|
|
||||||
|
|
||||||
self._message = InputMessage(
|
|
||||||
text=text,
|
|
||||||
link_preview=link_preview,
|
|
||||||
silent=silent,
|
silent=silent,
|
||||||
reply_markup=reply_markup,
|
buttons=buttons,
|
||||||
fmt_entities=formatting_entities,
|
ttl=ttl,
|
||||||
file=file,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -446,7 +419,7 @@ class Message(ChatGetter, SenderGetter):
|
||||||
sender_id = utils.get_peer_id(message.peer_id)
|
sender_id = utils.get_peer_id(message.peer_id)
|
||||||
|
|
||||||
# Note that these calls would reset the client
|
# Note that these calls would reset the client
|
||||||
ChatGetter.__init__(self, self.peer_id, broadcast=self.post)
|
ChatGetter.__init__(self, message.peer_id, broadcast=message.post)
|
||||||
SenderGetter.__init__(self, sender_id)
|
SenderGetter.__init__(self, sender_id)
|
||||||
self._client = client
|
self._client = client
|
||||||
self._message = message
|
self._message = message
|
||||||
|
@ -511,8 +484,8 @@ class Message(ChatGetter, SenderGetter):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@staticmethod
|
||||||
def set_default_parse_mode(cls, mode):
|
def set_default_parse_mode(mode):
|
||||||
"""
|
"""
|
||||||
Change the default parse mode when creating messages. The ``mode`` can be:
|
Change the default parse mode when creating messages. The ``mode`` can be:
|
||||||
|
|
||||||
|
@ -531,27 +504,29 @@ class Message(ChatGetter, SenderGetter):
|
||||||
if isinstance(mode, str):
|
if isinstance(mode, str):
|
||||||
mode = mode.lower()
|
mode = mode.lower()
|
||||||
if mode in ('md', 'markdown'):
|
if mode in ('md', 'markdown'):
|
||||||
cls._default_parse_mode = (_misc.markdown.parse, _misc.markdown.unparse)
|
mode = (_misc.markdown.parse, _misc.markdown.unparse)
|
||||||
elif mode in ('htm', 'html'):
|
elif mode in ('htm', 'html'):
|
||||||
cls._default_parse_mode = (_misc.html.parse, _misc.html.unparse)
|
mode = (_misc.html.parse, _misc.html.unparse)
|
||||||
else:
|
else:
|
||||||
raise ValueError(f'mode must be one of md, markdown, htm or html, but was {mode!r}')
|
raise ValueError(f'mode must be one of md, markdown, htm or html, but was {mode!r}')
|
||||||
elif callable(mode):
|
elif callable(mode):
|
||||||
cls._default_parse_mode = (mode, lambda t, e: t)
|
mode = (mode, lambda t, e: t)
|
||||||
elif isinstance(mode, tuple):
|
elif isinstance(mode, tuple):
|
||||||
if len(mode) == 2 and callable(mode[0]) and callable(mode[1]):
|
if len(mode) == 2 and callable(mode[0]) and callable(mode[1]):
|
||||||
cls._default_parse_mode = mode
|
mode = mode
|
||||||
else:
|
else:
|
||||||
raise ValueError(f'mode must be a tuple of exactly two callables')
|
raise ValueError(f'mode must be a tuple of exactly two callables')
|
||||||
else:
|
else:
|
||||||
raise TypeError(f'mode must be either a str, callable or tuple, but was {mode!r}')
|
raise TypeError(f'mode must be either a str, callable or tuple, but was {mode!r}')
|
||||||
|
|
||||||
|
InputMessage._default_parse_mode = mode
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_default_link_preview(cls, enabled):
|
def set_default_link_preview(cls, enabled):
|
||||||
"""
|
"""
|
||||||
Change the default value for link preview (either ``True`` or ``False``).
|
Change the default value for link preview (either ``True`` or ``False``).
|
||||||
"""
|
"""
|
||||||
cls._default_link_preview = enabled
|
InputMessage._default_link_preview = enabled
|
||||||
|
|
||||||
# endregion Initialization
|
# endregion Initialization
|
||||||
|
|
||||||
|
@ -1297,6 +1272,14 @@ class Message(ChatGetter, SenderGetter):
|
||||||
|
|
||||||
# region Private Methods
|
# region Private Methods
|
||||||
|
|
||||||
|
def _as_input(self):
|
||||||
|
if isinstance(self._message, InputMessage):
|
||||||
|
return self._message
|
||||||
|
|
||||||
|
return InputMessage(
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
async def _reload_message(self):
|
async def _reload_message(self):
|
||||||
"""
|
"""
|
||||||
Re-fetches this message to reload the sender and chat entities,
|
Re-fetches this message to reload the sender and chat entities,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user