mirror of
				https://github.com/LonamiWebs/Telethon.git
				synced 2025-10-30 23:47:33 +03:00 
			
		
		
		
	Support sending scheduled messages
This commit is contained in:
		
							parent
							
								
									9dd73cd494
								
							
						
					
					
						commit
						dab237e758
					
				|  | @ -123,6 +123,7 @@ class MessageParseMethods: | |||
| 
 | ||||
|         random_to_id = {} | ||||
|         id_to_message = {} | ||||
|         sched_to_message = {}  # scheduled IDs may collide with normal IDs | ||||
|         for update in updates: | ||||
|             if isinstance(update, types.UpdateMessageID): | ||||
|                 random_to_id[update.random_id] = update.id | ||||
|  | @ -145,12 +146,30 @@ class MessageParseMethods: | |||
|                     update.message._finish_init(self, entities, input_chat) | ||||
|                     return update.message | ||||
| 
 | ||||
|             elif isinstance(update, types.UpdateNewScheduledMessage): | ||||
|                 update.message._finish_init(self, entities, input_chat) | ||||
|                 sched_to_message[update.message.id] = update.message | ||||
| 
 | ||||
|         if request is None: | ||||
|             return id_to_message | ||||
| 
 | ||||
|         # Use the scheduled mapping if we got a request with a scheduled message | ||||
|         # | ||||
|         # This breaks if the schedule date is too young, however, since the message | ||||
|         # is sent immediately, so have a fallback. | ||||
|         if getattr(request, 'schedule_date', None) is None: | ||||
|             mapping = id_to_message | ||||
|             opposite = {}  # if there's no schedule it can never be scheduled | ||||
|         else: | ||||
|             mapping = sched_to_message | ||||
|             opposite = id_to_message  # scheduled may be treated as normal, though | ||||
| 
 | ||||
|         random_id = request if isinstance(request, int) else request.random_id | ||||
|         if not utils.is_list_like(random_id): | ||||
|             msg = id_to_message.get(random_to_id.get(random_id)) | ||||
|             msg = mapping.get(random_to_id.get(random_id)) | ||||
|             if not msg: | ||||
|                 msg = opposite.get(random_to_id.get(random_id)) | ||||
| 
 | ||||
|             if not msg: | ||||
|                 self._log[__name__].warning( | ||||
|                     'Request %s had missing message mapping %s', request, result) | ||||
|  | @ -158,15 +177,22 @@ class MessageParseMethods: | |||
|             return msg | ||||
| 
 | ||||
|         try: | ||||
|             return [id_to_message[random_to_id[rnd]] for rnd in random_id] | ||||
|             return [mapping[random_to_id[rnd]] for rnd in random_id] | ||||
|         except KeyError: | ||||
|             # Sometimes forwards fail (`MESSAGE_ID_INVALID` if a message gets | ||||
|             # deleted or `WORKER_BUSY_TOO_LONG_RETRY` if there are issues at | ||||
|             # Telegram), in which case we get some "missing" message mappings. | ||||
|             # Log them with the hope that we can better work around them. | ||||
|             self._log[__name__].warning( | ||||
|                 'Request %s had missing message mappings %s', request, result) | ||||
|             try: | ||||
|                 return [opposite[random_to_id[rnd]] for rnd in random_id] | ||||
|             except KeyError: | ||||
|                 # Sometimes forwards fail (`MESSAGE_ID_INVALID` if a message gets | ||||
|                 # deleted or `WORKER_BUSY_TOO_LONG_RETRY` if there are issues at | ||||
|                 # Telegram), in which case we get some "missing" message mappings. | ||||
|                 # Log them with the hope that we can better work around them. | ||||
|                 self._log[__name__].warning( | ||||
|                     'Request %s had missing message mappings %s', request, result) | ||||
| 
 | ||||
|             return [id_to_message.get(random_to_id.get(rnd)) for rnd in random_to_id] | ||||
|         return [ | ||||
|             mapping.get(random_to_id.get(rnd)) | ||||
|             or opposite.get(random_to_id.get(rnd)) | ||||
|             for rnd in random_to_id | ||||
|         ] | ||||
| 
 | ||||
