Skip to content

Commit 2f3bcd7

Browse files
committed
Add Message.copy bound method
1 parent c606f83 commit 2f3bcd7

3 files changed

Lines changed: 194 additions & 102 deletions

File tree

compiler/docs/compiler.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ def get_title_list(s: str) -> list:
432432
Message.delete
433433
Message.download
434434
Message.forward
435+
Message.copy
435436
Message.pin
436437
Message.edit_text
437438
Message.edit_caption

pyrogram/methods/messages/copy_messages.py

Lines changed: 12 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
1818

1919
import logging
20-
from functools import partial
21-
from typing import Union, Iterable, List
20+
from typing import Union, List
2221

2322
from pyrogram import types
2423
from pyrogram.scaffold import Scaffold
@@ -31,7 +30,7 @@ async def copy_messages(
3130
self,
3231
chat_id: Union[int, str],
3332
from_chat_id: Union[int, str],
34-
message_id: Union[int, Iterable[int]],
33+
message_id: int,
3534
caption: str = None,
3635
parse_mode: Union[str, None] = object,
3736
caption_entities: List["types.MessageEntity"] = None,
@@ -105,102 +104,13 @@ async def copy_messages(
105104
"""
106105
message: types.Message = await self.get_messages(from_chat_id, message_id)
107106

108-
if message.service:
109-
log.warning(f"Service messages cannot be copied. "
110-
f"chat_id: {message.chat.id}, message_id: {message.message_id}")
111-
elif message.game and not await self.storage.is_bot():
112-
log.warning(f"Users cannot send messages with Game media type. "
113-
f"chat_id: {message.chat.id}, message_id: {message.message_id}")
114-
elif message.text:
115-
return await self.send_message(
116-
chat_id,
117-
text=message.text,
118-
entities=message.entities,
119-
disable_web_page_preview=not message.web_page,
120-
disable_notification=disable_notification,
121-
schedule_date=schedule_date
122-
)
123-
elif message.media:
124-
send_media = partial(
125-
self.send_cached_media,
126-
chat_id=chat_id,
127-
disable_notification=disable_notification,
128-
reply_to_message_id=reply_to_message_id,
129-
schedule_date=schedule_date,
130-
reply_markup=reply_markup
131-
)
132-
133-
if message.photo:
134-
file_id = message.photo.file_id
135-
elif message.audio:
136-
file_id = message.audio.file_id
137-
elif message.document:
138-
file_id = message.document.file_id
139-
elif message.video:
140-
file_id = message.video.file_id
141-
elif message.animation:
142-
file_id = message.animation.file_id
143-
elif message.voice:
144-
file_id = message.voice.file_id
145-
elif message.sticker:
146-
file_id = message.sticker.file_id
147-
elif message.video_note:
148-
file_id = message.video_note.file_id
149-
elif message.contact:
150-
return await self.send_contact(
151-
chat_id,
152-
phone_number=message.contact.phone_number,
153-
first_name=message.contact.first_name,
154-
last_name=message.contact.last_name,
155-
vcard=message.contact.vcard,
156-
disable_notification=disable_notification,
157-
schedule_date=schedule_date
158-
)
159-
elif message.location:
160-
return await self.send_location(
161-
chat_id,
162-
latitude=message.location.latitude,
163-
longitude=message.location.longitude,
164-
disable_notification=disable_notification,
165-
schedule_date=schedule_date
166-
)
167-
elif message.venue:
168-
return await self.send_venue(
169-
chat_id,
170-
latitude=message.venue.location.latitude,
171-
longitude=message.venue.location.longitude,
172-
title=message.venue.title,
173-
address=message.venue.address,
174-
foursquare_id=message.venue.foursquare_id,
175-
foursquare_type=message.venue.foursquare_type,
176-
disable_notification=disable_notification,
177-
schedule_date=schedule_date
178-
)
179-
elif message.poll:
180-
return await self.send_poll(
181-
chat_id,
182-
question=message.poll.question,
183-
options=[opt.text for opt in message.poll.options],
184-
disable_notification=disable_notification,
185-
schedule_date=schedule_date
186-
)
187-
elif message.game:
188-
return await self.send_game(
189-
chat_id,
190-
game_short_name=message.game.short_name,
191-
disable_notification=disable_notification
192-
)
193-
else:
194-
raise ValueError("Unknown media type")
195-
196-
if message.sticker or message.video_note: # Sticker and VideoNote should have no caption
197-
return await send_media(file_id=file_id)
198-
else:
199-
return await send_media(
200-
file_id=file_id,
201-
caption=caption if caption is not None else message.caption,
202-
parse_mode=parse_mode,
203-
caption_entities=caption_entities or message.caption_entities
204-
)
205-
else:
206-
raise ValueError("Can't copy this message")
107+
return await message.copy(
108+
chat_id=chat_id,
109+
caption=caption,
110+
parse_mode=parse_mode,
111+
caption_entities=caption_entities,
112+
disable_notification=disable_notification,
113+
reply_to_message_id=reply_to_message_id,
114+
schedule_date=schedule_date,
115+
reply_markup=reply_markup
116+
)

pyrogram/types/messages_and_media/message.py

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
1818

1919
import logging
20+
from functools import partial
2021
from typing import List, Match, Union, BinaryIO
2122

2223
import pyrogram
@@ -2751,6 +2752,186 @@ async def forward(
27512752
schedule_date=schedule_date
27522753
)
27532754

2755+
async def copy(
2756+
self,
2757+
chat_id: Union[int, str],
2758+
caption: str = None,
2759+
parse_mode: Union[str, None] = object,
2760+
caption_entities: List["types.MessageEntity"] = None,
2761+
disable_notification: bool = None,
2762+
reply_to_message_id: int = None,
2763+
schedule_date: int = None,
2764+
reply_markup: Union[
2765+
"types.InlineKeyboardMarkup",
2766+
"types.ReplyKeyboardMarkup",
2767+
"types.ReplyKeyboardRemove",
2768+
"types.ForceReply"
2769+
] = None
2770+
) -> Union["types.Message", List["types.Message"]]:
2771+
"""Bound method *copy* of :obj:`~pyrogram.types.Message`.
2772+
2773+
Use as a shortcut for:
2774+
2775+
.. code-block:: python
2776+
2777+
client.copy_message(
2778+
chat_id=chat_id,
2779+
from_chat_id=message.chat.id,
2780+
message_ids=message.message_id
2781+
)
2782+
2783+
Example:
2784+
.. code-block:: python
2785+
2786+
message.copy(chat_id)
2787+
2788+
Parameters:
2789+
chat_id (``int`` | ``str``):
2790+
Unique identifier (int) or username (str) of the target chat.
2791+
For your personal cloud (Saved Messages) you can simply use "me" or "self".
2792+
For a contact that exists in your Telegram address book you can use his phone number (str).
2793+
2794+
caption (``string``, *optional*):
2795+
New caption for media, 0-1024 characters after entities parsing.
2796+
If not specified, the original caption is kept.
2797+
Pass "" (empty string) to remove the caption.
2798+
2799+
parse_mode (``str``, *optional*):
2800+
By default, texts are parsed using both Markdown and HTML styles.
2801+
You can combine both syntaxes together.
2802+
Pass "markdown" or "md" to enable Markdown-style parsing only.
2803+
Pass "html" to enable HTML-style parsing only.
2804+
Pass None to completely disable style parsing.
2805+
2806+
caption_entities (List of :obj:`~pyrogram.types.MessageEntity`):
2807+
List of special entities that appear in the new caption, which can be specified instead of __parse_mode__.
2808+
2809+
disable_notification (``bool``, *optional*):
2810+
Sends the message silently.
2811+
Users will receive a notification with no sound.
2812+
2813+
reply_to_message_id (``int``, *optional*):
2814+
If the message is a reply, ID of the original message.
2815+
2816+
schedule_date (``int``, *optional*):
2817+
Date when the message will be automatically sent. Unix time.
2818+
2819+
reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*):
2820+
Additional interface options. An object for an inline keyboard, custom reply keyboard,
2821+
instructions to remove reply keyboard or to force a reply from the user.
2822+
2823+
Returns:
2824+
:obj:`~pyrogram.types.Message`: On success, the copied message is returned.
2825+
2826+
Raises:
2827+
RPCError: In case of a Telegram RPC error.
2828+
"""
2829+
if self.service:
2830+
log.warning(f"Service messages cannot be copied. "
2831+
f"chat_id: {self.chat.id}, message_id: {self.message_id}")
2832+
elif self.game and not await self._client.storage.is_bot():
2833+
log.warning(f"Users cannot send messages with Game media type. "
2834+
f"chat_id: {self.chat.id}, message_id: {self.message_id}")
2835+
elif self.text:
2836+
return await self._client.send_message(
2837+
chat_id,
2838+
text=self.text,
2839+
entities=self.entities,
2840+
disable_web_page_preview=not self.web_page,
2841+
disable_notification=disable_notification,
2842+
reply_to_message_id=reply_to_message_id,
2843+
schedule_date=schedule_date,
2844+
reply_markup=reply_markup
2845+
)
2846+
elif self.media:
2847+
send_media = partial(
2848+
self._client.send_cached_media,
2849+
chat_id=chat_id,
2850+
disable_notification=disable_notification,
2851+
reply_to_message_id=reply_to_message_id,
2852+
schedule_date=schedule_date,
2853+
reply_markup=reply_markup
2854+
)
2855+
2856+
if self.photo:
2857+
file_id = self.photo.file_id
2858+
elif self.audio:
2859+
file_id = self.audio.file_id
2860+
elif self.document:
2861+
file_id = self.document.file_id
2862+
elif self.video:
2863+
file_id = self.video.file_id
2864+
elif self.animation:
2865+
file_id = self.animation.file_id
2866+
elif self.voice:
2867+
file_id = self.voice.file_id
2868+
elif self.sticker:
2869+
file_id = self.sticker.file_id
2870+
elif self.video_note:
2871+
file_id = self.video_note.file_id
2872+
elif self.contact:
2873+
return await self._client.send_contact(
2874+
chat_id,
2875+
phone_number=self.contact.phone_number,
2876+
first_name=self.contact.first_name,
2877+
last_name=self.contact.last_name,
2878+
vcard=self.contact.vcard,
2879+
disable_notification=disable_notification,
2880+
schedule_date=schedule_date
2881+
)
2882+
elif self.location:
2883+
return await self._client.send_location(
2884+
chat_id,
2885+
latitude=self.location.latitude,
2886+
longitude=self.location.longitude,
2887+
disable_notification=disable_notification,
2888+
schedule_date=schedule_date
2889+
)
2890+
elif self.venue:
2891+
return await self._client.send_venue(
2892+
chat_id,
2893+
latitude=self.venue.location.latitude,
2894+
longitude=self.venue.location.longitude,
2895+
title=self.venue.title,
2896+
address=self.venue.address,
2897+
foursquare_id=self.venue.foursquare_id,
2898+
foursquare_type=self.venue.foursquare_type,
2899+
disable_notification=disable_notification,
2900+
schedule_date=schedule_date
2901+
)
2902+
elif self.poll:
2903+
return await self._client.send_poll(
2904+
chat_id,
2905+
question=self.poll.question,
2906+
options=[opt.text for opt in self.poll.options],
2907+
disable_notification=disable_notification,
2908+
schedule_date=schedule_date
2909+
)
2910+
elif self.game:
2911+
return await self._client.send_game(
2912+
chat_id,
2913+
game_short_name=self.game.short_name,
2914+
disable_notification=disable_notification
2915+
)
2916+
else:
2917+
raise ValueError("Unknown media type")
2918+
2919+
if self.sticker or self.video_note: # Sticker and VideoNote should have no caption
2920+
return await send_media(file_id=file_id)
2921+
else:
2922+
if caption is None:
2923+
caption = self.caption
2924+
caption_entities = self.caption_entities
2925+
2926+
return await send_media(
2927+
file_id=file_id,
2928+
caption=caption,
2929+
parse_mode=parse_mode,
2930+
caption_entities=caption_entities
2931+
)
2932+
else:
2933+
raise ValueError("Can't copy this message")
2934+
27542935
async def delete(self, revoke: bool = True):
27552936
"""Bound method *delete* of :obj:`~pyrogram.types.Message`.
27562937

0 commit comments

Comments
 (0)