Allow sending multiple files as album (closes #455)

This commit is contained in:
Lonami Exo 2018-01-15 18:15:30 +01:00
parent 494c90af69
commit 36e2101910
2 changed files with 87 additions and 22 deletions

View File

@ -33,7 +33,8 @@ from .tl.functions.contacts import (
from .tl.functions.messages import ( from .tl.functions.messages import (
GetDialogsRequest, GetHistoryRequest, SendMediaRequest, GetDialogsRequest, GetHistoryRequest, SendMediaRequest,
SendMessageRequest, GetChatsRequest, GetAllDraftsRequest, SendMessageRequest, GetChatsRequest, GetAllDraftsRequest,
CheckChatInviteRequest, ReadMentionsRequest CheckChatInviteRequest, ReadMentionsRequest,
SendMultiMediaRequest, UploadMediaRequest
) )
from .tl.functions import channels from .tl.functions import channels
@ -53,7 +54,8 @@ from .tl.types import (
InputUserSelf, UserProfilePhoto, ChatPhoto, UpdateMessageID, InputUserSelf, UserProfilePhoto, ChatPhoto, UpdateMessageID,
UpdateNewChannelMessage, UpdateNewMessage, UpdateShortSentMessage, UpdateNewChannelMessage, UpdateNewMessage, UpdateShortSentMessage,
PeerUser, InputPeerUser, InputPeerChat, InputPeerChannel, MessageEmpty, PeerUser, InputPeerUser, InputPeerChat, InputPeerChannel, MessageEmpty,
ChatInvite, ChatInviteAlready, PeerChannel, Photo, InputPeerSelf ChatInvite, ChatInviteAlready, PeerChannel, Photo, InputPeerSelf,
InputSingleMedia, InputMediaPhoto, InputPhoto
) )
from .tl.types.messages import DialogsSlice from .tl.types.messages import DialogsSlice
from .extensions import markdown from .extensions import markdown
@ -512,9 +514,15 @@ class TelegramClient(TelegramBareClient):
@staticmethod @staticmethod
def _get_response_message(request, result): def _get_response_message(request, result):
"""Extracts the response message known a request and Update result""" """
Extracts the response message known a request and Update result.
The request may also be the ID of the message to match.
"""
# Telegram seems to send updateMessageID first, then updateNewMessage, # Telegram seems to send updateMessageID first, then updateNewMessage,
# however let's not rely on that just in case. # however let's not rely on that just in case.
if isinstance(request, int):
msg_id = request
else:
msg_id = None msg_id = None
for update in result.updates: for update in result.updates:
if isinstance(update, UpdateMessageID): if isinstance(update, UpdateMessageID):
@ -862,20 +870,33 @@ class TelegramClient(TelegramBareClient):
sent as a document, it will be sent as a voice note. sent as a document, it will be sent as a voice note.
Returns: Returns:
The message containing the sent file. The message (or messages) containing the sent file.
""" """
as_photo = False # First check if the user passed an iterable, in which case
if isinstance(file, str): # we may want to send as an album if all are photo files.
lowercase_file = file.lower() if hasattr(file, '__iter__'):
as_photo = any( # Convert to tuple so we can iterate several times
lowercase_file.endswith(ext) file = tuple(x for x in file)
for ext in ('.png', '.jpg', '.gif', '.jpeg') if all(utils.is_image(x) for x in file):
return self._send_album(
entity, file, caption=caption,
progress_callback=progress_callback, reply_to=reply_to,
allow_cache=allow_cache
) )
# Not all are images, so send all the files one by one
return [
self.send_file(
entity, x, allow_cache=False,
caption=caption, force_document=force_document,
progress_callback=progress_callback, reply_to=reply_to,
attributes=attributes, thumb=thumb, **kwargs
) for x in file
]
file_handle = self.upload_file( file_handle = self.upload_file(
file, progress_callback=progress_callback, allow_cache=allow_cache) file, progress_callback=progress_callback, allow_cache=allow_cache)
if as_photo and not force_document: if utils.is_image(file) and not force_document:
media = InputMediaUploadedPhoto(file_handle, caption) media = InputMediaUploadedPhoto(file_handle, caption)
else: else:
mime_type = None mime_type = None
@ -945,14 +966,52 @@ class TelegramClient(TelegramBareClient):
attributes=attributes, thumb=thumb, **kwargs attributes=attributes, thumb=thumb, **kwargs
) )
def send_voice_note(self, entity, file, caption='', upload_progress=None, def send_voice_note(self, entity, file, caption='', progress_callback=None,
reply_to=None): reply_to=None):
"""Wrapper method around .send_file() with is_voice_note=()""" """Wrapper method around .send_file() with is_voice_note=()"""
return self.send_file(entity, file, caption, return self.send_file(entity, file, caption,
upload_progress=upload_progress, progress_callback=progress_callback,
reply_to=reply_to, reply_to=reply_to,
is_voice_note=()) # empty tuple is enough is_voice_note=()) # empty tuple is enough
def _send_album(self, entity, files, caption='',
progress_callback=None, reply_to=None,
allow_cache=True):
"""Specialized version of .send_file for albums"""
entity = self.get_input_entity(entity)
reply_to = self._get_reply_to(reply_to)
try:
# Need to upload the media first
media = [
self(UploadMediaRequest(entity, InputMediaUploadedPhoto(
self.upload_file(file),
caption=caption
)))
for file in files
]
# Now we can construct the multi-media request
result = self(SendMultiMediaRequest(
entity, reply_to_msg_id=reply_to, multi_media=[
InputSingleMedia(InputMediaPhoto(
InputPhoto(m.photo.id, m.photo.access_hash),
caption=caption
))
for m in media
]
))
return [
self._get_response_message(update.id, result)
for update in result.updates
if isinstance(update, UpdateMessageID)
]
except FilePartMissingError:
if not allow_cache:
raise
return self._send_album(
entity, files, allow_cache=False, caption=caption,
progress_callback=progress_callback, reply_to=reply_to
)
# endregion # endregion
# region Downloading media requests # region Downloading media requests

View File

@ -312,6 +312,12 @@ def get_input_media(media, user_caption=None, is_photo=False):
_raise_cast_fail(media, 'InputMedia') _raise_cast_fail(media, 'InputMedia')
def is_image(file):
"""Returns True if the file extension looks like an image file"""
return (isinstance(file, str) and
bool(re.search(r'\.(png|jpe?g|gif)$', file, re.IGNORECASE)))
def parse_phone(phone): def parse_phone(phone):
"""Parses the given phone, or returns None if it's invalid""" """Parses the given phone, or returns None if it's invalid"""
if isinstance(phone, int): if isinstance(phone, int):