|     # endregion | ||||
|  |  | |||
|  | @ -536,7 +536,9 @@ class MessageMethods: | |||
|             force_document: bool = False, | ||||
|             clear_draft: bool = False, | ||||
|             buttons: 'hints.MarkupLike' = None, | ||||
|             silent: bool = None) -> 'types.Message': | ||||
|             silent: bool = None, | ||||
|             schedule: 'hints.DateLike' = None | ||||
|     ) -> 'types.Message': | ||||
|         """ | ||||
|         Sends a message to the specified user, chat or channel. | ||||
| 
 | ||||
|  | @ -609,6 +611,11 @@ class MessageMethods: | |||
|                 channel or not. Defaults to `False`, which means it will | ||||
|                 notify them. Set it to `True` to alter this behaviour. | ||||
| 
 | ||||
|             schedule (`hints.DateLike`, optional): | ||||
|                 If set, the message won't send immediately, and instead | ||||
|                 it will be scheduled to be automatically sent at a later | ||||
|                 time. | ||||
| 
 | ||||
|         Returns | ||||
|             The sent `custom.Message <telethon.tl.custom.message.Message>`. | ||||
| 
 | ||||
|  | @ -663,6 +670,10 @@ class MessageMethods: | |||
|                 # Forcing replies or clearing buttons. | ||||
|                 await client.send_message(chat, 'Reply to me', buttons=Button.force_reply()) | ||||
|                 await client.send_message(chat, 'Bye Keyboard!', buttons=Button.clear()) | ||||
| 
 | ||||
|                 # Scheduling a message to be sent after 5 minutes | ||||
|                 from datetime import timedelta | ||||
|                 await client.send_message(chat, 'Hi, future!', schedule=timedelta(minutes=5)) | ||||
|         """ | ||||
|         if file is not None: | ||||
|             return await self.send_file( | ||||
|  | @ -690,7 +701,8 @@ class MessageMethods: | |||
|                     silent=silent, | ||||
|                     reply_to=reply_to, | ||||
|                     buttons=markup, | ||||
|                     entities=message.entities | ||||
|                     entities=message.entities, | ||||
|                     schedule=schedule | ||||
|                 ) | ||||
| 
 | ||||
|             request = functions.messages.SendMessageRequest( | ||||
|  | @ -702,7 +714,8 @@ class MessageMethods: | |||
|                 entities=message.entities, | ||||
|                 clear_draft=clear_draft, | ||||
|                 no_webpage=not isinstance( | ||||
|                     message.media, types.MessageMediaWebPage) | ||||
|                     message.media, types.MessageMediaWebPage), | ||||
|                 schedule_date=schedule | ||||
|             ) | ||||
|             message = message.message | ||||
|         else: | ||||
|  | @ -720,7 +733,8 @@ class MessageMethods: | |||
|                 reply_to_msg_id=utils.get_message_id(reply_to), | ||||
|                 clear_draft=clear_draft, | ||||
|                 silent=silent, | ||||
|                 reply_markup=self.build_reply_markup(buttons) | ||||
|                 reply_markup=self.build_reply_markup(buttons), | ||||
|                 schedule_date=schedule | ||||
|             ) | ||||
| 
 | ||||
|         result = await self(request) | ||||
|  | @ -747,7 +761,9 @@ class MessageMethods: | |||
|             from_peer: 'hints.EntityLike' = None, | ||||
|             *, | ||||
|             silent: bool = None, | ||||
|             as_album: bool = None) -> 'typing.Sequence[types.Message]': | ||||
|             as_album: bool = None, | ||||
|             schedule: 'hints.DateLike' = None | ||||
|     ) -> 'typing.Sequence[types.Message]': | ||||
|         """ | ||||
|         Forwards the given messages to the specified entity. | ||||
| 
 | ||||
|  | @ -787,6 +803,11 @@ class MessageMethods: | |||
|                 `True` will group always (even converting separate | ||||
|                 images into albums), and `False` will never group. | ||||
| 
 | ||||
|             schedule (`hints.DateLike`, optional): | ||||
|                 If set, the message(s) won't forward immediately, and | ||||
|                 instead they will be scheduled to be automatically sent | ||||
|                 at a later time. | ||||
| 
 | ||||
|         Returns | ||||
|             The list of forwarded `Message <telethon.tl.custom.message.Message>`, | ||||
|             or a single one if a list wasn't provided as input. | ||||
|  | @ -873,7 +894,8 @@ class MessageMethods: | |||
|                 # Trying to send a single message as grouped will cause | ||||
|                 # GROUPED_MEDIA_INVALID. If more than one message is forwarded | ||||
|                 # (even without media...), this error goes away. | ||||
|                 grouped=len(chunk) > 1 and grouped | ||||
|                 grouped=len(chunk) > 1 and grouped, | ||||
|                 schedule_date=schedule | ||||
|             ) | ||||
|             result = await self(req) | ||||
|             sent.extend(self._get_response_message(req, result, entity)) | ||||
|  | @ -889,7 +911,9 @@ class MessageMethods: | |||
|             parse_mode: str = (), | ||||
|             link_preview: bool = True, | ||||
|             file: 'hints.FileLike' = None, | ||||
|             buttons: 'hints.MarkupLike' = None) -> 'types.Message': | ||||
|             buttons: 'hints.MarkupLike' = None, | ||||
|             schedule: 'hints.DateLike' = None | ||||
|     ) -> 'types.Message': | ||||
|         """ | ||||
|         Edits the given message to change its text or media. | ||||
| 
 | ||||
