From 2e31a686e86699387e2875804f732b5cb513f368 Mon Sep 17 00:00:00 2001 From: Lonami Exo Date: Fri, 2 Mar 2018 21:28:33 +0100 Subject: [PATCH] Upgrade to layer 75 Captions are now "messages" and also support message entities. --- .../extra/examples/working-with-messages.rst | 3 +- telethon/telegram_client.py | 36 +++++++++++++------ telethon/utils.py | 24 ++++--------- .../interactive_telegram_client.py | 4 +-- telethon_generator/scheme.tl | 36 +++++++++---------- 5 files changed, 52 insertions(+), 51 deletions(-) diff --git a/readthedocs/extra/examples/working-with-messages.rst b/readthedocs/extra/examples/working-with-messages.rst index ab38788c..e2471a25 100644 --- a/readthedocs/extra/examples/working-with-messages.rst +++ b/readthedocs/extra/examples/working-with-messages.rst @@ -114,8 +114,7 @@ send yourself the very first sticker you have: id=InputDocument( id=stickers.documents[0].id, access_hash=stickers.documents[0].access_hash - ), - caption='' + ) ) )) diff --git a/telethon/telegram_client.py b/telethon/telegram_client.py index 9690fcb4..24615ace 100644 --- a/telethon/telegram_client.py +++ b/telethon/telegram_client.py @@ -1128,6 +1128,7 @@ class TelegramClient(TelegramBareClient): attributes=None, thumb=None, allow_cache=True, + parse_mode='md', **kwargs): """ Sends a file to the specified entity. @@ -1177,6 +1178,9 @@ class TelegramClient(TelegramBareClient): Must be ``False`` if you wish to use different attributes or thumb than those that were used when the file was cached. + parse_mode (:obj:`str`, optional): + The parse mode for the caption message. + Kwargs: If "is_voice_note" in kwargs, despite its value, and the file is sent as a document, it will be sent as a voice note. @@ -1210,18 +1214,21 @@ class TelegramClient(TelegramBareClient): entity = self.get_input_entity(entity) reply_to = self._get_message_id(reply_to) + caption, msg_entities = self._parse_message_text(caption, parse_mode) if not isinstance(file, (str, bytes, io.IOBase)): # 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. try: - media = utils.get_input_media(file, user_caption=caption) + media = utils.get_input_media(file) except TypeError: pass # Can't turn whatever was given into media else: request = SendMediaRequest(entity, media, - reply_to_msg_id=reply_to) + reply_to_msg_id=reply_to, + message=caption, + entities=msg_entities) return self._get_response_message(request, self(request)) as_image = utils.is_image(file) and not force_document @@ -1234,11 +1241,11 @@ class TelegramClient(TelegramBareClient): if isinstance(file_handle, use_cache): # File was cached, so an instance of use_cache was returned if as_image: - media = InputMediaPhoto(file_handle, caption or '') + media = InputMediaPhoto(file_handle) else: - media = InputMediaDocument(file_handle, caption or '') + media = InputMediaDocument(file_handle) elif as_image: - media = InputMediaUploadedPhoto(file_handle, caption or '') + media = InputMediaUploadedPhoto(file_handle) else: mime_type = None if isinstance(file, str): @@ -1309,13 +1316,13 @@ class TelegramClient(TelegramBareClient): file=file_handle, mime_type=mime_type, attributes=list(attr_dict.values()), - caption=caption or '', **input_kw ) # Once the media type is properly specified and the file uploaded, # send the media message to the desired entity. - request = SendMediaRequest(entity, media, reply_to_msg_id=reply_to) + request = SendMediaRequest(entity, media, reply_to_msg_id=reply_to, + message=caption, entities=msg_entities) msg = self._get_response_message(request, self(request)) if msg and isinstance(file_handle, InputSizedFile): # There was a response message and we didn't use cached @@ -1335,15 +1342,18 @@ class TelegramClient(TelegramBareClient): return self.send_file(*args, **kwargs) def _send_album(self, entity, files, caption=None, - progress_callback=None, reply_to=None): + progress_callback=None, reply_to=None, + parse_mode='md'): """Specialized version of .send_file for albums""" # We don't care if the user wants to avoid cache, we will use it # anyway. Why? The cached version will be exactly the same thing # we need to produce right now to send albums (uploadMedia), and # cache only makes a difference for documents where the user may - # want the attributes used on them to change. Caption's ignored. + # want the attributes used on them to change. + # TODO Support a different captions for each file entity = self.get_input_entity(entity) caption = caption or '' + caption, msg_entities = self._parse_message_text(caption, parse_mode) reply_to = self._get_message_id(reply_to) # Need to upload the media first, but only if they're not cached yet @@ -1353,11 +1363,15 @@ class TelegramClient(TelegramBareClient): fh = self.upload_file(file, use_cache=InputPhoto) if not isinstance(fh, InputPhoto): input_photo = utils.get_input_photo(self(UploadMediaRequest( - entity, media=InputMediaUploadedPhoto(fh, caption) + entity, media=InputMediaUploadedPhoto(fh) )).photo) self.session.cache_file(fh.md5, fh.size, input_photo) fh = input_photo - media.append(InputSingleMedia(InputMediaPhoto(fh, caption))) + media.append(InputSingleMedia( + InputMediaPhoto(fh), + message=caption, + entities=msg_entities + )) # Now we can construct the multi-media request result = self(SendMultiMediaRequest( diff --git a/telethon/utils.py b/telethon/utils.py index ed93bdfa..faf69649 100644 --- a/telethon/utils.py +++ b/telethon/utils.py @@ -241,7 +241,7 @@ def get_input_geo(geo): _raise_cast_fail(geo, 'InputGeoPoint') -def get_input_media(media, user_caption=None, is_photo=False): +def get_input_media(media, is_photo=False): """Similar to get_input_peer, but for media. If the media is a file location and is_photo is known to be True, @@ -256,31 +256,23 @@ def get_input_media(media, user_caption=None, is_photo=False): if isinstance(media, MessageMediaPhoto): return InputMediaPhoto( id=get_input_photo(media.photo), - ttl_seconds=media.ttl_seconds, - caption=((media.caption if user_caption is None else user_caption) - or '') + ttl_seconds=media.ttl_seconds ) if isinstance(media, MessageMediaDocument): return InputMediaDocument( id=get_input_document(media.document), - ttl_seconds=media.ttl_seconds, - caption=((media.caption if user_caption is None else user_caption) - or '') + ttl_seconds=media.ttl_seconds ) if isinstance(media, FileLocation): if is_photo: - return InputMediaUploadedPhoto( - file=media, - caption=user_caption or '' - ) + return InputMediaUploadedPhoto(file=media) else: return InputMediaUploadedDocument( file=media, mime_type='application/octet-stream', # unknown, assume bytes - attributes=[DocumentAttributeFilename('unnamed')], - caption=user_caption or '' + attributes=[DocumentAttributeFilename('unnamed')] ) if isinstance(media, MessageMediaGame): @@ -291,7 +283,7 @@ def get_input_media(media, user_caption=None, is_photo=False): media = media.photo_small else: media = media.photo_big - return get_input_media(media, user_caption=user_caption, is_photo=True) + return get_input_media(media, is_photo=True) if isinstance(media, MessageMediaContact): return InputMediaContact( @@ -319,9 +311,7 @@ def get_input_media(media, user_caption=None, is_photo=False): return InputMediaEmpty() if isinstance(media, Message): - return get_input_media( - media.media, user_caption=user_caption, is_photo=is_photo - ) + return get_input_media(media.media, is_photo=is_photo) _raise_cast_fail(media, 'InputMedia') diff --git a/telethon_examples/interactive_telegram_client.py b/telethon_examples/interactive_telegram_client.py index f6986370..44185995 100644 --- a/telethon_examples/interactive_telegram_client.py +++ b/telethon_examples/interactive_telegram_client.py @@ -222,10 +222,8 @@ class InteractiveTelegramClient(TelegramClient): # Format the message content if getattr(msg, 'media', None): self.found_media[msg.id] = msg - # The media may or may not have a caption - caption = getattr(msg.media, 'caption', '') content = '<{}> {}'.format( - type(msg.media).__name__, caption) + type(msg.media).__name__, msg.message) elif hasattr(msg, 'message'): content = msg.message diff --git a/telethon_generator/scheme.tl b/telethon_generator/scheme.tl index 491f0c9e..a736b066 100644 --- a/telethon_generator/scheme.tl +++ b/telethon_generator/scheme.tl @@ -158,16 +158,16 @@ inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; inputMediaEmpty#9664f57f = InputMedia; -inputMediaUploadedPhoto#2f37e231 flags:# file:InputFile caption:string stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; -inputMediaPhoto#81fa373a flags:# id:InputPhoto caption:string ttl_seconds:flags.0?int = InputMedia; +inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; +inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia; inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia; -inputMediaUploadedDocument#e39621fd flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector caption:string stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; -inputMediaDocument#5acb668e flags:# id:InputDocument caption:string ttl_seconds:flags.0?int = InputMedia; +inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; +inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia; inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; inputMediaGifExternal#4843b0fd url:string q:string = InputMedia; -inputMediaPhotoExternal#922aec1 flags:# url:string caption:string ttl_seconds:flags.0?int = InputMedia; -inputMediaDocumentExternal#b6f74335 flags:# url:string caption:string ttl_seconds:flags.0?int = InputMedia; +inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia; +inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia; inputMediaGame#d33f43f3 id:InputGame = InputMedia; inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia; inputMediaGeoLive#7b1a118f geo_point:InputGeoPoint period:int = InputMedia; @@ -243,11 +243,11 @@ message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:fl messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; -messageMediaPhoto#b5223b0f flags:# photo:flags.0?Photo caption:flags.1?string ttl_seconds:flags.2?int = MessageMedia; +messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia; messageMediaUnsupported#9f84f49e = MessageMedia; -messageMediaDocument#7c4414d3 flags:# document:flags.0?Document caption:flags.1?string ttl_seconds:flags.2?int = MessageMedia; +messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia; messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia; messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; messageMediaGame#fdb19008 game:Game = MessageMedia; @@ -688,7 +688,7 @@ messages.foundGifs#450a1c0a next_offset:int results:Vector = messages. messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; messages.savedGifs#2e0709a5 hash:int gifs:Vector = messages.SavedGifs; -inputBotInlineMessageMediaAuto#292fed13 flags:# caption:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; +inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; @@ -700,7 +700,7 @@ inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_m inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; -botInlineMessageMediaAuto#a74b15b flags:# caption:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; +botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaVenue#4366232e flags:# geo:GeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; @@ -711,7 +711,7 @@ botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int users:Vector = messages.BotResults; -exportedMessageLink#1f486803 link:string = ExportedMessageLink; +exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; messageFwdHeader#559ebe6d flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader; @@ -896,7 +896,7 @@ langPackDifference#f385c1f6 lang_code:string from_version:int version:int string langPackLanguage#117698f1 name:string native_name:string lang_code:string = LangPackLanguage; -channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true manage_call:flags.10?true = ChannelAdminRights; +channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true = ChannelAdminRights; channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights; @@ -938,7 +938,7 @@ recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; -inputSingleMedia#5eaa7809 media:InputMedia random_id:long = InputSingleMedia; +inputSingleMedia#31bc3d25 media:InputMedia flags:# random_id:long message:string entities:flags.0?Vector = InputSingleMedia; ---functions--- @@ -966,7 +966,7 @@ auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentC auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; -account.registerDevice#f75874d1 token_type:int token:string other_uids:Vector = Bool; +account.registerDevice#1389cc token_type:int token:string app_sandbox:Bool other_uids:Vector = Bool; account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; @@ -1023,7 +1023,7 @@ messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = me messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool; messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; -messages.sendMedia#c8f16791 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates; +messages.sendMedia#b8d1262b flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Updates; messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; @@ -1035,7 +1035,6 @@ messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates; messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates; messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates; messages.createChat#9cb126e users:Vector title:string = Updates; -messages.forwardMessage#33963bf9 peer:InputPeer id:int random_id:long = Updates; messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; @@ -1048,8 +1047,9 @@ messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long da messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; +messages.getStickers#ae22e045 emoticon:string hash:string = messages.Stickers; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; -messages.getWebPagePreview#25223e24 message:string = MessageMedia; +messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; @@ -1199,4 +1199,4 @@ langpack.getStrings#2e1ee318 lang_code:string keys:Vector = Vector; -// LAYER 74 +// LAYER 75