|  | @ -936,6 +960,14 @@ class MessageMethods: | |||
|                 you have signed in as a bot. You can also pass your own | ||||
|                 :tl:`ReplyMarkup` here. | ||||
| 
 | ||||
|             schedule (`hints.DateLike`, optional): | ||||
|                 If set, the message won't be edited immediately, and instead | ||||
|                 it will be scheduled to be automatically edited at a later | ||||
|                 time. | ||||
| 
 | ||||
|                 Note that this parameter will have no effect if you are | ||||
|                 trying to edit a message that was sent via inline bots. | ||||
| 
 | ||||
|         Returns | ||||
|             The edited `Message <telethon.tl.custom.message.Message>`, | ||||
|             unless `entity` was a :tl:`InputBotInlineMessageID` in which | ||||
|  | @ -993,7 +1025,8 @@ class MessageMethods: | |||
|             no_webpage=not link_preview, | ||||
|             entities=msg_entities, | ||||
|             media=media, | ||||
|             reply_markup=self.build_reply_markup(buttons) | ||||
|             reply_markup=self.build_reply_markup(buttons), | ||||
|             schedule_date=schedule | ||||
|         ) | ||||
|         msg = self._get_response_message(request, await self(request), entity) | ||||
|         await self._cache_media(msg, file, file_handle, image=image) | ||||
|  |  | |||
|  | @ -104,6 +104,7 @@ class UploadMethods: | |||
|             buttons: 'hints.MarkupLike' = None, | ||||
|             silent: bool = None, | ||||
|             supports_streaming: bool = False, | ||||
|             schedule: 'hints.DateLike' = None, | ||||
|             **kwargs) -> 'types.Message': | ||||
|         """ | ||||
|         Sends message with the given file to the specified entity. | ||||
|  | @ -230,6 +231,11 @@ class UploadMethods: | |||
|                 these to MP4 before sending if you want them to be streamable. | ||||
|                 Unsupported formats will result in ``VideoContentTypeError``. | ||||
| 
 | ||||
|             schedule (`hints.DateLike`, optional): | ||||
|                 If set, the file won't send immediately, and instead | ||||
|                 it will be scheduled to be automatically sent at a later | ||||
|                 time. | ||||
| 
 | ||||
|         Returns | ||||
|             The `Message <telethon.tl.custom.message.Message>` (or messages) | ||||
|             containing the sent file, or messages if a list of them was passed. | ||||
|  | @ -295,7 +301,7 @@ class UploadMethods: | |||
|                 result += await self._send_album( | ||||
|                     entity, images[:10], caption=image_captions[:10], | ||||
|                     progress_callback=progress_callback, reply_to=reply_to, | ||||
|                     parse_mode=parse_mode, silent=silent | ||||
|                     parse_mode=parse_mode, silent=silent, schedule=schedule | ||||
|                 ) | ||||
|                 images = images[10:] | ||||
|                 image_captions = image_captions[10:] | ||||
|  | @ -307,7 +313,7 @@ class UploadMethods: | |||
|                     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, | ||||
|                     supports_streaming=supports_streaming, schedule=schedule, | ||||
|                     **kwargs | ||||
|                 )) | ||||
| 
 | ||||
|  | @ -339,7 +345,8 @@ class UploadMethods: | |||
|         markup = self.build_reply_markup(buttons) | ||||
|         request = functions.messages.SendMediaRequest( | ||||
|             entity, media, reply_to_msg_id=reply_to, message=caption, | ||||
|             entities=msg_entities, reply_markup=markup, silent=silent | ||||
|             entities=msg_entities, reply_markup=markup, silent=silent, | ||||
|             schedule_date=schedule | ||||
|         ) | ||||
|         msg = self._get_response_message(request, await self(request), entity) | ||||
|         await self._cache_media(msg, file, file_handle, image=image) | ||||
|  | @ -348,7 +355,7 @@ class UploadMethods: | |||
| 
 | ||||
|     async def _send_album(self: 'TelegramClient', entity, files, caption='', | ||||
|                           progress_callback=None, reply_to=None, | ||||
|                           parse_mode=(), silent=None): | ||||
|                           parse_mode=(), silent=None, schedule=None): | ||||
|         """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 | ||||
|  | @ -398,7 +405,8 @@ class UploadMethods: | |||
| 
 | ||||
|         # Now we can construct the multi-media request | ||||
|         result = await self(functions.messages.SendMultiMediaRequest( | ||||
|             entity, reply_to_msg_id=reply_to, multi_media=media, silent=silent | ||||
|             entity, reply_to_msg_id=reply_to, multi_media=media, | ||||
|             silent=silent, schedule_date=schedule | ||||
|         )) | ||||
| 
 | ||||
|         # We never sent a `random_id` for the messages that resulted from | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user